| 27 */ |
27 */ |
| 28 |
28 |
| 29 #import "Container.h" |
29 #import "Container.h" |
| 30 #import "GridLayout.h" |
30 #import "GridLayout.h" |
| 31 #import "BoxContainer.h" |
31 #import "BoxContainer.h" |
| 32 |
32 #import "TabView.h" |
| 33 /* ------------------------- container classes ------------------------- */ |
|
| 34 |
|
| 35 /* |
|
| 36 @implementation BoxContainer |
|
| 37 |
|
| 38 @synthesize label=_label; |
|
| 39 @synthesize uilayout=_uilayout; |
|
| 40 @synthesize newline=_newline; |
|
| 41 |
|
| 42 - (BoxContainer*)init:(NSUserInterfaceLayoutOrientation)orientation spacing:(int)spacing { |
|
| 43 self = [super init]; |
|
| 44 _label = NULL; |
|
| 45 _uilayout = (UiLayout){ 0 }; |
|
| 46 _newline = false; |
|
| 47 |
|
| 48 self.distribution = NSStackViewDistributionFillProportionally; |
|
| 49 self.spacing = spacing; |
|
| 50 |
|
| 51 self.orientation = orientation; |
|
| 52 if(orientation == NSUserInterfaceLayoutOrientationHorizontal) { |
|
| 53 self.alignment = NSLayoutAttributeHeight; |
|
| 54 } else { |
|
| 55 self.alignment = NSLayoutAttributeWidth; |
|
| 56 } |
|
| 57 |
|
| 58 |
|
| 59 return self; |
|
| 60 } |
|
| 61 |
|
| 62 - (void) addView:(NSView*)view { |
|
| 63 UiBool fill = _uilayout.fill; |
|
| 64 |
|
| 65 [self addArrangedSubview:view]; |
|
| 66 |
|
| 67 if(self.orientation == NSUserInterfaceLayoutOrientationHorizontal) { |
|
| 68 [view.heightAnchor constraintEqualToAnchor:self.heightAnchor].active = YES; |
|
| 69 if(!fill) { |
|
| 70 NSSize isize = view.intrinsicContentSize; |
|
| 71 [view.widthAnchor constraintEqualToConstant:isize.width].active = YES; |
|
| 72 } |
|
| 73 } else { |
|
| 74 [view.widthAnchor constraintEqualToAnchor:self.widthAnchor].active = YES; |
|
| 75 if(!fill) { |
|
| 76 NSSize isize = view.intrinsicContentSize; |
|
| 77 NSRect frame = view.frame; |
|
| 78 CGFloat height = isize.height > 0 ? isize.height : frame.size.height; |
|
| 79 if(height == 0) { |
|
| 80 printf("debug"); |
|
| 81 } |
|
| 82 if(height > 0) { |
|
| 83 [view.heightAnchor constraintEqualToConstant:height].active = YES; |
|
| 84 } |
|
| 85 } |
|
| 86 } |
|
| 87 |
|
| 88 // at the moment, only the fill layout option needs to be reset |
|
| 89 _uilayout.fill = UI_DEFAULT; |
|
| 90 } |
|
| 91 |
|
| 92 @end |
|
| 93 */ |
|
| 94 |
|
| 95 |
33 |
| 96 /* -------------------- public container functions --------------------- */ |
34 /* -------------------- public container functions --------------------- */ |
| 97 |
35 |
| 98 static UIWIDGET ui_box_create(UiObject *obj, UiContainerArgs *args, NSUserInterfaceLayoutOrientation orientation) { |
36 static UIWIDGET ui_box_create(UiObject *obj, UiContainerArgs *args, NSUserInterfaceLayoutOrientation orientation) { |
| 99 BoxContainer *box = [[BoxContainer alloc] init:orientation spacing:args->spacing]; |
37 BoxContainer *box = [[BoxContainer alloc] init:orientation spacing:args->spacing]; |
| 100 box.translatesAutoresizingMaskIntoConstraints = false; |
38 box.translatesAutoresizingMaskIntoConstraints = false; |
| |
39 UiContainerX *container = ui_create_container(obj, box); |
| 101 |
40 |
| 102 // add box to the parent |
41 // add box to the parent |
| 103 UiLayout layout = UI_INIT_LAYOUT(args); |
42 UiLayout layout = UI_INIT_LAYOUT(args); |
| 104 ui_container_add(obj, box, &layout); |
43 ui_container_add(obj, box, &layout); |
| 105 |
44 |
| 106 // add new box to the obj container chain |
45 // add new box to the obj container chain |
| 107 uic_object_push_container(obj, ui_create_container(obj, box)); |
46 uic_object_push_container(obj, container); |
| 108 |
47 |
| 109 return (__bridge void*)box; |
48 return (__bridge void*)box; |
| 110 } |
49 } |
| 111 |
50 |
| 112 UIWIDGET ui_vbox_create(UiObject *obj, UiContainerArgs *args) { |
51 UIWIDGET ui_vbox_create(UiObject *obj, UiContainerArgs *args) { |
| 118 } |
57 } |
| 119 |
58 |
| 120 UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs *args) { |
59 UIWIDGET ui_grid_create(UiObject *obj, UiContainerArgs *args) { |
| 121 GridLayout *grid = [[GridLayout alloc] init]; |
60 GridLayout *grid = [[GridLayout alloc] init]; |
| 122 grid.translatesAutoresizingMaskIntoConstraints = false; |
61 grid.translatesAutoresizingMaskIntoConstraints = false; |
| |
62 grid.columnspacing = args->columnspacing; |
| |
63 grid.rowspacing = args->rowspacing; |
| |
64 UiContainerX *container = ui_create_container(obj, grid); |
| |
65 grid.container = container; |
| 123 |
66 |
| 124 // add box to the parent |
67 // add box to the parent |
| 125 UiLayout layout = UI_INIT_LAYOUT(args); |
68 UiLayout layout = UI_INIT_LAYOUT(args); |
| 126 ui_container_add(obj, grid, &layout); |
69 ui_container_add(obj, grid, &layout); |
| 127 |
70 |
| 128 // add new box to the obj container chain |
71 // add new box to the obj container chain |
| 129 uic_object_push_container(obj, ui_create_container(obj, grid)); |
72 uic_object_push_container(obj, container); |
| 130 |
73 |
| 131 return (__bridge void*)grid; |
74 return (__bridge void*)grid; |
| 132 } |
75 } |
| |
76 |
| |
77 UIWIDGET ui_frame_create(UiObject *obj, UiFrameArgs *args) { |
| |
78 NSString *title = args->label ? [[NSString alloc]initWithUTF8String:args->label] : nil; |
| |
79 FrameContainer *frame = [[FrameContainer alloc] init:title]; |
| |
80 UiLayout layout = UI_ARGS2LAYOUT(args); |
| |
81 ui_container_add(obj, frame, &layout); |
| |
82 |
| |
83 // add container to the chain |
| |
84 UiContainerX *container; |
| |
85 UiLayout subLayout = {0}; |
| |
86 switch(args->subcontainer) { |
| |
87 default: { |
| |
88 // UI_CONTAINER_NO_SUB |
| |
89 container = ui_create_container(obj, frame); |
| |
90 break; |
| |
91 } |
| |
92 case UI_CONTAINER_VBOX: { |
| |
93 BoxContainer *box = [[BoxContainer alloc]init:NSUserInterfaceLayoutOrientationVertical spacing:args->spacing]; |
| |
94 box.translatesAutoresizingMaskIntoConstraints = false; |
| |
95 [frame addView:box layout:&subLayout]; |
| |
96 container = ui_create_container(obj, box); |
| |
97 break; |
| |
98 } |
| |
99 case UI_CONTAINER_HBOX: { |
| |
100 BoxContainer *box = [[BoxContainer alloc]init:NSUserInterfaceLayoutOrientationHorizontal spacing:args->spacing]; |
| |
101 box.translatesAutoresizingMaskIntoConstraints = false; |
| |
102 [frame addView:box layout:&subLayout]; |
| |
103 container = ui_create_container(obj, box); |
| |
104 break; |
| |
105 } |
| |
106 case UI_CONTAINER_GRID: { |
| |
107 GridLayout *grid = [[GridLayout alloc] init]; |
| |
108 grid.translatesAutoresizingMaskIntoConstraints = false; |
| |
109 grid.columnspacing = args->columnspacing; |
| |
110 grid.rowspacing = args->rowspacing; |
| |
111 [frame addView:grid layout:&subLayout]; |
| |
112 container = ui_create_container(obj, grid); |
| |
113 break; |
| |
114 } |
| |
115 } |
| |
116 |
| |
117 uic_object_push_container(obj, container); |
| |
118 |
| |
119 return (__bridge void*)frame; |
| |
120 } |
| |
121 |
| |
122 UIWIDGET ui_expander_create(UiObject *obj, UiFrameArgs *args) { |
| |
123 return ui_frame_create(obj, args); // TODO |
| |
124 } |
| |
125 |
| |
126 UIWIDGET ui_scrolledwindow_create(UiObject *obj, UiFrameArgs *args) { |
| |
127 int colspacing = args->spacing; |
| |
128 int rowspacing = args->spacing; |
| |
129 if(args->subcontainer == UI_CONTAINER_GRID) { |
| |
130 colspacing = args->columnspacing; |
| |
131 rowspacing = args->rowspacing; |
| |
132 } |
| |
133 ScrollViewContainer *scrollview = [[ScrollViewContainer alloc]init:args->subcontainer columnSpacing:colspacing rowSpacing:rowspacing]; |
| |
134 scrollview.hasVerticalScroller = YES; |
| |
135 scrollview.scrollerStyle = NSScrollerStyleOverlay; |
| |
136 scrollview.autohidesScrollers = YES; |
| |
137 UiLayout layout = UI_ARGS2LAYOUT(args); |
| |
138 ui_container_add(obj, scrollview, &layout); |
| |
139 |
| |
140 UiContainerX *container = ui_create_container(obj, scrollview); |
| |
141 uic_object_push_container(obj, container); |
| |
142 |
| |
143 return (__bridge void*)scrollview; |
| |
144 } |
| |
145 |
| |
146 UIWIDGET ui_tabview_create(UiObject *obj, UiTabViewArgs *args) { |
| |
147 NSView<TabView, Container> *tabview; |
| |
148 switch(args->tabview) { |
| |
149 default: tabview = [[UiTopTabView alloc]init:obj args:args]; break; |
| |
150 } |
| |
151 |
| |
152 UiLayout layout = UI_ARGS2LAYOUT(args); |
| |
153 ui_container_add(obj, tabview, &layout); |
| |
154 |
| |
155 UiContainerX *container = ui_create_container(obj, tabview); |
| |
156 uic_object_push_container(obj, container); |
| |
157 |
| |
158 return (__bridge void*)tabview; |
| |
159 } |
| |
160 |
| |
161 void ui_tab_create(UiObject *obj, const char* title) { |
| |
162 UiContainerX *ctn = obj->container_end; |
| |
163 id<TabView> tabview = (__bridge id<TabView>)ctn->container; |
| |
164 NSString *s = title ? [[NSString alloc]initWithUTF8String:title] : @""; |
| |
165 NSView<Container> *sub = [tabview createTab:-1 title:s]; |
| |
166 |
| |
167 UiContainerX *container = ui_create_container(obj, sub); |
| |
168 uic_object_push_container(obj, container); |
| |
169 } |
| |
170 |
| |
171 void ui_tabview_select(UIWIDGET tabview, int tab) { |
| |
172 id<TabView> tabv = (__bridge id<TabView>)tabview; |
| |
173 [tabv selectTab:tab]; |
| |
174 } |
| |
175 |
| |
176 void ui_tabview_remove(UIWIDGET tabview, int tab) { |
| |
177 id<TabView> tabv = (__bridge id<TabView>)tabview; |
| |
178 [tabv removeTab:tab]; |
| |
179 } |
| |
180 |
| |
181 UiObject* ui_tabview_add(UIWIDGET tabview, const char *name, int tab_index) { |
| |
182 id<TabView> tabv = (__bridge id<TabView>)tabview; |
| |
183 NSString *s = name ? [[NSString alloc]initWithUTF8String:name] : @""; |
| |
184 return [tabv addTab:tab_index title:s]; |
| |
185 } |
| |
186 |
| |
187 |
| |
188 |
| 133 |
189 |
| 134 void ui_container_begin_close(UiObject *obj) { |
190 void ui_container_begin_close(UiObject *obj) { |
| 135 UiContainerX *ct = obj->container_end; |
191 UiContainerX *ct = obj->container_end; |
| 136 ct->close = 1; |
192 ct->close = 1; |
| 137 } |
193 } |
| 142 ui_end_new(obj); |
198 ui_end_new(obj); |
| 143 return 0; |
199 return 0; |
| 144 } |
200 } |
| 145 return 1; |
201 return 1; |
| 146 } |
202 } |
| |
203 |
| |
204 /* -------------------------- Frame Container -------------------------- */ |
| |
205 |
| |
206 @implementation FrameContainer |
| |
207 |
| |
208 @synthesize container = _container; |
| |
209 |
| |
210 - (id)init:(NSString*)title { |
| |
211 self = [super init]; |
| |
212 self.title = title; |
| |
213 self.boxType = NSBoxPrimary; |
| |
214 if(title != nil) { |
| |
215 self.titlePosition = NSAtTop; |
| |
216 } |
| |
217 return self; |
| |
218 } |
| |
219 |
| |
220 - (void) addView:(NSView*)view layout:(UiLayout*)layout { |
| |
221 [self.contentView addSubview:view]; |
| |
222 view.translatesAutoresizingMaskIntoConstraints = NO; |
| |
223 [NSLayoutConstraint activateConstraints:@[ |
| |
224 [view.topAnchor constraintEqualToAnchor:self.contentView.topAnchor constant:0], |
| |
225 [view.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:0], |
| |
226 [view.bottomAnchor constraintEqualToAnchor:self.contentView.bottomAnchor constant:-0], |
| |
227 [view.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor constant:-0] |
| |
228 ]]; |
| |
229 } |
| |
230 |
| |
231 @end |
| |
232 |
| |
233 |
| |
234 /* -------------------------- Expander Container -------------------------- */ |
| |
235 |
| |
236 // TODO |
| |
237 |
| |
238 |
| |
239 /* ------------------------ ScrollView Container ------------------------ */ |
| |
240 |
| |
241 @implementation ScrollViewContainer |
| |
242 |
| |
243 @synthesize container = _container; |
| |
244 |
| |
245 - (id)init:(UiSubContainerType)subContainer columnSpacing:(int)columnSpacing rowSpacing:(int)rowSpacing { |
| |
246 self = [super init]; |
| |
247 |
| |
248 if(subContainer != UI_CONTAINER_NO_SUB) { |
| |
249 GridLayout *child; |
| |
250 switch(subContainer) { |
| |
251 default: |
| |
252 case UI_CONTAINER_VBOX: { |
| |
253 child = [[BoxContainer alloc]init:NSUserInterfaceLayoutOrientationVertical spacing:columnSpacing]; |
| |
254 break; |
| |
255 } |
| |
256 case UI_CONTAINER_HBOX: { |
| |
257 child = [[BoxContainer alloc]init:NSUserInterfaceLayoutOrientationHorizontal spacing:columnSpacing]; |
| |
258 break; |
| |
259 } |
| |
260 case UI_CONTAINER_GRID: { |
| |
261 child = [[GridLayout alloc]init]; |
| |
262 child.columnspacing = columnSpacing; |
| |
263 child.rowspacing = rowSpacing; |
| |
264 break; |
| |
265 } |
| |
266 } |
| |
267 child.translatesAutoresizingMaskIntoConstraints = NO; |
| |
268 |
| |
269 self.documentView = child; |
| |
270 [child.widthAnchor constraintEqualToAnchor:self.contentView.widthAnchor].active = YES; |
| |
271 |
| |
272 _child = child; |
| |
273 } |
| |
274 |
| |
275 |
| |
276 return self; |
| |
277 } |
| |
278 |
| |
279 - (void) addView:(NSView*)view layout:(UiLayout*)layout { |
| |
280 if(_child != nil) { |
| |
281 _child.container = self.container; // required, otherwise child has no container and can't access the newline property |
| |
282 view.translatesAutoresizingMaskIntoConstraints = NO; |
| |
283 [_child addView:view layout:layout]; |
| |
284 } else { |
| |
285 self.documentView = view; |
| |
286 [view.widthAnchor constraintEqualToAnchor:self.contentView.widthAnchor].active = YES; |
| |
287 } |
| |
288 } |
| |
289 |
| |
290 @end |
| 147 |
291 |
| 148 /* ------------------------- private functions ------------------------- */ |
292 /* ------------------------- private functions ------------------------- */ |
| 149 |
293 |
| 150 UiContainerX* ui_create_container(UiObject *obj, id<Container> container) { |
294 UiContainerX* ui_create_container(UiObject *obj, id<Container> container) { |
| 151 UiContainerX *ctn = ui_malloc(obj->ctx, sizeof(UiContainerX)); |
295 UiContainerX *ctn = ui_malloc(obj->ctx, sizeof(UiContainerX)); |
| 152 ctn->container = (__bridge void*)container; |
296 ctn->container = (__bridge void*)container; |
| 153 ctn->close = 0; |
297 ctn->close = 0; |
| 154 ctn->prev = NULL; |
298 ctn->prev = NULL; |
| 155 ctn->next = NULL; |
299 ctn->next = NULL; |
| |
300 container.container = ctn; |
| 156 return ctn; |
301 return ctn; |
| 157 } |
302 } |
| 158 |
303 |
| 159 void ui_container_add(UiObject *obj, NSView *view, UiLayout *layout) { |
304 void ui_container_add(UiObject *obj, NSView *view, UiLayout *layout) { |
| 160 UiContainerX *ctn = obj->container_end; |
305 UiContainerX *ctn = obj->container_end; |
| 161 id<Container> container = (__bridge id<Container>)ctn->container; |
306 id<Container> container = (__bridge id<Container>)ctn->container; |
| 162 container.uilayout = *layout; |
307 UiLayout adjustedLayout = *layout; |
| 163 [container addView:view]; |
308 if(adjustedLayout.margin > 0) { |
| 164 } |
309 adjustedLayout.margin_left = adjustedLayout.margin; |
| 165 |
310 adjustedLayout.margin_right = adjustedLayout.margin; |
| 166 /* ---------------------- public layout functions ----------------------- */ |
311 adjustedLayout.margin_top = adjustedLayout.margin; |
| 167 |
312 adjustedLayout.margin_bottom = adjustedLayout.margin; |
| 168 void ui_newline(UiObject *obj) { |
313 } |
| 169 UiContainerX *ctn = obj->container_end; |
314 [container addView:view layout:&adjustedLayout]; |
| 170 if(ctn) { |
315 } |
| 171 id<Container> container = (__bridge id<Container>)ctn->container; |
316 |
| 172 container.newline = TRUE; |
|
| 173 } else { |
|
| 174 fprintf(stderr, "Error: obj has no container\n"); |
|
| 175 } |
|
| 176 } |
|