ObjectivelyMVC
Object oriented MVC framework for SDL3 and GNU C
Loading...
Searching...
No Matches
StackView.c File Reference
#include <assert.h>
#include "StackView.h"

Go to the source code of this file.

Macros

#define _Class   _StackView
 

Functions

Class * _StackView (void)
 
static void applyStyle (View *self, const Style *style)
 
static View * init (View *self)
 
static void initialize (Class *clazz)
 
static StackView * initWithFrame (StackView *self, const SDL_Rect *frame)
 
static void layoutSubviews (View *self)
 
static SDL_Size sizeThatFits (const View *self)
 

Variables

const EnumName StackViewAxisNames []
 
const EnumName StackViewDistributionNames []
 

Macro Definition Documentation

◆ _Class

#define _Class   _StackView

Definition at line 39 of file StackView.c.

Function Documentation

◆ _StackView()

Class * _StackView ( void  )

Definition at line 358 of file StackView.c.

358 {
359 static Class *clazz;
360 static Once once;
361
362 do_once(&once, {
363 clazz = _initialize(&(const ClassDef) {
364 .name = "StackView",
365 .superclass = _View(),
366 .instanceSize = sizeof(StackView),
367 .interfaceSize = sizeof(StackViewInterface),
368 .initialize = initialize,
369 });
370 });
371
372 return clazz;
373}
static void initialize(Class *clazz)
Definition StackView.c:343
Class * _View(void)
Definition View.c:2336
StackViews are containers that manage the arrangement of their subviews.
Definition StackView.h:68

◆ applyStyle()

static void applyStyle ( View *  self,
const Style *  style 
)
static
See also
View::applyStyle(View *, const Style *)

Definition at line 46 of file StackView.c.

46 {
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("reversed", InletTypeBool, &this->reversed, NULL),
55 MakeInlet("distribution", InletTypeEnum, &this->distribution, (ident) StackViewDistributionNames),
56 MakeInlet("spacing", InletTypeInteger, &this->spacing, NULL)
57 );
58
59 $(self, bind, inlets, (Dictionary *) style->attributes);
60}
const EnumName StackViewAxisNames[]
Definition StackView.c:28
static void applyStyle(View *self, const Style *style)
Definition StackView.c:46
const EnumName StackViewDistributionNames[]
Definition StackView.c:33
@ InletTypeEnum
Definition View+JSON.h:75
@ InletTypeBool
Definition View+JSON.h:46
@ InletTypeInteger
Definition View+JSON.h:89
#define MakeInlets(...)
Creates a null-termianted array of Inlets.
Definition View+JSON.h:215
#define MakeInlet(name, type, dest, data)
Creates an Inlet with the specified parameters.
Definition View+JSON.h:210
Inlets enable inbound data binding of View attributes through JSON.
Definition View+JSON.h:149
Dictionary * attributes
Definition Style.h:59
Views are the fundamental building blocks of ObjectivelyMVC user interfaces.
Definition View.h:225

◆ init()

static View * init ( View *  self)
static
See also
View::init(View *)

Definition at line 65 of file StackView.c.

65 {
66 return (View *) $((StackView *) self, initWithFrame, NULL);
67}
static StackView * initWithFrame(StackView *self, const SDL_Rect *frame)
Definition StackView.c:329

◆ initialize()

static void initialize ( Class *  clazz)
static
See also
Class::initialize(Class *)

Definition at line 343 of file StackView.c.

343 {
344
345 ((ViewInterface *) clazz->interface)->applyStyle = applyStyle;
346 ((ViewInterface *) clazz->interface)->init = init;
347
348 ((ViewInterface *) clazz->interface)->layoutSubviews = layoutSubviews;
349 ((ViewInterface *) clazz->interface)->sizeThatFits = sizeThatFits;
350
351 ((StackViewInterface *) clazz->interface)->initWithFrame = initWithFrame;
352}
static View * init(View *self)
Definition StackView.c:65
static SDL_Size sizeThatFits(const View *self)
Definition StackView.c:258
static void layoutSubviews(View *self)
Definition StackView.c:72
layoutSubviews(View *self)
Arranges this View's immediate subviews within its (already final) frame.
Definition Box.c:74

◆ initWithFrame()

static StackView * initWithFrame ( StackView *  self,
const SDL_Rect *  frame 
)
static

Definition at line 329 of file StackView.c.

329 {
330
331 self = (StackView *) super(View, self, initWithFrame, frame);
332 if (self) {
333 }
334
335 return self;
336}

◆ layoutSubviews()

static void layoutSubviews ( View *  self)
static
See also
View::layoutSubviews(View *)

Definition at line 72 of file StackView.c.

72 {
73
74 Array *subviews = $(self, visibleSubviews);
75 if (subviews->count) {
76
77 const SDL_Rect bounds = $(self, bounds);
78
79 StackView *this = (StackView *) self;
80
81 int availableSize, requestedSize = 0;
82 switch (this->axis) {
84 availableSize = bounds.h;
85 break;
87 availableSize = bounds.w;
88 break;
89 }
90
91 availableSize -= this->spacing * (subviews->count - 1);
92
93 const ViewConstraint unspecified = MakeConstraint(ViewConstraintUnspecified, 0);
94
95 SDL_Size sizes[subviews->count];
96
97 for (size_t i = 0; i < subviews->count; i++) {
98
99 View *subview = $(subviews, objectAtIndex, i);
100
101 sizes[i] = $(subview, sizeThatSatisfies, unspecified, unspecified);
102
103 switch (this->axis) {
105 requestedSize += sizes[i].h;
106 break;
108 requestedSize += sizes[i].w;
109 break;
110 }
111 }
112
113 int numStretch = 0;
114 for (size_t i = 0; i < subviews->count; i++) {
115 const View *subview = $(subviews, objectAtIndex, i);
116 if (subview->stretch) {
117 numStretch++;
118 }
119 }
120
121 int remaining = this->distribution == StackViewDistributionDefault && numStretch ?
122 max(availableSize - requestedSize, 0) : 0;
123
124 int pos = 0;
125
126 const float scale = requestedSize ? availableSize / (float) requestedSize : 1.f;
127
128 for (size_t j = 0; j < subviews->count; j++) {
129
130 const size_t i = this->reversed ? subviews->count - 1 - j : j;
131
132 View *subview = $(subviews, objectAtIndex, i);
133
134 switch (this->axis) {
136 subview->frame.y = pos;
137 break;
139 subview->frame.x = pos;
140 break;
141 }
142
143 SDL_Size subviewSize = sizes[i];
144
145 switch (this->axis) {
148 subviewSize.w = bounds.w;
149 }
150 break;
153 subviewSize.h = bounds.h;
154 }
155 break;
156 }
157
158 // Distribute along primary axis
159
160 switch (this->distribution) {
162 break;
163
165 switch (this->axis) {
167 subviewSize.h *= scale;
168 break;
170 subviewSize.w *= scale;
171 break;
172 }
173 break;
174
176 switch (this->axis) {
178 subviewSize.h = max(availableSize / (float) subviews->count, sizes[i].h);
179 break;
181 subviewSize.w = max(availableSize / (float) subviews->count, sizes[i].w);
182 break;
183 }
184 break;
185 }
186
187 const bool stretch = subview->stretch && remaining;
188 if (stretch) {
189 const int share = --numStretch ? remaining / (numStretch + 1) : remaining;
190 switch (this->axis) {
192 subviewSize.h += share;
193 break;
195 subviewSize.w += share;
196 break;
197 }
198 }
199
200 $(subview, layoutWithSize, &subviewSize);
201
202 if (stretch) {
203 switch (this->axis) {
205 remaining -= max(subview->frame.h - sizes[i].h, 0);
206 subviewSize.h = subview->frame.h;
207 break;
209 remaining -= max(subview->frame.w - sizes[i].w, 0);
210 subviewSize.w = subview->frame.w;
211 break;
212 }
213 }
214
215 // Align along secondary axis
216
217 switch (this->axis) {
219 switch (subview->alignment & ViewAlignmentMaskHorizontal) {
221 subview->frame.x = 0;
222 break;
224 subview->frame.x = (bounds.w - subview->frame.w) * 0.5f;
225 break;
227 subview->frame.x = bounds.w - subview->frame.w;
228 break;
229 }
230 pos += subviewSize.h;
231 break;
233 switch (subview->alignment & ViewAlignmentMaskVertical) {
235 subview->frame.y = 0;
236 break;
238 subview->frame.y = (bounds.h - subview->frame.h) * 0.5f;
239 break;
241 subview->frame.y = bounds.h - subview->frame.h;
242 break;
243 }
244 pos += subviewSize.w;
245 break;
246 }
247
248 pos += this->spacing;
249 }
250 }
251
252 release(subviews);
253}
static Array * visibleSubviews(const View *self)
Definition PageView.c:92
@ 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
static SDL_Size sizeThatSatisfies(View *self, ViewConstraint width, ViewConstraint height)
Definition View.c:1979
static void layoutWithSize(View *self, const SDL_Size *size)
Definition View.c:1267
static SDL_Rect bounds(const View *self)
Definition View.c:552
#define ViewAlignmentMaskBottom
Definition View.h:46
#define ViewAlignmentMaskTop
Definition View.h:44
#define ViewAlignmentMaskMiddle
Definition View.h:45
#define MakeConstraint(mode, value)
Definition View.h:163
#define ViewAlignmentMaskHorizontal
Definition View.h:55
#define ViewAlignmentMaskVertical
Definition View.h:52
@ ViewAutoresizingWidth
Definition View.h:91
@ ViewAutoresizingHeight
Definition View.h:92
@ ViewAlignmentCenter
Definition View.h:70
@ ViewAlignmentLeft
Definition View.h:69
@ ViewAlignmentRight
Definition View.h:71
A constraint offered by an ancestor View to a descendant during View::sizeThatSatisfies.
Definition View.h:131
ViewAlignment alignment
The alignment.
Definition View.h:242
int autoresizingMask
The ViewAutoresizing bitmask.
Definition View.h:248
bool stretch
Whether this View takes a share of the space its StackView leaves along its axis.
Definition View.h:436
SDL_Rect frame
The frame, relative to the superview.
Definition View.h:301

◆ sizeThatFits()

static SDL_Size sizeThatFits ( const View *  self)
static
See also
View::sizeThatFits(const View *)

Definition at line 258 of file StackView.c.

258 {
259
260 const StackView *this = (StackView *) self;
261
262 SDL_Size size = MakeSize(0, 0);
263
264 switch (this->axis) {
266 size.h = self->padding.top + self->padding.bottom;
267 break;
269 size.w = self->padding.left + self->padding.right;
270 break;
271 }
272
273 Array *subviews = $(self, visibleSubviews);
274
275 const ViewConstraint unspecified = MakeConstraint(ViewConstraintUnspecified, 0);
276
277 for (size_t i = 0; i < subviews->count; i++) {
278
279 View *subview = $(subviews, objectAtIndex, i);
280
281 const SDL_Size subviewSize = $(subview, sizeThatSatisfies, unspecified, unspecified);
282
283 switch (this->axis) {
285 size.w = max(size.w, subviewSize.w);
286 size.h += subviewSize.h;
287 break;
289 size.w += subviewSize.w;
290 size.h = max(size.h, subviewSize.h);
291 break;
292 }
293 }
294
295 switch (this->axis) {
297 size.w += self->padding.left + self->padding.right;
298 break;
300 size.h += self->padding.top + self->padding.bottom;
301 break;
302 }
303
304 if (subviews->count) {
305 switch (this->axis) {
307 size.h += this->spacing * (subviews->count - 1);
308 break;
310 size.w += this->spacing * (subviews->count - 1);
311 break;
312 }
313 }
314
315 release(subviews);
316
317 size.w = ClampSize(size.w, self->minSize.w, self->maxSize.w);
318 size.h = ClampSize(size.h, self->minSize.h, self->maxSize.h);
319
320 return size;
321}
static SDL_Size size(const Image *self)
Definition Image.c:416
#define ClampSize(size, min, max)
Clamps size to min and max, where a max of zero is unbounded.
Definition View.h:103
ViewPadding padding
The padding.
Definition View.h:398
SDL_Size minSize
The minimum size this View may be resized to during layout.
Definition View.h:345
SDL_Size maxSize
The maximum size this View may be resized to during layout.
Definition View.h:339
int top
Definition View.h:170
int bottom
Definition View.h:170
int right
Definition View.h:170
int left
Definition View.h:170

Variable Documentation

◆ StackViewAxisNames

const EnumName StackViewAxisNames[]
Initial value:
= MakeEnumNames(
MakeEnumAlias(StackViewAxisVertical, vertical),
MakeEnumAlias(StackViewAxisHorizontal, horizontal)
)

Definition at line 28 of file StackView.c.

◆ StackViewDistributionNames

const EnumName StackViewDistributionNames[]
Initial value:
= MakeEnumNames(
MakeEnumAlias(StackViewDistributionDefault, default),
MakeEnumAlias(StackViewDistributionFill, fill),
MakeEnumAlias(StackViewDistributionFillEqually, fill-equally)
)

Definition at line 33 of file StackView.c.