| /* |
| htop |
| (C) 2004-2011 Hisham H. Muhammad |
| Released under the GNU GPL, see the COPYING file |
| in the source distribution for its full text. |
| */ |
| |
| #include "ScreenManager.h" |
| #include "Panel.h" |
| #include "Object.h" |
| #include "Vector.h" |
| #include "Header.h" |
| #include "FunctionBar.h" |
| |
| #include "debug.h" |
| #include <assert.h> |
| #include <time.h> |
| |
| #include <stdbool.h> |
| |
| /*{ |
| |
| typedef enum Orientation_ { |
| VERTICAL, |
| HORIZONTAL |
| } Orientation; |
| |
| typedef struct ScreenManager_ { |
| int x1; |
| int y1; |
| int x2; |
| int y2; |
| Orientation orientation; |
| Vector* items; |
| Vector* fuBars; |
| int itemCount; |
| const FunctionBar* fuBar; |
| const Header* header; |
| time_t lastScan; |
| bool owner; |
| } ScreenManager; |
| |
| }*/ |
| |
| ScreenManager* ScreenManager_new(int x1, int y1, int x2, int y2, Orientation orientation, const Header* header, bool owner) { |
| ScreenManager* this; |
| this = malloc(sizeof(ScreenManager)); |
| this->x1 = x1; |
| this->y1 = y1; |
| this->x2 = x2; |
| this->y2 = y2; |
| this->fuBar = NULL; |
| this->orientation = orientation; |
| this->items = Vector_new(PANEL_CLASS, owner, DEFAULT_SIZE, NULL); |
| this->fuBars = Vector_new(FUNCTIONBAR_CLASS, true, DEFAULT_SIZE, NULL); |
| this->itemCount = 0; |
| this->header = header; |
| this->owner = owner; |
| return this; |
| } |
| |
| void ScreenManager_delete(ScreenManager* this) { |
| Vector_delete(this->items); |
| Vector_delete(this->fuBars); |
| free(this); |
| } |
| |
| inline int ScreenManager_size(ScreenManager* this) { |
| return this->itemCount; |
| } |
| |
| void ScreenManager_add(ScreenManager* this, Panel* item, FunctionBar* fuBar, int size) { |
| if (this->orientation == HORIZONTAL) { |
| int lastX = 0; |
| if (this->itemCount > 0) { |
| Panel* last = (Panel*) Vector_get(this->items, this->itemCount - 1); |
| lastX = last->x + last->w + 1; |
| } |
| if (size > 0) { |
| Panel_resize(item, size, LINES-this->y1+this->y2); |
| } else { |
| Panel_resize(item, COLS-this->x1+this->x2-lastX, LINES-this->y1+this->y2); |
| } |
| Panel_move(item, lastX, this->y1); |
| } |
| // TODO: VERTICAL |
| Vector_add(this->items, item); |
| if (fuBar) |
| Vector_add(this->fuBars, fuBar); |
| else |
| Vector_add(this->fuBars, FunctionBar_new(NULL, NULL, NULL)); |
| if (!this->fuBar && fuBar) this->fuBar = fuBar; |
| item->needsRedraw = true; |
| this->itemCount++; |
| } |
| |
| Panel* ScreenManager_remove(ScreenManager* this, int idx) { |
| assert(this->itemCount > idx); |
| Panel* panel = (Panel*) Vector_remove(this->items, idx); |
| Vector_remove(this->fuBars, idx); |
| this->fuBar = NULL; |
| this->itemCount--; |
| return panel; |
| } |
| |
| void ScreenManager_resize(ScreenManager* this, int x1, int y1, int x2, int y2) { |
| this->x1 = x1; |
| this->y1 = y1; |
| this->x2 = x2; |
| this->y2 = y2; |
| int items = this->itemCount; |
| int lastX = 0; |
| for (int i = 0; i < items - 1; i++) { |
| Panel* panel = (Panel*) Vector_get(this->items, i); |
| Panel_resize(panel, panel->w, LINES-y1+y2); |
| Panel_move(panel, lastX, y1); |
| lastX = panel->x + panel->w + 1; |
| } |
| Panel* panel = (Panel*) Vector_get(this->items, items-1); |
| Panel_resize(panel, COLS-x1+x2-lastX, LINES-y1+y2); |
| Panel_move(panel, lastX, y1); |
| } |
| |
| void ScreenManager_run(ScreenManager* this, Panel** lastFocus, int* lastKey) { |
| bool quit = false; |
| int focus = 0; |
| |
| Panel* panelFocus = (Panel*) Vector_get(this->items, focus); |
| if (this->fuBar) |
| FunctionBar_draw(this->fuBar, NULL); |
| |
| this->lastScan = 0; |
| |
| int ch = 0; |
| while (!quit) { |
| int items = this->itemCount; |
| if (this->header) { |
| time_t now = time(NULL); |
| if (now > this->lastScan) { |
| ProcessList_scan(this->header->pl); |
| this->lastScan = now; |
| } |
| Header_draw(this->header); |
| } |
| for (int i = 0; i < items; i++) { |
| Panel* panel = (Panel*) Vector_get(this->items, i); |
| Panel_draw(panel, i == focus); |
| if (i < items) { |
| if (this->orientation == HORIZONTAL) { |
| mvvline(panel->y, panel->x+panel->w, ' ', panel->h+1); |
| } |
| } |
| } |
| FunctionBar* bar = (FunctionBar*) Vector_get(this->fuBars, focus); |
| if (bar) |
| this->fuBar = bar; |
| if (this->fuBar) |
| FunctionBar_draw(this->fuBar, NULL); |
| |
| ch = getch(); |
| |
| if (ch == KEY_MOUSE) { |
| MEVENT mevent; |
| int ok = getmouse(&mevent); |
| if (ok == OK) { |
| if (mevent.y == LINES - 1) { |
| ch = FunctionBar_synthesizeEvent(this->fuBar, mevent.x); |
| } else { |
| for (int i = 0; i < this->itemCount; i++) { |
| Panel* panel = (Panel*) Vector_get(this->items, i); |
| if (mevent.x > panel->x && mevent.x <= panel->x+panel->w && |
| mevent.y > panel->y && mevent.y <= panel->y+panel->h) { |
| focus = i; |
| panelFocus = panel; |
| Panel_setSelected(panel, mevent.y - panel->y + panel->scrollV - 1); |
| break; |
| } |
| } |
| } |
| } |
| } |
| |
| if (panelFocus->eventHandler) { |
| HandlerResult result = panelFocus->eventHandler(panelFocus, ch); |
| if (result == HANDLED) { |
| continue; |
| } else if (result == BREAK_LOOP) { |
| quit = true; |
| continue; |
| } |
| } |
| |
| switch (ch) { |
| case ERR: |
| continue; |
| case KEY_RESIZE: |
| { |
| ScreenManager_resize(this, this->x1, this->y1, this->x2, this->y2); |
| continue; |
| } |
| case KEY_LEFT: |
| case KEY_CTRLB: |
| tryLeft: |
| if (focus > 0) |
| focus--; |
| panelFocus = (Panel*) Vector_get(this->items, focus); |
| if (Panel_size(panelFocus) == 0 && focus > 0) |
| goto tryLeft; |
| break; |
| case KEY_RIGHT: |
| case KEY_CTRLF: |
| case 9: |
| tryRight: |
| if (focus < this->itemCount - 1) |
| focus++; |
| panelFocus = (Panel*) Vector_get(this->items, focus); |
| if (Panel_size(panelFocus) == 0 && focus < this->itemCount - 1) |
| goto tryRight; |
| break; |
| case KEY_F(10): |
| case 'q': |
| case 27: |
| quit = true; |
| continue; |
| default: |
| Panel_onKey(panelFocus, ch); |
| break; |
| } |
| } |
| |
| *lastFocus = panelFocus; |
| *lastKey = ch; |
| } |