Files
degvi/View.c
2013-02-10 23:54:06 +09:00

328 lines
5.8 KiB
C

#include "init.h"
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include "View.h"
View View_create(Window window, Text text, int tabWidth)
{
View this;
this = malloc(sizeof(struct View_struct));
if (this == NULL) {
fprintf(stderr, "malloc failed\n");
exit(EXIT_FAILURE);
}
this->window = window;
this->text = text;
this->tabWidth = tabWidth;
this->origin = 0;
this->cursorLine = 0;
this->cursorCharacter = 0;
return this;
}
void View_destroy(View this)
{
if (this == NULL) {
return;
}
free(this);
}
void View_setTabWidth(View this, int tabWidth)
{
this->tabWidth = tabWidth;
}
static void toView(View this, int lineIndex, int characterIndex, int *resultX, int *resultY)
{
int x;
int y;
int j;
assert(lineIndex >= this->origin);
y = 0;
for (j = this->origin; j <= lineIndex; j++) {
Line line;
int i;
line = Text_getLine(this->text, j);
x = 0;
for (i = 0; i < Line_size(line); i++) {
Character c;
if (j == lineIndex && i == characterIndex) {
break;
}
c = Line_getCharacter(line, i);
if (c == '\t') {
x = x / this->tabWidth * this->tabWidth + this->tabWidth;
} else {
x += Character_width(c);
}
if (x >= Window_width(this->window)) {
x = 0;
y++;
}
}
if (j < lineIndex) {
y++;
}
}
*resultX = x;
*resultY = y;
}
void View_updateCursorPosition(View this)
{
int x;
int y;
if (Text_size(this->text) < 1) {
x = 0;
y = 0;
} else {
toView(this, this->cursorLine, this->cursorCharacter, &x, &y);
}
Window_setCursorPosition(this->window, x, y);
}
void View_paint(View this)
{
int lineIndex;
int y;
int i;
lineIndex = this->origin;
y = 0;
for (;;) {
int x;
int k;
Window_setCursorPosition(this->window, 0, y);
x = 0;
if (lineIndex < Text_size(this->text)) {
Line line;
line = Text_getLine(this->text, lineIndex);
lineIndex++;
for (i = 0; i < Line_size(line); i++) {
Character c;
c = Line_getCharacter(line, i);
if (c == '\t') {
int x2;
int l;
x2 = x / this->tabWidth * this->tabWidth + this->tabWidth;
for (l = x; l < x2; l++) {
fputc(' ', stdout);
}
x = x2;
} else {
Character_write(c, stdout);
x += Character_width(c);
}
if (x >= Window_width(this->window)) {
x = 0;
y++;
if (y >= Window_height(this->window)) {
break;
}
Window_setCursorPosition(this->window, 0, y);
}
}
} else {
fputc('~', stdout);
x++;
}
for (k = x; k < Window_width(this->window); k++) {
fputc(' ', stdout);
}
y++;
if (y >= Window_height(this->window)) {
break;
}
}
}
int View_lastLineIndex(View this)
{
int x;
int y;
int j;
if (Text_size(this->text) < 1) {
return 0;
}
y = 0;
j = this->origin;
for (;;) {
Line line;
int i;
line = Text_getLine(this->text, j);
x = 0;
for (i = 0; i < Line_size(line); i++) {
Character c;
c = Line_getCharacter(line, i);
if (c == '\t') {
x = x / this->tabWidth * this->tabWidth + this->tabWidth;
} else {
x++;
}
if (x >= Window_width(this->window)) {
x = 0;
y++;
}
}
y++;
if (y == Window_height(this->window)) {
break;
} else if (y > Window_height(this->window)) {
j--;
break;
} else if (j >= Text_size(this->text) - 1) {
break;
} else {
j++;
}
}
return j;
}
void View_moveToTop(View this)
{
this->cursorLine = 0;
this->cursorCharacter = 0;
this->origin = 0;
View_paint(this);
View_updateCursorPosition(this);
}
void View_moveToLine(View this, int index)
{
if (Text_size(this->text) < 1) {
return;
}
assert(index >= 0 && index < Text_size(this->text));
this->cursorLine = index;
this->cursorCharacter = 0;
this->origin = this->cursorLine;
View_paint(this);
View_updateCursorPosition(this);
}
void View_moveToHead(View this)
{
this->cursorCharacter = 0;
View_updateCursorPosition(this);
}
void View_moveToTail(View this)
{
Line line;
if (Text_size(this->text) < 1) {
return;
}
line = Text_getLine(this->text, this->cursorLine);
if (Line_size(line) < 1) {
return;
}
this->cursorCharacter = Line_size(line) - 1;
View_updateCursorPosition(this);
}
void View_moveUp(View this, int repeat)
{
int size;
if (Text_size(this->text) < 1) {
return;
}
this->cursorLine -= repeat;
if (this->cursorLine < 0) {
this->cursorLine = 0;
}
size = Line_size(Text_getLine(this->text, this->cursorLine));
if (size < 1) {
this->cursorCharacter = 0;
} else if (this->cursorCharacter >= size) {
this->cursorCharacter = size - 1;
}
if (this->cursorLine < this->origin) {
this->origin = this->cursorLine;
View_paint(this);
}
View_updateCursorPosition(this);
}
void View_moveDown(View this, int repeat)
{
int size;
int lastLine;
if (this->cursorLine >= Text_size(this->text) - 1) {
return;
}
this->cursorLine += repeat;
if (this->cursorLine >= Text_size(this->text)) {
this->cursorLine = Text_size(this->text) - 1;
if (this->cursorLine < 0) {
this->cursorLine = 0;
}
}
size = Line_size(Text_getLine(this->text, this->cursorLine));
if (size < 1) {
this->cursorCharacter = 0;
} else if (this->cursorCharacter >= size) {
this->cursorCharacter = size - 1;
}
lastLine = View_lastLineIndex(this);
if (this->cursorLine > lastLine) {
this->origin += this->cursorLine - lastLine;
View_paint(this);
}
View_updateCursorPosition(this);
}
void View_moveLeft(View this, int repeat)
{
this->cursorCharacter -= repeat;
if (this->cursorCharacter < 0) {
this->cursorCharacter = 0;
}
View_updateCursorPosition(this);
}
void View_moveRight(View this, int repeat)
{
if (Text_size(this->text) < 1) {
return;
}
this->cursorCharacter += repeat;
if (this->cursorCharacter >= Line_size(Text_getLine(this->text, this->cursorLine))) {
this->cursorCharacter = Line_size(Text_getLine(this->text, this->cursorLine)) - 1;
if (this->cursorCharacter < 0) {
this->cursorCharacter = 0;
}
}
View_updateCursorPosition(this);
}