ObjectivelyMVC 0.1.0
Object oriented MVC framework for OpenGL, SDL2 and GNU C
StackView.c
Go to the documentation of this file.
1/*
2 * ObjectivelyMVC: Object oriented MVC framework for OpenGL, SDL2 and GNU 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 StackView *this = (StackView *) self;
79
80 const SDL_Rect bounds = $(self, bounds);
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 const View *subview = $(subviews, objectAtIndex, i);
97 const SDL_Size size = $(subview, size);
98
99 switch (this->axis) {
101 requestedSize += size.h;
102 break;
104 requestedSize += size.w;
105 break;
106 }
107 }
108
109 int pos = 0;
110
111 const float scale = requestedSize ? availableSize / (float) requestedSize : 1.0;
112
113 for (size_t i = 0; i < subviews->count; i++) {
114
115 View *subview = $(subviews, objectAtIndex, i);
116
117 switch (this->axis) {
119 subview->frame.y = pos;
120 break;
122 subview->frame.x = pos;
123 break;
124 }
125
126 SDL_Size subviewSize = $(subview, size);
127
128 switch (this->distribution) {
130 break;
131
133 switch (this->axis) {
135 subviewSize.h *= scale;
136 break;
138 subviewSize.w *= scale;
139 break;
140 }
141 break;
142
144 switch (this->axis) {
146 subviewSize.h = availableSize / (float) subviews->count;
147 break;
149 subviewSize.w = availableSize / (float) subviews->count;
150 break;
151 }
152 break;
153 }
154
155 $(subview, resize, &subviewSize);
156
157 switch (this->axis) {
159 pos += subviewSize.h;
160 break;
162 pos += subviewSize.w;
163 break;
164 }
165
166 pos += this->spacing;
167 }
168 }
169
170 release(subviews);
171}
172
176static SDL_Size sizeThatFits(const View *self) {
177
178 SDL_Size size = super(View, self, sizeThatFits);
179
180 if ($(self, isContainer)) {
181
182 const StackView *this = (StackView *) self;
183
184 switch (this->axis) {
186 size.h = self->padding.top + self->padding.bottom;
187 break;
189 size.w = self->padding.left + self->padding.right;
190 break;
191 }
192
193 Array *subviews = $(self, visibleSubviews);
194 for (size_t i = 0; i < subviews->count; i++) {
195
196 const View *subview = $(subviews, objectAtIndex, i);
197 const SDL_Size subviewSize = $(subview, sizeThatContains);
198
199 switch (this->axis) {
201 size.h += subviewSize.h;
202 break;
204 size.w += subviewSize.w;
205 break;
206 }
207 }
208
209 if (subviews->count) {
210 switch (this->axis) {
212 size.h += this->spacing * (subviews->count - 1);
213 break;
215 size.w += this->spacing * (subviews->count - 1);
216 break;
217 }
218 }
219
220 release(subviews);
221 }
222
223 return size;
224}
225
226#pragma mark - StackView
227
232static StackView *initWithFrame(StackView *self, const SDL_Rect *frame) {
233
234 self = (StackView *) super(View, self, initWithFrame, frame);
235 if (self) {
237 }
238
239 return self;
240}
241
242#pragma mark - Class lifecycle
243
247static void initialize(Class *clazz) {
248
249 ((ViewInterface *) clazz->interface)->applyStyle = applyStyle;
250 ((ViewInterface *) clazz->interface)->init = init;
251
252 ((ViewInterface *) clazz->interface)->layoutSubviews = layoutSubviews;
253 ((ViewInterface *) clazz->interface)->sizeThatFits = sizeThatFits;
254
255 ((StackViewInterface *) clazz->interface)->initWithFrame = initWithFrame;
256}
257
262Class *_StackView(void) {
263 static Class *clazz;
264 static Once once;
265
266 do_once(&once, {
267 clazz = _initialize(&(const ClassDef) {
268 .name = "StackView",
269 .superclass = _View(),
270 .instanceSize = sizeof(StackView),
271 .interfaceOffset = offsetof(StackView, interface),
272 .interfaceSize = sizeof(StackViewInterface),
274 });
275 });
276
277 return clazz;
278}
279
280#undef _Class
const EnumName StackViewAxisNames[]
Definition: StackView.c:28
const EnumName StackViewDistributionNames[]
Definition: StackView.c:33
static void initialize(Class *clazz)
Definition: StackView.c:247
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
@ ViewAutoresizingContain
Definition: View.h:91
Box * initWithFrame(Box *self, const SDL_Rect *frame)
Initializes this Box with the given frame.
Definition: Box.c:92
CollectionView * init(CollectionView *self, const SDL_Rect *frame)
Initializes this CollectionView with the specified frame and style.
SDL_Size size(const Image *self)
Definition: Image.c:181
Inlets enable inbound data binding of View attributes through JSON.
Definition: View+JSON.h:155
The SDL_Size type.
Definition: Types.h:62
int w
Definition: Types.h:63
int h
Definition: Types.h:63
StackViews are containers that manage the arrangement of their subviews.
Definition: StackView.h:68
View view
The superclass.
Definition: StackView.h:73
Class * _StackView(void)
The StackView archetype.
Definition: StackView.c:262
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:133
SDL_Rect bounds(const View *self)
Definition: View.c:394
_Bool bind(View *self, const Inlet *inlets, const Dictionary *dictionary)
Performs data binding for the Inlets described in dictionary.
Class * _View(void)
The View archetype.
Definition: View.c:1769
Array * visibleSubviews(const View *self)
Definition: PageView.c:78
void applyStyle(View *self, const Style *style)
Applies the given Style to this View.
void resize(View *self, const SDL_Size *size)
Resizes this View to the specified size.
Definition: View.c:1326
int autoresizingMask
The ViewAutoresizing bitmask.
Definition: View.h:154
void sizeThatFits(const View *self)
ViewPadding padding
The padding.
Definition: View.h:233
layoutSubviews(View *self)
Performs layout for this View's immediate subviews.
Definition: Box.c:74
SDL_Size sizeThatContains(const View *self)
Definition: View.c:1423
_Bool isContainer(const View *self)
Definition: View.c:830
SDL_Rect frame
The frame, relative to the superview.
Definition: View.h:190
int top
Definition: View.h:100
int bottom
Definition: View.h:100
int right
Definition: View.h:100
int left
Definition: View.h:100