diff --git a/src/land.c b/src/land.c index 4ec7fd6..6297ba6 100644 --- a/src/land.c +++ b/src/land.c @@ -30,7 +30,7 @@ #define COMMODITY_HEIGHT 400 /* Outfits. */ -#define OUTFITS_WIDTH 700 +#define OUTFITS_WIDTH 800 #define OUTFITS_HEIGHT 600 /* Shipyard. */ @@ -241,7 +241,9 @@ static void commodity_sell(char* str) { } static void outfits_open(void) { + int i; char** soutfits; + glTexture** toutfits; int noutfits; char buf[128]; @@ -274,7 +276,8 @@ static void outfits_open(void) { BUTTON_WIDTH, BUTTON_HEIGHT, "cstMod", 0, outfits_renderMod, NULL); - window_addText(secondary_wid, 40+200+20, -60, + /* The descriptive text. */ + window_addText(secondary_wid, 40+300+20, -60, 80, 96, 0, "txtSDesc", &gl_smallFont, &cDConsole, "Name:\n" "Type:\n" @@ -286,11 +289,11 @@ static void outfits_open(void) { "Price:\n" "Money:\n"); - window_addText(secondary_wid, 40+200+40+60, -60, + window_addText(secondary_wid, 40+300+40+60, -60, 250, 96, 0, "txtDDesc", &gl_smallFont, &cBlack, NULL); - window_addText(secondary_wid, 20+200+40, -220, - OUTFITS_WIDTH-300, 180, 0, "txtDescription", + window_addText(secondary_wid, 20+300+40, -220, + OUTFITS_WIDTH-400, 180, 0, "txtDescription", &gl_smallFont, NULL, NULL); /* Set up the outfits to buy/sell. */ @@ -299,12 +302,18 @@ static void outfits_open(void) { if(noutfits <= 0) { /* No outfits. */ soutfits = malloc(sizeof(char*)); soutfits[0] = strdup("None"); + toutfits = malloc(sizeof(glTexture*)); + toutfits[0] = NULL; noutfits = 1; + } else { + toutfits = malloc(sizeof(glTexture*)*noutfits); + for(i = 0; i < noutfits; i++) + toutfits[i] = outfit_get(soutfits[i])->gfx_store; } - - window_addList(secondary_wid, 20, 40, - 200, OUTFITS_HEIGHT-80, "lstOutfits", - soutfits, noutfits, 0, outfits_update); + + window_addImageArray(secondary_wid, 20, 40, + 310, OUTFITS_HEIGHT-80, "iarOutfits", 64, 64, + toutfits, soutfits, noutfits, outfits_update); /* Write the outfits stuff. */ outfits_update(NULL); @@ -327,7 +336,7 @@ static void outfits_update(char* str) { Outfit* outfit; char buf[128], buf2[16], buf3[16]; - outfitname = toolkit_getList(secondary_wid, "lstOutfits"); + outfitname = toolkit_getImageArray(secondary_wid, "iarOutfits"); if(strcmp(outfitname, "None")==0) { /* No outfits. */ window_modifyImage(secondary_wid, "imgOutfit", NULL); @@ -439,7 +448,7 @@ static void outfits_buy(char* str) { Outfit* outfit; int q; - outfitname = toolkit_getList(secondary_wid, "lstOutfits"); + outfitname = toolkit_getImageArray(secondary_wid, "iarOutfits"); outfit = outfit_get(outfitname); q = outfits_getMod(); @@ -480,7 +489,7 @@ static void outfits_sell(char* str) { Outfit* outfit; int q; - outfitname = toolkit_getList(secondary_wid, "lstOutfits"); + outfitname = toolkit_getImageArray(secondary_wid, "iarOutfits"); outfit = outfit_get(outfitname); q = outfits_getMod(); diff --git a/src/toolkit.c b/src/toolkit.c index 0fb6e82..67fbdb8 100644 --- a/src/toolkit.c +++ b/src/toolkit.c @@ -24,7 +24,8 @@ typedef enum WidgetType_ { WIDGET_LIST, WIDGET_RECT, WIDGET_CUST, - WIDGET_INPUT + WIDGET_INPUT, + WIDGET_IMAGEARRAY } WidgetType; typedef enum WidgetStatus_ { @@ -88,6 +89,16 @@ typedef struct Widget_ { int oneline; /* Is it a one-line? '\n' and co. if no. */ int view, pos; /* View and cursor position. */ } inp; + struct { + glTexture** images; /**< Image array. */ + char** captions; /**< Corresponding caption array. */ + int nelements; /**< Number of elements. */ + int selected; /**< Currently selected element. */ + double pos; /**< Current y position. */ + int iw; /**< Image width to use. */ + int ih; /**< Image height to use. */ + void(*fptr)(char*); /**< Modify callback - triggered on selection. */ + } iar; /**< WIDGET_IMAGEARRAY */ } dat; } Widget; @@ -141,6 +152,7 @@ static void toolkit_triggerFocus(void); static Widget* toolkit_getFocus(void); static void toolkit_listScroll(Widget* wgt, int direction); static void toolkit_listFocus(Widget* lst, double bx, double by); +static void toolkit_imgarrFocus(Widget* iar, double dx, double by); /* Render. */ static void window_render(Window* w); static void toolkit_renderButton(Widget* btn, double bx, double by); @@ -150,6 +162,7 @@ static void toolkit_renderList(Widget* lst, double bx, double by); static void toolkit_renderRect(Widget* rct, double bx, double by); static void toolkit_renderCust(Widget* cst, double bx, double by); static void toolkit_renderInput(Widget* inp, double bx, double by); +static void toolkit_renderImageArray(Widget* iar, double bx, double by); static void toolkit_drawOutline(double x, double y, double w, double h, double b, glColour* c, glColour* lc); static void toolkit_clip(double x, double y, double w, double h); @@ -341,6 +354,54 @@ void window_addInput(const unsigned int wid, toolkit_setPos(wdw, wgt, x, y); } +/** + * @brief Add an Image array. + * @param wid Window to add to. + * @param x X position. + * @param y Y position. + * @param w Width. + * @param h Height. + * @param name Internal widget name. + * @param iw Image width to use. + * @param ih Image height to use. + * @param tex Texture array to use (not freed). + * @param caption Caption array to use (freed). + * @param nelem Elements in tex and caption. + * @param call Callback when modified. + */ +void window_addImageArray(const unsigned int wid, + const int x, const int y, /* Position. */ + const int w, const int h, /* Size. */ + char* name, const int iw, const int ih, /* Name and image sizes. */ + glTexture** tex, char** caption, int nelem, /* Elements. */ + void(*call) (char*)) { + + Window* wdw = window_wget(wid); + Widget* wgt = window_newWidget(wdw); + + /* Generic. */ + wgt->type = WIDGET_IMAGEARRAY; + wgt->name = strdup(name); + + /* Specific. */ + wgt->dat.iar.images = tex; + wgt->dat.iar.captions = caption; + wgt->dat.iar.nelements = nelem; + wgt->dat.iar.selected = 0; + wgt->dat.iar.pos = 0; + wgt->dat.iar.iw = iw; + wgt->dat.iar.ih = ih; + wgt->dat.iar.fptr = call; + + /* Position/Size. */ + wgt->w = (double)w; + wgt->h = (double)h; + toolkit_setPos(wdw, wgt, x, y); + + if(wdw->focus == -1) /* Initialize the focus. */ + toolkit_nextFocus(); +} + /* Return pointer to newly allocated widget. */ static Widget* window_newWidget(Window* w) { Widget* wgt = NULL; @@ -585,6 +646,15 @@ static void widget_cleanup(Widget* widget) { case WIDGET_INPUT: free(widget->dat.inp.input); /* Free the input buffer. */ break; + case WIDGET_IMAGEARRAY: + if(widget->dat.iar.nelements > 0) { /* Free each text individually. */ + for(i = 0; i < widget->dat.iar.nelements; i++) + if(widget->dat.iar.captions[i]); + /* Free the arrays. */ + free(widget->dat.iar.captions); + free(widget->dat.iar.images); + } + break; default: break; } @@ -895,6 +965,9 @@ static void window_render(Window* w) { case WIDGET_INPUT: toolkit_renderInput(&w->widgets[i], x, y); break; + case WIDGET_IMAGEARRAY: + toolkit_renderImageArray(&w->widgets[i], x, y); + break; } } /* Focus widget. */ @@ -1104,6 +1177,98 @@ static void toolkit_renderInput(Widget* inp, double bx, double by) { toolkit_colDark, NULL); } +/** + * @fn static void toolkit_renderImageArray(Widget* iar, double bx, double by) + * + * @brief Renders an image array. + */ +static void toolkit_renderImageArray(Widget* iar, double bx, double by) { + int i, j; + double x, y, w, h, xcurs, ycurs; + double scroll_pos, sx, sy; + int xelem, yelem, xspace; + glColour* c, *dc, *lc; + + x = bx + iar->x; + y = by + iar->y; + + /* Calculations. */ + 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); + xspace = (((int)iar->w - 10) % (int)w) / (xelem + 1); + yelem = (int)iar->dat.iar.nelements / xelem + 1; + + /* Background. */ + toolkit_drawRect(x, y, iar->w, iar->h, toolkit_colDark, NULL); + + /* Scrollbar. */ + + /* scrollbar background. */ + toolkit_drawRect(x+iar->w - 10., y, 10., iar->h, + toolkit_colDark, toolkit_col); + toolkit_drawOutline(x + iar->w - 10., y, 10., iar->h, 1., + toolkit_colLight, toolkit_col); + toolkit_drawOutline(x + iar->w - 10., y, 10., iar->h, 2., + toolkit_colDark, NULL); + + /* The bar */ + scroll_pos = iar->dat.iar.pos / (h * (yelem - (int)(iar->h / h))); + sx = x + iar->w - 10.; + sy = y + iar->h - (iar->h - 30.) * scroll_pos - 30.; + toolkit_drawRect(sx, sy, 10., 30., toolkit_colLight, toolkit_col); + toolkit_drawOutline(sx, sy, 10., 30., 0., toolkit_colDark, NULL); + + /* Main drawing loop. */ + toolkit_clip(x, y, iar->w, iar->h); + ycurs = y + iar->h + (double)SCREEN_H/2. - h + iar->dat.iar.pos; + for(j = 0; j < yelem; j++) { + xcurs = x + xspace + (double)SCREEN_W/2.; + for(i = 0; i < xelem; i++) { + /* Outfit elements. */ + if((j*xelem + i) >= iar->dat.iar.nelements) + break; + + /* Image. */ + if(iar->dat.iar.images[j*xelem + i] != NULL) + gl_blitScale(iar->dat.iar.images[j*xelem + i], + xcurs + 5., ycurs + gl_smallFont.h + 7., + iar->dat.iar.iw, iar->dat.iar.ih, NULL); + + /* Caption. */ + gl_printMid(&gl_smallFont, iar->dat.iar.iw, xcurs + 5., ycurs + 5., + &cBlack, iar->dat.iar.captions[j*xelem + i]); + + /* Outline. */ + if(iar->dat.iar.selected == j*xelem + i) { + lc = &cWhite; + c = &cGrey80; + dc = &cGrey60; + } else { + lc = toolkit_colLight; + c = toolkit_col; + dc = toolkit_colDark; + } + toolkit_drawOutline(xcurs-(double)SCREEN_W/2. + 2., + ycurs-(double)SCREEN_H/2. + 2., + w - 4., h - 4., 1., lc, c); + toolkit_drawOutline(xcurs-(double)SCREEN_W/2. + 2., + ycurs-(double)SCREEN_H/2. +2., + w - 4., h - 4., 2., dc, NULL); + + xcurs += w + xspace; + } + ycurs -= h; + } + toolkit_unclip(); + + /* Final outline. */ + toolkit_drawOutline(x, y+1, iar->w-1, iar->h-1, 1., toolkit_colLight, toolkit_col); + toolkit_drawOutline(x, y+1, iar->w-1, iar->h-1, 2., toolkit_colDark, NULL); +} + /* Handle input for input widget. */ static int toolkit_inputInput(Uint8 type, Widget* inp, SDLKey key) { int n; @@ -1232,10 +1397,15 @@ static void toolkit_mouseEvent(SDL_Event* event) { if(toolkit_isFocusable(wgt)) w->focus = i; - if(wgt->type == WIDGET_LIST) + if(wgt->type == WIDGET_LIST) { toolkit_listFocus(wgt, x-wgt->x, y-wgt->y); - + //input_key = 0; /* Hack to avoid weird bug with permascroll. */ + } + + if(wgt->type == WIDGET_IMAGEARRAY) + toolkit_imgarrFocus(wgt, x-wgt->x, y-wgt->y); break; + case SDL_MOUSEBUTTONUP: if(wgt->status == WIDGET_STATUS_MOUSEDOWN) { if((wgt->type == WIDGET_BUTTON) && @@ -1443,6 +1613,58 @@ static void toolkit_listScroll(Widget* wgt, int direction) { } } +/* Get what is selected currently in a list. */ +char* toolkit_getList(const unsigned int wid, char* name) { + Widget* wgt = window_getwgt(wid, name); + + if(wgt == NULL) { + WARN("Widget '%s' not found", name); + return NULL; + } + + if((wgt->type != WIDGET_LIST) || (wgt->dat.lst.selected == -1)) + return NULL; + + return wgt->dat.lst.options[wgt->dat.lst.selected]; +} + +/* Get the position of current item in the list. */ +int toolkit_getListPos(const unsigned int wid, char* name) { + Widget* wgt = window_getwgt(wid, name); + + if(wgt == NULL) { + WARN("Widget '%s' not found", name); + return -1; + } + + if((wgt->type != WIDGET_LIST) || (wgt->dat.lst.selected == -1)) + return -1; + + return wgt->dat.lst.selected; +} + +/** + * @fn char* toolkit_getImageArray(const unsigned int wid, char* name) + * + * @brief Get what is currently selected in an image array. + * @param wid Window to get array data from. + * @param name Name of the image array widget. + * @return Caption of the currently selected element. + */ +char* toolkit_getImageArray(const unsigned int wid, char* name) { + Widget* wgt = window_getwgt(wid, name); + + if(wgt == NULL) { + WARN("Widget '%s' not found", name); + return NULL; + } + + if((wgt->type != WIDGET_IMAGEARRAY) || (wgt->dat.iar.selected == -1)) + return NULL; + + return wgt->dat.iar.captions[wgt->dat.iar.selected]; +} + /* List mouse even focus. */ static void toolkit_listFocus(Widget* lst, double bx, double by) { (void)bx; @@ -1456,24 +1678,82 @@ static void toolkit_listFocus(Widget* lst, double bx, double by) { } } -/* Get what is selected currently in a list. */ -char* toolkit_getList(const unsigned int wid, char* name) { - Widget* wgt = window_getwgt(wid, name); +/** + * @fn static void toolkit_imgarrFocus(Widget* iar, double bx, double by) + * + * @brief Mouse event focus on image array. + * @param iar Image array widget. + * @param bx X position click. + * @param by Y position click. + */ +static void toolkit_imgarrFocus(Widget* iar, double bx, double by) { + int i, j; + double x, y, w, h, ycurs, xcurs; + double scroll_pos, hmax; + int xelem, xspace, yelem; - if((wgt->type != WIDGET_LIST) || (wgt->dat.lst.selected == -1)) - return NULL; + /* Positions. */ + x = bx + iar->x; + y = by + iar->y; - return wgt->dat.lst.options[wgt->dat.lst.selected]; -} + /* Element dimensions. */ + w = iar->dat.iar.iw + 5.*2.; /* Includes border. */ + h = iar->dat.iar.ih + 5.*2. + 2. + gl_smallFont.h; -/* Get the position of current item in the list. */ -int toolkit_getListPos(const unsigned int wid, char* name) { - Widget* wgt = window_getwgt(wid, name); + /* Number of elements. */ + xelem = (int)((iar->w - 10.) / w); + xspace = (((int)iar->w - 10) % (int)w) / (xelem + 1); + yelem = (int)iar->dat.iar.nelements / xelem + 1; - if((wgt->type != WIDGET_LIST) || (wgt->dat.lst.selected == -1)) - return -1; + /* Normal click. */ + if(bx < iar->w - 10.) { + /* Loop through elements until finding collision. */ + ycurs = iar->h - h + iar->dat.iar.pos; + for(j = 0; j < yelem; j++) { + xcurs = xspace; + for(i = 0; i < xelem; i++) { + /* Out of elements. */ + if((j*xelem + i) >= iar->dat.iar.nelements) + break; + + /* Check for collision. */ + if((bx > xcurs) && (bx < xcurs+w-4.) && + (by > ycurs) && (by < ycurs+h-4.)) { + iar->dat.iar.selected = j*xelem+i; + if(iar->dat.iar.fptr != NULL) + (*iar->dat.iar.fptr)(iar->name); + return; + } + xcurs += xspace + w; + } + ycurs -= h; + } + } else { /* Scrollbar click. */ + /* Get bar position (center). */ + hmax = h * (yelem - (int)(iar->h / h)); + scroll_pos = iar->dat.iar.pos / hmax; + y = iar->h - (iar->h - 30.) * scroll_pos - 15.; + + /* Click below the bar. */ + if(by < y-15.) { + iar->dat.iar.pos += h*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; + + } - return wgt->dat.lst.selected; } /* Return the focused widget. */ diff --git a/src/toolkit.h b/src/toolkit.h index ca010f6..5150a7e 100644 --- a/src/toolkit.h +++ b/src/toolkit.h @@ -43,6 +43,13 @@ void window_addInput(const unsigned int wid, const int w, const int h, char* name, const int max, const int oneline); +void window_addImageArray(const unsigned int wid, + const int x, const int y, /* Position. */ + const int w, const int h, /* Size. */ + char* name, const int iw, const int ih, /* Name and images sizes. */ + glTexture** tex, char** caption, int nelem, /* Elements. */ + void(*call)(char*)); + /* Modification. */ void window_setAccept(const unsigned int wid, void(*fptr)(char*)); void window_setCancel(const unsigned int wid, void(*cancel)(char*)); @@ -67,6 +74,7 @@ void window_moveWidget(const unsigned int wid, /* Specific. */ char* toolkit_getList(const unsigned int wid, char* name); int toolkit_getListPos(const unsigned int wid, char* name); +char* toolkit_getImageArray(const unsigned int wid, char* name); glTexture* window_getImage(const unsigned int wid, char* name); /* Destroy window. */