36 |
36 |
37 #include <cx/linked_list.h> |
37 #include <cx/linked_list.h> |
38 #include <cx/array_list.h> |
38 #include <cx/array_list.h> |
39 #include <cx/compare.h> |
39 #include <cx/compare.h> |
40 |
40 |
41 |
41 #include <Xm/XmAll.h> |
42 UIWIDGET ui_button(UiObject *obj, char *label, ui_callback f, void *data) { |
42 |
43 UiContainer *ct = uic_get_current_container(obj); |
43 |
44 XmString str = XmStringCreateLocalized(label); |
44 UIWIDGET ui_button_create(UiObject* obj, UiButtonArgs args) { |
45 |
45 Arg xargs[16]; |
46 int n = 0; |
46 int n = 0; |
47 Arg args[16]; |
47 |
48 |
48 UiContainerPrivate *ctn = ui_obj_container(obj); |
49 XtSetArg(args[n], XmNlabelString, str); |
49 UI_APPLY_LAYOUT(ctn->layout, args); |
50 n++; |
50 |
51 |
51 Widget parent = ctn->prepare(ctn, xargs, &n); |
52 Widget parent = ct->prepare(ct, args, &n, FALSE); |
52 |
53 Widget button = XmCreatePushButton(parent, "button", args, n); |
53 XmString label = NULL; |
54 ct->add(ct, button); |
54 if(args.label) { |
55 |
55 label = XmStringCreateLocalized((char*)args.label); |
56 if(f) { |
56 XtSetArg(xargs[n], XmNlabelString, label); n++; |
57 UiEventData *event = cxMalloc( |
57 } |
58 obj->ctx->allocator, |
58 |
59 sizeof(UiEventData)); |
59 char *name = args.name ? (char*)args.name : "button"; |
60 event->obj = obj; |
60 Widget button = XmCreatePushButton(parent, name, xargs, n); |
61 event->userdata = data; |
61 XtManageChild(button); |
62 event->callback = f; |
62 ctn->add(ctn, button); |
63 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; |
64 XtAddCallback( |
72 XtAddCallback( |
65 button, |
73 button, |
66 XmNactivateCallback, |
74 XmNactivateCallback, |
67 (XtCallbackProc)ui_push_button_callback, |
75 (XtCallbackProc)ui_push_button_callback, |
68 event); |
76 eventdata); |
69 } |
77 XtAddCallback( |
70 |
78 button, |
71 XtManageChild(button); |
79 XmNdestroyCallback, |
72 |
80 (XtCallbackProc)ui_destroy_eventdata, |
|
81 eventdata); |
|
82 } |
|
83 |
|
84 |
|
85 XmStringFree(label); |
73 return button; |
86 return button; |
74 } |
|
75 |
|
76 // wrapper |
|
77 int64_t ui_toggle_button_get(UiInteger *i) { |
|
78 int state = 0; |
|
79 XtVaGetValues(i->obj, XmNset, &state, NULL); |
|
80 i->value = state; |
|
81 return state; |
|
82 } |
|
83 |
|
84 void ui_toggle_button_set(UiInteger *i, int64_t value) { |
|
85 Arg arg; |
|
86 XtSetArg(arg, XmNset, value); |
|
87 XtSetValues(i->obj, &arg, 1); |
|
88 i->value = value; |
|
89 } |
|
90 |
|
91 void ui_toggle_button_callback( |
|
92 Widget widget, |
|
93 UiEventData *event, |
|
94 XmToggleButtonCallbackStruct *tb) |
|
95 { |
|
96 UiEvent e; |
|
97 e.obj = event->obj; |
|
98 e.window = event->obj->window; |
|
99 // TODO: e.document |
|
100 e.intval = tb->set; |
|
101 event->callback(&e, event->userdata); |
|
102 } |
87 } |
103 |
88 |
104 void ui_push_button_callback(Widget widget, UiEventData *event, XtPointer d) { |
89 void ui_push_button_callback(Widget widget, UiEventData *event, XtPointer d) { |
105 UiEvent e; |
90 UiEvent e; |
106 e.obj = event->obj; |
91 e.obj = event->obj; |
108 e.document = event->obj->ctx->document; |
93 e.document = event->obj->ctx->document; |
109 e.intval = event->value; |
94 e.intval = event->value; |
110 event->callback(&e, event->userdata); |
95 event->callback(&e, event->userdata); |
111 } |
96 } |
112 |
97 |
113 |
98 UIWIDGET ui_togglebutton_create(UiObject* obj, UiToggleArgs args) { |
114 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, |
115 Widget widget, |
190 Widget widget, |
116 RadioEventData *event, |
191 const char *varname, |
117 XmToggleButtonCallbackStruct *tb) |
192 UiInteger *value, |
|
193 ui_callback onchange, |
|
194 void *onchangedata, |
|
195 int enable_state) |
118 { |
196 { |
119 if(tb->set) { |
197 UiVar* var = uic_widget_var(obj->ctx, obj->ctx, value, varname, UI_VAR_INTEGER); |
120 RadioButtonGroup *group = event->group; |
198 if(var) { |
121 if(group->current) { |
199 value = (UiInteger*)var->value; |
122 Arg arg; |
200 value->obj = widget; |
123 XtSetArg(arg, XmNset, FALSE); |
201 value->get = ui_togglebutton_get; |
124 XtSetValues(group->current, &arg, 1); |
202 value->set = ui_togglebutton_set; |
125 } |
203 |
126 group->current = widget; |
204 if(value->value) { |
127 } |
205 XmToggleButtonSetState(widget, True, False); |
128 } |
206 } |
129 |
207 } |
130 UIWIDGET ui_radiobutton(UiObject *obj, char *label, UiInteger *rgroup) { |
208 |
131 UiContainer *ct = uic_get_current_container(obj); |
209 UiVarEventData *event = malloc(sizeof(UiVarEventData)); |
132 XmString str = XmStringCreateLocalized(label); |
210 event->obj = obj; |
133 |
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 UIWIDGET ui_radiobutton_create(UiObject* obj, UiToggleArgs args) { |
|
295 Arg xargs[16]; |
134 int n = 0; |
296 int n = 0; |
135 Arg args[16]; |
297 |
136 |
298 UiContainerPrivate *ctn = ui_obj_container(obj); |
137 XtSetArg(args[n], XmNlabelString, str); |
299 UI_APPLY_LAYOUT(ctn->layout, args); |
138 n++; |
300 |
139 XtSetArg(args[n], XmNindicatorType, XmONE_OF_MANY_ROUND); |
301 Widget parent = ctn->prepare(ctn, xargs, &n); |
140 n++; |
302 XtSetArg(xargs[n], XmNindicatorType, XmONE_OF_MANY_ROUND); n++; |
141 |
303 XmString label = NULL; |
142 Widget parent = ct->prepare(ct, args, &n, FALSE); |
304 if(args.label) { |
143 Widget button = XmCreateToggleButton(parent, "radiobutton", args, n); |
305 label = XmStringCreateLocalized((char*)args.label); |
144 ct->add(ct, button); |
306 XtSetArg(xargs[n], XmNlabelString, label); n++; |
145 |
307 } |
146 if(rgroup) { |
308 |
147 RadioButtonGroup *group; |
309 char *name = args.name ? (char*)args.name : "button"; |
148 if(rgroup->obj) { |
310 Widget button = XmCreateToggleButton(parent, name, xargs, n); |
149 group = rgroup->obj; |
311 XtManageChild(button); |
150 if(!group->buttons) { |
312 ctn->add(ctn, button); |
151 group->buttons = cxArrayListCreate(cxDefaultAllocator, cx_cmp_uintptr, CX_STORE_POINTERS, 8); |
313 |
152 } |
314 ui_set_widget_groups(obj->ctx, button, args.groups); |
153 cxListAdd(group->buttons, button); |
315 |
154 group->ref++; |
316 UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args.value, args.varname, UI_VAR_INTEGER); |
155 } else { |
317 if(var) { |
156 group = malloc(sizeof(RadioButtonGroup)); |
318 UiInteger *value = var->value; |
157 group->buttons = cxArrayListCreate(cxDefaultAllocator, cx_cmp_uintptr, CX_STORE_POINTERS, 8); |
319 CxList *rb = value->obj; |
158 cxListAdd(group->buttons, button); |
320 if(!rb) { |
159 group->current = button; |
321 // first button in the radiobutton group |
160 // this is the first button in the radiobutton group |
322 // create a list for all buttons and use the list as value obj |
161 // so we should enable it |
323 rb = cxArrayListCreateSimple(CX_STORE_POINTERS, 4); |
162 Arg arg; |
324 value->obj = rb; |
163 XtSetArg(arg, XmNset, TRUE); |
325 value->get = ui_radiobutton_get; |
164 XtSetValues(button, &arg, 1); |
326 value->set = ui_radiobutton_set; |
165 rgroup->obj = group; |
|
166 |
327 |
167 group->current = button; |
328 // the first radio button is also responsible for cleanup |
168 } |
329 XtAddCallback( |
|
330 button, |
|
331 XmNdestroyCallback, |
|
332 (XtCallbackProc)destroy_list, |
|
333 rb); |
|
334 } |
|
335 cxListAdd(rb, button); |
169 |
336 |
170 RadioEventData *event = malloc(sizeof(RadioEventData)); |
337 // set the radiobutton state, if the value is already set |
171 event->obj = obj; |
338 if(cxListSize(rb) == value->value) { |
172 event->callback = NULL; |
339 XmToggleButtonSetState(button, True, False); |
173 event->userdata = NULL; |
340 } |
174 event->group = group; |
341 } |
175 XtAddCallback( |
342 |
|
343 // the radio button needs to handle change events to update all |
|
344 // other buttons in the radio button group |
|
345 UiVarEventData *event = malloc(sizeof(UiVarEventData)); |
|
346 event->obj = obj; |
|
347 event->callback = args.onchange; |
|
348 event->userdata = args.onchangedata; |
|
349 event->observers = NULL; |
|
350 event->var = var; |
|
351 event->value = args.enable_group; |
|
352 XtAddCallback( |
176 button, |
353 button, |
177 XmNvalueChangedCallback, |
354 XmNvalueChangedCallback, |
178 (XtCallbackProc)radio_callback, |
355 (XtCallbackProc)radiobutton_changed, |
179 event); |
356 event); |
180 |
357 XtAddCallback( |
181 rgroup->get = ui_radiobutton_get; |
358 button, |
182 rgroup->set = ui_radiobutton_set; |
359 XmNdestroyCallback, |
183 } |
360 (XtCallbackProc)ui_destroy_eventdata, |
184 |
361 event); |
185 XtManageChild(button); |
362 |
|
363 XmStringFree(label); |
186 return button; |
364 return button; |
187 } |
365 |
188 |
366 |
189 int64_t ui_radiobutton_get(UiInteger *value) { |
367 } |
190 RadioButtonGroup *group = value->obj; |
368 |
191 |
369 int64_t ui_radiobutton_get(UiInteger *i) { |
192 int i = cxListFind(group->buttons, group->current); |
370 // the UiInteger should be updated automatically by change events |
193 if (i >= 0) { |
371 return i->value; |
194 value->value = i; |
372 } |
195 return i; |
373 |
196 } else { |
374 void ui_radiobutton_set(UiInteger *i, int64_t value) { |
197 return 0; |
375 CxList *list = i->obj; |
198 } |
376 if(i->value > 0) { |
199 } |
377 Widget current = cxListAt(list, i->value-1); |
200 |
378 if(current) { |
201 void ui_radiobutton_set(UiInteger *value, int64_t i) { |
379 XmToggleButtonSetState(current, False, False); |
202 RadioButtonGroup *group = value->obj; |
380 } |
203 Arg arg; |
381 } |
204 |
382 if(value > 0 && value <= cxListSize(list)) { |
205 XtSetArg(arg, XmNset, FALSE); |
383 Widget button = cxListAt(list, value-1); |
206 XtSetValues(group->current, &arg, 1); |
384 if(button) { |
207 |
385 XmToggleButtonSetState(button, True, False); |
208 Widget button = cxListAt(group->buttons, i); |
386 i->value = value; |
209 if(button) { |
387 } |
210 XtSetArg(arg, XmNset, TRUE); |
388 } |
211 XtSetValues(button, &arg, 1); |
389 } |
212 group->current = button; |
|
213 } |
|
214 } |
|