diff options
Diffstat (limited to 'src/cursesview.c')
-rw-r--r-- | src/cursesview.c | 291 |
1 files changed, 291 insertions, 0 deletions
diff --git a/src/cursesview.c b/src/cursesview.c new file mode 100644 index 0000000..fcfa2d2 --- /dev/null +++ b/src/cursesview.c @@ -0,0 +1,291 @@ +#include "cursesview.h" + +#include <pthread.h> +#include <curses.h> +#include <panel.h> +#include <string.h> + +#define CURSESWIN_COUNT 3 + +// Global variable shared by all threads to say "finish current operation and go away" +extern int end; + +// window updated by cursesUpdateSliceDump callback from "worker" thread, with a mutex for prevent fuzzy concurrent updates +WINDOW *winUpdateSliceDump=NULL; +static pthread_mutex_t ncursesWriteMutex = PTHREAD_MUTEX_INITIALIZER; +address_t sliceDumpBegin, sliceDumpEnd, sliceDumpMin, sliceDumpMax; + +// Helpers declaration (below the interesting code of this file) +int cursesInit(WINDOW *wins[], PANEL *panels[], int count); +void cursesUnInit(WINDOW *wins[], PANEL *panels[], int count); +void cursesUpdateSliceDump(slices_evt_t *slicesEvt, slice_t *modifiedSlice); +//void printInMiddle(WINDOW *win, int starty, int startx, int width, char *string, chtype color); +void makeWin(WINDOW **win, PANEL **panel, int h, int w, int y, int x, char title[]); + +void cursesMainLoop(slices_evt_t *slicesEvt) { + char msg[255]; + int ch, i; + + WINDOW *wins[CURSESWIN_COUNT]; + PANEL *panels[CURSESWIN_COUNT]; + +#ifdef NCURSES_MOUSE_VERSION + int dispatched, res; + int (*mouseEventListener)(MEVENT mevent, WINDOW *winDebug); + MEVENT mevent; + PANEL *p; +#endif + + cursesInit(wins, panels, CURSESWIN_COUNT); + + sliceDumpBegin=sliceDumpMin=slicesEvt->data->min; + sliceDumpEnd=sliceDumpMax=slicesEvt->data->max; + + wattron(wins[CURSESWIN_COUNT-1], COLOR_PAIR(4)); + mvwprintw(wins[CURSESWIN_COUNT-1], 1, 0, "F2:Exit F5:Zoom left F6:Unzoom left F7:Unzoom right F8:Zoom right"); +// wattroff(wins[CURSESWIN_COUNT-1], COLOR_PAIR(4)); + +// update_panels(); + doupdate(); + + /* Enable worker listener */ + //FIXME : check pointers ? + winUpdateSliceDump=wins[1]; + slicesEvt->eventListener=cursesUpdateSliceDump; + + while((ch = getch()) != KEY_F(2)) { + + pthread_mutex_lock(&ncursesWriteMutex); + + switch(ch) { + // Zoom handling + //FIXME : Do something less stupid. Try to reuse mouse event zoom code for keyboard + case KEY_F(5): + sliceDumpEnd=(sliceDumpBegin+sliceDumpEnd)/2; + break; + case KEY_F(6): + sliceDumpBegin=sliceDumpMin; + break; + case KEY_F(7): + sliceDumpEnd=sliceDumpMax; + break; + case KEY_F(8): + sliceDumpBegin=(sliceDumpBegin+sliceDumpEnd)/2; + break; + + // Panel focus + case '1': + case '2': + case '3': + i=ch-'0'; + if (i>0 && i<=CURSESWIN_COUNT) { + top_panel(panels[i-1]); + update_panels(); + } + break; +#ifdef NCURSES_MOUSE_VERSION + case KEY_MOUSE: + // Seems to have a mouse event + res = getmouse(&mevent); + if ( res == OK ) { + // Try to find in which panel (search first in top-level panel and go down) + p=NULL; + while ( ( p=panel_below(p) ) != NULL) { + if ( wenclose(panel_window(p), mevent.y, mevent.x) ) { + break; + } + } + + // If we found a panel, dispatch the event if a listener is set + if (p != NULL) { + mouseEventListener=(int (*)(MEVENT mevent, WINDOW *winDebug)) panel_userptr(p); + dispatched=(mouseEventListener==NULL)?0:mouseEventListener(mevent, wins[0]); + if ( ! dispatched ) { + // If no listener or event not consumed, use the default behavior : set the panel on top if BUTTON1_CLICKED + if ( (mevent.bstate & BUTTON1_CLICKED) == BUTTON1_CLICKED) { + top_panel(p); + } + } + } + } + break; +#endif + default: + sprintf(msg, "Unhandled key ch==0x%x", ch); + wattron(wins[0], COLOR_PAIR(4)); + mvwprintw(wins[0], 2, 0, msg); + + } + + doupdate(); + + sprintf(msg, "Viewing [%lli-%lli] of [%lli-%lli] working region ", sliceDumpBegin, sliceDumpEnd, slicesEvt->data->min, slicesEvt->data->max); + wattron(wins[0], COLOR_PAIR(4)); + mvwprintw(wins[0], 1, 0, msg); + + pthread_mutex_unlock(&ncursesWriteMutex); + } + + pthread_mutex_lock(&(slicesEvt->eventListenerMutex)); + slicesEvt->eventListener=NULL; + pthread_mutex_unlock(&(slicesEvt->eventListenerMutex)); + + end=1; + cursesUnInit(wins, panels, CURSESWIN_COUNT); +} + +// TODO : faire une structure avec tous les éléments graphiques utiles au listener et tout passer par référence de la mainloop à ce listener +#define DEFAULT_ZOOM_FACTOR 2.f + +int winSlicesMouseEventListener(MEVENT mevent, WINDOW *winDebug) { + bool resb; + int pX, pY, maxX, maxY; + address_t delta; + float pos; + // For debugging char buf[255]; + + pY=mevent.y; + pX=mevent.x; + resb=wmouse_trafo(winUpdateSliceDump, &pY, &pX, false); + if ( resb == TRUE ) { + getmaxyx(winUpdateSliceDump, maxY, maxX); + // First ligne (pY) is line 1 but first char (pX) is char 0 so we have to translate Y coords by -1 + pos=(0.0f+(pY-1)*maxX+pX)/((maxY-1)*maxX-1); + delta=sliceDumpEnd-sliceDumpBegin; + sliceDumpBegin+=delta*pos/DEFAULT_ZOOM_FACTOR*(DEFAULT_ZOOM_FACTOR-1); + sliceDumpEnd-=delta*(1-pos)/DEFAULT_ZOOM_FACTOR*(DEFAULT_ZOOM_FACTOR-1); + } + +/* + // Debug code + sprintf(buf, "Debug : pX==%i, pY==%i, maxX==%i, maxY==%i, pos==%f, sliceDumpEnd==%lli, sliceDumpBegin=%lli, delta==%lli", pX, pY, maxX, maxY, pos, sliceDumpEnd, sliceDumpBegin, delta); + wattron(winDebug, COLOR_PAIR(4)); + mvwprintw(winDebug, 2, 0, buf); +*/ + return 1; +} + +int cursesInit(WINDOW *wins[], PANEL *panels[], int count) { + int screenH, screenW; +#ifdef NCURSES_MOUSE_VERSION + char buf[255]; + mmask_t mmask; +#endif + + /* Initialize curses */ + initscr(); + start_color(); + raw(); + keypad(stdscr, TRUE); + noecho(); +#ifdef NCURSES_MOUSE_VERSION + mmask = mousemask(REPORT_MOUSE_POSITION|BUTTON1_CLICKED, NULL); +#endif + + /* Initialize all the colors */ + init_pair(1, COLOR_WHITE, COLOR_BLACK); + init_pair(2, COLOR_WHITE, COLOR_BLUE); + init_pair(3, COLOR_BLUE, COLOR_BLACK); + init_pair(4, COLOR_CYAN, COLOR_BLACK); + + /* Initialize windows and panels */ + getmaxyx(stdscr, screenH, screenW); + if ( screenH < 8 || screenW < 40 ) return 1; + + makeWin(wins+0, panels+0, 3 , screenW, 0 , 0, "Menu"); + makeWin(wins+1, panels+1, screenH-6 , screenW, 3 , 0, "Main Win"); + makeWin(wins+2, panels+2, 2 , screenW, screenH-3 , 0, "Commands"); + + /* Set up the user pointers to the next panel + set_panel_userptr(panels[0], panels[1]); + set_panel_userptr(panels[1], panels[2]); + set_panel_userptr(panels[2], panels[0]); + */ + + set_panel_userptr(panels[1], winSlicesMouseEventListener); + +#ifdef NCURSES_MOUSE_VERSION + sprintf(buf, "Debug infos : mmask=%lx", mmask); + mvprintw(LINES - 3, 0, buf); +#endif + + /* Update the stacking order. 2nd panel will be on top */ + update_panels(); + + return 0; +} + +void cursesUnInit(WINDOW *wins[], PANEL *panels[], int count) { + int i; + + for (i=0;i<count;i++) { + del_panel(panels[i]); + delwin(wins[i]); + } + endwin(); +} + +void cursesUpdateSliceDump(slices_evt_t *slicesEvt, slice_t *modifiedSlice) { +// char *strProgress="|/-\\"; +// static int progress=0; + char *toPrint; + address_t blockSize=0; + unsigned int charCount=(getmaxx(winUpdateSliceDump)-getbegx(winUpdateSliceDump))*(getmaxy(winUpdateSliceDump)-getbegy(winUpdateSliceDump)+2); + + //TODO : refesh only right parts of the representation + // This need a representation that not depends on what is already drawn because of consistency and because it not possible to re-read printed ASCII representation in curse windows + + pthread_mutex_lock(&ncursesWriteMutex); + + + toPrint=slicesDump(slicesEvt->data, &blockSize, charCount, sliceDumpBegin, sliceDumpEnd); + if (toPrint != NULL) { + attron(COLOR_PAIR(4)); + mvwprintw(winUpdateSliceDump, 1, 0, toPrint); +// attroff(COLOR_PAIR(4)); + + update_panels(); + doupdate(); + + free(toPrint); + } + +/* sprintf(toPrint, "%c - %p %p", strProgress[progress], slicesEvt, modifiedSlice); + progress=(progress+1)%strlen(strProgress); +*/ + pthread_mutex_unlock(&ncursesWriteMutex); +} + +/* +void printInMiddle(WINDOW *win, int starty, int startx, int width, char *string, chtype color) +{ int length, x, y; + float temp; + + if(win == NULL) + win = stdscr; + getyx(win, y, x); + if(startx != 0) + x = startx; + if(starty != 0) + y = starty; + if(width == 0) + width = 80; + + length = strlen(string); + temp = (width - length)/ 2; + x = startx + (int)temp; + wattron(win, color); + mvwprintw(win, y, x, "%s", string); + wattroff(win, color); + refresh(); +} +*/ +void makeWin(WINDOW **win, PANEL **panel, int h, int w, int y, int x, char title[]) { + int i; + *win = newwin(h, w, y, x); + mvwprintw(*win, 0, 0, "%s", title); + mvwchgat(*win, 0, 0, -1, A_BOLD, 2, NULL); + for(i=1;i<h;i++) mvwchgat(*win, i, 0, -1, A_STANDOUT, 1, NULL); + *panel = new_panel(*win); +} + |