| 257 menu_stateitem_update(item); |
256 menu_stateitem_update(item); |
| 258 } |
257 } |
| 259 } |
258 } |
| 260 } |
259 } |
| 261 |
260 |
| |
261 static void menuitem_list_remove_binding(void *obj) { |
| |
262 UiActiveMenuItemList *ls = obj; |
| |
263 UiList *list = ls->var->value; |
| |
264 CxList *bindings = list->obj; |
| |
265 if(bindings) { |
| |
266 (void)cxListFindRemove(bindings, obj); |
| |
267 if(cxListSize(bindings) == 0) { |
| |
268 cxListFree(bindings); |
| |
269 list->obj = NULL; |
| |
270 list->update = NULL; |
| |
271 } |
| |
272 } |
| |
273 } |
| |
274 |
| 262 void ui_add_menu_list(HMENU parent, int pos, UiMenuItemI *item, UiObject *obj) { |
275 void ui_add_menu_list(HMENU parent, int pos, UiMenuItemI *item, UiObject *obj) { |
| 263 |
276 UiMenuItemList *il = (UiMenuItemList*)item; |
| 264 } |
277 const CxAllocator *a = obj->ctx->allocator; |
| |
278 |
| |
279 UiVar *var = uic_create_var(ui_global_context(), il->varname, UI_VAR_LIST); |
| |
280 if (!var) { |
| |
281 return; |
| |
282 } |
| |
283 |
| |
284 UiActiveMenuItemList *ls = cxMalloc( |
| |
285 a, |
| |
286 sizeof(UiActiveMenuItemList)); |
| |
287 ls->object = obj; |
| |
288 ls->menu = parent; |
| |
289 ls->command_ids = cxArrayListCreate(a, sizeof(uint64_t), 16); |
| |
290 ls->index = pos; |
| |
291 ls->getvalue = il->getvalue; |
| |
292 ls->callback = il->callback; |
| |
293 ls->userdata = il->userdata; |
| |
294 ls->addseparator = il->addseparator; |
| |
295 ls->var = var; |
| |
296 |
| |
297 UiList *list = ls->var->value; |
| |
298 list->update = ui_menulist_update; |
| |
299 list->getselection = NULL; |
| |
300 list->setselection = NULL; |
| |
301 |
| |
302 // It is possible, that the UiVar is from a global shared context, |
| |
303 // used by multiple windows. To support this usecase, the list->obj |
| |
304 // binding object is a list of all connected UiActiveMenuItemList. |
| |
305 CxList *bindings = list->obj; |
| |
306 if(!bindings) { |
| |
307 bindings = cxLinkedListCreate(ls->var->from_ctx->mp->allocator, CX_STORE_POINTERS); |
| |
308 list->obj = bindings; |
| |
309 } |
| |
310 cxListAdd(bindings, ls); |
| |
311 |
| |
312 // The destruction of the toplevel obj must remove the menulist binding |
| |
313 uic_context_add_destructor(obj->ctx, menuitem_list_remove_binding, ls); |
| |
314 |
| |
315 ui_update_menuitem_list(ls); |
| |
316 } |
| |
317 |
| |
318 void ui_menulist_update(UiList *list, int ignored) { |
| |
319 CxList *bindings = list->obj; |
| |
320 CxIterator i = cxListIterator(bindings); |
| |
321 cx_foreach(UiActiveMenuItemList *, ls, i) { |
| |
322 ui_update_menuitem_list(ls); |
| |
323 } |
| |
324 } |
| |
325 |
| |
326 void ui_update_menuitem_list(UiActiveMenuItemList *list) { |
| |
327 UiObject *obj = list->object; |
| |
328 |
| |
329 UiList *ls; |
| |
330 if(list->var && list->var->value) { |
| |
331 ls = list->var->value; |
| |
332 } else { |
| |
333 return; |
| |
334 } |
| |
335 |
| |
336 CxIterator i = cxListIterator(list->command_ids); |
| |
337 cx_foreach(uint64_t *, id, i) { |
| |
338 DeleteMenu(list->menu, *id, MF_BYCOMMAND); |
| |
339 } |
| |
340 cxListClear(list->command_ids); // TODO: we could reuse some of the ids |
| |
341 |
| |
342 ui_getvaluefunc getvalue = list->getvalue; |
| |
343 void* elm = ui_list_first(ls); |
| |
344 |
| |
345 int pos = list->index; |
| |
346 while(elm) { |
| |
347 char *label = (char*) (getvalue ? getvalue(elm, 0) : elm); |
| |
348 if (!label) { |
| |
349 label = ""; |
| |
350 } |
| |
351 |
| |
352 uint64_t id = ++obj->ctx->command_id_counter; |
| |
353 InsertMenu(list->menu, pos++, MF_STRING, id, label); |
| |
354 cxListAdd(list->command_ids, &id); |
| |
355 |
| |
356 elm = ui_list_next(ls); |
| |
357 } |
| |
358 } |
| |
359 |
| 265 |
360 |
| 266 void ui_add_menu_checklist(HMENU parent, int pos, UiMenuItemI *item, UiObject *obj) { |
361 void ui_add_menu_checklist(HMENU parent, int pos, UiMenuItemI *item, UiObject *obj) { |
| 267 |
362 |
| 268 } |
363 } |
| 269 |
364 |