Sorry about the mega-patch.

This is a work-in-progress, code is currently broken.
(Some actions, and notably, the header, are missing.)
This commit is contained in:
Hisham Muhammad
2015-01-21 23:27:31 -02:00
parent 36b7832884
commit 3383d8e556
51 changed files with 2011 additions and 1777 deletions

179
Panel.c
View File

@ -28,9 +28,11 @@ in the source distribution for its full text.
typedef struct Panel_ Panel;
typedef enum HandlerResult_ {
HANDLED,
IGNORED,
BREAK_LOOP
HANDLED = 0x00,
IGNORED = 0x01,
BREAK_LOOP = 0x02,
REFRESH = 0x04,
RECALCULATE = 0x08,
} HandlerResult;
#define EVENT_SETSELECTED -1
@ -54,7 +56,7 @@ struct Panel_ {
Vector* items;
int selected;
int oldSelected;
char* eventHandlerBuffer;
void* eventHandlerState;
int scrollV;
short scrollH;
bool needsRedraw;
@ -102,7 +104,7 @@ void Panel_init(Panel* this, int x, int y, int w, int h, ObjectClass* type, bool
this->y = y;
this->w = w;
this->h = h;
this->eventHandlerBuffer = NULL;
this->eventHandlerState = NULL;
this->items = Vector_new(type, owner, DEFAULT_SIZE);
this->scrollV = 0;
this->scrollH = 0;
@ -114,7 +116,7 @@ void Panel_init(Panel* this, int x, int y, int w, int h, ObjectClass* type, bool
void Panel_done(Panel* this) {
assert (this != NULL);
free(this->eventHandlerBuffer);
free(this->eventHandlerState);
Vector_delete(this->items);
RichString_end(this->header);
}
@ -246,30 +248,11 @@ void Panel_setSelected(Panel* this, int selected) {
void Panel_draw(Panel* this, bool focus) {
assert (this != NULL);
int itemCount = Vector_size(this->items);
int size = Vector_size(this->items);
int scrollH = this->scrollH;
int y = this->y; int x = this->x;
int first = this->scrollV;
if (itemCount > this->h && first > itemCount - this->h) {
first = itemCount - this->h;
this->scrollV = first;
}
int last = MIN(itemCount, first + MIN(itemCount, this->h));
if (this->selected < first) {
first = this->selected;
this->scrollV = first;
this->needsRedraw = true;
}
if (this->selected >= last) {
last = MIN(itemCount, this->selected + 1);
first = last - this->h;
this->scrollV = first;
this->needsRedraw = true;
}
if (first < 0)
first = 0;
if (last > itemCount)
last = itemCount;
int y = this->y;
int x = this->x;
int h = this->h;
int headerLen = RichString_sizeVal(this->header);
if (headerLen > 0) {
@ -285,14 +268,34 @@ void Panel_draw(Panel* this, bool focus) {
attrset(CRT_colors[RESET_COLOR]);
y++;
}
// ensure scroll area is on screen
if (this->scrollV < 0) {
this->scrollV = 0;
this->needsRedraw = true;
} else if (this->scrollV >= size) {
this->scrollV = MAX(size - 1, 0);
this->needsRedraw = true;
}
// ensure selection is on screen
if (this->selected < this->scrollV) {
this->scrollV = this->selected;
this->needsRedraw = true;
} else if (this->selected >= this->scrollV + h) {
this->scrollV = this->selected - h + 1;
this->needsRedraw = true;
}
int first = this->scrollV;
int upTo = MIN(first + h, size);
int highlight = focus
? CRT_colors[PANEL_HIGHLIGHT_FOCUS]
: CRT_colors[PANEL_HIGHLIGHT_UNFOCUS];
if (this->needsRedraw) {
for(int i = first, j = 0; j < this->h && i < last; i++, j++) {
int line = 0;
for(int i = first; line < h && i < upTo; i++) {
Object* itemObj = Vector_get(this->items, i);
assert(itemObj); if(!itemObj) continue;
RichString_begin(item);
@ -304,15 +307,18 @@ void Panel_draw(Panel* this, bool focus) {
attrset(highlight);
RichString_setAttr(&item, highlight);
}
mvhline(y + j, x, ' ', this->w);
mvhline(y + line, x, ' ', this->w);
if (amt > 0)
RichString_printoffnVal(item, y+j, x, scrollH, amt);
RichString_printoffnVal(item, y + line, x, scrollH, amt);
if (selected)
attrset(CRT_colors[RESET_COLOR]);
RichString_end(item);
line++;
}
while (line < h) {
mvhline(y + line, x, ' ', this->w);
line++;
}
for (int i = y + (last - first); i < y + this->h; i++)
mvhline(i, x+0, ' ', this->w);
this->needsRedraw = false;
} else {
@ -325,15 +331,15 @@ void Panel_draw(Panel* this, bool focus) {
RichString_begin(new);
Object_display(newObj, &new);
int newLen = RichString_sizeVal(new);
mvhline(y+ this->oldSelected - this->scrollV, x+0, ' ', this->w);
mvhline(y+ this->oldSelected - first, x+0, ' ', this->w);
if (scrollH < oldLen)
RichString_printoffnVal(old, y+this->oldSelected - this->scrollV, x,
RichString_printoffnVal(old, y+this->oldSelected - first, x,
scrollH, MIN(oldLen - scrollH, this->w));
attrset(highlight);
mvhline(y+this->selected - this->scrollV, x+0, ' ', this->w);
mvhline(y+this->selected - first, x+0, ' ', this->w);
RichString_setAttr(&new, highlight);
if (scrollH < newLen)
RichString_printoffnVal(new, y+this->selected - this->scrollV, x,
RichString_printoffnVal(new, y+this->selected - first, x,
scrollH, MIN(newLen - scrollH, this->w));
attrset(CRT_colors[RESET_COLOR]);
RichString_end(new);
@ -345,38 +351,26 @@ void Panel_draw(Panel* this, bool focus) {
bool Panel_onKey(Panel* this, int key) {
assert (this != NULL);
int size = Vector_size(this->items);
switch (key) {
case KEY_DOWN:
case KEY_CTRLN:
if (this->selected + 1 < Vector_size(this->items))
this->selected++;
return true;
this->selected++;
break;
case KEY_UP:
case KEY_CTRLP:
if (this->selected > 0)
this->selected--;
return true;
this->selected--;
break;
#ifdef KEY_C_DOWN
case KEY_C_DOWN:
if (this->selected + 1 < Vector_size(this->items)) {
this->selected++;
if (this->scrollV < Vector_size(this->items) - this->h) {
this->scrollV++;
this->needsRedraw = true;
}
}
return true;
this->selected++;
break;
#endif
#ifdef KEY_C_UP
case KEY_C_UP:
if (this->selected > 0) {
this->selected--;
if (this->scrollV > 0) {
this->scrollV--;
this->needsRedraw = true;
}
}
return true;
this->selected--;
break;
#endif
case KEY_LEFT:
case KEY_CTRLB:
@ -384,71 +378,74 @@ bool Panel_onKey(Panel* this, int key) {
this->scrollH -= CRT_scrollHAmount;
this->needsRedraw = true;
}
return true;
break;
case KEY_RIGHT:
case KEY_CTRLF:
this->scrollH += CRT_scrollHAmount;
this->needsRedraw = true;
return true;
break;
case KEY_PPAGE:
this->selected -= (this->h - 1);
this->scrollV -= (this->h - 1);
if (this->selected < 0)
this->selected = 0;
if (this->scrollV < 0)
this->scrollV = 0;
this->needsRedraw = true;
return true;
break;
case KEY_NPAGE:
this->selected += (this->h - 1);
int size = Vector_size(this->items);
if (this->selected < 0)
this->selected = 0;
if (this->selected >= size)
this->selected = size - 1;
this->scrollV += (this->h - 1);
if (this->scrollV >= MAX(0, size - this->h))
this->scrollV = MAX(0, size - this->h - 1);
this->needsRedraw = true;
return true;
break;
case KEY_HOME:
this->selected = 0;
return true;
break;
case KEY_END:
this->selected = Vector_size(this->items) - 1;
return true;
this->selected = size - 1;
break;
default:
return false;
}
return false;
// ensure selection within bounds
if (this->selected < 0) {
this->selected = 0;
this->needsRedraw = true;
} else if (this->selected >= size) {
this->selected = size - 1;
this->needsRedraw = true;
}
return true;
}
HandlerResult Panel_selectByTyping(Panel* this, int ch) {
int size = Panel_size(this);
if (!this->eventHandlerBuffer)
this->eventHandlerBuffer = calloc(100, 1);
if (!this->eventHandlerState)
this->eventHandlerState = calloc(100, 1);
char* buffer = this->eventHandlerState;
if (isalnum(ch)) {
int len = strlen(this->eventHandlerBuffer);
int len = strlen(buffer);
if (len < 99) {
this->eventHandlerBuffer[len] = ch;
this->eventHandlerBuffer[len+1] = '\0';
buffer[len] = ch;
buffer[len+1] = '\0';
}
for (int try = 0; try < 2; try++) {
len = strlen(this->eventHandlerBuffer);
len = strlen(buffer);
for (int i = 0; i < size; i++) {
char* cur = ((ListItem*) Panel_get(this, i))->value;
while (*cur == ' ') cur++;
if (strncasecmp(cur, this->eventHandlerBuffer, len) == 0) {
if (strncasecmp(cur, buffer, len) == 0) {
Panel_setSelected(this, i);
return HANDLED;
}
}
this->eventHandlerBuffer[0] = ch;
this->eventHandlerBuffer[1] = '\0';
// if current word did not match,
// retry considering the character the start of a new word.
buffer[0] = ch;
buffer[1] = '\0';
}
return HANDLED;
} else if (ch != ERR) {
this->eventHandlerBuffer[0] = '\0';
buffer[0] = '\0';
}
if (ch == 13) {
return BREAK_LOOP;