diff --git a/src/toolkit.c b/src/toolkit.c index 67fbdb8..3603ce7 100644 --- a/src/toolkit.c +++ b/src/toolkit.c @@ -31,7 +31,8 @@ typedef enum WidgetType_ { typedef enum WidgetStatus_ { WIDGET_STATUS_NORMAL, WIDGET_STATUS_MOUSEOVER, - WIDGET_STATUS_MOUSEDOWN + WIDGET_STATUS_MOUSEDOWN, + WIDGET_STATUS_SCROLLING } WidgetStatus; typedef struct Widget_ { @@ -135,6 +136,10 @@ static glColour* toolkit_colLight = &cGrey90; static glColour* toolkit_col = &cGrey70; static glColour* toolkit_colDark = &cGrey30; +/* Converts absolute mouse events to relative mouse events. */ +static double last_x = 0.; /**< Last x mouse position. */ +static double last_y = 0.; /**< Last y mouse position. */ + /* Widgets. */ static Widget* window_newWidget(Window* w); static void widget_cleanup(Widget* widget); @@ -145,6 +150,7 @@ static void toolkit_setPos(Window* wdw, Widget* wgt, int x, int y); static int toolkit_inputInput(Uint8 type, Widget* inp, SDLKey key); static void toolkit_mouseEvent(SDL_Event* event); static int toolkit_keyEvent(SDL_Event* event); +static void toolkit_imgarrMove(Widget* iar, double ry); /* Focus. */ static void toolkit_nextFocus(void); static int toolkit_isFocusable(Widget* wgt); @@ -1188,6 +1194,7 @@ static void toolkit_renderImageArray(Widget* iar, double bx, double by) { double scroll_pos, sx, sy; int xelem, yelem, xspace; glColour* c, *dc, *lc; + int is_selected; x = bx + iar->x; y = by + iar->y; @@ -1202,7 +1209,7 @@ static void toolkit_renderImageArray(Widget* iar, double bx, double by) { yelem = (int)iar->dat.iar.nelements / xelem + 1; /* Background. */ - toolkit_drawRect(x, y, iar->w, iar->h, toolkit_colDark, NULL); + toolkit_drawRect(x, y, iar->w, iar->h, &cBlack, NULL); /* Scrollbar. */ @@ -1227,10 +1234,17 @@ static void toolkit_renderImageArray(Widget* iar, double bx, double by) { for(j = 0; j < yelem; j++) { xcurs = x + xspace + (double)SCREEN_W/2.; for(i = 0; i < xelem; i++) { - /* Outfit elements. */ + /* Out of elements. */ if((j*xelem + i) >= iar->dat.iar.nelements) break; + is_selected = (iar->dat.iar.selected == j*xelem + i) ? 1 : 0; + + if(is_selected) + toolkit_drawRect(xcurs-(double)SCREEN_W/2. + 2., + ycurs-(double)SCREEN_H/2. + 2., + w - 4., h - 4., &cDConsole, NULL); + /* Image. */ if(iar->dat.iar.images[j*xelem + i] != NULL) gl_blitScale(iar->dat.iar.images[j*xelem + i], @@ -1239,10 +1253,11 @@ static void toolkit_renderImageArray(Widget* iar, double bx, double by) { /* Caption. */ gl_printMid(&gl_smallFont, iar->dat.iar.iw, xcurs + 5., ycurs + 5., - &cBlack, iar->dat.iar.captions[j*xelem + i]); + (is_selected) ? &cBlack : &cWhite, + iar->dat.iar.captions[j*xelem + i]); /* Outline. */ - if(iar->dat.iar.selected == j*xelem + i) { + if(is_selected) { lc = &cWhite; c = &cGrey80; dc = &cGrey60; @@ -1347,7 +1362,7 @@ int toolkit_input(SDL_Event* event) { static int mouse_down = 0; static void toolkit_mouseEvent(SDL_Event* event) { int i; - double x, y; + double x, y, rel_x, rel_y; Window* w; Widget* wgt, *wgt_func; @@ -1359,6 +1374,11 @@ static void toolkit_mouseEvent(SDL_Event* event) { if(event->type == SDL_MOUSEMOTION) { x = (double)event->motion.x; y = SCREEN_H - (double)event->motion.y; + /* Create relative events. */ + rel_x = x - last_x; + rel_y = y - last_y; + last_x = x; + last_y = y; } else if((event->type == SDL_MOUSEBUTTONDOWN) || (event->type == SDL_MOUSEBUTTONUP)) { x = (double)event->button.x; @@ -1390,10 +1410,24 @@ static void toolkit_mouseEvent(SDL_Event* event) { case SDL_MOUSEMOTION: if(!mouse_down) wgt->status = WIDGET_STATUS_MOUSEOVER; + else { + if(wgt->type == WIDGET_IMAGEARRAY) + toolkit_imgarrMove(wgt, rel_y); + } break; case SDL_MOUSEBUTTONDOWN: wgt->status = WIDGET_STATUS_MOUSEDOWN; + /* Handle mouse wheel. */ + if(event->button.button == SDL_BUTTON_WHEELUP) { + toolkit_listScroll(wgt, +1); + break; + } + if(event->button.button == SDL_BUTTON_WHEELDOWN) { + toolkit_listScroll(wgt, -1); + break; + } + if(toolkit_isFocusable(wgt)) w->focus = i; @@ -1407,6 +1441,11 @@ static void toolkit_mouseEvent(SDL_Event* event) { break; case SDL_MOUSEBUTTONUP: + /* Since basically only buttons are handled here, we ignore + * it all except the left mouse button. */ + if(event->button.button != SDL_BUTTON_LEFT) + break; + if(wgt->status == WIDGET_STATUS_MOUSEDOWN) { if((wgt->type == WIDGET_BUTTON) && (wgt->dat.btn.disabled==0)) { @@ -1428,6 +1467,9 @@ static void toolkit_mouseEvent(SDL_Event* event) { else if(!mouse_down) wgt->status = WIDGET_STATUS_NORMAL; } + + /* We trigger this at the end in case it destroys the window that is calling + * this function. Otherwise ugly segfaults appear. */ if(wgt_func) (*wgt_func->dat.btn.fptr)(wgt_func->name); } @@ -1568,6 +1610,7 @@ static int toolkit_isFocusable(Widget* wgt) { if(wgt->dat.btn.disabled == 1) return 0; case WIDGET_LIST: case WIDGET_INPUT: + case WIDGET_IMAGEARRAY: return 1; default: return 0; @@ -1599,6 +1642,10 @@ static void toolkit_triggerFocus(void) { /* Try to scroll up/down by direction. */ static void toolkit_listScroll(Widget* wgt, int direction) { + double w, h; + int xelem, yelem; + double hmax; + if(wgt == NULL) return; switch(wgt->type) { @@ -1608,6 +1655,28 @@ static void toolkit_listScroll(Widget* wgt, int direction) { wgt->dat.lst.selected = MIN(wgt->dat.lst.selected, wgt->dat.lst.noptions-1); if(wgt->dat.lst.fptr) (*wgt->dat.lst.fptr)(wgt->name); break; + + case WIDGET_IMAGEARRAY: + /* Element dimensions. */ + w = wgt->dat.iar.iw + 5.*2.; /* Includes border. */ + h = wgt->dat.iar.ih + 5.*2. + 2 + gl_smallFont.h; + + /* Number of elements. */ + xelem = (int)((wgt->w - 10.) / w); + yelem = (int)wgt->dat.iar.nelements / xelem + 1; + + /* Maximum. */ + hmax = h * (yelem - (int)(wgt->h / h)); + + /* Move. */ + wgt->dat.iar.pos -= direction * h; + + /* Boundry check. */ + wgt->dat.iar.pos = MAX(wgt->dat.iar.pos, 0.); + wgt->dat.iar.pos = MIN(wgt->dat.iar.pos, hmax); + if(wgt->dat.iar.fptr)(*wgt->dat.iar.fptr)(wgt->name); + break; + default: break; } @@ -1735,25 +1804,46 @@ static void toolkit_imgarrFocus(Widget* iar, double bx, double by) { y = iar->h - (iar->h - 30.) * scroll_pos - 15.; /* Click below the bar. */ - if(by < y-15.) { - iar->dat.iar.pos += h*2.; - } + if(by < y-15.) + toolkit_listScroll(iar, -2); /* Click above the bar. */ - else if(by > y+15.) { - iar->dat.iar.pos -= h*2.; - } else { - - } - - /* Boundry check. */ - if(iar->dat.iar.pos < 0.) - iar->dat.iar.pos = 0.; - else if(iar->dat.iar.pos > hmax) - iar->dat.iar.pos = hmax; - + else if(by > y+15.) + toolkit_listScroll(iar, +2); + /* Click on the bar. */ + else + iar->status = WIDGET_STATUS_SCROLLING; } +} +/** + * @fn static void toolkit_imgarrMove(Widget* iar, double ry) + * + * @brief Handles image array movement. + * @param iar Image Array that has mouse movement. + * @param ry Relative Y mouse movement. + */ +static void toolkit_imgarrMove(Widget* iar, double ry) { + double w, h; + int xelem, yelem; + double hmax; + + if(iar->status == WIDGET_STATUS_SCROLLING) { + /* Element dimensions. */ + w = iar->dat.iar.iw + 5.*2.; /* Includes border. */ + h = iar->dat.iar.ih + 5.*2. + 2. + gl_smallFont.h; + + /* Number of elements. */ + xelem = (int)((iar->w - 10.) / w); + yelem = (int)iar->dat.iar.nelements / xelem + 1; + + hmax = h * (yelem - (int)(iar->h / h)); + + iar->dat.iar.pos -= (ry * (iar->w - 30.) / hmax) / 2.; + + /* Does boundry checks. */ + toolkit_listScroll(iar, 0); + } } /* Return the focused widget. */