| 30 #include "widget.h" |
30 #include "widget.h" |
| 31 |
31 |
| 32 #include <stdio.h> |
32 #include <stdio.h> |
| 33 #include <stdlib.h> |
33 #include <stdlib.h> |
| 34 |
34 |
| |
35 #include <cx/array_list.h> |
| |
36 |
| 35 #include <commctrl.h> |
37 #include <commctrl.h> |
| 36 |
38 |
| 37 static W32WidgetClass button_widget_class = { |
39 static W32WidgetClass button_widget_class = { |
| 38 .eventproc = ui_button_eventproc, |
40 .eventproc = ui_button_eventproc, |
| |
41 .enable = w32_widget_default_enable, |
| |
42 .show = w32_widget_default_show, |
| |
43 .get_preferred_size = ui_button_get_preferred_size, |
| |
44 .destroy = w32_widget_default_destroy |
| |
45 }; |
| |
46 |
| |
47 static W32WidgetClass togglebutton_widget_class = { |
| |
48 .eventproc = ui_togglebutton_eventproc, |
| |
49 .enable = w32_widget_default_enable, |
| |
50 .show = w32_widget_default_show, |
| |
51 .get_preferred_size = ui_button_get_preferred_size, |
| |
52 .destroy = w32_widget_default_destroy |
| |
53 }; |
| |
54 |
| |
55 static W32WidgetClass radiobutton_widget_class = { |
| |
56 .eventproc = ui_radiobutton_eventproc, |
| 39 .enable = w32_widget_default_enable, |
57 .enable = w32_widget_default_enable, |
| 40 .show = w32_widget_default_show, |
58 .show = w32_widget_default_show, |
| 41 .get_preferred_size = ui_button_get_preferred_size, |
59 .get_preferred_size = ui_button_get_preferred_size, |
| 42 .destroy = w32_widget_default_destroy |
60 .destroy = w32_widget_default_destroy |
| 43 }; |
61 }; |
| 98 e.set = ui_get_setop(); |
117 e.set = ui_get_setop(); |
| 99 |
118 |
| 100 if (w->callback) { |
119 if (w->callback) { |
| 101 w->callback(&e, w->callbackdata); |
120 w->callback(&e, w->callbackdata); |
| 102 } |
121 } |
| 103 } |
122 |
| |
123 return 0; |
| |
124 } |
| |
125 |
| |
126 static UIWIDGET create_togglebutton(UiObject *obj, UiToggleArgs *args, unsigned long type) { |
| |
127 HINSTANCE hInstance = GetModuleHandle(NULL); |
| |
128 UiContainerPrivate *container = ui_obj_container(obj); |
| |
129 HWND parent = ui_container_get_parent(container); |
| |
130 UiLayout layout = UI_ARGS2LAYOUT(args); |
| |
131 |
| |
132 HWND hwnd = CreateWindow( |
| |
133 "BUTTON", |
| |
134 args->label, |
| |
135 WS_VISIBLE | WS_CHILD | type, |
| |
136 0, 0, 100, 30, |
| |
137 parent, |
| |
138 (HMENU)1, |
| |
139 hInstance, |
| |
140 NULL); |
| |
141 ui_win32_set_ui_font(hwnd); |
| |
142 |
| |
143 W32Widget *widget = w32_widget_create(&togglebutton_widget_class, hwnd, sizeof(UiWidget)); |
| |
144 ui_container_add(container, widget, &layout); |
| |
145 |
| |
146 UiVar *var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_INTEGER); |
| |
147 if (var) { |
| |
148 UiInteger *i = var->value; |
| |
149 i->obj = widget; |
| |
150 i->get = ui_togglebutton_get; |
| |
151 i->set = ui_togglebutton_set; |
| |
152 if (i->value != 0) { |
| |
153 SendMessage(hwnd, BM_SETCHECK, BST_CHECKED, 0); |
| |
154 } |
| |
155 } |
| |
156 |
| |
157 UiWidget *btn = (UiWidget*)widget; |
| |
158 btn->obj = obj; |
| |
159 btn->var = var; |
| |
160 btn->callback = args->onchange; |
| |
161 btn->callbackdata = args->onchangedata; |
| |
162 |
| |
163 return widget; |
| |
164 } |
| |
165 |
| |
166 UIWIDGET ui_togglebutton_create(UiObject *obj, UiToggleArgs *args) { |
| |
167 return create_togglebutton(obj, args, BS_AUTOCHECKBOX | BS_PUSHLIKE); |
| |
168 } |
| |
169 |
| |
170 UIWIDGET ui_checkbox_create(UiObject *obj, UiToggleArgs *args) { |
| |
171 return create_togglebutton(obj, args, BS_AUTOCHECKBOX); |
| |
172 } |
| |
173 |
| |
174 UIWIDGET ui_switch_create(UiObject *obj, UiToggleArgs *args) { |
| |
175 return create_togglebutton(obj, args, BS_AUTOCHECKBOX); |
| |
176 } |
| |
177 |
| |
178 int64_t ui_togglebutton_get(UiInteger *i) { |
| |
179 UiWidget *btn = (UiWidget*)i->obj; |
| |
180 LRESULT state = SendMessage(btn->widget.hwnd, BM_GETCHECK, 0, 0); |
| |
181 i->value = state; |
| |
182 return state; |
| |
183 } |
| |
184 |
| |
185 void ui_togglebutton_set(UiInteger *i, int64_t v) { |
| |
186 UiWidget *btn = (UiWidget*)i->obj; |
| |
187 WPARAM state = v ? BST_CHECKED : BST_UNCHECKED; |
| |
188 SendMessage(btn->widget.hwnd, BM_SETCHECK, state, 0); |
| |
189 i->value = v; |
| |
190 } |
| |
191 |
| |
192 int ui_togglebutton_eventproc(W32Widget *widget, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { |
| |
193 if (uMsg != WM_COMMAND) { |
| |
194 return 0; |
| |
195 } |
| |
196 UiWidget *w = (UiWidget*)widget; |
| |
197 |
| |
198 UiEvent e; |
| |
199 e.obj = w->obj; |
| |
200 e.document = e.obj->ctx->document; |
| |
201 e.window = e.obj->window; |
| |
202 e.eventdata = NULL; |
| |
203 e.eventdatatype = 0; |
| |
204 e.intval = SendMessage(w->widget.hwnd, BM_GETCHECK, 0, 0); |
| |
205 e.set = ui_get_setop(); |
| |
206 |
| |
207 if (w->callback) { |
| |
208 w->callback(&e, w->callbackdata); |
| |
209 } |
| |
210 |
| |
211 return 0; |
| |
212 } |
| |
213 |
| |
214 |
| |
215 UIWIDGET ui_radiobutton_create(UiObject *obj, UiToggleArgs *args) { |
| |
216 HINSTANCE hInstance = GetModuleHandle(NULL); |
| |
217 UiContainerPrivate *container = ui_obj_container(obj); |
| |
218 HWND parent = ui_container_get_parent(container); |
| |
219 UiLayout layout = UI_ARGS2LAYOUT(args); |
| |
220 |
| |
221 HWND hwnd = CreateWindow( |
| |
222 "BUTTON", |
| |
223 args->label, |
| |
224 WS_VISIBLE | WS_CHILD | BS_AUTORADIOBUTTON | WS_GROUP , |
| |
225 0, 0, 100, 30, |
| |
226 parent, |
| |
227 (HMENU)1, |
| |
228 hInstance, |
| |
229 NULL); |
| |
230 ui_win32_set_ui_font(hwnd); |
| |
231 |
| |
232 W32Widget *widget = w32_widget_create(&radiobutton_widget_class, hwnd, sizeof(UiWidget)); |
| |
233 ui_container_add(container, widget, &layout); |
| |
234 UiWidget *btn = (UiWidget*)widget; |
| |
235 |
| |
236 UiVar *var = uic_widget_var(obj->ctx, obj->ctx, args->value, args->varname, UI_VAR_INTEGER); |
| |
237 if (var) { |
| |
238 UiInteger *i = var->value; |
| |
239 // Use a CxList as binding object (i->obj) and add all radiobuttons to it |
| |
240 // The first radiobutton, which binds to this var, creates the CxList |
| |
241 CxList *group = NULL; |
| |
242 if (i->obj) { |
| |
243 group = i->obj; |
| |
244 } else { |
| |
245 group = cxArrayListCreate(obj->ctx->allocator, NULL, CX_STORE_POINTERS, 8); |
| |
246 i->obj = group; |
| |
247 } |
| |
248 |
| |
249 cxListAdd(group, btn); |
| |
250 if (i->value == cxListSize(group)) { |
| |
251 // TODO: select |
| |
252 } |
| |
253 } |
| |
254 |
| |
255 btn->obj = obj; |
| |
256 btn->var = var; |
| |
257 btn->callback = args->onchange; |
| |
258 btn->callbackdata = args->onchangedata; |
| |
259 |
| |
260 return widget; |
| |
261 } |
| |
262 |
| |
263 int ui_radiobutton_eventproc(W32Widget *widget, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { |
| |
264 if (uMsg != WM_COMMAND) { |
| |
265 return 0; |
| |
266 } |
| |
267 UiWidget *w = (UiWidget*)widget; |
| |
268 |
| |
269 int checked = SendMessage(w->widget.hwnd, BM_GETCHECK, 0, 0); |
| |
270 if (!checked) { |
| |
271 return 0; // ignore uncheck events |
| |
272 } |
| |
273 |
| |
274 int b = 0; |
| |
275 if (w->var) { |
| |
276 UiInteger *i = w->var->value; |
| |
277 CxList *group = i->obj; |
| |
278 // Find selected index and uncheck all radiobuttons in this group |
| |
279 // that are not this event widget |
| |
280 CxIterator iter = cxListIterator(group); |
| |
281 cx_foreach(UiWidget *, radiobutton, iter) { |
| |
282 if (radiobutton == w) { |
| |
283 i->value = iter.index+1; |
| |
284 b = i->value; |
| |
285 } else { |
| |
286 SendMessage(radiobutton->widget.hwnd, BM_SETCHECK, BST_UNCHECKED, 0); |
| |
287 } |
| |
288 } |
| |
289 } |
| |
290 |
| |
291 UiEvent e; |
| |
292 e.obj = w->obj; |
| |
293 e.document = e.obj->ctx->document; |
| |
294 e.window = e.obj->window; |
| |
295 e.eventdata = NULL; |
| |
296 e.eventdatatype = 0; |
| |
297 e.intval = b; |
| |
298 e.set = ui_get_setop(); |
| |
299 |
| |
300 if (w->callback) { |
| |
301 w->callback(&e, w->callbackdata); |
| |
302 } |
| |
303 |
| |
304 return 0; |
| |
305 } |
| |
306 |
| |
307 int64_t ui_radiobutton_get(UiInteger *i) { |
| |
308 return i->value; |
| |
309 } |
| |
310 |
| |
311 void ui_radiobutton_set(UiInteger *i, int64_t v) { |
| |
312 CxList *group = i->obj; |
| |
313 CxIterator iter = cxListIterator(group); |
| |
314 cx_foreach(UiWidget *, radiobutton, iter) { |
| |
315 SendMessage(radiobutton->widget.hwnd, BM_SETCHECK, iter.index+1 == v ? BST_CHECKED : BST_UNCHECKED, 0); |
| |
316 } |
| |
317 i->value = v; |
| |
318 } |