30 #include <stdlib.h> |
30 #include <stdlib.h> |
31 |
31 |
32 #include "button.h" |
32 #include "button.h" |
33 #include "container.h" |
33 #include "container.h" |
34 #include "../common/context.h" |
34 #include "../common/context.h" |
35 #include <ucx/mempool.h> |
35 #include <cx/mempool.h> |
36 |
36 |
37 |
37 #include <cx/linked_list.h> |
38 UIWIDGET ui_button(UiObject *obj, char *label, ui_callback f, void *data) { |
38 #include <cx/array_list.h> |
39 UiContainer *ct = uic_get_current_container(obj); |
39 #include <cx/compare.h> |
40 XmString str = XmStringCreateLocalized(label); |
40 |
41 |
41 #include <Xm/XmAll.h> |
|
42 |
|
43 |
|
44 UIWIDGET ui_button_create(UiObject* obj, UiButtonArgs args) { |
|
45 Arg xargs[16]; |
42 int n = 0; |
46 int n = 0; |
43 Arg args[16]; |
47 |
44 |
48 UiContainerPrivate *ctn = ui_obj_container(obj); |
45 XtSetArg(args[n], XmNlabelString, str); |
49 UI_APPLY_LAYOUT(ctn->layout, args); |
46 n++; |
50 |
47 |
51 Widget parent = ctn->prepare(ctn, xargs, &n); |
48 Widget parent = ct->prepare(ct, args, &n, FALSE); |
52 |
49 Widget button = XmCreatePushButton(parent, "button", args, n); |
53 XmString label = NULL; |
50 ct->add(ct, button); |
54 if(args.label) { |
51 |
55 label = XmStringCreateLocalized((char*)args.label); |
52 if(f) { |
56 XtSetArg(xargs[n], XmNlabelString, label); n++; |
53 UiEventData *event = ucx_mempool_malloc( |
57 } |
54 obj->ctx->mempool, |
58 |
55 sizeof(UiEventData)); |
59 char *name = args.name ? (char*)args.name : "button"; |
56 event->obj = obj; |
60 Widget button = XmCreatePushButton(parent, name, xargs, n); |
57 event->userdata = data; |
61 XtManageChild(button); |
58 event->callback = f; |
62 ctn->add(ctn, button); |
59 event->value = 0; |
63 |
|
64 ui_set_widget_groups(obj->ctx, button, args.groups); |
|
65 |
|
66 if(args.onclick) { |
|
67 UiEventData *eventdata = malloc(sizeof(UiEventData)); |
|
68 eventdata->callback = args.onclick; |
|
69 eventdata->userdata = args.onclickdata; |
|
70 eventdata->obj = obj; |
|
71 eventdata->value = 0; |
60 XtAddCallback( |
72 XtAddCallback( |
61 button, |
73 button, |
62 XmNactivateCallback, |
74 XmNactivateCallback, |
63 (XtCallbackProc)ui_push_button_callback, |
75 (XtCallbackProc)ui_push_button_callback, |
64 event); |
76 eventdata); |
65 } |
77 XtAddCallback( |
66 |
78 button, |
67 XtManageChild(button); |
79 XmNdestroyCallback, |
68 |
80 (XtCallbackProc)ui_destroy_eventdata, |
|
81 eventdata); |
|
82 } |
|
83 |
|
84 |
|
85 XmStringFree(label); |
69 return button; |
86 return button; |
70 } |
|
71 |
|
72 // wrapper |
|
73 int64_t ui_toggle_button_get(UiInteger *i) { |
|
74 int state = 0; |
|
75 XtVaGetValues(i->obj, XmNset, &state, NULL); |
|
76 i->value = state; |
|
77 return state; |
|
78 } |
|
79 |
|
80 void ui_toggle_button_set(UiInteger *i, int64_t value) { |
|
81 Arg arg; |
|
82 XtSetArg(arg, XmNset, value); |
|
83 XtSetValues(i->obj, &arg, 1); |
|
84 i->value = value; |
|
85 } |
|
86 |
|
87 void ui_toggle_button_callback( |
|
88 Widget widget, |
|
89 UiEventData *event, |
|
90 XmToggleButtonCallbackStruct *tb) |
|
91 { |
|
92 UiEvent e; |
|
93 e.obj = event->obj; |
|
94 e.window = event->obj->window; |
|
95 // TODO: e.document |
|
96 e.intval = tb->set; |
|
97 event->callback(&e, event->userdata); |
|
98 } |
87 } |
99 |
88 |
100 void ui_push_button_callback(Widget widget, UiEventData *event, XtPointer d) { |
89 void ui_push_button_callback(Widget widget, UiEventData *event, XtPointer d) { |
101 UiEvent e; |
90 UiEvent e; |
102 e.obj = event->obj; |
91 e.obj = event->obj; |
104 e.document = event->obj->ctx->document; |
93 e.document = event->obj->ctx->document; |
105 e.intval = event->value; |
94 e.intval = event->value; |
106 event->callback(&e, event->userdata); |
95 event->callback(&e, event->userdata); |
107 } |
96 } |
108 |
97 |
109 |
98 UIWIDGET ui_togglebutton_create(UiObject* obj, UiToggleArgs args) { |
110 static void radio_callback( |
99 Arg xargs[16]; |
|
100 int n = 0; |
|
101 |
|
102 UiContainerPrivate *ctn = ui_obj_container(obj); |
|
103 UI_APPLY_LAYOUT(ctn->layout, args); |
|
104 |
|
105 Widget parent = ctn->prepare(ctn, xargs, &n); |
|
106 XtSetArg(xargs[n], XmNfillOnSelect, True); n++; |
|
107 XtSetArg(xargs[n], XmNindicatorOn, False); n++; |
|
108 |
|
109 XmString label = NULL; |
|
110 if(args.label) { |
|
111 label = XmStringCreateLocalized((char*)args.label); |
|
112 XtSetArg(xargs[n], XmNlabelString, label); n++; |
|
113 } |
|
114 |
|
115 char *name = args.name ? (char*)args.name : "togglebutton"; |
|
116 Widget button = XmCreateToggleButton(parent, name, xargs, n); |
|
117 XtManageChild(button); |
|
118 ctn->add(ctn, button); |
|
119 |
|
120 ui_set_widget_groups(obj->ctx, button, args.groups); |
|
121 |
|
122 ui_bind_togglebutton(obj, button, args.varname, args.value, args.onchange, args.onchangedata, args.enable_group); |
|
123 |
|
124 XmStringFree(label); |
|
125 return button; |
|
126 } |
|
127 |
|
128 UIWIDGET ui_checkbox_create(UiObject* obj, UiToggleArgs args) { |
|
129 Arg xargs[16]; |
|
130 int n = 0; |
|
131 |
|
132 UiContainerPrivate *ctn = ui_obj_container(obj); |
|
133 UI_APPLY_LAYOUT(ctn->layout, args); |
|
134 |
|
135 Widget parent = ctn->prepare(ctn, xargs, &n); |
|
136 |
|
137 XmString label = NULL; |
|
138 if(args.label) { |
|
139 label = XmStringCreateLocalized((char*)args.label); |
|
140 XtSetArg(xargs[n], XmNlabelString, label); n++; |
|
141 } |
|
142 |
|
143 char *name = args.name ? (char*)args.name : "button"; |
|
144 Widget button = XmCreateToggleButton(parent, name, xargs, n); |
|
145 XtManageChild(button); |
|
146 ctn->add(ctn, button); |
|
147 |
|
148 ui_set_widget_groups(obj->ctx, button, args.groups); |
|
149 |
|
150 ui_bind_togglebutton(obj, button, args.varname, args.value, args.onchange, args.onchangedata, args.enable_group); |
|
151 |
|
152 XmStringFree(label); |
|
153 return button; |
|
154 } |
|
155 |
|
156 UIWIDGET ui_switch_create(UiObject* obj, UiToggleArgs args) { |
|
157 return ui_checkbox_create(obj, args); |
|
158 } |
|
159 |
|
160 static void togglebutton_changed(Widget w, UiVarEventData *event, XmToggleButtonCallbackStruct *tb) { |
|
161 if(event->value > 0) { |
|
162 // button in configured to enable/disable states |
|
163 if(tb->set) { |
|
164 ui_set_group(event->obj->ctx, event->value); |
|
165 } else { |
|
166 ui_unset_group(event->obj->ctx, event->value); |
|
167 } |
|
168 } |
|
169 |
|
170 UiEvent e; |
|
171 e.obj = event->obj; |
|
172 e.window = e.obj->window; |
|
173 e.document = e.obj->ctx->document; |
|
174 e.eventdata = NULL; |
|
175 e.intval = XmToggleButtonGetState(w); |
|
176 |
|
177 if(event->callback) { |
|
178 event->callback(&e, event->userdata); |
|
179 } |
|
180 |
|
181 if(event->var && event->var->value) { |
|
182 UiInteger *v = event->var->value; |
|
183 v->value = e.intval; |
|
184 ui_notify_evt(v->observers, &e); |
|
185 } |
|
186 } |
|
187 |
|
188 void ui_bind_togglebutton( |
|
189 UiObject *obj, |
111 Widget widget, |
190 Widget widget, |
112 RadioEventData *event, |
191 const char *varname, |
113 XmToggleButtonCallbackStruct *tb) |
192 UiInteger *value, |
|
193 ui_callback onchange, |
|
194 void *onchangedata, |
|
195 int enable_state) |
114 { |
196 { |
115 if(tb->set) { |
197 UiVar* var = uic_widget_var(obj->ctx, obj->ctx, value, varname, UI_VAR_INTEGER); |
116 RadioButtonGroup *group = event->group; |
198 if(var) { |
117 if(group->current) { |
199 value = (UiInteger*)var->value; |
118 Arg arg; |
200 value->obj = widget; |
119 XtSetArg(arg, XmNset, FALSE); |
201 value->get = ui_togglebutton_get; |
120 XtSetValues(group->current, &arg, 1); |
202 value->set = ui_togglebutton_set; |
121 } |
203 |
122 group->current = widget; |
204 if(value->value) { |
123 } |
205 XmToggleButtonSetState(widget, True, False); |
124 } |
206 } |
125 |
207 } |
126 UIWIDGET ui_radiobutton(UiObject *obj, char *label, UiInteger *rgroup) { |
208 |
127 UiContainer *ct = uic_get_current_container(obj); |
209 UiVarEventData *event = malloc(sizeof(UiVarEventData)); |
128 XmString str = XmStringCreateLocalized(label); |
210 event->obj = obj; |
129 |
211 event->callback = onchange; |
|
212 event->userdata = onchangedata; |
|
213 event->var = var; |
|
214 event->observers = NULL; |
|
215 event->value = enable_state; |
|
216 XtAddCallback( |
|
217 widget, |
|
218 XmNvalueChangedCallback, |
|
219 (XtCallbackProc)togglebutton_changed, |
|
220 event); |
|
221 XtAddCallback( |
|
222 widget, |
|
223 XmNdestroyCallback, |
|
224 (XtCallbackProc)ui_destroy_eventdata, |
|
225 event); |
|
226 } |
|
227 |
|
228 int64_t ui_togglebutton_get(UiInteger *i) { |
|
229 Widget togglebutton = i->obj; |
|
230 Boolean state = XmToggleButtonGetState(togglebutton); |
|
231 i->value = state; |
|
232 return state; |
|
233 } |
|
234 |
|
235 void ui_togglebutton_set(UiInteger *i, int64_t value) { |
|
236 Widget togglebutton = i->obj; |
|
237 i->value = value; |
|
238 XmToggleButtonSetState(togglebutton, (Boolean)value, False); |
|
239 } |
|
240 |
|
241 static void destroy_list(Widget w, CxList *list, XtPointer d) { |
|
242 cxListDestroy(list); |
|
243 } |
|
244 |
|
245 static void radiobutton_changed(Widget w, UiVarEventData *event, XmToggleButtonCallbackStruct *tb) { |
|
246 if(event->value > 0) { |
|
247 // button in configured to enable/disable states |
|
248 if(tb->set) { |
|
249 ui_set_group(event->obj->ctx, event->value); |
|
250 } else { |
|
251 ui_unset_group(event->obj->ctx, event->value); |
|
252 } |
|
253 } |
|
254 |
|
255 if(!tb->set) { |
|
256 return; // only handle set-events |
|
257 } |
|
258 |
|
259 UiInteger *value = NULL; |
|
260 int64_t v = 0; |
|
261 if(event->var) { |
|
262 value = event->var->value; |
|
263 // find widget index and update all radiobuttons |
|
264 // the UiInteger value must always be up-to-date |
|
265 CxList *list = value->obj; |
|
266 CxIterator i = cxListIterator(list); |
|
267 cx_foreach(Widget, button, i) { |
|
268 Boolean state = False; |
|
269 if(button == w) { |
|
270 value->value = i.index+1; // update value |
|
271 state = True; |
|
272 } |
|
273 XmToggleButtonSetState(button, state, False); |
|
274 } |
|
275 v = value->value; |
|
276 } |
|
277 |
|
278 UiEvent e; |
|
279 e.obj = event->obj; |
|
280 e.window = e.obj->window; |
|
281 e.document = e.obj->ctx->document; |
|
282 e.eventdata = value; |
|
283 e.intval = v; |
|
284 |
|
285 if(event->callback) { |
|
286 event->callback(&e, event->userdata); |
|
287 } |
|
288 |
|
289 if(value) { |
|
290 ui_notify_evt(value->observers, &e); |
|
291 } |
|
292 } |
|
293 |
|
294 void ui_bind_radiobutton(UiObject *obj, Widget rbutton, UiInteger *value, const char *varname, ui_callback onchange, void *onchangedata, int enable_group) { |
|
295 UiVar* var = uic_widget_var(obj->ctx, obj->ctx, value, varname, UI_VAR_INTEGER); |
|
296 if(var) { |
|
297 UiInteger *value = var->value; |
|
298 CxList *rb = value->obj; |
|
299 if(!rb) { |
|
300 // first button in the radiobutton group |
|
301 // create a list for all buttons and use the list as value obj |
|
302 rb = cxArrayListCreateSimple(CX_STORE_POINTERS, 4); |
|
303 value->obj = rb; |
|
304 value->get = ui_radiobutton_get; |
|
305 value->set = ui_radiobutton_set; |
|
306 |
|
307 // the first radio button is also responsible for cleanup |
|
308 XtAddCallback( |
|
309 rbutton, |
|
310 XmNdestroyCallback, |
|
311 (XtCallbackProc)destroy_list, |
|
312 rb); |
|
313 } |
|
314 cxListAdd(rb, rbutton); |
|
315 |
|
316 // set the radiobutton state, if the value is already set |
|
317 if(cxListSize(rb) == value->value) { |
|
318 XmToggleButtonSetState(rbutton, True, False); |
|
319 } |
|
320 } |
|
321 |
|
322 // the radio button needs to handle change events to update all |
|
323 // other buttons in the radio button group |
|
324 UiVarEventData *event = malloc(sizeof(UiVarEventData)); |
|
325 event->obj = obj; |
|
326 event->callback = onchange; |
|
327 event->userdata = onchangedata; |
|
328 event->observers = NULL; |
|
329 event->var = var; |
|
330 event->value = enable_group; |
|
331 XtAddCallback( |
|
332 rbutton, |
|
333 XmNvalueChangedCallback, |
|
334 (XtCallbackProc)radiobutton_changed, |
|
335 event); |
|
336 XtAddCallback( |
|
337 rbutton, |
|
338 XmNdestroyCallback, |
|
339 (XtCallbackProc)ui_destroy_eventdata, |
|
340 event); |
|
341 } |
|
342 |
|
343 UIWIDGET ui_radiobutton_create(UiObject* obj, UiToggleArgs args) { |
|
344 Arg xargs[16]; |
130 int n = 0; |
345 int n = 0; |
131 Arg args[16]; |
346 |
132 |
347 UiContainerPrivate *ctn = ui_obj_container(obj); |
133 XtSetArg(args[n], XmNlabelString, str); |
348 UI_APPLY_LAYOUT(ctn->layout, args); |
134 n++; |
349 |
135 XtSetArg(args[n], XmNindicatorType, XmONE_OF_MANY_ROUND); |
350 Widget parent = ctn->prepare(ctn, xargs, &n); |
136 n++; |
351 XtSetArg(xargs[n], XmNindicatorType, XmONE_OF_MANY_ROUND); n++; |
137 |
352 XmString label = NULL; |
138 Widget parent = ct->prepare(ct, args, &n, FALSE); |
353 if(args.label) { |
139 Widget button = XmCreateToggleButton(parent, "radiobutton", args, n); |
354 label = XmStringCreateLocalized((char*)args.label); |
140 ct->add(ct, button); |
355 XtSetArg(xargs[n], XmNlabelString, label); n++; |
141 |
356 } |
142 if(rgroup) { |
357 |
143 RadioButtonGroup *group; |
358 char *name = args.name ? (char*)args.name : "button"; |
144 if(rgroup->obj) { |
359 Widget button = XmCreateToggleButton(parent, name, xargs, n); |
145 group = rgroup->obj; |
360 XtManageChild(button); |
146 group->buttons = ucx_list_append(group->buttons, button); |
361 ctn->add(ctn, button); |
147 group->ref++; |
362 |
148 } else { |
363 ui_set_widget_groups(obj->ctx, button, args.groups); |
149 group = malloc(sizeof(RadioButtonGroup)); |
364 |
150 group->buttons = ucx_list_append(NULL, button); |
365 UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args.value, args.varname, UI_VAR_INTEGER); |
151 group->current = button; |
366 if(var) { |
152 // this is the first button in the radiobutton group |
367 UiInteger *value = var->value; |
153 // so we should enable it |
368 CxList *rb = value->obj; |
154 Arg arg; |
369 if(!rb) { |
155 XtSetArg(arg, XmNset, TRUE); |
370 // first button in the radiobutton group |
156 XtSetValues(button, &arg, 1); |
371 // create a list for all buttons and use the list as value obj |
157 rgroup->obj = group; |
372 rb = cxArrayListCreateSimple(CX_STORE_POINTERS, 4); |
|
373 value->obj = rb; |
|
374 value->get = ui_radiobutton_get; |
|
375 value->set = ui_radiobutton_set; |
158 |
376 |
159 group->current = button; |
377 // the first radio button is also responsible for cleanup |
160 } |
378 XtAddCallback( |
|
379 button, |
|
380 XmNdestroyCallback, |
|
381 (XtCallbackProc)destroy_list, |
|
382 rb); |
|
383 } |
|
384 cxListAdd(rb, button); |
161 |
385 |
162 RadioEventData *event = malloc(sizeof(RadioEventData)); |
386 // set the radiobutton state, if the value is already set |
163 event->obj = obj; |
387 if(cxListSize(rb) == value->value) { |
164 event->callback = NULL; |
388 XmToggleButtonSetState(button, True, False); |
165 event->userdata = NULL; |
389 } |
166 event->group = group; |
390 } |
167 XtAddCallback( |
391 |
|
392 // the radio button needs to handle change events to update all |
|
393 // other buttons in the radio button group |
|
394 UiVarEventData *event = malloc(sizeof(UiVarEventData)); |
|
395 event->obj = obj; |
|
396 event->callback = args.onchange; |
|
397 event->userdata = args.onchangedata; |
|
398 event->observers = NULL; |
|
399 event->var = var; |
|
400 event->value = args.enable_group; |
|
401 XtAddCallback( |
168 button, |
402 button, |
169 XmNvalueChangedCallback, |
403 XmNvalueChangedCallback, |
170 (XtCallbackProc)radio_callback, |
404 (XtCallbackProc)radiobutton_changed, |
171 event); |
405 event); |
172 |
406 XtAddCallback( |
173 rgroup->get = ui_radiobutton_get; |
407 button, |
174 rgroup->set = ui_radiobutton_set; |
408 XmNdestroyCallback, |
175 } |
409 (XtCallbackProc)ui_destroy_eventdata, |
176 |
410 event); |
177 XtManageChild(button); |
411 |
|
412 XmStringFree(label); |
178 return button; |
413 return button; |
179 } |
414 |
180 |
415 |
181 int64_t ui_radiobutton_get(UiInteger *value) { |
416 } |
182 RadioButtonGroup *group = value->obj; |
417 |
183 |
418 int64_t ui_radiobutton_get(UiInteger *i) { |
184 int i = ucx_list_find(group->buttons, group->current, NULL, NULL); |
419 // the UiInteger should be updated automatically by change events |
185 if (i >= 0) { |
420 return i->value; |
186 value->value = i; |
421 } |
187 return i; |
422 |
188 } else { |
423 void ui_radiobutton_set(UiInteger *i, int64_t value) { |
189 return 0; |
424 CxList *list = i->obj; |
190 } |
425 if(i->value > 0) { |
191 } |
426 Widget current = cxListAt(list, i->value-1); |
192 |
427 if(current) { |
193 void ui_radiobutton_set(UiInteger *value, int64_t i) { |
428 XmToggleButtonSetState(current, False, False); |
194 RadioButtonGroup *group = value->obj; |
429 } |
195 Arg arg; |
430 } |
196 |
431 if(value > 0 && value <= cxListSize(list)) { |
197 XtSetArg(arg, XmNset, FALSE); |
432 Widget button = cxListAt(list, value-1); |
198 XtSetValues(group->current, &arg, 1); |
433 if(button) { |
199 |
434 XmToggleButtonSetState(button, True, False); |
200 UcxList *elm = ucx_list_get(group->buttons, i); |
435 i->value = value; |
201 if(elm) { |
436 } |
202 Widget button = elm->data; |
437 } |
203 XtSetArg(arg, XmNset, TRUE); |
438 } |
204 XtSetValues(button, &arg, 1); |
|
205 group->current = button; |
|
206 } |
|
207 } |
|