webperimental: Mountain vision bonus.
[freeciv.git] / client / gui-sdl2 / widget_combo.c
blob3408952c2a0cfff9ba329afd212062c98ae8d6fc
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.
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 ***********************************************************************/
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
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 */
25 /* utility */
26 #include "log.h"
27 #include "string_vector.h"
29 /* client/gui-sdl2 */
30 #include "colors.h"
31 #include "gui_iconv.h"
32 #include "gui_id.h"
33 #include "gui_string.h"
34 #include "gui_tilespec.h"
35 #include "mapview.h"
36 #include "widget.h"
37 #include "widget_p.h"
39 struct combo_menu {
40 struct widget *begin_widget_list;
41 struct widget *end_widget_list;
44 static int (*baseclass_redraw) (struct widget *widget) = NULL;
47 /****************************************************************************
48 Redraw the combo box widget.
49 ****************************************************************************/
50 static int combo_redraw(struct widget *combo)
52 SDL_Rect dest = { combo->size.x, combo->size.y, 0, 0 };
53 SDL_Surface *text, *surface;
54 struct combo_menu *menu;
55 int ret;
57 ret = baseclass_redraw(combo);
58 if (0 != ret) {
59 return ret;
62 surface = create_bcgnd_surf(combo->theme, get_wstate(combo),
63 combo->size.w, combo->size.h);
65 if (NULL == surface) {
66 return -1;
69 /* Blit theme. */
70 alphablit(surface, NULL, combo->dst->surface, &dest, 255);
72 /* Set position and blit text. */
73 text = create_text_surf_from_utf8(combo->string_utf8);
74 if (NULL != text) {
75 dest.y += (surface->h - surface->h) / 2;
76 /* Blit centred text to botton. */
77 if (combo->string_utf8->style & SF_CENTER) {
78 dest.x += (surface->w - text->w) / 2;
79 } else {
80 if (combo->string_utf8->style & SF_CENTER_RIGHT) {
81 dest.x += surface->w - text->w - adj_size(5);
82 } else {
83 dest.x += adj_size(5); /* center left */
87 alphablit(text, NULL, combo->dst->surface, &dest, 255);
89 /* text. */
90 ret = surface->h;
92 /* Free memory */
93 FREESURFACE(text);
94 FREESURFACE(surface);
96 menu = (struct combo_menu *) combo->private_data.ptr;
97 if (NULL != menu) {
98 ret = redraw_group(menu->begin_widget_list, menu->end_widget_list, 0);
101 return ret;
104 /****************************************************************************
105 User interacted with the combo menu window.
106 ****************************************************************************/
107 static int combo_menu_callback(struct widget *window)
109 if (Main.event.button.button == SDL_BUTTON_LEFT) {
110 struct combo_menu *menu =
111 (struct combo_menu *)window->data.widget->private_data.ptr;
113 move_window_group(menu->begin_widget_list, menu->end_widget_list);
116 return -1;
119 /****************************************************************************
120 User interacted with a single item of the combo menu.
121 ****************************************************************************/
122 static int combo_menu_item_callback(struct widget *label)
124 struct widget *combo = label->data.widget;
126 if (Main.event.button.button == SDL_BUTTON_LEFT) {
127 copy_chars_to_utf8_str(combo->string_utf8, label->string_utf8->text);
128 widget_redraw(combo);
129 widget_mark_dirty(combo);
131 combo_popdown(combo);
133 return -1;
136 /****************************************************************************
137 Popup the combo box widget.
138 ****************************************************************************/
139 void combo_popup(struct widget *combo)
141 struct combo_menu *menu;
142 struct widget *window, *label = NULL;
143 int longest = 0, h = 0, x, y;
145 fc_assert_ret(NULL != combo);
146 fc_assert_ret(WT_COMBO == get_wtype(combo));
148 if (NULL != combo->private_data.ptr) {
149 return;
152 if (0 >= strvec_size(combo->data.vector)) {
153 return;
156 /* Menu. */
157 window = create_window_skeleton(NULL, NULL, 0);
158 window->action = combo_menu_callback;
159 window->data.widget = combo;
160 set_wstate(window, FC_WS_NORMAL);
161 add_to_gui_list(ID_COMBO_MENU, window);
163 /* Labels. */
164 strvec_iterate(combo->data.vector, string) {
165 label = create_iconlabel_from_chars(NULL, window->dst, string,
166 adj_font(10), WF_RESTORE_BACKGROUND);
167 label->action = combo_menu_item_callback;
168 label->data.widget = combo;
169 set_wstate(label, FC_WS_NORMAL);
170 add_to_gui_list(ID_LABEL, label);
172 longest = MAX(longest, label->size.w);
173 widget_set_position(label, adj_size(10), h);
174 h += adj_size(15);
175 } strvec_iterate_end;
177 /* Resize and relocate the window. */
178 resize_window(window, NULL, NULL, longest + 2 * adj_size(10), h);
180 x = combo->size.x + combo->dst->dest_rect.x;
181 if (x + window->size.w > main_window_width()) {
182 x = main_window_width() - window->size.w;
184 if (x < 0) {
185 x = 0;
188 y = combo->size.y - h + combo->dst->dest_rect.y;
189 if (y + window->size.h > main_window_height()) {
190 y = main_window_height() - window->size.h;
192 if (y < 0) {
193 y = 0;
196 widget_set_position(window, x, y);
198 /* Make data. */
199 menu = fc_malloc(sizeof(*menu));
200 menu->begin_widget_list = label;
201 menu->end_widget_list = window;
202 combo->private_data.ptr = menu;
204 /* Redraw. */
205 redraw_group(menu->begin_widget_list, menu->end_widget_list, 0);
206 widget_mark_dirty(window);
207 flush_dirty();
210 /****************************************************************************
211 Popdown the combo box widget.
212 ****************************************************************************/
213 void combo_popdown(struct widget *combo)
215 struct combo_menu *menu;
217 fc_assert_ret(NULL != combo);
218 fc_assert_ret(WT_COMBO == get_wtype(combo));
220 menu = (struct combo_menu *) combo->private_data.ptr;
221 if (NULL == menu) {
222 return;
225 widget_mark_dirty(menu->end_widget_list);
226 popdown_window_group_dialog(menu->begin_widget_list,
227 menu->end_widget_list);
228 free(menu);
229 combo->private_data.ptr = NULL;
230 flush_dirty();
233 /****************************************************************************
234 Create a combo box widget.
235 ****************************************************************************/
236 struct widget *combo_new(SDL_Surface *background, struct gui_layer *dest,
237 utf8_str *pstr, const struct strvec *vector,
238 int length, Uint32 flags)
240 SDL_Rect buf = {0, 0, 0, 0};
241 struct widget *combo = widget_new();
243 combo->theme = current_theme->Edit;
244 combo->theme2 = background;
245 combo->string_utf8 = pstr;
246 set_wflag(combo, WF_FREE_STRING | WF_FREE_GFX | flags);
247 set_wstate(combo, FC_WS_DISABLED);
248 set_wtype(combo, WT_COMBO);
249 combo->mod = KMOD_NONE;
251 baseclass_redraw = combo->redraw;
252 combo->redraw = combo_redraw;
253 combo->destroy = combo_popdown;
255 if (NULL != pstr) {
256 combo->string_utf8->style |= SF_CENTER;
257 utf8_str_size(pstr, &buf);
258 buf.h += adj_size(4);
261 length = MAX(length, buf.w + adj_size(10));
262 correct_size_bcgnd_surf(current_theme->Edit, &length, &buf.h);
263 combo->size.w = buf.w + adj_size(10);
264 combo->size.h = buf.h;
266 if (dest) {
267 combo->dst = dest;
268 } else {
269 combo->dst = add_gui_layer(combo->size.w, combo->size.h);
271 combo->data.vector = vector;
272 combo->private_data.ptr = NULL;
274 return combo;