| 56 |
58 |
| 57 void ui_add_menu(HMENU parent, int pos, UiMenuItemI *item, UiObject *obj) { |
59 void ui_add_menu(HMENU parent, int pos, UiMenuItemI *item, UiObject *obj) { |
| 58 UiMenu *menu = (UiMenu*)item; |
60 UiMenu *menu = (UiMenu*)item; |
| 59 HMENU hMenu = CreatePopupMenu(); |
61 HMENU hMenu = CreatePopupMenu(); |
| 60 AppendMenu(parent, MF_POPUP, (UINT_PTR)hMenu, menu->label); |
62 AppendMenu(parent, MF_POPUP, (UINT_PTR)hMenu, menu->label); |
| 61 |
|
| 62 int i = 0; |
63 int i = 0; |
| 63 UiMenuItemI *child = menu->items_begin; |
64 UiMenuItemI *child = menu->items_begin; |
| 64 while (child) { |
65 while (child) { |
| 65 createMenuItem[child->type](hMenu, i++, child, obj); |
66 createMenuItem[child->type](hMenu, i++, child, obj); |
| 66 child = child->next; |
67 child = child->next; |
| 67 } |
68 } |
| 68 } |
69 } |
| 69 |
70 |
| |
71 static void menu_item_clicked(UiObject *obj, uint64_t id, UiMenuItem *item) { |
| |
72 UiEvent event; |
| |
73 event.obj = obj; |
| |
74 event.window = obj->window; |
| |
75 event.document = obj->ctx->document; |
| |
76 event.eventdata = NULL; |
| |
77 event.eventdatatype = 0; |
| |
78 event.intval = 0; |
| |
79 event.set = 0; |
| |
80 if (item->callback) { |
| |
81 item->callback(&event, item->userdata); |
| |
82 } |
| |
83 } |
| |
84 |
| 70 void ui_add_menu_item(HMENU parent, int pos, UiMenuItemI *item, UiObject *obj) { |
85 void ui_add_menu_item(HMENU parent, int pos, UiMenuItemI *item, UiObject *obj) { |
| |
86 uint64_t id = ++obj->ctx->command_id_counter; |
| |
87 |
| 71 UiMenuItem *i = (UiMenuItem*)item; |
88 UiMenuItem *i = (UiMenuItem*)item; |
| 72 AppendMenu(parent, MF_STRING, 0, i->label); |
89 AppendMenu(parent, MF_STRING, id, i->label); |
| |
90 |
| |
91 UiCommand cmd; |
| |
92 cmd.callback = (ui_command_func)menu_item_clicked; |
| |
93 cmd.userdata = i; |
| |
94 cxMapPut(obj->ctx->command_map, id, &cmd); |
| |
95 } |
| |
96 |
| |
97 static void menu_stateitem_update(UiStateMenuItem *item) { |
| |
98 MENUITEMINFO mi = { 0 }; |
| |
99 mi.cbSize = sizeof(mi); |
| |
100 mi.fMask = MIIM_STATE; |
| |
101 mi.fState = item->state ? MFS_CHECKED : MFS_UNCHECKED; |
| |
102 SetMenuItemInfo(item->menu, item->id, FALSE, &mi); |
| |
103 } |
| |
104 |
| |
105 static void menu_checkitem_clicked(UiObject *obj, uint64_t id, UiStateMenuItem *item) { |
| |
106 item->state = !item->state; |
| |
107 menu_stateitem_update(item); |
| |
108 |
| |
109 UiEvent event; |
| |
110 event.obj = obj; |
| |
111 event.window = obj->window; |
| |
112 event.document = obj->ctx->document; |
| |
113 event.eventdata = NULL; |
| |
114 event.eventdatatype = 0; |
| |
115 event.intval = 0; |
| |
116 event.set = 0; |
| |
117 if (item->onchange) { |
| |
118 item->onchange(&event, item->userdata); |
| |
119 } |
| |
120 |
| |
121 if (item->var) { |
| |
122 UiInteger *i = item->var->value; |
| |
123 ui_notify_evt(i->observers, &event); |
| |
124 } |
| 73 } |
125 } |
| 74 |
126 |
| 75 void ui_add_menu_checkitem(HMENU parent, int pos, UiMenuItemI *item, UiObject *obj) { |
127 void ui_add_menu_checkitem(HMENU parent, int pos, UiMenuItemI *item, UiObject *obj) { |
| 76 |
128 uint64_t id = ++obj->ctx->command_id_counter; |
| |
129 |
| |
130 UiMenuCheckItem *i = (UiMenuCheckItem*)item; |
| |
131 AppendMenu(parent, MF_STRING, id, i->label); |
| |
132 |
| |
133 // create an UiStateMenuItem with the same lifetime as the UiObject |
| |
134 UiStateMenuItem *sitem = ui_malloc(obj->ctx, sizeof(UiStateMenuItem)); |
| |
135 memset(sitem, 0, sizeof(UiStateMenuItem)); |
| |
136 sitem->obj = obj; |
| |
137 sitem->menu = parent; |
| |
138 sitem->id = id; |
| |
139 sitem->onchange = i->callback; |
| |
140 sitem->userdata = i->userdata; |
| |
141 sitem->var = uic_widget_var(obj->ctx, obj->ctx, NULL, i->varname, UI_VAR_INTEGER); |
| |
142 // bind to var |
| |
143 if (sitem->var) { |
| |
144 UiInteger *v = sitem->var->value; |
| |
145 sitem->state = v->value != 0; |
| |
146 v->obj = sitem; |
| |
147 v->get = ui_checkitem_get; |
| |
148 v->set = ui_checkitem_set; |
| |
149 } |
| |
150 |
| |
151 // register command id |
| |
152 UiCommand cmd; |
| |
153 cmd.callback = (ui_command_func)menu_checkitem_clicked; |
| |
154 cmd.userdata = sitem; |
| |
155 cxMapPut(obj->ctx->command_map, id, &cmd); |
| |
156 |
| |
157 menu_stateitem_update(sitem); |
| |
158 } |
| |
159 |
| |
160 int64_t ui_checkitem_get(UiInteger *i) { |
| |
161 return i->value; |
| |
162 } |
| |
163 |
| |
164 void ui_checkitem_set(UiInteger *i, int64_t value) { |
| |
165 i->value = value; |
| |
166 menu_stateitem_update(i->obj); |
| |
167 } |
| |
168 |
| |
169 static void menu_radioitem_clicked(UiObject *obj, uint64_t id, UiStateMenuItem *item) { |
| |
170 UiInteger *i = item->var->value; // UiVar is always not NULL for radio items |
| |
171 ui_set(i, item->index+1); |
| |
172 |
| |
173 UiEvent event; |
| |
174 event.obj = obj; |
| |
175 event.window = obj->window; |
| |
176 event.document = obj->ctx->document; |
| |
177 event.eventdata = i; |
| |
178 event.eventdatatype = UI_EVENT_DATA_INTEGER_VALUE; |
| |
179 event.intval = item->state; |
| |
180 event.set = ui_get_setop(); |
| |
181 |
| |
182 if (item->onchange) { |
| |
183 item->onchange(&event, item->userdata); |
| |
184 } |
| |
185 |
| |
186 event.intval = (int)ui_get(i); |
| |
187 ui_notify_evt(i->observers, &event); |
| 77 } |
188 } |
| 78 |
189 |
| 79 void ui_add_menu_radioitem(HMENU parent, int pos, UiMenuItemI *item, UiObject *obj) { |
190 void ui_add_menu_radioitem(HMENU parent, int pos, UiMenuItemI *item, UiObject *obj) { |
| 80 |
191 uint64_t id = ++obj->ctx->command_id_counter; |
| |
192 |
| |
193 UiMenuRadioItem *i = (UiMenuRadioItem*)item; |
| |
194 AppendMenu(parent, MF_STRING, id, i->label); |
| |
195 |
| |
196 UiVar *var = uic_widget_var(obj->ctx, obj->ctx, NULL, i->varname, UI_VAR_INTEGER); |
| |
197 if (!var) { |
| |
198 return; // radio item without var is useless |
| |
199 } |
| |
200 |
| |
201 UiInteger *v = var->value; |
| |
202 CxList *group = v->obj; |
| |
203 if (!group) { |
| |
204 // first radio button in this group |
| |
205 group = cxArrayListCreate(obj->ctx->allocator, sizeof(UiStateMenuItem), 4); |
| |
206 v->obj = group; |
| |
207 v->get = ui_radioitem_get; |
| |
208 v->set = ui_radioitem_set; |
| |
209 } |
| |
210 |
| |
211 UiStateMenuItem sitem = { 0 }; |
| |
212 sitem.obj = obj; |
| |
213 sitem.menu = parent; |
| |
214 sitem.id = id; |
| |
215 sitem.onchange = i->callback; |
| |
216 sitem.userdata = i->userdata; |
| |
217 sitem.var = var; |
| |
218 sitem.index = (int)cxListSize(group); |
| |
219 cxListAdd(group, &sitem); |
| |
220 |
| |
221 if (v->value == sitem.index+1) { |
| |
222 sitem.state = 1; |
| |
223 menu_stateitem_update(&sitem); |
| |
224 } |
| |
225 |
| |
226 |
| |
227 UiStateMenuItem *sitem_ptr = cxListAt(group, sitem.index); |
| |
228 // register command id |
| |
229 UiCommand cmd; |
| |
230 cmd.callback = (ui_command_func)menu_radioitem_clicked; |
| |
231 cmd.userdata = sitem_ptr; |
| |
232 cxMapPut(obj->ctx->command_map, id, &cmd); |
| |
233 } |
| |
234 |
| |
235 int64_t ui_radioitem_get(UiInteger *i) { |
| |
236 return i->value; |
| |
237 } |
| |
238 |
| |
239 void ui_radioitem_set(UiInteger *i, int64_t value) { |
| |
240 CxList *group = i->obj; |
| |
241 // de-select all items |
| |
242 CxIterator it = cxListIterator(group); |
| |
243 cx_foreach(UiStateMenuItem *, item, it) { |
| |
244 if (item->state) { |
| |
245 item->state = FALSE; |
| |
246 menu_stateitem_update(item); |
| |
247 } |
| |
248 } |
| |
249 |
| |
250 if (value > 0) { |
| |
251 UiStateMenuItem *item = cxListAt(group, value-1); |
| |
252 if (item) { |
| |
253 item->state = TRUE; |
| |
254 menu_stateitem_update(item); |
| |
255 } |
| |
256 } |
| 81 } |
257 } |
| 82 |
258 |
| 83 void ui_add_menu_list(HMENU parent, int pos, UiMenuItemI *item, UiObject *obj) { |
259 void ui_add_menu_list(HMENU parent, int pos, UiMenuItemI *item, UiObject *obj) { |
| 84 |
260 |
| 85 } |
261 } |