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