123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515 |
- /*
- htop - Panel.c
- (C) 2004-2011 Hisham H. Muhammad
- Released under the GNU GPLv2+, see the COPYING file
- in the source distribution for its full text.
- */
- #include "config.h" // IWYU pragma: keep
- #include "Panel.h"
- #include <assert.h>
- #include <ctype.h>
- #include <stdbool.h>
- #include <stdlib.h>
- #include <string.h>
- #include <strings.h>
- #include "CRT.h"
- #include "ListItem.h"
- #include "Macros.h"
- #include "ProvideCurses.h"
- #include "RichString.h"
- #include "XUtils.h"
- const PanelClass Panel_class = {
- .super = {
- .extends = Class(Object),
- .delete = Panel_delete
- },
- .eventHandler = Panel_selectByTyping,
- };
- Panel* Panel_new(int x, int y, int w, int h, const ObjectClass* type, bool owner, FunctionBar* fuBar) {
- Panel* this;
- this = xMalloc(sizeof(Panel));
- Object_setClass(this, Class(Panel));
- Panel_init(this, x, y, w, h, type, owner, fuBar);
- 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, const ObjectClass* type, bool owner, FunctionBar* fuBar) {
- this->x = x;
- this->y = y;
- this->w = w;
- this->h = h;
- this->cursorX = 0;
- this->cursorY = 0;
- this->eventHandlerState = NULL;
- this->items = Vector_new(type, owner, DEFAULT_SIZE);
- this->scrollV = 0;
- this->scrollH = 0;
- this->selected = 0;
- this->oldSelected = 0;
- this->selectedLen = 0;
- this->needsRedraw = true;
- this->cursorOn = false;
- this->wasFocus = false;
- RichString_beginAllocated(this->header);
- this->defaultBar = fuBar;
- this->currentBar = fuBar;
- this->selectionColorId = PANEL_SELECTION_FOCUS;
- }
- void Panel_done(Panel* this) {
- assert (this != NULL);
- free(this->eventHandlerState);
- Vector_delete(this->items);
- FunctionBar_delete(this->defaultBar);
- RichString_delete(&this->header);
- }
- void Panel_setCursorToSelection(Panel* this) {
- this->cursorY = this->y + this->selected - this->scrollV + 1;
- this->cursorX = this->x + this->selectedLen - this->scrollH;
- }
- void Panel_setSelectionColor(Panel* this, ColorElements colorId) {
- this->selectionColorId = colorId;
- }
- inline void Panel_setHeader(Panel* this, const char* header) {
- RichString_writeWide(&(this->header), CRT_colors[PANEL_HEADER_FOCUS], header);
- this->needsRedraw = true;
- }
- 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);
- 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);
- if (Vector_size(this->items) > 0) {
- return Vector_get(this->items, this->selected);
- } else {
- return NULL;
- }
- }
- 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(const Panel* this) {
- assert (this != NULL);
- return this->selected;
- }
- int Panel_size(const Panel* this) {
- assert (this != NULL);
- return Vector_size(this->items);
- }
- void Panel_setSelected(Panel* this, int selected) {
- assert (this != NULL);
- int size = Vector_size(this->items);
- if (selected >= size) {
- selected = size - 1;
- }
- if (selected < 0) {
- selected = 0;
- }
- this->selected = selected;
- if (Panel_eventHandlerFn(this)) {
- Panel_eventHandler(this, EVENT_SET_SELECTED);
- }
- }
- void Panel_splice(Panel* this, Vector* from) {
- assert (this != NULL);
- assert (from != NULL);
- Vector_splice(this->items, from);
- this->needsRedraw = true;
- }
- void Panel_draw(Panel* this, bool force_redraw, bool focus, bool highlightSelected, bool hideFunctionBar) {
- assert (this != NULL);
- int size = Vector_size(this->items);
- int scrollH = this->scrollH;
- int y = this->y;
- int x = this->x;
- int h = this->h;
- if (hideFunctionBar)
- h++;
- const int header_attr = focus
- ? CRT_colors[PANEL_HEADER_FOCUS]
- : CRT_colors[PANEL_HEADER_UNFOCUS];
- if (force_redraw) {
- if (Panel_printHeaderFn(this))
- Panel_printHeader(this);
- else
- RichString_setAttr(&this->header, header_attr);
- }
- int headerLen = RichString_sizeVal(this->header);
- if (headerLen > 0) {
- attrset(header_attr);
- mvhline(y, x, ' ', this->w);
- if (scrollH < headerLen) {
- RichString_printoffnVal(this->header, y, x, scrollH,
- MINIMUM(headerLen - scrollH, this->w));
- }
- attrset(CRT_colors[RESET_COLOR]);
- y++;
- h--;
- }
- // ensure scroll area is on screen
- if (this->scrollV < 0) {
- this->scrollV = 0;
- this->needsRedraw = true;
- } else if (this->scrollV > size - h) {
- this->scrollV = MAXIMUM(size - h, 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 = MINIMUM(first + h, size);
- int selectionColor = focus
- ? CRT_colors[this->selectionColorId]
- : CRT_colors[PANEL_SELECTION_UNFOCUS];
- if (this->needsRedraw || force_redraw) {
- int line = 0;
- for (int i = first; line < h && i < upTo; i++) {
- const Object* itemObj = Vector_get(this->items, i);
- RichString_begin(item);
- Object_display(itemObj, &item);
- int itemLen = RichString_sizeVal(item);
- int amt = MINIMUM(itemLen - scrollH, this->w);
- if (highlightSelected && i == this->selected) {
- item.highlightAttr = selectionColor;
- }
- if (item.highlightAttr) {
- attrset(item.highlightAttr);
- RichString_setAttr(&item, item.highlightAttr);
- this->selectedLen = itemLen;
- }
- mvhline(y + line, x, ' ', this->w);
- if (amt > 0)
- RichString_printoffnVal(item, y + line, x, scrollH, amt);
- if (item.highlightAttr)
- attrset(CRT_colors[RESET_COLOR]);
- RichString_delete(&item);
- line++;
- }
- while (line < h) {
- mvhline(y + line, x, ' ', this->w);
- line++;
- }
- } else {
- const Object* oldObj = Vector_get(this->items, this->oldSelected);
- RichString_begin(old);
- Object_display(oldObj, &old);
- int oldLen = RichString_sizeVal(old);
- const Object* newObj = Vector_get(this->items, this->selected);
- RichString_begin(new);
- Object_display(newObj, &new);
- int newLen = RichString_sizeVal(new);
- this->selectedLen = newLen;
- mvhline(y + this->oldSelected - first, x + 0, ' ', this->w);
- if (scrollH < oldLen)
- RichString_printoffnVal(old, y + this->oldSelected - first, x,
- scrollH, MINIMUM(oldLen - scrollH, this->w));
- attrset(selectionColor);
- mvhline(y + this->selected - first, x + 0, ' ', this->w);
- RichString_setAttr(&new, selectionColor);
- if (scrollH < newLen)
- RichString_printoffnVal(new, y + this->selected - first, x,
- scrollH, MINIMUM(newLen - scrollH, this->w));
- attrset(CRT_colors[RESET_COLOR]);
- RichString_delete(&new);
- RichString_delete(&old);
- }
- if (focus && (this->needsRedraw || force_redraw || !this->wasFocus)) {
- if (Panel_drawFunctionBarFn(this))
- Panel_drawFunctionBar(this, hideFunctionBar);
- else if (!hideFunctionBar)
- FunctionBar_draw(this->currentBar);
- }
- this->oldSelected = this->selected;
- this->wasFocus = focus;
- this->needsRedraw = false;
- }
- static int Panel_headerHeight(const Panel* this) {
- return RichString_sizeVal(this->header) > 0 ? 1 : 0;
- }
- bool Panel_onKey(Panel* this, int key) {
- assert (this != NULL);
- const int size = Vector_size(this->items);
- #define PANEL_SCROLL(amount) \
- do { \
- this->selected += (amount); \
- this->scrollV = CLAMP(this->scrollV + (amount), 0, MAXIMUM(0, (size - this->h - Panel_headerHeight(this)))); \
- this->needsRedraw = true; \
- } while (0)
- switch (key) {
- case KEY_DOWN:
- case KEY_CTRL('N'):
- #ifdef KEY_C_DOWN
- case KEY_C_DOWN:
- #endif
- this->selected++;
- break;
- case KEY_UP:
- case KEY_CTRL('P'):
- #ifdef KEY_C_UP
- case KEY_C_UP:
- #endif
- this->selected--;
- break;
- case KEY_LEFT:
- case KEY_CTRL('B'):
- if (this->scrollH > 0) {
- this->scrollH -= MAXIMUM(CRT_scrollHAmount, 0);
- this->needsRedraw = true;
- }
- break;
- case KEY_RIGHT:
- case KEY_CTRL('F'):
- this->scrollH += CRT_scrollHAmount;
- this->needsRedraw = true;
- break;
- case KEY_PPAGE:
- PANEL_SCROLL(-(this->h - Panel_headerHeight(this)));
- break;
- case KEY_NPAGE:
- PANEL_SCROLL(+(this->h - Panel_headerHeight(this)));
- break;
- case KEY_WHEELUP:
- PANEL_SCROLL(-CRT_scrollWheelVAmount);
- break;
- case KEY_WHEELDOWN:
- PANEL_SCROLL(+CRT_scrollWheelVAmount);
- break;
- case KEY_HOME:
- this->selected = 0;
- break;
- case KEY_END:
- this->selected = size - 1;
- break;
- case KEY_CTRL('A'):
- case '^':
- this->scrollH = 0;
- this->needsRedraw = true;
- break;
- case KEY_CTRL('E'):
- case '$':
- this->scrollH = MAXIMUM(this->selectedLen - this->w, 0);
- this->needsRedraw = true;
- break;
- default:
- return false;
- }
- #undef PANEL_SCROLL
- // ensure selection within bounds
- if (this->selected < 0 || size == 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 (ch == '#')
- return IGNORED;
- if (!this->eventHandlerState)
- this->eventHandlerState = xCalloc(100, sizeof(char));
- char* buffer = this->eventHandlerState;
- if (0 < ch && ch < 255 && isgraph((unsigned char)ch)) {
- int len = strlen(buffer);
- if (!len) {
- if ('/' == ch) {
- ch = '\001';
- } else if ('q' == ch) {
- return BREAK_LOOP;
- }
- } else if (1 == len && '\001' == buffer[0]) {
- len--;
- }
- if (len < 99) {
- buffer[len] = (char) ch;
- buffer[len + 1] = '\0';
- }
- for (int try = 0; try < 2; try++) {
- len = strlen(buffer);
- for (int i = 0; i < size; i++) {
- const char* cur = ((ListItem*) Panel_get(this, i))->value;
- while (*cur == ' ')
- cur++;
- if (strncasecmp(cur, buffer, len) == 0) {
- Panel_setSelected(this, i);
- return HANDLED;
- }
- }
- // if current word did not match,
- // retry considering the character the start of a new word.
- buffer[0] = (char) ch;
- buffer[1] = '\0';
- }
- return HANDLED;
- } else if (ch != ERR) {
- buffer[0] = '\0';
- }
- if (ch == 13) {
- return BREAK_LOOP;
- }
- return IGNORED;
- }
- int Panel_getCh(Panel* this) {
- if (this->cursorOn) {
- move(this->cursorY, this->cursorX);
- curs_set(1);
- } else {
- curs_set(0);
- }
- #ifdef HAVE_SET_ESCDELAY
- set_escdelay(25);
- #endif
- return getch();
- }
|