You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
353 lines
8.5 KiB
353 lines
8.5 KiB
/* |
|
htop - Panel.c |
|
(C) 2004-2006 Hisham H. Muhammad |
|
Released under the GNU GPL, see the COPYING file |
|
in the source distribution for its full text. |
|
*/ |
|
|
|
#include "Object.h" |
|
#include "Panel.h" |
|
#include "Vector.h" |
|
#include "CRT.h" |
|
#include "RichString.h" |
|
|
|
#include <math.h> |
|
#include <stdbool.h> |
|
|
|
#include "debug.h" |
|
#include <assert.h> |
|
|
|
#include <curses.h> |
|
//#link curses |
|
|
|
/*{ |
|
|
|
typedef struct Panel_ Panel; |
|
|
|
typedef enum HandlerResult_ { |
|
HANDLED, |
|
IGNORED, |
|
BREAK_LOOP |
|
} HandlerResult; |
|
|
|
typedef HandlerResult(*Panel_EventHandler)(Panel*, int); |
|
|
|
struct Panel_ { |
|
Object super; |
|
int x, y, w, h; |
|
WINDOW* window; |
|
Vector* items; |
|
int selected; |
|
int scrollV, scrollH; |
|
int oldSelected; |
|
bool needsRedraw; |
|
RichString header; |
|
Panel_EventHandler eventHandler; |
|
}; |
|
|
|
extern char* PANEL_CLASS; |
|
|
|
}*/ |
|
|
|
#ifndef MIN |
|
#define MIN(a,b) ((a)<(b)?(a):(b)) |
|
#endif |
|
#ifndef MAX |
|
#define MAX(a,b) ((a)>(b)?(a):(b)) |
|
#endif |
|
|
|
/* private property */ |
|
char* PANEL_CLASS = "Panel"; |
|
|
|
Panel* Panel_new(int x, int y, int w, int h, char* type, bool owner) { |
|
Panel* this; |
|
this = malloc(sizeof(Panel)); |
|
Panel_init(this, x, y, w, h, type, owner); |
|
return this; |
|
} |
|
|
|
void Panel_delete(Object* cast) { |
|
Panel* this = (Panel*)cast; |
|
Panel_done(this); |
|
free(this); |
|
} |
|
|
|
void Panel_init(Panel* this, int x, int y, int w, int h, char* type, bool owner) { |
|
Object* super = (Object*) this; |
|
super->class = PANEL_CLASS; |
|
super->delete = Panel_delete; |
|
this->x = x; |
|
this->y = y; |
|
this->w = w; |
|
this->h = h; |
|
this->eventHandler = NULL; |
|
this->items = Vector_new(type, owner, DEFAULT_SIZE); |
|
this->scrollV = 0; |
|
this->scrollH = 0; |
|
this->selected = 0; |
|
this->oldSelected = 0; |
|
this->needsRedraw = true; |
|
this->header.len = 0; |
|
} |
|
|
|
void Panel_done(Panel* this) { |
|
assert (this != NULL); |
|
RichString_delete(this->header); |
|
Vector_delete(this->items); |
|
} |
|
|
|
inline void Panel_setRichHeader(Panel* this, RichString header) { |
|
assert (this != NULL); |
|
|
|
if (this->header.len > 0) { |
|
RichString_delete(this->header); |
|
} |
|
this->header = header; |
|
this->needsRedraw = true; |
|
} |
|
|
|
inline void Panel_setHeader(Panel* this, char* header) { |
|
Panel_setRichHeader(this, RichString_quickString(CRT_colors[PANEL_HEADER_FOCUS], header)); |
|
} |
|
|
|
void Panel_setEventHandler(Panel* this, Panel_EventHandler eh) { |
|
this->eventHandler = eh; |
|
} |
|
|
|
void Panel_move(Panel* this, int x, int y) { |
|
assert (this != NULL); |
|
|
|
this->x = x; |
|
this->y = y; |
|
this->needsRedraw = true; |
|
} |
|
|
|
void Panel_resize(Panel* this, int w, int h) { |
|
assert (this != NULL); |
|
|
|
if (this->header.len > 0) |
|
h--; |
|
this->w = w; |
|
this->h = h; |
|
this->needsRedraw = true; |
|
} |
|
|
|
void Panel_prune(Panel* this) { |
|
assert (this != NULL); |
|
|
|
Vector_prune(this->items); |
|
this->scrollV = 0; |
|
this->selected = 0; |
|
this->oldSelected = 0; |
|
this->needsRedraw = true; |
|
} |
|
|
|
void Panel_add(Panel* this, Object* o) { |
|
assert (this != NULL); |
|
|
|
Vector_add(this->items, o); |
|
this->needsRedraw = true; |
|
} |
|
|
|
void Panel_insert(Panel* this, int i, Object* o) { |
|
assert (this != NULL); |
|
|
|
Vector_insert(this->items, i, o); |
|
this->needsRedraw = true; |
|
} |
|
|
|
void Panel_set(Panel* this, int i, Object* o) { |
|
assert (this != NULL); |
|
|
|
Vector_set(this->items, i, o); |
|
} |
|
|
|
Object* Panel_get(Panel* this, int i) { |
|
assert (this != NULL); |
|
|
|
return Vector_get(this->items, i); |
|
} |
|
|
|
Object* Panel_remove(Panel* this, int i) { |
|
assert (this != NULL); |
|
|
|
this->needsRedraw = true; |
|
Object* removed = Vector_remove(this->items, i); |
|
if (this->selected > 0 && this->selected >= Vector_size(this->items)) |
|
this->selected--; |
|
return removed; |
|
} |
|
|
|
Object* Panel_getSelected(Panel* this) { |
|
assert (this != NULL); |
|
|
|
return Vector_get(this->items, this->selected); |
|
} |
|
|
|
void Panel_moveSelectedUp(Panel* this) { |
|
assert (this != NULL); |
|
|
|
Vector_moveUp(this->items, this->selected); |
|
if (this->selected > 0) |
|
this->selected--; |
|
} |
|
|
|
void Panel_moveSelectedDown(Panel* this) { |
|
assert (this != NULL); |
|
|
|
Vector_moveDown(this->items, this->selected); |
|
if (this->selected + 1 < Vector_size(this->items)) |
|
this->selected++; |
|
} |
|
|
|
int Panel_getSelectedIndex(Panel* this) { |
|
assert (this != NULL); |
|
|
|
return this->selected; |
|
} |
|
|
|
int Panel_getSize(Panel* this) { |
|
assert (this != NULL); |
|
|
|
return Vector_size(this->items); |
|
} |
|
|
|
void Panel_setSelected(Panel* this, int selected) { |
|
assert (this != NULL); |
|
|
|
selected = MAX(0, MIN(Vector_size(this->items) - 1, selected)); |
|
this->selected = selected; |
|
} |
|
|
|
void Panel_draw(Panel* this, bool focus) { |
|
assert (this != NULL); |
|
|
|
int first, last; |
|
int itemCount = Vector_size(this->items); |
|
int scrollH = this->scrollH; |
|
int y = this->y; int x = this->x; |
|
first = this->scrollV; |
|
|
|
if (this->h > itemCount) { |
|
last = this->scrollV + itemCount; |
|
move(y + last, x + 0); |
|
} else { |
|
last = MIN(itemCount, this->scrollV + 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 = MAX(0, last - this->h); |
|
this->scrollV = first; |
|
this->needsRedraw = true; |
|
} |
|
assert(first >= 0); |
|
assert(last <= itemCount); |
|
|
|
if (this->header.len > 0) { |
|
int attr = focus |
|
? CRT_colors[PANEL_HEADER_FOCUS] |
|
: CRT_colors[PANEL_HEADER_UNFOCUS]; |
|
attrset(attr); |
|
mvhline(y, x, ' ', this->w); |
|
if (scrollH < this->header.len) { |
|
mvaddchnstr(y, x, this->header.chstr + scrollH, |
|
MIN(this->header.len - scrollH, this->w)); |
|
} |
|
attrset(CRT_colors[RESET_COLOR]); |
|
y++; |
|
} |
|
|
|
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++) { |
|
Object* itemObj = Vector_get(this->items, i); |
|
RichString itemRef = RichString_new(); |
|
itemObj->display(itemObj, &itemRef); |
|
int amt = MIN(itemRef.len - scrollH, this->w); |
|
if (i == this->selected) { |
|
attrset(highlight); |
|
RichString_setAttr(&itemRef, highlight); |
|
mvhline(y + j, x+0, ' ', this->w); |
|
if (amt > 0) |
|
mvaddchnstr(y+j, x+0, itemRef.chstr + scrollH, amt); |
|
attrset(CRT_colors[RESET_COLOR]); |
|
} else { |
|
mvhline(y+j, x+0, ' ', this->w); |
|
if (amt > 0) |
|
mvaddchnstr(y+j, x+0, itemRef.chstr + scrollH, amt); |
|
} |
|
} |
|
for (int i = y + (last - first); i < y + this->h; i++) |
|
mvhline(i, x+0, ' ', this->w); |
|
this->needsRedraw = false; |
|
|
|
} else { |
|
Object* oldObj = Vector_get(this->items, this->oldSelected); |
|
RichString oldRef = RichString_new(); |
|
oldObj->display(oldObj, &oldRef); |
|
Object* newObj = Vector_get(this->items, this->selected); |
|
RichString newRef = RichString_new(); |
|
newObj->display(newObj, &newRef); |
|
mvhline(y+ this->oldSelected - this->scrollV, x+0, ' ', this->w); |
|
if (scrollH < oldRef.len) |
|
mvaddchnstr(y+ this->oldSelected - this->scrollV, x+0, oldRef.chstr + this->scrollH, MIN(oldRef.len - scrollH, this->w)); |
|
attrset(highlight); |
|
mvhline(y+this->selected - this->scrollV, x+0, ' ', this->w); |
|
RichString_setAttr(&newRef, highlight); |
|
if (scrollH < newRef.len) |
|
mvaddchnstr(y+this->selected - this->scrollV, x+0, newRef.chstr + this->scrollH, MIN(newRef.len - scrollH, this->w)); |
|
attrset(CRT_colors[RESET_COLOR]); |
|
} |
|
this->oldSelected = this->selected; |
|
move(0, 0); |
|
} |
|
|
|
void Panel_onKey(Panel* this, int key) { |
|
assert (this != NULL); |
|
switch (key) { |
|
case KEY_DOWN: |
|
if (this->selected + 1 < Vector_size(this->items)) |
|
this->selected++; |
|
break; |
|
case KEY_UP: |
|
if (this->selected > 0) |
|
this->selected--; |
|
break; |
|
case KEY_LEFT: |
|
if (this->scrollH > 0) { |
|
this->scrollH -= 5; |
|
this->needsRedraw = true; |
|
} |
|
break; |
|
case KEY_RIGHT: |
|
this->scrollH += 5; |
|
this->needsRedraw = true; |
|
break; |
|
case KEY_PPAGE: |
|
this->selected -= this->h; |
|
if (this->selected < 0) |
|
this->selected = 0; |
|
break; |
|
case KEY_NPAGE: |
|
this->selected += this->h; |
|
int size = Vector_size(this->items); |
|
if (this->selected >= size) |
|
this->selected = size - 1; |
|
break; |
|
case KEY_HOME: |
|
this->selected = 0; |
|
break; |
|
case KEY_END: |
|
this->selected = Vector_size(this->items) - 1; |
|
break; |
|
} |
|
}
|
|
|