| 28 |
28 |
| 29 #import "MainWindow.h" |
29 #import "MainWindow.h" |
| 30 #import "Container.h" |
30 #import "Container.h" |
| 31 #import "GridLayout.h" |
31 #import "GridLayout.h" |
| 32 #import "../common/object.h" |
32 #import "../common/object.h" |
| |
33 #import <objc/runtime.h> |
| |
34 |
| |
35 #import "EventData.h" |
| |
36 #import "menu.h" |
| 33 |
37 |
| 34 @implementation MainWindow |
38 @implementation MainWindow |
| 35 |
39 |
| 36 - (MainWindow*)init:(UiObject*)obj { |
40 - (MainWindow*)init:(UiObject*)obj { |
| 37 self.uiobj = obj; |
|
| 38 NSRect frame = NSMakeRect(300, 200, 600, 500); |
41 NSRect frame = NSMakeRect(300, 200, 600, 500); |
| 39 |
42 |
| 40 self = [self initWithContentRect:frame |
43 self = [self initWithContentRect:frame |
| 41 styleMask:NSWindowStyleMaskTitled | |
44 styleMask:NSWindowStyleMaskTitled | |
| 42 NSWindowStyleMaskResizable | |
45 NSWindowStyleMaskResizable | |
| 61 |
64 |
| 62 return self; |
65 return self; |
| 63 } |
66 } |
| 64 |
67 |
| 65 @end |
68 @end |
| |
69 |
| |
70 |
| |
71 |
| |
72 @implementation MainWindowController |
| |
73 |
| |
74 - (MainWindowController*)initWithWindow:(UiObject*)obj window:(NSWindow*)window { |
| |
75 self = [super initWithWindow:window]; |
| |
76 _uiobj = obj; |
| |
77 |
| |
78 self.checkItemStates = [[NSMutableDictionary alloc] init]; |
| |
79 self.radioItems = [[NSMutableDictionary alloc] init]; |
| |
80 |
| |
81 // bind all stateful menu items (checkbox, radiobuttons, lists) |
| |
82 NSArray *menuBindItems = ui_get_binding_items(); // returns all items that require binding |
| |
83 for(MenuItem *item in menuBindItems) { |
| |
84 if(item.checkItem || item.radioItem) { |
| |
85 // simple check item (ui_menu_toggleitem_create) |
| |
86 UiVar *var = uic_widget_var(obj->ctx, obj->ctx, NULL, item.checkItem ? item.checkItem->varname : item.radioItem->varname, UI_VAR_INTEGER); |
| |
87 // create the state object for this item/window |
| |
88 MenuItemState *state = [[MenuItemState alloc] init]; |
| |
89 state.mainWindow = self; |
| |
90 state.var = var; |
| |
91 if(var) { |
| |
92 UiInteger *i = var->value; |
| |
93 if(item.checkItem) { |
| |
94 // bind toggle item |
| |
95 state.state = (int)i->value; |
| |
96 i->obj = (__bridge void*)state; |
| |
97 i->get = ui_menu_check_item_get; |
| |
98 i->set = ui_menu_check_item_set; |
| |
99 } else { |
| |
100 // bind radio item |
| |
101 NSMutableArray *rgroup = nil; |
| |
102 if(i->obj) { |
| |
103 rgroup = (__bridge NSMutableArray*)i->obj; |
| |
104 } else { |
| |
105 // create a new rgroup array and register it in the window |
| |
106 rgroup = [[NSMutableArray alloc] init]; |
| |
107 NSString *varname = [[NSString alloc] initWithUTF8String:item.radioItem->varname]; |
| |
108 [_radioItems setObject:rgroup forKey:varname]; |
| |
109 i->obj = (__bridge void*)rgroup; |
| |
110 } |
| |
111 i->get = ui_menu_radio_item_get; |
| |
112 i->set = ui_menu_radio_item_set; |
| |
113 [rgroup addObject:state]; // add this item state to the radio group |
| |
114 // i->value can contain a non-zero value, which means a specific radiobutton |
| |
115 // should be pre-selected |
| |
116 if(i->value == rgroup.count) { |
| |
117 state.state = NSControlStateValueOn; |
| |
118 } |
| |
119 } |
| |
120 } else { |
| |
121 state.state = 0; |
| |
122 } |
| |
123 [_checkItemStates setObject:state forKey:item.itemId]; |
| |
124 } |
| |
125 } |
| |
126 |
| |
127 return self; |
| |
128 } |
| |
129 |
| |
130 - (void) windowDidLoad { |
| |
131 [self.window setNextResponder:self]; |
| |
132 } |
| |
133 |
| |
134 - (void)menuItemAction:(id)sender { |
| |
135 EventData *event = objc_getAssociatedObject(sender, "eventdata"); |
| |
136 if(event) { |
| |
137 event.obj = self.uiobj; // temporary set the event object |
| |
138 [event handleEvent:sender]; |
| |
139 } |
| |
140 } |
| |
141 |
| |
142 - (void)menuCheckItemAction:(id)sender { |
| |
143 NSMenuItem *menuItem = sender; |
| |
144 MenuItem *item = objc_getAssociatedObject(sender, "menuitem"); |
| |
145 if(!item || !item.checkItem) { |
| |
146 return; |
| |
147 } |
| |
148 |
| |
149 MenuItemState *state = [_checkItemStates objectForKey:item.itemId]; |
| |
150 state.state = state.state == NSControlStateValueOff ? NSControlStateValueOn : NSControlStateValueOff; |
| |
151 menuItem.state = state.state; |
| |
152 |
| |
153 UiMenuCheckItem *it = item.checkItem; |
| |
154 if(it->callback) { |
| |
155 UiEvent event; |
| |
156 event.obj = _uiobj; |
| |
157 event.window = event.obj->window; |
| |
158 event.document = event.obj->ctx->document; |
| |
159 event.eventdata = state.var ? state.var->value : NULL; |
| |
160 event.intval = state.state; |
| |
161 it->callback(&event, it->userdata); |
| |
162 } |
| |
163 } |
| |
164 |
| |
165 - (void)menuRadioItemAction:(id)sender { |
| |
166 NSMenuItem *menuItem = sender; |
| |
167 MenuItem *item = objc_getAssociatedObject(sender, "menuitem"); |
| |
168 if(!item || !item.radioItem) { |
| |
169 return; |
| |
170 } |
| |
171 |
| |
172 UiMenuRadioItem *it = item.radioItem; |
| |
173 if(!it->varname) { |
| |
174 return; |
| |
175 } |
| |
176 |
| |
177 MenuItemState *state = [_checkItemStates objectForKey:item.itemId]; // current state of this menu item |
| |
178 |
| |
179 NSString *varname = [[NSString alloc] initWithUTF8String:it->varname]; |
| |
180 NSArray *radioGroup = [_radioItems objectForKey:varname]; |
| |
181 if(!radioGroup) { |
| |
182 return; |
| |
183 } |
| |
184 int index = 1; |
| |
185 int value = 0; |
| |
186 for(MenuItemState *g in radioGroup) { |
| |
187 if(g == state) { |
| |
188 menuItem.state = NSControlStateValueOn; |
| |
189 g.state = NSControlStateValueOn; |
| |
190 value = index; |
| |
191 } else { |
| |
192 menuItem.state = NSControlStateValueOff; |
| |
193 g.state = NSControlStateValueOff; |
| |
194 } |
| |
195 } |
| |
196 |
| |
197 if(it->callback) { |
| |
198 UiEvent event; |
| |
199 event.obj = _uiobj; |
| |
200 event.window = event.obj->window; |
| |
201 event.document = event.obj->ctx->document; |
| |
202 event.eventdata = state.var ? state.var->value : NULL; |
| |
203 event.intval = value; |
| |
204 it->callback(&event, it->userdata); |
| |
205 } |
| |
206 } |
| |
207 |
| |
208 |
| |
209 - (BOOL) validateMenuItem:(NSMenuItem *) menuItem { |
| |
210 MenuItem *item = objc_getAssociatedObject(menuItem, "menuitem"); |
| |
211 if(item) { |
| |
212 MenuItemState *state = [_checkItemStates objectForKey:item.itemId]; |
| |
213 if(state) { |
| |
214 menuItem.state = state.state; |
| |
215 } else { |
| |
216 menuItem.state = NSControlStateValueOff; |
| |
217 } |
| |
218 } |
| |
219 |
| |
220 return YES; |
| |
221 } |
| |
222 |
| |
223 @end |
| |
224 |
| |
225 @implementation MenuItemState |
| |
226 |
| |
227 @end |
| |
228 |
| |
229 int64_t ui_menu_check_item_get(UiInteger *i) { |
| |
230 MenuItemState *state = (__bridge MenuItemState*)i->obj; |
| |
231 i->value = state.state; |
| |
232 return i->value; |
| |
233 } |
| |
234 |
| |
235 void ui_menu_check_item_set(UiInteger *i, int64_t value) { |
| |
236 MenuItemState *state = (__bridge MenuItemState*)i->obj; |
| |
237 i->value = value; |
| |
238 state.state = (int)value; |
| |
239 } |
| |
240 |
| |
241 int64_t ui_menu_radio_item_get(UiInteger *i) { |
| |
242 NSArray *rgroup = (__bridge NSArray*)i->obj; |
| |
243 i->value = 0; |
| |
244 int index = 1; |
| |
245 for(MenuItemState *state in rgroup) { |
| |
246 if(state.state == NSControlStateValueOn) { |
| |
247 i->value = index; |
| |
248 break; |
| |
249 } |
| |
250 index++; |
| |
251 } |
| |
252 return i->value; |
| |
253 } |
| |
254 |
| |
255 void ui_menu_radio_item_set(UiInteger *i, int64_t value) { |
| |
256 NSArray *rgroup = (__bridge NSArray*)i->obj; |
| |
257 i->value = 0; |
| |
258 int index = 1; |
| |
259 for(MenuItemState *state in rgroup) { |
| |
260 state.state = value == index; |
| |
261 index++; |
| |
262 } |
| |
263 } |