1 /***********************************************************************
2  Freeciv - Copyright (C) 2006 - The Freeciv Project
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License as published by
5    the Free Software Foundation; either version 2, or (at your option)
6    any later version.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12 ***********************************************************************/
13 
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
17 
18 /* SDL */
19 #include <SDL/SDL.h>
20 
21 /* utility */
22 #include "log.h"
23 
24 /* gui-sdl */
25 #include "colors.h"
26 #include "graphics.h"
27 #include "gui_id.h"
28 #include "gui_tilespec.h"
29 #include "mapview.h"
30 #include "themespec.h"
31 
32 #include "widget.h"
33 #include "widget_p.h"
34 
35 struct UP_DOWN {
36   struct widget *pBegin;
37   struct widget *pEnd;
38   struct widget *pBeginWidgetLIST;
39   struct widget *pEndWidgetLIST;
40   struct ScrollBar *pVscroll;
41   float old_y;
42   int step;
43   int prev_x;
44   int prev_y;
45   int offset; /* number of pixels the mouse is away from the slider origin */
46 };
47 
48 #define UpperAdd(pNew_Widget, pAdd_Dock)	\
49 do {						\
50   pNew_Widget->prev = pAdd_Dock;		\
51   pNew_Widget->next = pAdd_Dock->next;		\
52   if(pAdd_Dock->next) {			\
53     pAdd_Dock->next->prev = pNew_Widget;	\
54   }						\
55   pAdd_Dock->next = pNew_Widget;		\
56 } while(0)
57 
58 static int (*baseclass_redraw)(struct widget *pwidget);
59 
60 /* =================================================== */
61 /* ===================== VSCROOLBAR ================== */
62 /* =================================================== */
63 
64 /**************************************************************************
65   Create background image for vscrollbars
66   then return pointer to this image.
67 
68   Graphic is taken from pVert_theme surface and blit to new created image.
69 
70   height depend of 'High' parameter.
71 **************************************************************************/
create_vertical_surface(SDL_Surface * pVert_theme,enum widget_state state,Uint16 High)72 static SDL_Surface *create_vertical_surface(SDL_Surface *pVert_theme,
73                                             enum widget_state state, Uint16 High)
74 {
75   SDL_Surface *pVerSurf = NULL;
76   SDL_Rect src, des;
77   Uint16 i;
78   Uint16 start_y;
79   Uint16 tile_count_midd;
80   Uint8 tile_len_end;
81   Uint8 tile_len_midd;
82 
83   tile_len_end = pVert_theme->h / 16;
84 
85   start_y = 0 + state * (pVert_theme->h / 4);
86 
87   /* tile_len_midd = pVert_theme->h/4  - tile_len_end*2; */
88   tile_len_midd = pVert_theme->h / 4 - tile_len_end * 2;
89 
90   tile_count_midd = (High - tile_len_end * 2) / tile_len_midd;
91 
92   /* correction */
93   if (tile_len_midd * tile_count_midd + tile_len_end * 2 < High)
94     tile_count_midd++;
95 
96   if (!tile_count_midd) {
97     pVerSurf = create_surf_alpha(pVert_theme->w, tile_len_end * 2, SDL_SWSURFACE);
98   } else {
99     pVerSurf = create_surf_alpha(pVert_theme->w, High, SDL_SWSURFACE);
100   }
101 
102   src.x = 0;
103   src.y = start_y;
104   src.w = pVert_theme->w;
105   src.h = tile_len_end;
106   alphablit(pVert_theme, &src, pVerSurf, NULL);
107 
108   src.y = start_y + tile_len_end;
109   src.h = tile_len_midd;
110 
111   des.x = 0;
112 
113   for (i = 0; i < tile_count_midd; i++) {
114     des.y = tile_len_end + i * tile_len_midd;
115     alphablit(pVert_theme, &src, pVerSurf, &des);
116   }
117 
118   src.y = start_y + tile_len_end + tile_len_midd;
119   src.h = tile_len_end;
120   des.y = pVerSurf->h - tile_len_end;
121   alphablit(pVert_theme, &src, pVerSurf, &des);
122 
123   return pVerSurf;
124 }
125 
126 /**************************************************************************
127   ...
128 **************************************************************************/
redraw_vert(struct widget * pVert)129 static int redraw_vert(struct widget *pVert)
130 {
131   int ret;
132   SDL_Rect dest = pVert->size;
133   SDL_Surface *pVert_Surf;
134 
135   ret = (*baseclass_redraw)(pVert);
136   if (ret != 0) {
137     return ret;
138   }
139 
140   pVert_Surf = create_vertical_surface(pVert->theme,
141 				       get_wstate(pVert),
142 				       pVert->size.h);
143   ret =
144       blit_entire_src(pVert_Surf, pVert->dst->surface, dest.x, dest.y);
145 
146   FREESURFACE(pVert_Surf);
147 
148   return ret;
149 }
150 
151 /**************************************************************************
152   Create ( malloc ) VSrcrollBar widget structure.
153 
154   Theme graphic is taken from pVert_theme surface;
155 
156   This function determinate future size of VScrollBar
157   ( width = 'pVert_theme->w', height = 'height' ) and
158   save this in: pWidget->size rectangle ( SDL_Rect )
159 
160   function return pointer to allocated widget.
161 **************************************************************************/
create_vertical(SDL_Surface * pVert_theme,struct gui_layer * pDest,Uint16 height,Uint32 flags)162 struct widget *create_vertical(SDL_Surface *pVert_theme, struct gui_layer *pDest,
163                                Uint16 height, Uint32 flags)
164 {
165   struct widget *pVer = widget_new();
166 
167   pVer->theme = pVert_theme;
168   pVer->size.w = pVert_theme->w;
169   pVer->size.h = height;
170   set_wflag(pVer, (WF_FREE_STRING | WF_FREE_GFX | flags));
171   set_wstate(pVer, FC_WS_DISABLED);
172   set_wtype(pVer, WT_VSCROLLBAR);
173   pVer->mod = KMOD_NONE;
174   pVer->dst = pDest;
175 
176   baseclass_redraw = pVer->redraw;
177   pVer->redraw = redraw_vert;
178 
179   return pVer;
180 }
181 
182 /**************************************************************************
183   ...
184 **************************************************************************/
draw_vert(struct widget * pVert,Sint16 x,Sint16 y)185 int draw_vert(struct widget *pVert, Sint16 x, Sint16 y)
186 {
187   pVert->size.x = x;
188   pVert->size.y = y;
189   pVert->gfx = crop_rect_from_surface(pVert->dst->surface, &pVert->size);
190   return redraw_vert(pVert);
191 }
192 
193 /* =================================================== */
194 /* ===================== HSCROOLBAR ================== */
195 /* =================================================== */
196 
197 /**************************************************************************
198   Create background image for hscrollbars
199   then return	pointer to this image.
200 
201   Graphic is taken from pHoriz_theme surface and blit to new created image.
202 
203   hight depend of 'Width' parametr.
204 
205   Type of image depend of "state" parametr.
206     state = 0 - normal
207     state = 1 - selected
208     state = 2 - pressed
209     state = 3 - disabled
210 **************************************************************************/
create_horizontal_surface(SDL_Surface * pHoriz_theme,Uint8 state,Uint16 Width)211 static SDL_Surface *create_horizontal_surface(SDL_Surface * pHoriz_theme,
212 					      Uint8 state, Uint16 Width)
213 {
214   SDL_Surface *pHorSurf = NULL;
215   SDL_Rect src, des;
216 
217   Uint16 i;
218   Uint16 start_x;
219 
220   Uint16 tile_count_midd;
221   Uint8 tile_len_end;
222   Uint8 tile_len_midd;
223 
224   tile_len_end = pHoriz_theme->w / 16;
225 
226   start_x = 0 + state * (pHoriz_theme->w / 4);
227 
228   tile_len_midd = pHoriz_theme->w / 4 - tile_len_end * 2;
229 
230   tile_count_midd = (Width - tile_len_end * 2) / tile_len_midd;
231 
232   /* correction */
233   if (tile_len_midd * tile_count_midd + tile_len_end * 2 < Width) {
234     tile_count_midd++;
235   }
236 
237   if (!tile_count_midd) {
238     pHorSurf = create_surf_alpha(tile_len_end * 2, pHoriz_theme->h, SDL_SWSURFACE);
239   } else {
240     pHorSurf = create_surf_alpha(Width, pHoriz_theme->h, SDL_SWSURFACE);
241   }
242 
243   src.y = 0;
244   src.x = start_x;
245   src.h = pHoriz_theme->h;
246   src.w = tile_len_end;
247   alphablit(pHoriz_theme, &src, pHorSurf, NULL);
248 
249   src.x = start_x + tile_len_end;
250   src.w = tile_len_midd;
251 
252   des.y = 0;
253 
254   for (i = 0; i < tile_count_midd; i++) {
255     des.x = tile_len_end + i * tile_len_midd;
256     alphablit(pHoriz_theme, &src, pHorSurf, &des);
257   }
258 
259   src.x = start_x + tile_len_end + tile_len_midd;
260   src.w = tile_len_end;
261   des.x = pHorSurf->w - tile_len_end;
262   alphablit(pHoriz_theme, &src, pHorSurf, &des);
263 
264   return pHorSurf;
265 }
266 
267 /**************************************************************************
268   ...
269 **************************************************************************/
redraw_horiz(struct widget * pHoriz)270 static int redraw_horiz(struct widget *pHoriz)
271 {
272   int ret;
273   SDL_Rect dest = pHoriz->size;
274   SDL_Surface *pHoriz_Surf;
275 
276   ret = (*baseclass_redraw)(pHoriz);
277   if (ret != 0) {
278     return ret;
279   }
280 
281   pHoriz_Surf = create_horizontal_surface(pHoriz->theme,
282 					  get_wstate(pHoriz),
283 					  pHoriz->size.w);
284   ret = blit_entire_src(pHoriz_Surf, pHoriz->dst->surface, dest.x, dest.y);
285 
286   FREESURFACE(pHoriz_Surf);
287 
288   return ret;
289 }
290 
291 /**************************************************************************
292   Create ( malloc ) VSrcrollBar widget structure.
293 
294   Theme graphic is taken from pVert_theme surface;
295 
296   This function determinate future size of VScrollBar
297   ( width = 'width', height = 'pHoriz_theme->h' ) and
298   save this in: pWidget->size rectangle ( SDL_Rect )
299 
300   function return pointer to allocated widget.
301 **************************************************************************/
create_horizontal(SDL_Surface * pHoriz_theme,struct gui_layer * pDest,Uint16 width,Uint32 flags)302 struct widget *create_horizontal(SDL_Surface *pHoriz_theme, struct gui_layer *pDest,
303                                  Uint16 width, Uint32 flags)
304 {
305   struct widget *pHor = widget_new();
306 
307   pHor->theme = pHoriz_theme;
308   pHor->size.w = width;
309   pHor->size.h = pHoriz_theme->h;
310   set_wflag(pHor, WF_FREE_STRING | flags);
311   set_wstate(pHor, FC_WS_DISABLED);
312   set_wtype(pHor, WT_HSCROLLBAR);
313   pHor->mod = KMOD_NONE;
314   pHor->dst = pDest;
315 
316   baseclass_redraw = pHor->redraw;
317   pHor->redraw = redraw_horiz;
318 
319   return pHor;
320 }
321 
322 /**************************************************************************
323   ...
324 **************************************************************************/
draw_horiz(struct widget * pHoriz,Sint16 x,Sint16 y)325 int draw_horiz(struct widget *pHoriz, Sint16 x, Sint16 y)
326 {
327   pHoriz->size.x = x;
328   pHoriz->size.y = y;
329   pHoriz->gfx = crop_rect_from_surface(pHoriz->dst->surface, &pHoriz->size);
330   return redraw_horiz(pHoriz);
331 }
332 
333 /* =================================================== */
334 /* =====================            ================== */
335 /* =================================================== */
336 
337 /**************************************************************************
338   ...
339 **************************************************************************/
get_step(struct ScrollBar * pScroll)340 static int get_step(struct ScrollBar *pScroll)
341 {
342   float step = pScroll->max - pScroll->min;
343   step *= (float) (1.0 - (float) (pScroll->active * pScroll->step) /
344 						  (float)pScroll->count);
345   step /= (float)(pScroll->count - pScroll->active * pScroll->step);
346   step *= (float)pScroll->step;
347   step++;
348   return (int)step;
349 }
350 
351 /**************************************************************************
352   ...
353 **************************************************************************/
get_position(struct ADVANCED_DLG * pDlg)354 static int get_position(struct ADVANCED_DLG *pDlg)
355 {
356   struct widget *pBuf = pDlg->pActiveWidgetList;
357   int count = pDlg->pScroll->active * pDlg->pScroll->step - 1;
358   int step = get_step(pDlg->pScroll);
359 
360   /* find last seen widget */
361   while(count) {
362     if(pBuf == pDlg->pBeginActiveWidgetList) {
363       break;
364     }
365     count--;
366     pBuf = pBuf->prev;
367   }
368 
369   count = 0;
370   if(pBuf != pDlg->pBeginActiveWidgetList) {
371     do {
372       count++;
373       pBuf = pBuf->prev;
374     } while (pBuf != pDlg->pBeginActiveWidgetList);
375   }
376 
377   if (pDlg->pScroll->pScrollBar) {
378   return pDlg->pScroll->max - pDlg->pScroll->pScrollBar->size.h -
379 					count * (float)step / pDlg->pScroll->step;
380   } else {
381     return pDlg->pScroll->max - count * (float)step / pDlg->pScroll->step;
382   }
383 }
384 
385 
386 /**************************************************************************
387   			Vertical ScrollBar
388 **************************************************************************/
389 
390 static struct widget *up_scroll_widget_list(struct ScrollBar *pVscroll,
391 				  struct widget *pBeginActiveWidgetLIST,
392 				  struct widget *pBeginWidgetLIST,
393 				  struct widget *pEndWidgetLIST);
394 
395 static struct widget *down_scroll_widget_list(struct ScrollBar *pVscroll,
396 				    struct widget *pBeginActiveWidgetLIST,
397 				    struct widget *pBeginWidgetLIST,
398 				    struct widget *pEndWidgetLIST);
399 
400 static struct widget *vertic_scroll_widget_list(struct ScrollBar *pVscroll,
401 				      struct widget *pBeginActiveWidgetLIST,
402 				      struct widget *pBeginWidgetLIST,
403 				      struct widget *pEndWidgetLIST);
404 
405 /**************************************************************************
406   ...
407 **************************************************************************/
std_up_advanced_dlg_callback(struct widget * pWidget)408 static int std_up_advanced_dlg_callback(struct widget *pWidget)
409 {
410   if (Main.event.button.button == SDL_BUTTON_LEFT) {
411     struct ADVANCED_DLG *pDlg = pWidget->private_data.adv_dlg;
412     struct widget *pBegin = up_scroll_widget_list(
413                           pDlg->pScroll,
414                           pDlg->pActiveWidgetList,
415                           pDlg->pBeginActiveWidgetList,
416                           pDlg->pEndActiveWidgetList);
417 
418     if (pBegin) {
419       pDlg->pActiveWidgetList = pBegin;
420     }
421 
422     unsellect_widget_action();
423     pSellected_Widget = pWidget;
424     set_wstate(pWidget, FC_WS_SELLECTED);
425     widget_redraw(pWidget);
426     widget_flush(pWidget);
427   }
428   return -1;
429 }
430 
431 /**************************************************************************
432   ...
433 **************************************************************************/
std_down_advanced_dlg_callback(struct widget * pWidget)434 static int std_down_advanced_dlg_callback(struct widget *pWidget)
435 {
436   if (Main.event.button.button == SDL_BUTTON_LEFT) {
437     struct ADVANCED_DLG *pDlg = pWidget->private_data.adv_dlg;
438     struct widget *pBegin = down_scroll_widget_list(
439                               pDlg->pScroll,
440                               pDlg->pActiveWidgetList,
441                               pDlg->pBeginActiveWidgetList,
442                               pDlg->pEndActiveWidgetList);
443 
444     if (pBegin) {
445       pDlg->pActiveWidgetList = pBegin;
446     }
447 
448     unsellect_widget_action();
449     pSellected_Widget = pWidget;
450     set_wstate(pWidget, FC_WS_SELLECTED);
451     widget_redraw(pWidget);
452     widget_flush(pWidget);
453   }
454   return -1;
455 }
456 
457 /**************************************************************************
458   FIXME : fix main funct : vertic_scroll_widget_list(...)
459 **************************************************************************/
std_vscroll_advanced_dlg_callback(struct widget * pScrollBar)460 static int std_vscroll_advanced_dlg_callback(struct widget *pScrollBar)
461 {
462   if (Main.event.button.button == SDL_BUTTON_LEFT) {
463     struct ADVANCED_DLG *pDlg = pScrollBar->private_data.adv_dlg;
464     struct widget *pBegin = vertic_scroll_widget_list(
465                               pDlg->pScroll,
466                               pDlg->pActiveWidgetList,
467                               pDlg->pBeginActiveWidgetList,
468                               pDlg->pEndActiveWidgetList);
469 
470     if (pBegin) {
471       pDlg->pActiveWidgetList = pBegin;
472     }
473     unsellect_widget_action();
474     set_wstate(pScrollBar, FC_WS_SELLECTED);
475     pSellected_Widget = pScrollBar;
476     redraw_vert(pScrollBar);
477     widget_flush(pScrollBar);
478   }
479   return -1;
480 }
481 
482 
483 /**************************************************************************
484   ...
485 **************************************************************************/
create_vertical_scrollbar(struct ADVANCED_DLG * pDlg,Uint8 step,Uint8 active,bool create_scrollbar,bool create_buttons)486 Uint32 create_vertical_scrollbar(struct ADVANCED_DLG *pDlg,
487                                  Uint8 step, Uint8 active,
488                                  bool create_scrollbar, bool create_buttons)
489 {
490   Uint16 count = 0;
491   struct widget *pBuf = NULL, *pWindow = NULL;
492 
493   fc_assert_ret_val(pDlg != NULL, 0);
494 
495   pWindow = pDlg->pEndWidgetList;
496 
497   if (!pDlg->pScroll) {
498     pDlg->pScroll = fc_calloc(1, sizeof(struct ScrollBar));
499 
500     pBuf = pDlg->pEndActiveWidgetList;
501     while (pBuf && (pBuf != pDlg->pBeginActiveWidgetList->prev)) {
502       pBuf = pBuf->prev;
503       count++;
504     }
505 
506     pDlg->pScroll->count = count;
507   }
508 
509   pDlg->pScroll->active = active;
510   pDlg->pScroll->step = step;
511 
512   if (create_buttons) {
513     /* create up button */
514     pBuf = create_themeicon_button(current_theme->UP_Icon, pWindow->dst,
515                                    NULL, WF_RESTORE_BACKGROUND);
516 
517     pBuf->ID = ID_BUTTON;
518     pBuf->private_data.adv_dlg = pDlg;
519     pBuf->action = std_up_advanced_dlg_callback;
520     set_wstate(pBuf, FC_WS_NORMAL);
521 
522     pDlg->pScroll->pUp_Left_Button = pBuf;
523     DownAdd(pBuf, pDlg->pBeginWidgetList);
524     pDlg->pBeginWidgetList = pBuf;
525 
526     count = pBuf->size.w;
527 
528     /* create down button */
529     pBuf = create_themeicon_button(current_theme->DOWN_Icon, pWindow->dst,
530                                    NULL, WF_RESTORE_BACKGROUND);
531 
532     pBuf->ID = ID_BUTTON;
533     pBuf->private_data.adv_dlg = pDlg;
534     pBuf->action = std_down_advanced_dlg_callback;
535     set_wstate(pBuf, FC_WS_NORMAL);
536 
537     pDlg->pScroll->pDown_Right_Button = pBuf;
538     DownAdd(pBuf, pDlg->pBeginWidgetList);
539     pDlg->pBeginWidgetList = pBuf;
540 
541   }
542 
543   if (create_scrollbar) {
544     /* create vsrollbar */
545     pBuf = create_vertical(current_theme->Vertic, pWindow->dst,
546                            adj_size(10), WF_RESTORE_BACKGROUND);
547 
548     pBuf->ID = ID_SCROLLBAR;
549     pBuf->private_data.adv_dlg = pDlg;
550     pBuf->action = std_vscroll_advanced_dlg_callback;
551     set_wstate(pBuf, FC_WS_NORMAL);
552 
553     pDlg->pScroll->pScrollBar = pBuf;
554     DownAdd(pBuf, pDlg->pBeginWidgetList);
555     pDlg->pBeginWidgetList = pBuf;
556 
557     if(!count) {
558       count = pBuf->size.w;
559     }
560   }
561 
562   return count;
563 }
564 
565 /**************************************************************************
566   ...
567 **************************************************************************/
setup_vertical_scrollbar_area(struct ScrollBar * pScroll,Sint16 start_x,Sint16 start_y,Uint16 hight,bool swap_start_x)568 void setup_vertical_scrollbar_area(struct ScrollBar *pScroll,
569 	Sint16 start_x, Sint16 start_y, Uint16 hight, bool swap_start_x)
570 {
571   bool buttons_exist;
572 
573   fc_assert_ret(pScroll != NULL);
574 
575   buttons_exist = (pScroll->pDown_Right_Button && pScroll->pUp_Left_Button);
576 
577   if(buttons_exist) {
578     /* up */
579     pScroll->pUp_Left_Button->size.y = start_y;
580     if(swap_start_x) {
581       pScroll->pUp_Left_Button->size.x = start_x -
582     					pScroll->pUp_Left_Button->size.w;
583     } else {
584       pScroll->pUp_Left_Button->size.x = start_x;
585     }
586     pScroll->min = start_y + pScroll->pUp_Left_Button->size.h;
587     /* -------------------------- */
588     /* down */
589     pScroll->pDown_Right_Button->size.y = start_y + hight -
590 				  pScroll->pDown_Right_Button->size.h;
591     if(swap_start_x) {
592       pScroll->pDown_Right_Button->size.x = start_x -
593 				pScroll->pDown_Right_Button->size.w;
594     } else {
595       pScroll->pDown_Right_Button->size.x = start_x;
596     }
597     pScroll->max = pScroll->pDown_Right_Button->size.y;
598   }
599   /* --------------- */
600   /* scrollbar */
601   if (pScroll->pScrollBar) {
602 
603     if(swap_start_x) {
604       pScroll->pScrollBar->size.x = start_x - pScroll->pScrollBar->size.w + 2;
605     } else {
606       pScroll->pScrollBar->size.x = start_x;
607     }
608 
609     if(buttons_exist) {
610       pScroll->pScrollBar->size.y = start_y +
611 				      pScroll->pUp_Left_Button->size.h;
612       if(pScroll->count > pScroll->active * pScroll->step) {
613 	pScroll->pScrollBar->size.h = scrollbar_size(pScroll);
614       } else {
615 	pScroll->pScrollBar->size.h = pScroll->max - pScroll->min;
616       }
617     } else {
618       pScroll->pScrollBar->size.y = start_y;
619       pScroll->pScrollBar->size.h = hight;
620       pScroll->min = start_y;
621       pScroll->max = start_y + hight;
622     }
623   }
624 }
625 
626 /* =================================================== */
627 /* ============ Vertical Scroll Group List =========== */
628 /* =================================================== */
629 
630 /**************************************************************************
631   scroll pointers on list.
632   dir == directions: up == -1, down == 1.
633 **************************************************************************/
vertical_scroll_widget_list(struct widget * pActiveWidgetLIST,struct widget * pBeginWidgetLIST,struct widget * pEndWidgetLIST,int active,int step,int dir)634 static struct widget *vertical_scroll_widget_list(struct widget *pActiveWidgetLIST,
635 				      struct widget *pBeginWidgetLIST,
636 				      struct widget *pEndWidgetLIST,
637 				      int active, int step, int dir)
638 {
639   struct widget *pBegin = pActiveWidgetLIST;
640   struct widget *pBuf = pActiveWidgetLIST;
641   struct widget *pTmp = NULL;
642   int count = active; /* row */
643   int count_step = step; /* col */
644 
645   if (dir < 0) {
646     /* up */
647     bool real = TRUE;
648     if (pBuf != pEndWidgetLIST) {
649       /*
650        move pointers to positions and unhidde scrolled widgets
651        B = pBuf - new top
652        T = pTmp - current top == pActiveWidgetLIST
653        [B] [ ] [ ]
654        -----------
655        [T] [ ] [ ]
656        [ ] [ ] [ ]
657        -----------
658        [ ] [ ] [ ]
659     */
660       pTmp = pBuf; /* now pBuf == pActiveWidgetLIST == current Top */
661       while (count_step > 0) {
662       	pBuf = pBuf->next;
663 	clear_wflag(pBuf, WF_HIDDEN);
664 	count_step--;
665       }
666       count_step = step;
667 
668       /* setup new ActiveWidget pointer */
669       pBegin = pBuf;
670 
671       /*
672        scroll pointers up
673        B = pBuf
674        T = pTmp
675        [B0] [B1] [B2]
676        -----------
677        [T0] [T1] [T2]   => B position = T position
678        [T3] [T4] [T5]
679        -----------
680        [  ] [  ] [  ]
681 
682        start from B0 and go downd list
683        B0 = T0, B1 = T1, B2 = T2
684        T0 = T3, T1 = T4, T2 = T5
685        etc...
686     */
687 
688       /* pBuf == pBegin == new top widget */
689 
690       while (count > 0) {
691 	if(real) {
692 	  pBuf->size.x = pTmp->size.x;
693 	  pBuf->size.y = pTmp->size.y;
694           pBuf->gfx = pTmp->gfx;
695 
696           if ((pBuf->size.w != pTmp->size.w) || (pBuf->size.h != pTmp->size.h)) {
697             widget_undraw(pTmp);
698             widget_mark_dirty(pTmp);
699             if (get_wflags(pBuf) & WF_RESTORE_BACKGROUND) {
700               refresh_widget_background(pBuf);
701             }
702           }
703 
704 	  pTmp->gfx = NULL;
705 
706 	  if(count == 1) {
707 	    set_wflag(pTmp, WF_HIDDEN);
708 	  }
709 	  if(pTmp == pBeginWidgetLIST) {
710 	    real = FALSE;
711 	  }
712 	  pTmp = pTmp->prev;
713 	} else {
714 	  /*
715 	     unsymetric list support.
716 	     This is big problem becouse we can't take position from no exist
717 	     list memeber. We must put here some hypotetical positions
718 
719 	     [B0] [B1] [B2]
720              --------------
721              [T0] [T1]
722 
723 	  */
724 	  if (active > 1) {
725 	    /* this work good if active > 1 but is buggy when active == 1 */
726 	    pBuf->size.y += pBuf->size.h;
727 	  } else {
728 	    /* this work good if active == 1 but may be broken if "next"
729 	       element have another "y" position */
730 	    pBuf->size.y = pBuf->next->size.y;
731 	  }
732 	  pBuf->gfx = NULL;
733 	}
734 
735 	pBuf = pBuf->prev;
736 	count_step--;
737 	if(!count_step) {
738 	  count_step = step;
739 	  count--;
740 	}
741       }
742 
743     }
744   } else {
745     /* down */
746     count = active * step; /* row * col */
747 
748     /*
749        find end
750        B = pBuf
751        A - start (pBuf == pActiveWidgetLIST)
752        [ ] [ ] [ ]
753        -----------
754        [A] [ ] [ ]
755        [ ] [ ] [ ]
756        -----------
757        [B] [ ] [ ]
758     */
759     while (count && pBuf != pBeginWidgetLIST->prev) {
760       pBuf = pBuf->prev;
761       count--;
762     }
763 
764     if (!count && pBuf != pBeginWidgetLIST->prev) {
765       /*
766        move pointers to positions and unhidde scrolled widgets
767        B = pBuf
768        T = pTmp
769        A - start (pActiveWidgetLIST)
770        [ ] [ ] [ ]
771        -----------
772        [A] [ ] [ ]
773        [ ] [ ] [T]
774        -----------
775        [ ] [ ] [B]
776     */
777       pTmp = pBuf->next;
778       count_step = step - 1;
779       while(count_step && pBuf != pBeginWidgetLIST) {
780 	clear_wflag(pBuf, WF_HIDDEN);
781 	pBuf = pBuf->prev;
782 	count_step--;
783       }
784       clear_wflag(pBuf, WF_HIDDEN);
785 
786       /*
787        Unsymetric list support.
788        correct pTmp and undraw empty fields
789        B = pBuf
790        T = pTmp
791        A - start (pActiveWidgetLIST)
792        [ ] [ ] [ ]
793        -----------
794        [A] [ ] [ ]
795        [ ] [T] [U]  <- undraw U
796        -----------
797        [ ] [B]
798     */
799       count = count_step;
800       while(count) {
801 	/* hack - clear area under no exist list members */
802         widget_undraw(pTmp);
803 	widget_mark_dirty(pTmp);
804 	FREESURFACE(pTmp->gfx);
805 	if (active == 1) {
806 	  set_wflag(pTmp, WF_HIDDEN);
807 	}
808 	pTmp = pTmp->next;
809 	count--;
810       }
811 
812       /* reset counters */
813       count = active;
814       if(count_step) {
815         count_step = step - count_step;
816       } else {
817 	count_step = step;
818       }
819 
820       /*
821        scroll pointers down
822        B = pBuf
823        T = pTmp
824        [  ] [  ] [  ]
825        -----------
826        [  ] [  ] [  ]
827        [T2] [T1] [T0]   => B position = T position
828        -----------
829        [B2] [B1] [B0]
830     */
831       while (count) {
832 	pBuf->size.x = pTmp->size.x;
833 	pBuf->size.y = pTmp->size.y;
834 	pBuf->gfx = pTmp->gfx;
835 
836         if ((pBuf->size.w != pTmp->size.w) || (pBuf->size.h != pTmp->size.h)) {
837           widget_undraw(pTmp);
838           widget_mark_dirty(pTmp);
839           if (get_wflags(pBuf) & WF_RESTORE_BACKGROUND) {
840             refresh_widget_background(pBuf);
841           }
842         }
843 
844         pTmp->gfx = NULL;
845 
846 	if(count == 1) {
847 	  set_wflag(pTmp, WF_HIDDEN);
848 	}
849 
850 	pTmp = pTmp->next;
851 	pBuf = pBuf->next;
852 	count_step--;
853 	if(!count_step) {
854 	  count_step = step;
855 	  count--;
856 	}
857       }
858       /* setup new ActiveWidget pointer */
859       pBegin = pBuf->prev;
860     }
861   }
862 
863   return pBegin;
864 }
865 
866 /**************************************************************************
867   ...
868 **************************************************************************/
inside_scroll_down_loop(void * pData)869 static void inside_scroll_down_loop(void *pData)
870 {
871   struct UP_DOWN *pDown = (struct UP_DOWN *)pData;
872 
873   if (pDown->pEnd != pDown->pBeginWidgetLIST) {
874       if (pDown->pVscroll->pScrollBar
875 	&& pDown->pVscroll->pScrollBar->size.y <=
876 	  pDown->pVscroll->max - pDown->pVscroll->pScrollBar->size.h) {
877 
878 	/* draw bcgd */
879         widget_undraw(pDown->pVscroll->pScrollBar);
880 	widget_mark_dirty(pDown->pVscroll->pScrollBar);
881 
882 	if (pDown->pVscroll->pScrollBar->size.y + pDown->step >
883 	    pDown->pVscroll->max - pDown->pVscroll->pScrollBar->size.h) {
884 	  pDown->pVscroll->pScrollBar->size.y =
885 	      pDown->pVscroll->max - pDown->pVscroll->pScrollBar->size.h;
886 	} else {
887 	  pDown->pVscroll->pScrollBar->size.y += pDown->step;
888 	}
889       }
890 
891       pDown->pBegin = vertical_scroll_widget_list(pDown->pBegin,
892 			  pDown->pBeginWidgetLIST, pDown->pEndWidgetLIST,
893 			  pDown->pVscroll->active, pDown->pVscroll->step, 1);
894 
895       pDown->pEnd = pDown->pEnd->prev;
896 
897       redraw_group(pDown->pBeginWidgetLIST, pDown->pEndWidgetLIST, TRUE);
898 
899       if (pDown->pVscroll->pScrollBar) {
900 	/* redraw scrollbar */
901         if (get_wflags(pDown->pVscroll->pScrollBar) & WF_RESTORE_BACKGROUND) {
902 	  refresh_widget_background(pDown->pVscroll->pScrollBar);
903         }
904 	redraw_vert(pDown->pVscroll->pScrollBar);
905 
906 	widget_mark_dirty(pDown->pVscroll->pScrollBar);
907       }
908 
909       flush_dirty();
910     }
911 }
912 
913 /**************************************************************************
914   ...
915 **************************************************************************/
inside_scroll_up_loop(void * pData)916 static void inside_scroll_up_loop(void *pData)
917 {
918   struct UP_DOWN *pUp = (struct UP_DOWN *)pData;
919 
920   if (pUp && pUp->pBegin != pUp->pEndWidgetLIST) {
921 
922     if (pUp->pVscroll->pScrollBar
923       && (pUp->pVscroll->pScrollBar->size.y >= pUp->pVscroll->min)) {
924 
925       /* draw bcgd */
926       widget_undraw(pUp->pVscroll->pScrollBar);
927       widget_mark_dirty(pUp->pVscroll->pScrollBar);
928 
929       if (((pUp->pVscroll->pScrollBar->size.y - pUp->step) < pUp->pVscroll->min)) {
930 	pUp->pVscroll->pScrollBar->size.y = pUp->pVscroll->min;
931       } else {
932 	pUp->pVscroll->pScrollBar->size.y -= pUp->step;
933       }
934     }
935 
936     pUp->pBegin = vertical_scroll_widget_list(pUp->pBegin,
937 			pUp->pBeginWidgetLIST, pUp->pEndWidgetLIST,
938 			pUp->pVscroll->active, pUp->pVscroll->step, -1);
939 
940     redraw_group(pUp->pBeginWidgetLIST, pUp->pEndWidgetLIST, TRUE);
941 
942     if (pUp->pVscroll->pScrollBar) {
943       /* redraw scroolbar */
944       if (get_wflags(pUp->pVscroll->pScrollBar) & WF_RESTORE_BACKGROUND) {
945         refresh_widget_background(pUp->pVscroll->pScrollBar);
946       }
947       redraw_vert(pUp->pVscroll->pScrollBar);
948       widget_mark_dirty(pUp->pVscroll->pScrollBar);
949     }
950 
951     flush_dirty();
952   }
953 }
954 
955 /**************************************************************************
956   FIXME
957 **************************************************************************/
scroll_mouse_motion_handler(SDL_MouseMotionEvent * pMotionEvent,void * pData)958 static Uint16 scroll_mouse_motion_handler(SDL_MouseMotionEvent *pMotionEvent, void *pData)
959 {
960   struct UP_DOWN *pMotion = (struct UP_DOWN *)pData;
961   int yrel;
962   int y;
963   int normalized_y;
964   int net_slider_area;
965   int net_count;
966   float scroll_step;
967 
968   yrel = pMotionEvent->y - pMotion->prev_y;
969   pMotion->prev_x = pMotionEvent->x;
970   pMotion->prev_y = pMotionEvent->y;
971 
972   y = pMotionEvent->y - pMotion->pVscroll->pScrollBar->dst->dest_rect.y;
973 
974   normalized_y = (y - pMotion->offset);
975 
976   net_slider_area = (pMotion->pVscroll->max - pMotion->pVscroll->min - pMotion->pVscroll->pScrollBar->size.h);
977   net_count = round((float)pMotion->pVscroll->count / pMotion->pVscroll->step) - pMotion->pVscroll->active + 1;
978   scroll_step = (float)net_slider_area / net_count;
979 
980   if ((yrel != 0) &&
981      ((normalized_y >= pMotion->pVscroll->min) ||
982       ((normalized_y < pMotion->pVscroll->min) && (pMotion->pVscroll->pScrollBar->size.y > pMotion->pVscroll->min))) &&
983      ((normalized_y <= pMotion->pVscroll->max - pMotion->pVscroll->pScrollBar->size.h) ||
984       ((normalized_y > pMotion->pVscroll->max) && (pMotion->pVscroll->pScrollBar->size.y < (pMotion->pVscroll->max - pMotion->pVscroll->pScrollBar->size.h)))) ) {
985 
986     int count;
987 
988     /* draw bcgd */
989     widget_undraw(pMotion->pVscroll->pScrollBar);
990     widget_mark_dirty(pMotion->pVscroll->pScrollBar);
991 
992     if ((pMotion->pVscroll->pScrollBar->size.y + yrel) >
993 	 (pMotion->pVscroll->max - pMotion->pVscroll->pScrollBar->size.h)) {
994 
995       pMotion->pVscroll->pScrollBar->size.y =
996         (pMotion->pVscroll->max - pMotion->pVscroll->pScrollBar->size.h);
997 
998     } else if ((pMotion->pVscroll->pScrollBar->size.y + yrel) < pMotion->pVscroll->min) {
999 
1000 	pMotion->pVscroll->pScrollBar->size.y = pMotion->pVscroll->min;
1001 
1002     } else {
1003 
1004 	pMotion->pVscroll->pScrollBar->size.y += yrel;
1005 
1006     }
1007 
1008     count = round((pMotion->pVscroll->pScrollBar->size.y - pMotion->old_y) / scroll_step);
1009 
1010     if (count != 0) {
1011 
1012       int i = count;
1013       while (i != 0) {
1014 
1015 	pMotion->pBegin = vertical_scroll_widget_list(pMotion->pBegin,
1016 			pMotion->pBeginWidgetLIST, pMotion->pEndWidgetLIST,
1017 				pMotion->pVscroll->active,
1018 				pMotion->pVscroll->step, i);
1019 	if (i > 0) {
1020 	  i--;
1021 	} else {
1022 	  i++;
1023 	}
1024 
1025       }	/* while (i != 0) */
1026 
1027       pMotion->old_y = pMotion->pVscroll->min +
1028         ((round((pMotion->old_y - pMotion->pVscroll->min) / scroll_step) + count) * scroll_step);
1029 
1030       redraw_group(pMotion->pBeginWidgetLIST, pMotion->pEndWidgetLIST, TRUE);
1031     }
1032 
1033     /* redraw slider */
1034     if (get_wflags(pMotion->pVscroll->pScrollBar) & WF_RESTORE_BACKGROUND) {
1035       refresh_widget_background(pMotion->pVscroll->pScrollBar);
1036     }
1037     redraw_vert(pMotion->pVscroll->pScrollBar);
1038     widget_mark_dirty(pMotion->pVscroll->pScrollBar);
1039 
1040     flush_dirty();
1041   }
1042 
1043   return ID_ERROR;
1044 }
1045 
1046 /**************************************************************************
1047   ...
1048 **************************************************************************/
scroll_mouse_button_up(SDL_MouseButtonEvent * pButtonEvent,void * pData)1049 static Uint16 scroll_mouse_button_up(SDL_MouseButtonEvent *pButtonEvent, void *pData)
1050 {
1051   return (Uint16)ID_SCROLLBAR;
1052 }
1053 
1054 /**************************************************************************
1055   ...
1056 **************************************************************************/
down_scroll_widget_list(struct ScrollBar * pVscroll,struct widget * pBeginActiveWidgetLIST,struct widget * pBeginWidgetLIST,struct widget * pEndWidgetLIST)1057 static struct widget *down_scroll_widget_list(struct ScrollBar *pVscroll,
1058 				    struct widget *pBeginActiveWidgetLIST,
1059 				    struct widget *pBeginWidgetLIST,
1060 				    struct widget *pEndWidgetLIST)
1061 {
1062   struct UP_DOWN pDown;
1063   struct widget *pBegin = pBeginActiveWidgetLIST;
1064   int step = pVscroll->active * pVscroll->step - 1;
1065 
1066   while (step--) {
1067     pBegin = pBegin->prev;
1068   }
1069 
1070   pDown.step = get_step(pVscroll);
1071   pDown.pBegin = pBeginActiveWidgetLIST;
1072   pDown.pEnd = pBegin;
1073   pDown.pBeginWidgetLIST = pBeginWidgetLIST;
1074   pDown.pEndWidgetLIST = pEndWidgetLIST;
1075   pDown.pVscroll = pVscroll;
1076 
1077   gui_event_loop((void *)&pDown, inside_scroll_down_loop,
1078 	NULL, NULL, NULL, scroll_mouse_button_up, NULL);
1079 
1080   return pDown.pBegin;
1081 }
1082 
1083 /**************************************************************************
1084   ...
1085 **************************************************************************/
up_scroll_widget_list(struct ScrollBar * pVscroll,struct widget * pBeginActiveWidgetLIST,struct widget * pBeginWidgetLIST,struct widget * pEndWidgetLIST)1086 static struct widget *up_scroll_widget_list(struct ScrollBar *pVscroll,
1087 				  struct widget *pBeginActiveWidgetLIST,
1088 				  struct widget *pBeginWidgetLIST,
1089 				  struct widget *pEndWidgetLIST)
1090 {
1091   struct UP_DOWN pUp;
1092 
1093   pUp.step = get_step(pVscroll);
1094   pUp.pBegin = pBeginActiveWidgetLIST;
1095   pUp.pBeginWidgetLIST = pBeginWidgetLIST;
1096   pUp.pEndWidgetLIST = pEndWidgetLIST;
1097   pUp.pVscroll = pVscroll;
1098 
1099   gui_event_loop((void *)&pUp, inside_scroll_up_loop,
1100 	NULL, NULL, NULL, scroll_mouse_button_up, NULL);
1101 
1102   return pUp.pBegin;
1103 }
1104 
1105 /**************************************************************************
1106   FIXME
1107 **************************************************************************/
vertic_scroll_widget_list(struct ScrollBar * pVscroll,struct widget * pBeginActiveWidgetLIST,struct widget * pBeginWidgetLIST,struct widget * pEndWidgetLIST)1108 static struct widget *vertic_scroll_widget_list(struct ScrollBar *pVscroll,
1109 				      struct widget *pBeginActiveWidgetLIST,
1110 				      struct widget *pBeginWidgetLIST,
1111 				      struct widget *pEndWidgetLIST)
1112 {
1113   struct UP_DOWN pMotion;
1114 
1115   pMotion.step = get_step(pVscroll);
1116   pMotion.pBegin = pBeginActiveWidgetLIST;
1117   pMotion.pBeginWidgetLIST = pBeginWidgetLIST;
1118   pMotion.pEndWidgetLIST = pEndWidgetLIST;
1119   pMotion.pVscroll = pVscroll;
1120   pMotion.old_y = pVscroll->pScrollBar->size.y;
1121   SDL_GetMouseState(&pMotion.prev_x, &pMotion.prev_y);
1122   pMotion.offset = pMotion.prev_y - pVscroll->pScrollBar->dst->dest_rect.y - pVscroll->pScrollBar->size.y;
1123 
1124   MOVE_STEP_X = 0;
1125   MOVE_STEP_Y = 3;
1126   /* Filter mouse motion events */
1127   SDL_SetEventFilter(FilterMouseMotionEvents);
1128   gui_event_loop((void *)&pMotion, NULL, NULL, NULL, NULL,
1129 		  scroll_mouse_button_up, scroll_mouse_motion_handler);
1130   /* Turn off Filter mouse motion events */
1131   SDL_SetEventFilter(NULL);
1132   MOVE_STEP_X = DEFAULT_MOVE_STEP;
1133   MOVE_STEP_Y = DEFAULT_MOVE_STEP;
1134 
1135   return pMotion.pBegin;
1136 }
1137 
1138 /* ==================================================================== */
1139 
1140 /**************************************************************************
1141   Add new widget to srolled list and set draw position of all changed widgets.
1142   dir :
1143     TRUE - upper add => pAdd_Dock->next = pNew_Widget.
1144     FALSE - down add => pAdd_Dock->prev = pNew_Widget.
1145   start_x, start_y - positions of first seen widget (pActiveWidgetList).
1146   pDlg->pScroll ( scrollbar ) must exist.
1147   It isn't full secure to multi widget list.
1148 **************************************************************************/
add_widget_to_vertical_scroll_widget_list(struct ADVANCED_DLG * pDlg,struct widget * pNew_Widget,struct widget * pAdd_Dock,bool dir,Sint16 start_x,Sint16 start_y)1149 bool add_widget_to_vertical_scroll_widget_list(struct ADVANCED_DLG *pDlg,
1150                                                struct widget *pNew_Widget,
1151                                                struct widget *pAdd_Dock,
1152                                                bool dir,
1153                                                Sint16 start_x, Sint16 start_y)
1154 {
1155   struct widget *pBuf = NULL;
1156   struct widget *pEnd = NULL, *pOld_End = NULL;
1157   int count = 0;
1158   bool last = FALSE, seen = TRUE;
1159 
1160   fc_assert_ret_val(pNew_Widget != NULL, FALSE);
1161   fc_assert_ret_val(pDlg != NULL, FALSE);
1162   fc_assert_ret_val(pDlg->pScroll != NULL, FALSE);
1163 
1164   if (!pAdd_Dock) {
1165     pAdd_Dock = pDlg->pBeginWidgetList; /* last item */
1166   }
1167 
1168   pDlg->pScroll->count++;
1169 
1170   if (pDlg->pScroll->count > (pDlg->pScroll->active * pDlg->pScroll->step)) {
1171     /* -> scrollbar needed */
1172 
1173     if (pDlg->pActiveWidgetList) {
1174       /* -> scrollbar is already visible */
1175 
1176       int i = 0;
1177       /* find last active widget */
1178       pOld_End = pAdd_Dock;
1179       while(pOld_End != pDlg->pActiveWidgetList) {
1180         pOld_End = pOld_End->next;
1181 	i++;
1182 	if (pOld_End == pDlg->pEndActiveWidgetList) {
1183           /* implies (pOld_End == pDlg->pActiveWidgetList)? */
1184 	  seen = FALSE;
1185 	  break;
1186 	}
1187       }
1188 
1189       if (seen) {
1190         count = (pDlg->pScroll->active * pDlg->pScroll->step) - 1;
1191         if (i > count) {
1192 	  seen = FALSE;
1193         } else {
1194           while (count > 0) {
1195 	    pOld_End = pOld_End->prev;
1196 	    count--;
1197           }
1198           if (pOld_End == pAdd_Dock) {
1199 	    last = TRUE;
1200           }
1201 	}
1202       }
1203 
1204     } else {
1205       last = TRUE;
1206       pDlg->pActiveWidgetList = pDlg->pEndActiveWidgetList;
1207       show_scrollbar(pDlg->pScroll);
1208     }
1209   }
1210 
1211   count = 0;
1212 
1213   /* add Pointer to list */
1214   if (dir) {
1215     /* upper add */
1216     UpperAdd(pNew_Widget, pAdd_Dock);
1217 
1218     if(pAdd_Dock == pDlg->pEndWidgetList) {
1219       pDlg->pEndWidgetList = pNew_Widget;
1220     }
1221     if(pAdd_Dock == pDlg->pEndActiveWidgetList) {
1222       pDlg->pEndActiveWidgetList = pNew_Widget;
1223     }
1224     if(pAdd_Dock == pDlg->pActiveWidgetList) {
1225       pDlg->pActiveWidgetList = pNew_Widget;
1226     }
1227   } else {
1228     /* down add */
1229     DownAdd(pNew_Widget, pAdd_Dock);
1230 
1231     if(pAdd_Dock == pDlg->pBeginWidgetList) {
1232       pDlg->pBeginWidgetList = pNew_Widget;
1233     }
1234 
1235     if(pAdd_Dock == pDlg->pBeginActiveWidgetList) {
1236       pDlg->pBeginActiveWidgetList = pNew_Widget;
1237     }
1238   }
1239 
1240   /* setup draw positions */
1241   if (seen) {
1242     if(!pDlg->pBeginActiveWidgetList) {
1243       /* first element ( active list empty ) */
1244       fc_assert_msg(FALSE == dir, "Forbided List Operation");
1245       pNew_Widget->size.x = start_x;
1246       pNew_Widget->size.y = start_y;
1247       pDlg->pBeginActiveWidgetList = pNew_Widget;
1248       pDlg->pEndActiveWidgetList = pNew_Widget;
1249       if(!pDlg->pBeginWidgetList) {
1250         pDlg->pBeginWidgetList = pNew_Widget;
1251         pDlg->pEndWidgetList = pNew_Widget;
1252       }
1253     } else { /* there are some elements on local active list */
1254       if(last) {
1255         /* We add to last seen position */
1256         if(dir) {
1257 	  /* only swap pAdd_Dock with pNew_Widget on last seen positions */
1258 	  pNew_Widget->size.x = pAdd_Dock->size.x;
1259 	  pNew_Widget->size.y = pAdd_Dock->size.y;
1260 	  pNew_Widget->gfx = pAdd_Dock->gfx;
1261 	  pAdd_Dock->gfx = NULL;
1262 	  set_wflag(pAdd_Dock, WF_HIDDEN);
1263         } else {
1264 	  /* reposition all widgets */
1265 	  pBuf = pNew_Widget;
1266           do {
1267 	    pBuf->size.x = pBuf->next->size.x;
1268 	    pBuf->size.y = pBuf->next->size.y;
1269 	    pBuf->gfx = pBuf->next->gfx;
1270 	    pBuf->next->gfx = NULL;
1271 	    pBuf = pBuf->next;
1272           } while(pBuf != pDlg->pActiveWidgetList);
1273           pBuf->gfx = NULL;
1274           set_wflag(pBuf, WF_HIDDEN);
1275 	  pDlg->pActiveWidgetList = pDlg->pActiveWidgetList->prev;
1276         }
1277       } else { /* !last */
1278         pBuf = pNew_Widget;
1279         /* find last seen widget */
1280         if(pDlg->pActiveWidgetList) {
1281 	  pEnd = pDlg->pActiveWidgetList;
1282 	  count = pDlg->pScroll->active * pDlg->pScroll->step - 1;
1283           while(count && pEnd != pDlg->pBeginActiveWidgetList) {
1284 	    pEnd = pEnd->prev;
1285 	    count--;
1286           }
1287         }
1288         while(pBuf) {
1289           if(pBuf == pDlg->pBeginActiveWidgetList) {
1290 	    struct widget *pTmp = pBuf;
1291 	    count = pDlg->pScroll->step;
1292 	    while(count) {
1293 	      pTmp = pTmp->next;
1294 	      count--;
1295 	    }
1296 	    pBuf->size.x = pTmp->size.x;
1297 	    pBuf->size.y = pTmp->size.y + pTmp->size.h;
1298 	    /* break when last active widget or last seen widget */
1299 	    break;
1300           } else {
1301 	    pBuf->size.x = pBuf->prev->size.x;
1302 	    pBuf->size.y = pBuf->prev->size.y;
1303 	    pBuf->gfx = pBuf->prev->gfx;
1304 	    pBuf->prev->gfx = NULL;
1305 	    if(pBuf == pEnd) {
1306 	      break;
1307 	    }
1308           }
1309           pBuf = pBuf->prev;
1310         }
1311         if(pOld_End && pBuf->prev == pOld_End) {
1312           set_wflag(pOld_End, WF_HIDDEN);
1313         }
1314       }/* !last */
1315     } /* pDlg->pBeginActiveWidgetList */
1316   } else {/* !seen */
1317     set_wflag(pNew_Widget, WF_HIDDEN);
1318   }
1319 
1320   if(pDlg->pActiveWidgetList && pDlg->pScroll->pScrollBar) {
1321     widget_undraw(pDlg->pScroll->pScrollBar);
1322     widget_mark_dirty(pDlg->pScroll->pScrollBar);
1323 
1324     pDlg->pScroll->pScrollBar->size.h = scrollbar_size(pDlg->pScroll);
1325     if(last) {
1326       pDlg->pScroll->pScrollBar->size.y = get_position(pDlg);
1327     }
1328     if (get_wflags(pDlg->pScroll->pScrollBar) & WF_RESTORE_BACKGROUND) {
1329       refresh_widget_background(pDlg->pScroll->pScrollBar);
1330     }
1331     if (!seen) {
1332       redraw_vert(pDlg->pScroll->pScrollBar);
1333     }
1334   }
1335 
1336   return last;
1337 }
1338 
1339 /**************************************************************************
1340   Del widget from srolled list and set draw position of all changed widgets
1341   Don't free pDlg and pDlg->pScroll (if exist)
1342   It is full secure for multi widget list case.
1343 **************************************************************************/
del_widget_from_vertical_scroll_widget_list(struct ADVANCED_DLG * pDlg,struct widget * pWidget)1344 bool del_widget_from_vertical_scroll_widget_list(struct ADVANCED_DLG *pDlg,
1345   						struct widget *pWidget)
1346 {
1347   int count = 0;
1348   struct widget *pBuf = pWidget;
1349   fc_assert_ret_val(pWidget != NULL, FALSE);
1350   fc_assert_ret_val(pDlg != NULL, FALSE);
1351 
1352   /* if begin == end -> size = 1 */
1353   if (pDlg->pBeginActiveWidgetList == pDlg->pEndActiveWidgetList) {
1354 
1355     if(pDlg->pScroll) {
1356       pDlg->pScroll->count = 0;
1357     }
1358 
1359     if(pDlg->pBeginActiveWidgetList == pDlg->pBeginWidgetList) {
1360       pDlg->pBeginWidgetList = pDlg->pBeginWidgetList->next;
1361     }
1362 
1363     if(pDlg->pEndActiveWidgetList == pDlg->pEndWidgetList) {
1364       pDlg->pEndWidgetList = pDlg->pEndWidgetList->prev;
1365     }
1366 
1367     pDlg->pBeginActiveWidgetList = NULL;
1368     pDlg->pActiveWidgetList = NULL;
1369     pDlg->pEndActiveWidgetList = NULL;
1370 
1371     widget_undraw(pWidget);
1372     widget_mark_dirty(pWidget);
1373     del_widget_from_gui_list(pWidget);
1374     return FALSE;
1375   }
1376 
1377   if (pDlg->pScroll && pDlg->pActiveWidgetList) {
1378     /* scrollbar exist and active, start mod. from last seen label */
1379 
1380     struct widget *pLast;
1381     bool widget_found = FALSE;
1382 
1383     /* this is always true becouse no-scrolbar case (active*step < count)
1384        will be suported in other part of code (see "else" part) */
1385     count = pDlg->pScroll->active * pDlg->pScroll->step;
1386 
1387     /* find last */
1388     pBuf = pDlg->pActiveWidgetList;
1389     while (count > 0) {
1390       pBuf = pBuf->prev;
1391       count--;
1392     }
1393     if(!pBuf) {
1394       pLast = pDlg->pBeginActiveWidgetList;
1395     } else {
1396       pLast = pBuf->next;
1397     }
1398 
1399     if(pLast == pDlg->pBeginActiveWidgetList) {
1400 
1401       if(pDlg->pScroll->step == 1) {
1402         pDlg->pActiveWidgetList = pDlg->pActiveWidgetList->next;
1403         clear_wflag(pDlg->pActiveWidgetList, WF_HIDDEN);
1404 
1405         /* look for the widget in the non-visible part */
1406         pBuf = pDlg->pEndActiveWidgetList;
1407         while (pBuf != pDlg->pActiveWidgetList) {
1408           if (pBuf == pWidget) {
1409             widget_found = TRUE;
1410             pBuf = pDlg->pActiveWidgetList;
1411             break;
1412           }
1413           pBuf = pBuf->prev;
1414         }
1415 
1416         /* if we haven't found it yet, look in the visible part and update the
1417            positions of the other widgets */
1418         if (!widget_found) {
1419           while (pBuf != pWidget) {
1420             pBuf->gfx = pBuf->prev->gfx;
1421             pBuf->prev->gfx = NULL;
1422             pBuf->size.x = pBuf->prev->size.x;
1423             pBuf->size.y = pBuf->prev->size.y;
1424             pBuf = pBuf->prev;
1425           }
1426         }
1427       } else {
1428 	pBuf = pLast;
1429 	/* undraw last widget */
1430         widget_undraw(pBuf);
1431         widget_mark_dirty(pBuf);
1432         FREESURFACE(pBuf->gfx);
1433 	goto STD;
1434       }
1435     } else {
1436       clear_wflag(pBuf, WF_HIDDEN);
1437 STD:  while (pBuf != pWidget) {
1438         pBuf->gfx = pBuf->next->gfx;
1439         pBuf->next->gfx = NULL;
1440         pBuf->size.x = pBuf->next->size.x;
1441         pBuf->size.y = pBuf->next->size.y;
1442         pBuf = pBuf->next;
1443       }
1444     }
1445 
1446     if ((pDlg->pScroll->count - 1) <= (pDlg->pScroll->active * pDlg->pScroll->step)) {
1447       /* scrollbar not needed anymore */
1448       hide_scrollbar(pDlg->pScroll);
1449       pDlg->pActiveWidgetList = NULL;
1450     }
1451     pDlg->pScroll->count--;
1452 
1453     if(pDlg->pActiveWidgetList) {
1454       if (pDlg->pScroll->pScrollBar) {
1455         widget_undraw(pDlg->pScroll->pScrollBar);
1456         pDlg->pScroll->pScrollBar->size.h = scrollbar_size(pDlg->pScroll);
1457         refresh_widget_background(pDlg->pScroll->pScrollBar);
1458       }
1459     }
1460 
1461   } else { /* no scrollbar */
1462     pBuf = pDlg->pBeginActiveWidgetList;
1463 
1464     /* undraw last widget */
1465     widget_undraw(pBuf);
1466     widget_mark_dirty(pBuf);
1467     FREESURFACE(pBuf->gfx);
1468 
1469     while (pBuf != pWidget) {
1470       pBuf->gfx = pBuf->next->gfx;
1471       pBuf->next->gfx = NULL;
1472       pBuf->size.x = pBuf->next->size.x;
1473       pBuf->size.y = pBuf->next->size.y;
1474       pBuf = pBuf->next;
1475     }
1476 
1477     if (pDlg->pScroll) {
1478       pDlg->pScroll->count--;
1479     }
1480 
1481   }
1482 
1483   if (pWidget == pDlg->pBeginWidgetList) {
1484     pDlg->pBeginWidgetList = pWidget->next;
1485   }
1486 
1487   if (pWidget == pDlg->pBeginActiveWidgetList) {
1488     pDlg->pBeginActiveWidgetList = pWidget->next;
1489   }
1490 
1491   if (pWidget == pDlg->pEndActiveWidgetList) {
1492 
1493     if (pWidget == pDlg->pEndWidgetList) {
1494       pDlg->pEndWidgetList = pWidget->prev;
1495     }
1496 
1497     if (pWidget == pDlg->pActiveWidgetList) {
1498       pDlg->pActiveWidgetList = pWidget->prev;
1499     }
1500 
1501     pDlg->pEndActiveWidgetList = pWidget->prev;
1502 
1503   }
1504 
1505   if (pDlg->pActiveWidgetList && (pDlg->pActiveWidgetList == pWidget)) {
1506     pDlg->pActiveWidgetList = pWidget->prev;
1507   }
1508 
1509   del_widget_from_gui_list(pWidget);
1510 
1511   if(pDlg->pScroll && pDlg->pScroll->pScrollBar && pDlg->pActiveWidgetList) {
1512     widget_undraw(pDlg->pScroll->pScrollBar);
1513     pDlg->pScroll->pScrollBar->size.y = get_position(pDlg);
1514     refresh_widget_background(pDlg->pScroll->pScrollBar);
1515   }
1516 
1517   return TRUE;
1518 }
1519 
1520 /**************************************************************************
1521   ...
1522 **************************************************************************/
setup_vertical_scrollbar_default_callbacks(struct ScrollBar * pScroll)1523 void setup_vertical_scrollbar_default_callbacks(struct ScrollBar *pScroll)
1524 {
1525   fc_assert_ret(pScroll != NULL);
1526   if(pScroll->pUp_Left_Button) {
1527     pScroll->pUp_Left_Button->action = std_up_advanced_dlg_callback;
1528   }
1529   if(pScroll->pDown_Right_Button) {
1530     pScroll->pDown_Right_Button->action = std_down_advanced_dlg_callback;
1531   }
1532   if(pScroll->pScrollBar) {
1533     pScroll->pScrollBar->action = std_vscroll_advanced_dlg_callback;
1534   }
1535 }
1536 
1537 /**************************************************************************
1538   			Horizontal Scrollbar
1539 **************************************************************************/
1540 
1541 
1542 /**************************************************************************
1543   ...
1544 **************************************************************************/
create_horizontal_scrollbar(struct ADVANCED_DLG * pDlg,Sint16 start_x,Sint16 start_y,Uint16 width,Uint16 active,bool create_scrollbar,bool create_buttons,bool swap_start_y)1545 Uint32 create_horizontal_scrollbar(struct ADVANCED_DLG *pDlg,
1546 		  Sint16 start_x, Sint16 start_y, Uint16 width, Uint16 active,
1547 		  bool create_scrollbar, bool create_buttons, bool swap_start_y)
1548 {
1549   Uint16 count = 0;
1550   struct widget *pBuf = NULL, *pWindow = NULL;
1551 
1552   fc_assert_ret_val(pDlg != NULL, 0);
1553 
1554   pWindow = pDlg->pEndWidgetList;
1555 
1556   if(!pDlg->pScroll) {
1557     pDlg->pScroll = fc_calloc(1, sizeof(struct ScrollBar));
1558 
1559     pDlg->pScroll->active = active;
1560 
1561     pBuf = pDlg->pEndActiveWidgetList;
1562     while(pBuf && pBuf != pDlg->pBeginActiveWidgetList->prev) {
1563       pBuf = pBuf->prev;
1564       count++;
1565     }
1566 
1567     pDlg->pScroll->count = count;
1568   }
1569 
1570   if (create_buttons) {
1571     /* create up button */
1572     pBuf = create_themeicon_button(current_theme->LEFT_Icon, pWindow->dst, NULL, 0);
1573 
1574     pBuf->ID = ID_BUTTON;
1575     pBuf->data.ptr = (void *)pDlg;
1576     set_wstate(pBuf, FC_WS_NORMAL);
1577 
1578     pBuf->size.x = start_x;
1579     if(swap_start_y) {
1580       pBuf->size.y = start_y - pBuf->size.h;
1581     } else {
1582       pBuf->size.y = start_y;
1583     }
1584 
1585     pDlg->pScroll->min = start_x + pBuf->size.w;
1586     pDlg->pScroll->pUp_Left_Button = pBuf;
1587     DownAdd(pBuf, pDlg->pBeginWidgetList);
1588     pDlg->pBeginWidgetList = pBuf;
1589 
1590 
1591     count = pBuf->size.h;
1592 
1593     /* create down button */
1594     pBuf = create_themeicon_button(current_theme->RIGHT_Icon, pWindow->dst, NULL, 0);
1595 
1596     pBuf->ID = ID_BUTTON;
1597     pBuf->data.ptr = (void *)pDlg;
1598     set_wstate(pBuf, FC_WS_NORMAL);
1599 
1600     pBuf->size.x = start_x + width - pBuf->size.w;
1601     if(swap_start_y) {
1602       pBuf->size.y = start_y - pBuf->size.h;
1603     } else {
1604       pBuf->size.y = start_y;
1605     }
1606 
1607     pDlg->pScroll->max = pBuf->size.x;
1608     pDlg->pScroll->pDown_Right_Button = pBuf;
1609     DownAdd(pBuf, pDlg->pBeginWidgetList);
1610     pDlg->pBeginWidgetList = pBuf;
1611 
1612   }
1613 
1614   if (create_scrollbar) {
1615     /* create vsrollbar */
1616     pBuf = create_horizontal(current_theme->Horiz, pWindow->dst,
1617                              width, WF_RESTORE_BACKGROUND);
1618 
1619     pBuf->ID = ID_SCROLLBAR;
1620     pBuf->data.ptr = (void *)pDlg;
1621     set_wstate(pBuf, FC_WS_NORMAL);
1622 
1623     if(swap_start_y) {
1624       pBuf->size.y = start_y - pBuf->size.h;
1625     } else {
1626       pBuf->size.y = start_y;
1627     }
1628 
1629     if(create_buttons) {
1630       pBuf->size.x = start_x + pDlg->pScroll->pUp_Left_Button->size.w;
1631       if(pDlg->pScroll->count > pDlg->pScroll->active) {
1632 	pBuf->size.w = scrollbar_size(pDlg->pScroll);
1633       } else {
1634 	pBuf->size.w = pDlg->pScroll->max - pDlg->pScroll->min;
1635       }
1636     } else {
1637       pBuf->size.x = start_x;
1638       pDlg->pScroll->min = start_x;
1639       pDlg->pScroll->max = start_x + width;
1640     }
1641 
1642     pDlg->pScroll->pScrollBar = pBuf;
1643     DownAdd(pBuf, pDlg->pBeginWidgetList);
1644     pDlg->pBeginWidgetList = pBuf;
1645 
1646     if(!count) {
1647       count = pBuf->size.h;
1648     }
1649 
1650   }
1651 
1652   return count;
1653 }
1654