1 /*
2  * See Licensing and Copyright notice in naev.h
3  */
4 
5 /**
6  * @file imagearray.c
7  *
8  * @brief Image array widget.
9  */
10 
11 
12 #include "tk/toolkit_priv.h"
13 
14 #include <stdlib.h>
15 #include "nstring.h"
16 
17 #include "opengl.h"
18 
19 
20 /* Render. */
21 static void iar_render( Widget* iar, double bx, double by );
22 static void iar_renderOverlay( Widget* iar, double bx, double by );
23 /* Key. */
24 static int iar_key( Widget* iar, SDLKey key, SDLMod mod );
25 /* Mouse. */
26 static int iar_mclick( Widget* iar, int button, int x, int y );
27 #if SDL_VERSION_ATLEAST(2,0,0)
28 static int iar_mwheel( Widget* lst, SDL_MouseWheelEvent event );
29 #endif /* SDL_VERSION_ATLEAST(2,0,0) */
30 static int iar_mmove( Widget* iar, int x, int y, int rx, int ry );
31 /* Focus. */
32 static int iar_focusImage( Widget* iar, double bx, double by );
33 static void iar_focus( Widget* iar, double bx, double by );
34 static void iar_scroll( Widget* iar, int direction );
35 static void iar_centerSelected( Widget *iar );
36 /* Misc. */
37 static void iar_setAltTextPos( Widget *iar, double bx, double by );
38 static Widget *iar_getWidget( const unsigned int wid, const char *name );
39 static char* toolkit_getNameById( Widget *wgt, int elem );
40 /* Clean up. */
41 static void iar_cleanup( Widget* iar );
42 
43 
44 /**
45  * @brief Adds an Image Array widget.
46  *
47  * Position origin is 0,0 at bottom left. If you use negative X or Y
48  *  positions. They actually count from the opposite side in.
49  *
50  *    @param wid Window to add to.
51  *    @param x X position.
52  *    @param y Y position.
53  *    @param w Width.
54  *    @param h Height.
55  *    @param name Internal widget name.
56  *    @param iw Image width to use.
57  *    @param ih Image height to use.
58  *    @param tex Texture array to use (not freed).
59  *    @param caption Caption array to use (freed).
60  *    @param nelem Elements in tex and caption.
61  *    @param call Callback when modified.
62  */
window_addImageArray(const unsigned int wid,const int x,const int y,const int w,const int h,char * name,const int iw,const int ih,glTexture ** tex,char ** caption,int nelem,void (* call)(unsigned int wdw,char * wgtname),void (* rmcall)(unsigned int wdw,char * wgtname))63 void window_addImageArray( const unsigned int wid,
64                            const int x, const int y, /* position */
65                            const int w, const int h, /* size */
66                            char* name, const int iw, const int ih,
67                            glTexture** tex, char** caption, int nelem,
68                            void (*call) (unsigned int wdw, char* wgtname),
69                            void (*rmcall) (unsigned int wdw, char* wgtname) )
70 {
71    Window *wdw = window_wget(wid);
72    Widget *wgt = window_newWidget(wdw, name);
73    if (wgt == NULL)
74       return;
75 
76    /* generic */
77    wgt->type   = WIDGET_IMAGEARRAY;
78 
79    /* position/size */
80    wgt->w = (double) w;
81    wgt->h = (double) h;
82    toolkit_setPos( wdw, wgt, x, y );
83 
84    /* specific */
85    wgt->render             = iar_render;
86    wgt->renderOverlay      = iar_renderOverlay;
87    wgt->cleanup            = iar_cleanup;
88    wgt_setFlag(wgt, WGT_FLAG_CANFOCUS);
89    wgt->keyevent           = iar_key;
90    wgt->mclickevent        = iar_mclick;
91 #if SDL_VERSION_ATLEAST(2,0,0)
92    wgt->mwheelevent        = iar_mwheel;
93 #endif /* SDL_VERSION_ATLEAST(2,0,0) */
94    wgt->mmoveevent         = iar_mmove;
95    wgt_setFlag(wgt, WGT_FLAG_ALWAYSMMOVE);
96    wgt->dat.iar.images     = tex;
97    wgt->dat.iar.captions   = caption;
98    wgt->dat.iar.nelements  = nelem;
99    wgt->dat.iar.selected   = 0;
100    wgt->dat.iar.pos        = 0;
101    wgt->dat.iar.alt        = -1;
102    wgt->dat.iar.altx       = -1;
103    wgt->dat.iar.alty       = -1;
104    wgt->dat.iar.iw         = iw;
105    wgt->dat.iar.ih         = ih;
106    wgt->dat.iar.fptr       = call;
107    wgt->dat.iar.rmptr      = rmcall;
108    wgt->dat.iar.xelem      = floor((w - 10.) / (double)(wgt->dat.iar.iw+10));
109    wgt->dat.iar.yelem      = (wgt->dat.iar.xelem == 0) ? 0 :
110          (int)wgt->dat.iar.nelements / wgt->dat.iar.xelem + 1;
111 
112    if (wdw->focus == -1) /* initialize the focus */
113       toolkit_nextFocus( wdw );
114 }
115 
116 
117 /**
118  * @brief Gets image array effective dimensions.
119  */
iar_getDim(Widget * iar,double * w,double * h)120 static void iar_getDim( Widget* iar, double *w, double *h )
121 {
122    if (w != NULL)
123       *w = iar->dat.iar.iw + 5.*2.;
124    if (h != NULL)
125       *h = iar->dat.iar.ih + 5.*2. + 2. + gl_smallFont.h;
126 }
127 
128 
129 /**
130  * @brief Renders an image array.
131  *
132  *    @param iar Image array widget to render.
133  *    @param bx Base X position.
134  *    @param by Base Y position.
135  */
iar_render(Widget * iar,double bx,double by)136 static void iar_render( Widget* iar, double bx, double by )
137 {
138    int i,j, pos;
139    double x,y, w,h, xcurs,ycurs;
140    double scroll_pos;
141    int xelem, yelem;
142    double xspace;
143    const glColour *c, *dc, *lc;
144    glColour tc, fontcolour;
145    int is_selected;
146    int tw;
147    double d;
148 
149    /*
150     * Calculations.
151     */
152    /* position */
153    x = bx + iar->x;
154    y = by + iar->y;
155 
156    /* element dimensions */
157    iar_getDim( iar, &w, &h );
158 
159    /* number of elements */
160    xelem = iar->dat.iar.xelem;
161    yelem = iar->dat.iar.yelem;
162    xspace = (double)(((int)iar->w - 10) % (int)w) / (double)(xelem + 1);
163 
164    /* background */
165    toolkit_drawRect( x, y, iar->w, iar->h, &cBlack, NULL );
166 
167    /*
168     * Scrollbar.
169     */
170    d          = h * (yelem - (int)(iar->h / h));
171    if (fabs(d) < 1e-05)
172       scroll_pos = 0.;
173    else
174       scroll_pos = iar->dat.iar.pos / d;
175    toolkit_drawScrollbar( x + iar->w - 10., y, 10., iar->h, scroll_pos );
176 
177    /*
178     * Main drawing loop.
179     */
180    gl_clipRect( x, y, iar->w, iar->h );
181    ycurs = y + iar->h - h + iar->dat.iar.pos;
182    for (j=0; j<yelem; j++) {
183       xcurs = x + xspace;
184 
185       /*  Skip rows that are wholly outside of the viewport. */
186       if ((ycurs > y + iar->h) || (ycurs + h < y)) {
187          ycurs -= h;
188          continue;
189       }
190 
191       for (i=0; i<xelem; i++) {
192 
193          /* Get position. */
194          pos = j*xelem + i;
195 
196          /* Out of elements. */
197          if ((pos) >= iar->dat.iar.nelements)
198             break;
199 
200          is_selected = (iar->dat.iar.selected == pos) ? 1 : 0;
201 
202          fontcolour = cWhite;
203          /* Draw background. */
204          if (is_selected)
205             toolkit_drawRect( xcurs + 2.,
206                   ycurs + 2.,
207                   w - 5., h - 5., &cDConsole, NULL );
208          else if (iar->dat.iar.background != NULL) {
209             toolkit_drawRect( xcurs + 2.,
210                   ycurs + 2.,
211                   w - 5., h - 5., &iar->dat.iar.background[pos], NULL );
212 
213             tc = iar->dat.iar.background[pos];
214 
215             if (((tc.r + tc.g + tc.b) / 3) > 0.5)
216                fontcolour = cBlack;
217          }
218 
219          /* image */
220          if (iar->dat.iar.images[pos] != NULL)
221             gl_blitScale( iar->dat.iar.images[pos],
222                   xcurs + 5., ycurs + gl_smallFont.h + 7.,
223                   iar->dat.iar.iw, iar->dat.iar.ih, NULL );
224 
225          /* caption */
226          if (iar->dat.iar.captions[pos] != NULL)
227             gl_printMidRaw( &gl_smallFont, iar->dat.iar.iw, xcurs + 5., ycurs + 5.,
228                      (is_selected) ? &cBlack : &fontcolour,
229                      iar->dat.iar.captions[pos] );
230 
231          /* quantity. */
232          if (iar->dat.iar.quantity != NULL) {
233             if (iar->dat.iar.quantity[pos] != NULL) {
234                /* Rectangle to highlight better. */
235                tw = gl_printWidthRaw( &gl_smallFont,
236                      iar->dat.iar.quantity[pos] );
237 
238                if (is_selected)
239                   tc = cDConsole;
240                else if (iar->dat.iar.background != NULL)
241                   tc = iar->dat.iar.background[pos];
242                else
243                   tc = cBlack;
244 
245                tc.a = 0.75;
246                toolkit_drawRect( xcurs + 2.,
247                      ycurs + 5. + iar->dat.iar.ih,
248                      tw + 4., gl_smallFont.h + 4., &tc, NULL );
249                /* Quantity number. */
250                gl_printMaxRaw( &gl_smallFont, iar->dat.iar.iw,
251                      xcurs + 5., ycurs + iar->dat.iar.ih + 7.,
252                      &fontcolour, iar->dat.iar.quantity[pos] );
253             }
254          }
255 
256          /* Slot type. */
257          if (iar->dat.iar.slottype != NULL) {
258             if (iar->dat.iar.slottype[pos] != NULL) {
259                /* Rectangle to highlight better. Width is a hack due to lack of monospace font. */
260                tw = gl_printWidthRaw( &gl_smallFont, "M" );
261 
262                if (is_selected)
263                   tc = cDConsole;
264                else if (iar->dat.iar.background != NULL)
265                   tc = iar->dat.iar.background[pos];
266                else
267                   tc = cBlack;
268 
269                tc.a = 0.75;
270                toolkit_drawRect( xcurs + iar->dat.iar.iw - 6.,
271                      ycurs + 5. + iar->dat.iar.ih,
272                      tw + 2., gl_smallFont.h + 4., &tc, NULL );
273                /* Slot size letter. */
274                gl_printMaxRaw( &gl_smallFont, iar->dat.iar.iw,
275                      xcurs + iar->dat.iar.iw - 4., ycurs + iar->dat.iar.ih + 7.,
276                      &fontcolour, iar->dat.iar.slottype[pos] );
277             }
278          }
279 
280          /* outline */
281          if (is_selected) {
282             lc = &cWhite;
283             c = &cGrey80;
284             dc = &cGrey60;
285          }
286          else {
287             lc = toolkit_colLight;
288             c = toolkit_col;
289             dc = toolkit_colDark;
290          }
291          toolkit_drawOutline( xcurs + 2.,
292                ycurs + 2.,
293                w - 4., h - 4., 1., lc, c );
294          toolkit_drawOutline( xcurs + 2.,
295                ycurs + 2.,
296                w - 4., h - 4., 2., dc, NULL );
297          xcurs += w + xspace;
298       }
299       ycurs -= h;
300    }
301    gl_unclipRect();
302 
303    /*
304     * Final outline.
305     */
306    toolkit_drawOutline( x+1, y+1, iar->w-2, iar->h-2, 1., toolkit_colLight, toolkit_col );
307    toolkit_drawOutline( x+1, y+1, iar->w-2, iar->h-2, 2., toolkit_colDark, NULL );
308 }
309 
310 
311 /**
312  * @brief Renders the overlay.
313  */
iar_renderOverlay(Widget * iar,double bx,double by)314 static void iar_renderOverlay( Widget* iar, double bx, double by )
315 {
316    double x, y;
317 
318    /*
319     * Draw Alt text if applicable.
320     */
321    if ((iar->dat.iar.alts != NULL) && (iar->dat.iar.alt >= 0) &&
322          (iar->dat.iar.altx != -1) && (iar->dat.iar.alty != -1) &&
323          (iar->dat.iar.alts[iar->dat.iar.alt] != NULL)) {
324 
325       /* Calculate position. */
326       x = bx + iar->x + iar->dat.iar.altx;
327       y = by + iar->y + iar->dat.iar.alty;
328 
329       /* Draw alt text. */
330       toolkit_drawAltText( x, y, iar->dat.iar.alts[iar->dat.iar.alt] );
331    }
332 }
333 
334 
335 /**
336  * @brief Handles input for an image array widget.
337  *
338  *    @param iar Image array widget to handle event.
339  *    @param key Key being handled.
340  *    @param mod Mods when key is being pressed.
341  *    @return 1 if the event was used, 0 if it wasn't.
342  */
iar_key(Widget * iar,SDLKey key,SDLMod mod)343 static int iar_key( Widget* iar, SDLKey key, SDLMod mod )
344 {
345    (void) mod;
346 
347    switch (key) {
348       case SDLK_UP:
349          iar->dat.iar.selected -= iar->dat.iar.xelem;
350          break;
351       case SDLK_DOWN:
352          iar->dat.iar.selected += iar->dat.iar.xelem;
353          break;
354       case SDLK_RIGHT:
355          iar->dat.iar.selected += 1;
356          break;
357       case SDLK_LEFT:
358          iar->dat.iar.selected -= 1;
359          break;
360 
361       default:
362          return 0;
363    }
364 
365    /* Check boundaries. */
366    iar->dat.iar.selected = CLAMP( 0, iar->dat.iar.nelements-1, iar->dat.iar.selected);
367 
368    /* Run function pointer if needed. */
369    if (iar->dat.iar.fptr)
370       iar->dat.iar.fptr( iar->wdw, iar->name);
371 
372    iar_centerSelected( iar );
373    return 1;
374 }
375 
376 
377 /**
378  * @brief Centers on the selection if needed.
379  *
380  *    @param iar Widget to center on selection.
381  */
iar_centerSelected(Widget * iar)382 static void iar_centerSelected( Widget *iar )
383 {
384    int y;
385    double h;
386    double hmax;
387    double ypos;
388 
389    /* Get dimensions. */
390    iar_getDim( iar, NULL, &h );
391 
392    /* Ignore fancy stuff if smaller than height. */
393    if (h * iar->dat.iar.yelem < iar->h)
394       return;
395 
396    /* Move if needed. */
397    hmax = h * (iar->dat.iar.yelem - (int)(iar->h / h));
398    y = iar->dat.iar.selected / iar->dat.iar.xelem;
399    ypos = y * h;
400    /* Below. */
401    if (ypos < iar->dat.iar.pos)
402       iar->dat.iar.pos = ypos;
403    /* Above. */
404    if (ypos > iar->dat.iar.pos + iar->h - h)
405       iar->dat.iar.pos = ypos - h*floor(iar->h/h) + 10.;
406    iar->dat.iar.pos = CLAMP( 0., hmax, iar->dat.iar.pos );
407 
408    iar_setAltTextPos( iar, iar->dat.iar.altx, iar->dat.iar.alty );
409 }
410 
411 
412 /**
413  * @brief Image array widget mouse click handler.
414  *
415  *    @param iar Widget receiving the event.
416  *    @param mclick The mouse click event.
417  *    @return 1 if event is used.
418  */
iar_mclick(Widget * iar,int button,int x,int y)419 static int iar_mclick( Widget* iar, int button, int x, int y )
420 {
421    /* Handle different mouse clicks. */
422    switch (button) {
423       case SDL_BUTTON_LEFT:
424          iar_focus( iar, x, y );
425          return 1;
426 #if !SDL_VERSION_ATLEAST(2,0,0)
427       case SDL_BUTTON_WHEELUP:
428          iar_scroll( iar, +1 );
429          return 1;
430       case SDL_BUTTON_WHEELDOWN:
431          iar_scroll( iar, -1 );
432          return 1;
433 #endif /* !SDL_VERSION_ATLEAST(2,0,0) */
434       case SDL_BUTTON_RIGHT:
435          iar_focus( iar, x, y );
436          if (iar->dat.iar.rmptr != NULL)
437             iar->dat.iar.rmptr( iar->wdw, iar->name );
438 
439          iar_setAltTextPos( iar, x, y );
440 
441          return 1;
442 
443       default:
444          break;
445    }
446    return 0;
447 }
448 
449 
450 #if SDL_VERSION_ATLEAST(2,0,0)
451 /**
452  * @brief Handler for mouse wheel events for an image array.
453  *
454  *    @param iar The widget handling the mouse wheel event.
455  *    @param event The event the widget should handle.
456  *    @return 1 if the widget uses the event.
457  */
iar_mwheel(Widget * iar,SDL_MouseWheelEvent event)458 static int iar_mwheel( Widget* iar, SDL_MouseWheelEvent event )
459 {
460    if (event.y > 0)
461       iar_scroll( iar, +1 );
462    else
463       iar_scroll( iar, -1 );
464 
465    return 1;
466 }
467 #endif /* SDL_VERSION_ATLEAST(2,0,0) */
468 
469 
470 /**
471  * @brief Handles mouse movement for an image array.
472  *
473  *    @param iar Widget handling the mouse motion.
474  *    @param mmove Mouse motion event to handle.
475  *    @return 1 if the event is used.
476  */
iar_mmove(Widget * iar,int x,int y,int rx,int ry)477 static int iar_mmove( Widget* iar, int x, int y, int rx, int ry )
478 {
479    (void) rx;
480    (void) ry;
481    double w,h;
482    int yelem;
483    double hmax;
484 
485    if (iar->status == WIDGET_STATUS_SCROLLING) {
486 
487       y = CLAMP( 15, iar->h - 15., iar->h - y );
488 
489       /* element dimensions */
490       iar_getDim( iar, &w, &h );
491 
492       /* number of elements */
493       yelem = iar->dat.iar.yelem;
494 
495       hmax = h * (yelem - (int)(iar->h / h));
496       iar->dat.iar.pos = (y - 15.) * hmax / (iar->h - 30.);
497 
498       /* Does boundary checks. */
499       iar_scroll( iar, 0 );
500 
501       return 1;
502    }
503    else {
504       if ((x < 0) || (x >= iar->w) || (y < 0) || (y >= iar->h))
505          iar->dat.iar.alt  = -1;
506       else
507          iar_setAltTextPos( iar, x, y );
508    }
509 
510    return 0;
511 }
512 
513 
514 /**
515  * @brief Clean up function for the image array widget.
516  *
517  *    @param iar Image array widget to clean up.
518  */
iar_cleanup(Widget * iar)519 static void iar_cleanup( Widget* iar )
520 {
521    int i;
522 
523    if (iar->dat.iar.nelements > 0) { /* Free each text individually */
524       for (i=0; i<iar->dat.iar.nelements; i++) {
525          if (iar->dat.iar.captions[i])
526             free(iar->dat.iar.captions[i]);
527          if (iar->dat.iar.alts && iar->dat.iar.alts[i])
528             free(iar->dat.iar.alts[i]);
529          if (iar->dat.iar.quantity && iar->dat.iar.quantity[i])
530             free(iar->dat.iar.quantity[i]);
531       }
532    }
533 
534    /* Clean up slottypes. */
535    if (iar->dat.iar.slottype != NULL) {
536       for (i=0; i<iar->dat.iar.nelements; i++) {
537          if (iar->dat.iar.slottype[i] != NULL)
538             free( iar->dat.iar.slottype[i] );
539       }
540       free(iar->dat.iar.slottype);
541    }
542 
543 
544    /* Free the arrays */
545    if (iar->dat.iar.captions != NULL)
546       free( iar->dat.iar.captions );
547    if (iar->dat.iar.images != NULL)
548       free( iar->dat.iar.images );
549    if (iar->dat.iar.alts != NULL)
550       free(iar->dat.iar.alts);
551    if (iar->dat.iar.quantity != NULL)
552       free(iar->dat.iar.quantity);
553    if (iar->dat.iar.background != NULL)
554       free(iar->dat.iar.background);
555 }
556 
557 
558 /**
559  * @brief Tries to scroll a widget up/down by direction.
560  *
561  *    @param wgt Widget to scroll.
562  *    @param direction Direction to scroll. Positive is up, negative
563  *           is down and absolute value is number of elements to scroll.
564  */
iar_scroll(Widget * iar,int direction)565 static void iar_scroll( Widget* iar, int direction )
566 {
567    double w,h;
568    int yelem;
569    double hmax;
570 
571    if (iar == NULL)
572       return;
573 
574    /* element dimensions */
575    iar_getDim( iar, &w, &h );
576 
577    /* number of elements */
578    yelem = iar->dat.iar.yelem;
579 
580    /* maximum */
581    hmax = h * (yelem - (int)(iar->h / h));
582    if (hmax < 0.)
583       hmax = 0.;
584 
585    /* move */
586    iar->dat.iar.pos -= direction * h;
587 
588    /* Boundary check. */
589    iar->dat.iar.pos = CLAMP( 0., hmax, iar->dat.iar.pos );
590    if (iar->dat.iar.fptr)
591       iar->dat.iar.fptr( iar->wdw, iar->name );
592 
593    iar_setAltTextPos( iar, iar->dat.iar.altx, iar->dat.iar.alty );
594 }
595 
596 
597 /**
598  * @brief See what widget is being focused.
599  */
iar_focusImage(Widget * iar,double bx,double by)600 static int iar_focusImage( Widget* iar, double bx, double by )
601 {
602    int x, y;
603    double w, h;
604    int xelem;
605    double xspace;
606 
607    /* element dimensions */
608    iar_getDim( iar, &w, &h );
609 
610    /* number of elements */
611    xelem = iar->dat.iar.xelem;
612    xspace = (double)(((int)iar->w - 10) % (int)w) / (double)(xelem + 1);
613 
614    x = bx / (xspace + w);
615    y = (iar->h - by + iar->dat.iar.pos) / h;
616 
617    /* Reject anything too close to the scroll bar or exceeding nelements. */
618    if (y * xelem + x >= iar->dat.iar.nelements || bx >= iar->w - 10.)
619       return -1;
620 
621    /* Verify that the mouse is on an icon. */
622    if ((bx < (x+1) * xspace + x * w) || (bx > (x+1) * (xspace + w) - 4.) ||
623          (by > iar->h + iar->dat.iar.pos - y * h - 4.))
624       return -1;
625 
626    return y * xelem + x;
627 }
628 
629 
630 
631 /**
632  * @brief Mouse event focus on image array.
633  *
634  *    @param iar Image Array widget.
635  *    @param bx X position click.
636  *    @param by Y position click.
637  */
iar_focus(Widget * iar,double bx,double by)638 static void iar_focus( Widget* iar, double bx, double by )
639 {
640    double y, h;
641    double scroll_pos, hmax;
642    int yelem;
643    int selected;
644 
645    /* element dimensions */
646    iar_getDim( iar, NULL, &h );
647 
648    /* number of elements */
649    yelem = iar->dat.iar.yelem;
650 
651    /* Test for item click. */
652    selected = iar_focusImage( iar, bx, by );
653    if (selected >= 0) {
654       iar->dat.iar.selected = selected;
655       if (iar->dat.iar.fptr != NULL)
656          iar->dat.iar.fptr( iar->wdw, iar->name );
657    }
658    /* Scrollbar click. */
659    else if (bx > iar->w - 10.) {
660       /* Get bar position (center). */
661       hmax = h * (yelem - (int)(iar->h / h));
662       if (fabs(hmax) < 1e-05)
663          scroll_pos = 0.;
664       else
665          scroll_pos = iar->dat.iar.pos / hmax;
666       y = iar->h - (iar->h - 30.) * scroll_pos - 15.;
667 
668       /* Click below the bar. */
669       if (by < y-15.)
670          iar_scroll( iar, -2 );
671       /* Click above the bar. */
672       else if (by > y+15.)
673          iar_scroll( iar, +2 );
674       /* Click on the bar. */
675       else
676          iar->status = WIDGET_STATUS_SCROLLING;
677    }
678 }
679 
680 
681 /**
682  * @brief Chooses correct alt text for the given coordinates
683  *
684  */
iar_setAltTextPos(Widget * iar,double bx,double by)685 static void iar_setAltTextPos( Widget *iar, double bx, double by )
686 {
687    iar->dat.iar.alt  = iar_focusImage( iar, bx, by );
688    iar->dat.iar.altx = bx;
689    iar->dat.iar.alty = by;
690 }
691 
692 
693 /**
694  * @brief Gets an image array.
695  */
iar_getWidget(const unsigned int wid,const char * name)696 static Widget *iar_getWidget( const unsigned int wid, const char *name )
697 {
698    Widget *wgt = window_getwgt(wid,name);
699 
700    /* Must be found in stack. */
701    if (wgt == NULL) {
702       WARN("Widget '%s' not found", name);
703       return NULL;
704    }
705 
706    /* Must be an image array. */
707    if (wgt->type != WIDGET_IMAGEARRAY) {
708       WARN("Widget '%s' is not an image array.", name);
709       return NULL;
710    }
711 
712    return wgt;
713 }
714 
715 
716 /**
717  * @brief Gets the name of the element.
718  *
719  *    @param wid Window where image array is.
720  *    @param name Name of the image array.
721  *    @param elem The element in the image array.
722  *    @return The name of the selected object.
723  */
toolkit_getNameById(Widget * wgt,int elem)724 static char* toolkit_getNameById( Widget *wgt, int elem )
725 {
726    if (wgt == NULL)
727       return NULL;
728 
729    /* Nothing selected. */
730    if (elem == -1)
731       return NULL;
732 
733    return wgt->dat.iar.captions[ elem ];
734 }
735 
736 
737 /**
738  * @brief Gets what is selected currently in an Image Array.
739  *
740  *    @param wid Window where image array is.
741  *    @param name Name of the image array.
742  *    @return The name of the selected object.
743  */
toolkit_getImageArray(const unsigned int wid,const char * name)744 char* toolkit_getImageArray( const unsigned int wid, const char* name )
745 {
746    Widget *wgt = iar_getWidget( wid, name );
747    if (wgt == NULL)
748       return NULL;
749 
750    return toolkit_getNameById( wgt, wgt->dat.iar.selected );
751 }
752 
753 
754 /**
755  * @brief Sets an image array based on value.
756  */
toolkit_setImageArray(const unsigned int wid,const char * name,char * elem)757 int toolkit_setImageArray( const unsigned int wid, const char* name, char* elem )
758 {
759    int i;
760    Widget *wgt = iar_getWidget( wid, name );
761    if (wgt == NULL)
762       return -1;
763 
764    /* Case NULL. */
765    if (elem == NULL) {
766       wgt->dat.iar.selected = -1;
767       return 0;
768    }
769 
770    /* Try to find the element. */
771    for (i=0; i<wgt->dat.iar.nelements; i++) {
772       if (strcmp(elem,wgt->dat.iar.captions[i])==0) {
773          wgt->dat.iar.selected = i;
774          return 0;
775       }
776    }
777 
778    /* Element not found. */
779    return -1;
780 }
781 
782 
783 /**
784  * @brief Gets what is selected currently in an Image Array.
785  *
786  *    @param wid Window where image array is.
787  *    @param name Name of the image array.
788  *    @return The position of selected object.
789  */
toolkit_getImageArrayPos(const unsigned int wid,const char * name)790 int toolkit_getImageArrayPos( const unsigned int wid, const char* name )
791 {
792    Widget *wgt = iar_getWidget( wid, name );
793    if (wgt == NULL)
794       return -1;
795 
796    return wgt->dat.iar.selected;
797 }
798 
799 
800 /**
801  * @brief Gets the Image Array offset.
802  */
toolkit_getImageArrayOffset(const unsigned int wid,const char * name)803 double toolkit_getImageArrayOffset( const unsigned int wid, const char* name )
804 {
805    Widget *wgt = iar_getWidget( wid, name );
806    if (wgt == NULL)
807       return -1.;
808 
809    return wgt->dat.iar.pos;
810 }
811 
812 
813 /**
814  * @brief Sets the Image Array offset.
815  */
toolkit_setImageArrayOffset(const unsigned int wid,const char * name,double off)816 int toolkit_setImageArrayOffset( const unsigned int wid, const char* name, double off )
817 {
818    double h;
819    double hmax;
820 
821    Widget *wgt = iar_getWidget( wid, name );
822    if (wgt == NULL)
823       return -1;
824 
825    /* Get dimensions. */
826    iar_getDim( wgt, NULL, &h );
827 
828    /* Ignore fancy stuff if smaller than height. */
829    if (h * wgt->dat.iar.yelem < wgt->h) {
830       wgt->dat.iar.pos = 0.;
831       return 0;
832    }
833 
834    /* Move if needed. */
835    hmax = h * (wgt->dat.iar.yelem - (int)(wgt->h / h));
836    wgt->dat.iar.pos = CLAMP( 0., hmax, off );
837 
838    iar_setAltTextPos( wgt, wgt->dat.iar.altx, wgt->dat.iar.alty );
839 
840    return 0;
841 }
842 
843 
844 /**
845  * @brief Sets the active element in the Image Array.
846  *
847  *    @param wid Window where image array is.
848  *    @param name Name of the image array.
849  *    @param pos Position to set to.
850  *    @return 0 on success.
851  */
toolkit_setImageArrayPos(const unsigned int wid,const char * name,int pos)852 int toolkit_setImageArrayPos( const unsigned int wid, const char* name, int pos )
853 {
854    Widget *wgt = iar_getWidget( wid, name );
855    if (wgt == NULL)
856       return -1;
857 
858    /* Set position. */
859    wgt->dat.iar.selected = CLAMP( 0, wgt->dat.iar.nelements-1, pos );
860 
861    /* Call callback - dangerous if called from within callback. */
862    if (wgt->dat.iar.fptr != NULL)
863       wgt->dat.iar.fptr( wgt->wdw, wgt->name );
864 
865    iar_centerSelected( wgt );
866 
867    return 0;
868 }
869 
870 
871 /**
872  * @brief Sets the alt text for the images in the image array.
873  *
874  *    @param wid Window where image array is.
875  *    @param name Name of the image array.
876  *    @param alt Array of alt text the size of the images in the array.
877  *    @return 0 on success.
878  */
toolkit_setImageArrayAlt(const unsigned int wid,const char * name,char ** alt)879 int toolkit_setImageArrayAlt( const unsigned int wid, const char* name, char **alt )
880 {
881    int i;
882    Widget *wgt = iar_getWidget( wid, name );
883    if (wgt == NULL)
884       return -1;
885 
886    /* Clean up. */
887    if (wgt->dat.iar.alts != NULL) {
888       for (i=0; i<wgt->dat.iar.nelements; i++)
889          if (wgt->dat.iar.alts[i] != NULL)
890             free(wgt->dat.iar.alts[i]);
891       free(wgt->dat.iar.alts);
892    }
893 
894    /* Set. */
895    wgt->dat.iar.alts = alt;
896    return 0;
897 }
898 
899 
900 /**
901  * @brief Sets the quantity text for the images in the image array.
902  *
903  *    @param wid Window where image array is.
904  *    @param name Name of the image array.
905  *    @param quantity Array of quantities for the images in the array.
906  *    @return 0 on success.
907  */
toolkit_setImageArrayQuantity(const unsigned int wid,const char * name,char ** quantity)908 int toolkit_setImageArrayQuantity( const unsigned int wid, const char* name,
909       char **quantity )
910 {
911    int i;
912    Widget *wgt = iar_getWidget( wid, name );
913    if (wgt == NULL)
914       return -1;
915 
916    /* Clean up. */
917    if (wgt->dat.iar.quantity != NULL) {
918       for (i=0; i<wgt->dat.iar.nelements; i++)
919          if (wgt->dat.iar.quantity[i] != NULL)
920             free(wgt->dat.iar.quantity[i]);
921       free(wgt->dat.iar.quantity);
922    }
923 
924    /* Set. */
925    wgt->dat.iar.quantity = quantity;
926    return 0;
927 }
928 
929 
930 /**
931  * @brief Sets the slot type text for the images in the image array.
932  *
933  *    @param wid Window where image array is.
934  *    @param name Name of the image array.
935  *    @param slottype Array of slot sizes for the images in the array.
936  *    @return 0 on success.
937  */
toolkit_setImageArraySlotType(const unsigned int wid,const char * name,char ** slottype)938 int toolkit_setImageArraySlotType( const unsigned int wid, const char* name,
939       char **slottype )
940 {
941    int i;
942    Widget *wgt = iar_getWidget( wid, name );
943    if (wgt == NULL)
944       return -1;
945 
946    /* Clean up. */
947    if (wgt->dat.iar.slottype != NULL) {
948       for (i=0; i<wgt->dat.iar.nelements; i++)
949          if (wgt->dat.iar.slottype[i] != NULL)
950             free(wgt->dat.iar.slottype[i]);
951       free(wgt->dat.iar.slottype);
952    }
953 
954    /* Set. */
955    wgt->dat.iar.slottype = slottype;
956    return 0;
957 }
958 
959 
960 /**
961  * @brief Sets the background colour for the images in the image array.
962  *
963  *    @param wid Window where image array is.
964  *    @param name Name of the image array.
965  *    @param bg Background colour for the image array.
966  *    @return 0 on success.
967  */
toolkit_setImageArrayBackground(const unsigned int wid,const char * name,glColour * bg)968 int toolkit_setImageArrayBackground( const unsigned int wid, const char* name,
969       glColour *bg )
970 {
971    Widget *wgt = iar_getWidget( wid, name );
972    if (wgt == NULL)
973       return -1;
974 
975    /* Free if already exists. */
976    if (wgt->dat.iar.background != NULL)
977       free( wgt->dat.iar.background );
978 
979    /* Set. */
980    wgt->dat.iar.background = bg;
981    return 0;
982 }
983 
984 
985 /**
986  * @brief Stores several image array attributes.
987  *
988  *    @param wid Window containing the image array.
989  *    @param name Name of the image array widget.
990  *    @param iar_data Pointer to an iar_data_t struct.
991  *    @return 0 on success.
992  */
toolkit_saveImageArrayData(const unsigned int wid,const char * name,iar_data_t * iar_data)993 int toolkit_saveImageArrayData( const unsigned int wid, const char *name,
994       iar_data_t *iar_data )
995 {
996    Widget *wgt = iar_getWidget( wid, name );
997    if (wgt == NULL)
998       return -1;
999 
1000    iar_data->pos    = wgt->dat.iar.selected;
1001    iar_data->offset = wgt->dat.iar.pos;
1002 
1003    return 0;
1004 }
1005