ObjectivelyMVC
Object oriented MVC framework for SDL3 and GNU C
Loading...
Searching...
No Matches
StackView.c
Go to the documentation of this file.
1/*
2 * ObjectivelyMVC: Object oriented MVC framework for SDL3 and C.
3 * Copyright (C) 2014 Jay Dolan <jay@jaydolan.com>
4 *
5 * This software is provided 'as-is', without any express or implied
6 * warranty. In no event will the authors be held liable for any damages
7 * arising from the use of this software.
8 *
9 * Permission is granted to anyone to use this software for any purpose,
10 * including commercial applications, and to alter it and redistribute it
11 * freely, subject to the following restrictions:
12 *
13 * 1. The origin of this software must not be misrepresented; you must not
14 * claim that you wrote the original software. If you use this software
15 * in a product, an acknowledgment in the product documentation would be
16 * appreciated but is not required.
17 *
18 * 2. Altered source versions must be plainly marked as such, and must not be
19 * misrepresented as being the original software.
20 *
21 * 3. This notice may not be removed or altered from any source distribution.
22 */
23
24#include <assert.h>
25
26#include "StackView.h"
27
28const EnumName StackViewAxisNames[] = MakeEnumNames(
29 MakeEnumAlias(StackViewAxisVertical, vertical),
30 MakeEnumAlias(StackViewAxisHorizontal, horizontal)
31);
32
33const EnumName StackViewDistributionNames[] = MakeEnumNames(
34 MakeEnumAlias(StackViewDistributionDefault, default),
35 MakeEnumAlias(StackViewDistributionFill, fill),
36 MakeEnumAlias(StackViewDistributionFillEqually, fill-equally)
37);
38
39#define _Class _StackView
40
41#pragma mark - View
42
46static void applyStyle(View *self, const Style *style) {
47
48 super(View, self, applyStyle, style);
49
50 StackView *this = (StackView *) self;
51
52 const Inlet inlets[] = MakeInlets(
53 MakeInlet("axis", InletTypeEnum, &this->axis, (ident) StackViewAxisNames),
54 MakeInlet("distribution", InletTypeEnum, &this->distribution, (ident) StackViewDistributionNames),
55 MakeInlet("spacing", InletTypeInteger, &this->spacing, NULL)
56 );
57
58 $(self, bind, inlets, (Dictionary *) style->attributes);
59}
60
64static View *init(View *self) {
65 return (View *) $((StackView *) self, initWithFrame, NULL);
66}
67
71static void layoutSubviews(View *self) {
72
73 super(View, self, layoutSubviews);
74
75 Array *subviews = $(self, visibleSubviews);
76 if (subviews->count) {
77
78 const SDL_Rect bounds = $(self, bounds);
79
80 StackView *this = (StackView *) self;
81
82 int availableSize, requestedSize = 0;
83 switch (this->axis) {
85 availableSize = bounds.h;
86 break;
88 availableSize = bounds.w;
89 break;
90 }
91
92 availableSize -= this->spacing * (subviews->count - 1);
93
94 for (size_t i = 0; i < subviews->count; i++) {
95
96 View *subview = $(subviews, objectAtIndex, i);
97
98 const SDL_Size subviewSize = $(subview, size);
99
100 switch (this->axis) {
102 requestedSize += subviewSize.h;
103 break;
105 requestedSize += subviewSize.w;
106 break;
107 }
108 }
109
110 int pos = 0;
111
112 const float scale = requestedSize ? availableSize / (float) requestedSize : 1.f;
113
114 for (size_t i = 0; i < subviews->count; i++) {
115
116 View *subview = $(subviews, objectAtIndex, i);
117
118 switch (this->axis) {
120 subview->frame.y = pos;
121 break;
123 subview->frame.x = pos;
124 break;
125 }
126
127 SDL_Size subviewSize = $(subview, size);
128
129 switch (this->axis) {
132 subviewSize.w = bounds.w;
133 }
134 break;
137 subviewSize.h = bounds.h;
138 }
139 break;
140 }
141
142 switch (this->distribution) {
144 break;
145
147 switch (this->axis) {
149 subviewSize.h *= scale;
150 break;
152 subviewSize.w *= scale;
153 break;
154 }
155 break;
156
158 switch (this->axis) {
160 subviewSize.h = availableSize / (float) subviews->count;
161 break;
163 subviewSize.w = availableSize / (float) subviews->count;
164 break;
165 }
166 break;
167 }
168
169 $(subview, resize, &subviewSize);
170 $(subview, layoutIfNeeded);
171
172 switch (this->axis) {
174 pos += subviewSize.h;
175 break;
177 pos += subviewSize.w;
178 break;
179 }
180
181 pos += this->spacing;
182 }
183 }
184
185 release(subviews);
186}
187
191static SDL_Size sizeThatFits(const View *self) {
192
193 const StackView *this = (StackView *) self;
194
195 SDL_Size size = MakeSize(0, 0);
196
197 switch (this->axis) {
199 size.h = self->padding.top + self->padding.bottom;
200 break;
202 size.w = self->padding.left + self->padding.right;
203 break;
204 }
205
206 Array *subviews = $(self, visibleSubviews);
207 for (size_t i = 0; i < subviews->count; i++) {
208
209 const View *subview = $(subviews, objectAtIndex, i);
210
211 SDL_Size subviewSize;
213 subviewSize = $(subview, sizeThatContains);
214 } else if (subview->autoresizingMask & ViewAutoresizingFit) {
215 subviewSize = $(subview, sizeThatFits);
216 } else {
217 subviewSize = $(subview, size);
218 }
219
220 switch (this->axis) {
222 size.w = max(size.w, subviewSize.w);
223 size.h += subviewSize.h;
224 break;
226 size.w += subviewSize.w;
227 size.h = max(size.h, subviewSize.h);
228 break;
229 }
230 }
231
232 if (subviews->count) {
233 switch (this->axis) {
235 size.h += this->spacing * (subviews->count - 1);
236 break;
238 size.w += this->spacing * (subviews->count - 1);
239 break;
240 }
241 }
242
243 release(subviews);
244
245 size.w = clamp(size.w, self->minSize.w, self->maxSize.w);
246 size.h = clamp(size.h, self->minSize.h, self->maxSize.h);
247
248 return size;
249}
250
251#pragma mark - StackView
252
257static StackView *initWithFrame(StackView *self, const SDL_Rect *frame) {
258
259 self = (StackView *) super(View, self, initWithFrame, frame);
260 if (self) {
262 }
263
264 return self;
265}
266
267#pragma mark - Class lifecycle
268
272static void initialize(Class *clazz) {
273
274 ((ViewInterface *) clazz->interface)->applyStyle = applyStyle;
275 ((ViewInterface *) clazz->interface)->init = init;
276
277 ((ViewInterface *) clazz->interface)->layoutSubviews = layoutSubviews;
278 ((ViewInterface *) clazz->interface)->sizeThatFits = sizeThatFits;
279
280 ((StackViewInterface *) clazz->interface)->initWithFrame = initWithFrame;
281}
282
287Class *_StackView(void) {
288 static Class *clazz;
289 static Once once;
290
291 do_once(&once, {
292 clazz = _initialize(&(const ClassDef) {
293 .name = "StackView",
294 .superclass = _View(),
295 .instanceSize = sizeof(StackView),
296 .interfaceOffset = offsetof(StackView, interface),
297 .interfaceSize = sizeof(StackViewInterface),
299 });
300 });
301
302 return clazz;
303}
304
305#undef _Class
static SDL_Size size(const Image *self)
Definition Image.c:181
static Array * visibleSubviews(const View *self)
Definition PageView.c:92
const EnumName StackViewAxisNames[]
Definition StackView.c:28
static View * init(View *self)
Definition StackView.c:64
static void applyStyle(View *self, const Style *style)
Definition StackView.c:46
static SDL_Size sizeThatFits(const View *self)
Definition StackView.c:191
static StackView * initWithFrame(StackView *self, const SDL_Rect *frame)
Definition StackView.c:257
const EnumName StackViewDistributionNames[]
Definition StackView.c:33
static void initialize(Class *clazz)
Definition StackView.c:272
Class * _StackView(void)
Definition StackView.c:287
static void layoutSubviews(View *self)
Definition StackView.c:71
StackViews are containers that manage the arrangement of their subviews.
@ StackViewDistributionDefault
Definition StackView.h:53
@ StackViewDistributionFillEqually
Definition StackView.h:55
@ StackViewDistributionFill
Definition StackView.h:54
@ StackViewAxisHorizontal
Definition StackView.h:44
@ StackViewAxisVertical
Definition StackView.h:43
@ InletTypeEnum
Definition View+JSON.h:75
@ InletTypeInteger
Definition View+JSON.h:95
#define MakeInlets(...)
Creates a null-termianted array of Inlets.
Definition View+JSON.h:221
#define MakeInlet(name, type, dest, data)
Creates an Inlet with the specified parameters.
Definition View+JSON.h:216
static void resize(View *self, const SDL_Size *size)
Definition View.c:1527
static void layoutIfNeeded(View *self)
Definition View.c:1115
Class * _View(void)
Definition View.c:2067
static SDL_Size sizeThatContains(const View *self)
Definition View.c:1659
static SDL_Rect bounds(const View *self)
Definition View.c:492
@ ViewAutoresizingContain
Definition View.h:92
@ ViewAutoresizingWidth
Definition View.h:88
@ ViewAutoresizingHeight
Definition View.h:89
@ ViewAutoresizingFit
Definition View.h:91
Inlets enable inbound data binding of View attributes through JSON.
Definition View+JSON.h:155
StackViews are containers that manage the arrangement of their subviews.
Definition StackView.h:68
View view
The superclass.
Definition StackView.h:73
The Style type.
Definition Style.h:43
Dictionary * attributes
Definition Style.h:59
Views are the fundamental building blocks of ObjectivelyMVC user interfaces.
Definition View.h:134
void applyStyle(View *self, const Style *style)
Applies the given Style to this View.
int autoresizingMask
The ViewAutoresizing bitmask.
Definition View.h:155
ViewPadding padding
The padding.
Definition View.h:234
SDL_Size minSize
The minimum size this View may be resized to during layout.
Definition View.h:212
layoutSubviews(View *self)
Performs layout for this View's immediate subviews.
Definition Box.c:74
SDL_Size maxSize
The maximum size this View may be resized to during layout.
Definition View.h:207
SDL_Rect frame
The frame, relative to the superview.
Definition View.h:191
int top
Definition View.h:101
int bottom
Definition View.h:101
int right
Definition View.h:101
int left
Definition View.h:101