1 /*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 *
4 * Copyright 2012 Olaf Wintermann. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 #import "window.h"
34 #import "menu.h"
35 #import "toolbar.h"
36 #import "container.h"
37 #import <ucx/mempool.h>
38 #import "../common/context.h"
39
40 static int window_default_width = 600;
41 static int window_default_height = 500;
42
43 @implementation UiCocoaWindow
44
45 - (UiCocoaWindow*) init: (NSRect)frame object: (UiObject*)obj {
46 self = [self initWithContentRect:frame
47 styleMask:NSTitledWindowMask |
48 NSResizableWindowMask |
49 NSClosableWindowMask |
50 NSMiniaturizableWindowMask
51 backing:NSBackingStoreBuffered
52 defer:false];
53
54 uiobj = obj;
55 UcxAllocator *allocator = uiobj->ctx->mempool->allocator;
56 menus = ucx_map_new_a(allocator, 8);
57 items = ucx_map_new_a(allocator, 64);
58
59 return self;
60 }
61
62 - (UiObject*) object {
63 return uiobj;
64 }
65
66 - (void) setObject:(UiObject*)obj {
67 uiobj = obj;
68 }
69
70 - (void) setMenuItems:(UcxList*)menuItems {
71 UcxAllocator *allocator = uiobj->ctx->mempool->allocator;
72
73 UCX_FOREACH(elm, menuItems) {
74 UiStateItem *item = elm->data;
75 NSMenu *menu = [item->item menu];
76
77 // create UiMenuItem which represents an NSMenuItem for a Window
78 UiMenuItem *windowItem = ucx_mempool_malloc(uiobj->ctx->mempool, sizeof(UiMenuItem));
79 windowItem->item = item->item;
80 windowItem->state = 0;
81 if(item->var) {
82 // bind value
83 UiVar *var = uic_connect_var(uiobj->ctx, item->var, UI_VAR_INTEGER);
84 if(var) {
85 UiInteger *value = var->value;
86 value->obj = windowItem;
87 value->get = ui_menuitem_get;
88 value->set = ui_menuitem_set;
89 value = 0;
90 } else {
91 // TODO: error
92 }
93 }
94
95 // add item
96 UiAbstractMenuItem *abstractItem = malloc(sizeof(UiAbstractMenuItem));
97 abstractItem->update = ui_update_item;
98 abstractItem->item_data = windowItem;
99 UcxList *itemList = ucx_map_get(menus, ucx_key(&menu, sizeof(void*)));
100 itemList = ucx_list_append_a(allocator, itemList, abstractItem);
101 ucx_map_put(menus, ucx_key(&menu, sizeof(void*)), itemList);
102
103 ucx_map_put(items, ucx_key(&windowItem->item, sizeof(void*)), windowItem);
104 }
105 }
106
107 - (void) setMenuItemLists:(UcxList*)itemLists {
108 UcxAllocator *allocator = uiobj->ctx->mempool->allocator;
109
110 UCX_FOREACH(elm, itemLists) {
111 UiMenuItemList *list = elm->data;
112
113 UiAbstractMenuItem *abstractItem = malloc(sizeof(UiAbstractMenuItem));
114 abstractItem->update = ui_update_item_list;
115 abstractItem->item_data = list;
116
117 UcxList *itemList = ucx_map_get(menus, ucx_key(&list->menu, sizeof(void*)));
118 itemList = ucx_list_append_a(allocator, itemList, abstractItem);
119 ucx_map_put(menus, ucx_key(&list->menu, sizeof(void*)), itemList);
120
121 }
122 }
123
124 - (UiMenuItem*) getMenuItem:(NSMenuItem*)item {
125 return ucx_map_get(items, ucx_key(&item, sizeof(void*)));
126 }
127
128 - (void) updateMenu:(NSMenu*)menu {
129 UcxList *itemList = ucx_map_get(menus, ucx_key(&menu, sizeof(void*)));
130 UCX_FOREACH(elm, itemList) {
131 UiAbstractMenuItem *item = elm->data;
132 item->update(self, item->item_data);
133 }
134
135 // update group items
136 // TODO: use only one loop for all items
137 int ngroups = 0;
138 int *groups = ui_active_groups(uiobj->ctx, &ngroups);
139
140 NSArray *groupItems = [menu itemArray];
141 int count = [groupItems count];
142 for(int i=0;i<count;i++) {
143 id item = [groupItems objectAtIndex:i];
144 if([item class] == [UiGroupMenuItem class]) {
145 [item checkGroups: groups count:ngroups];
146 }
147 }
148 free(groups);
149 }
150
151 @end
152
153
154 /* ------------------------------ public API ------------------------------ */
155
156 UiObject* ui_window(char *title, void *window_data) {
157 UcxMempool *mp = ucx_mempool_new(256);
158 UiObject *obj = ucx_mempool_calloc(mp, 1, sizeof(UiObject));
159 obj->ctx = uic_context(obj, mp);
160
161 // create native window
162 NSRect frame = NSMakeRect(
163 300,
164 200,
165 window_default_width,
166 window_default_height);
167
168 /*
169 UiCocoaWindow *window = [[UiCocoaWindow alloc] initWithContentRect:frame
170 styleMask:NSTitledWindowMask | NSResizableWindowMask |
171 NSClosableWindowMask | NSMiniaturizableWindowMask
172 backing:NSBackingStoreBuffered
173 defer:false];
174 */
175 UiCocoaWindow *window = [[UiCocoaWindow alloc] init:frame object:obj];
176
177 NSString *titleStr = [[NSString alloc] initWithUTF8String:title];
178 [window setTitle:titleStr];
179
180 UiMenuDelegate *menuDelegate = ui_menu_delegate();
181 [window setMenuItems: [menuDelegate items]];
182 [window setMenuItemLists: [menuDelegate lists]];
183
184 NSToolbar *toolbar = ui_create_toolbar(obj);
185 [window setToolbar: toolbar];
186
187 obj->widget = (NSView*)window;
188 obj->window = window_data;
189 obj->container = ui_window_container(obj, window);
190
191
192 return obj;
193 }
194
195 void ui_close(UiObject *obj) {
196 // TODO
197 }
198
199 char* ui_openfiledialog(UiObject *obj) {
200 NSOpenPanel* op = [NSOpenPanel openPanel];
201 if ([op runModal] == NSOKButton) {
202 NSArray *urls = [op URLs];
203 NSURL *url = [urls objectAtIndex:0];
204
205 const char *str = [[url path] UTF8String];
206 return (char*)strdup(str);
207 }
208 return NULL;
209 }
210
211 char* ui_savefiledialog(UiObject *obj) {
212 NSSavePanel* sp = [NSSavePanel savePanel];
213 if ([sp runModal] == NSOKButton) {
214 NSURL *url = [sp URL];
215
216 const char *str = [[url path] UTF8String];
217 return (char*)strdup(str);
218 }
219 return NULL;
220 }
221