ObjectivelyMVC
Object oriented MVC framework for SDL3 and GNU C
Loading...
Searching...
No Matches
View+JSON.c
Go to the documentation of this file.
1/*
2 * Objectively: Ultra-lightweight object oriented framework for GNU C.
3 * Copyright (C) 2014 Jay Dolan <jay@jaydolan.com>
4 * This software is provided 'as-is', without any express or implied
5 * warranty. In no event will the authors be held liable for any damages
6 * arising from the use of this software.
7 * Permission is granted to anyone to use this software for any purpose,
8 * including commercial applications, and to alter it and redistribute it
9 * freely, subject to the following restrictions:
10 * 1. The origin of this software must not be misrepresented; you must not
11 * claim that you wrote the original software. If you use this software
12 * in a product, an acknowledgment in the product documentation would be
13 * appreciated but is not required.
14 * 2. Altered source versions must be plainly marked as such, and must not be
15 * misrepresented as being the original software.
16 * 3. This notice may not be removed or altered from any source distribution.
17 */
18
19#include <assert.h>
20#include <stdlib.h>
21#include <string.h>
22
23#include <Objectively.h>
24
25#include <ObjectivelyMVC.h>
26
27#define _Class _View
28
32static void bindBool(const Inlet *inlet, ident obj) {
33 *((bool *) inlet->dest) = cast(Boole, obj)->value;
34}
35
39static void bindCharacters(const Inlet *inlet, ident obj) {
40
41 char **dest = inlet->dest;
42
43 if (*dest) {
44 free(*dest);
45 }
46
47 *dest = strdup(cast(String, obj)->chars);
48}
49
53static void bindClassNames_enumerate(const Array *array, ident obj, ident data) {
54 $((View *) data, addClassName, cast(String, obj)->chars);
55}
56
60static void bindClassNames(const Inlet *inlet, ident obj) {
61 $(cast(Array, obj), enumerate, bindClassNames_enumerate, *(View **) inlet->dest);
62}
63
67static void bindColor(const Inlet *inlet, ident obj) {
68
69 SDL_Color color = Colors.Black;
70
71 if ($((Object *) obj, isKindOfClass, _String())) {
72
73 String *string = cast(String, obj);
74 if (string->length) {
75
76 if (strcmp("none", string->chars) == 0) {
77 return;
78 }
79
80 if (string->chars[0] == '#') {
81 color = MVC_HexToRGBA(string->chars + 1);
82 } else {
83 color = MVC_ColorForName(string->chars);
84 }
85 }
86
87 } else {
88 const Array *array = cast(Array, obj);
89
90 assert(array->count == 4);
91
92 const Number *r = $(array, objectAtIndex, 0);
93 const Number *g = $(array, objectAtIndex, 1);
94 const Number *b = $(array, objectAtIndex, 2);
95 const Number *a = $(array, objectAtIndex, 3);
96
97 #define ScaleColor(c) (c > 0.0 && c < 1.0 ? c * 255 : c)
98
99 color = MakeColor(
100 ScaleColor(r->value),
101 ScaleColor(g->value),
102 ScaleColor(b->value),
103 ScaleColor(a->value)
104 );
105 }
106
107 *((SDL_Color *) inlet->dest) = color;
108}
109
113static void bindDouble(const Inlet *inlet, ident obj) {
114 *((double *) inlet->dest) = cast(Number, obj)->value;
115}
116
120static void bindEnum(const Inlet *inlet, ident obj) {
121 *((int *) inlet->dest) = valueof(inlet->data, cast(String, obj)->chars);
122}
123
127static void bindFloat(const Inlet *inlet, ident obj) {
128 *((float *) inlet->dest) = cast(Number, obj)->value;
129}
130
134static void bindInteger(const Inlet *inlet, ident obj) {
135 *((int *) inlet->dest) = cast(Number, obj)->value;
136}
137
141static void bindPoint(const Inlet *inlet, ident obj) {
142
143 const Array *array = cast(Array, obj);
144
145 assert(array->count == 2);
146
147 const Number *x = $(array, objectAtIndex, 0);
148 const Number *y = $(array, objectAtIndex, 1);
149
150 *((SDL_Point *) inlet->dest) = MakePoint(x->value, y->value);
151}
152
156static void bindRectangle(const Inlet *inlet, ident obj) {
157
158 if ($((Object *) obj, isKindOfClass, _Number())) {
159 const Number *n = obj;
160
161 *((SDL_Rect *) inlet->dest) = MakeRect(n->value, n->value, n->value, n->value);
162 } else {
163 const Array *array = cast(Array, obj);
164
165 assert(array->count == 4);
166
167 const Number *x = $(array, objectAtIndex, 0);
168 const Number *y = $(array, objectAtIndex, 1);
169 const Number *w = $(array, objectAtIndex, 2);
170 const Number *h = $(array, objectAtIndex, 3);
171
172 *((SDL_Rect *) inlet->dest) = MakeRect(x->value, y->value, w->value, h->value);
173 }
174}
175
179static void bindSize(const Inlet *inlet, ident obj) {
180
181 const Array *array = cast(Array, obj);
182
183 assert(array->count == 2);
184
185 const Number *w = $(array, objectAtIndex, 0);
186 const Number *h = $(array, objectAtIndex, 1);
187
188 *((SDL_Size *) inlet->dest) = MakeSize(w->value, h->value);
189}
190
194static void bindView(const Inlet *inlet, ident obj) {
195
196 View *dest = *(View **) inlet->dest;
197
198 const Dictionary *dictionary = cast(Dictionary, obj);
199
200 const String *className = $(dictionary, objectForKeyPath, "class");
201 if (className || dest == NULL) {
202
203 Class *clazz = className ? classForName(className->chars) : _View();
204 assert(clazz);
205
206 const Class *c = clazz;
207 while (c) {
208 if (c == _View()) {
209 break;
210 }
211 c = c->def.superclass;
212 }
213 assert(c);
214
215 if (clazz != _View()) {
216 if (interfaceof(View, clazz)->init == interfaceof(View, clazz->def.superclass)->init) {
217 MVC_LogWarn("%s does not implement View::init\n", clazz->def.name);
218 }
219 }
220
221 View *view = $((View *) _alloc(clazz), init);
222 assert(view);
223
224 $(view, awakeWithDictionary, dictionary);
225
226 if (dest) {
227 if (dest->superview) {
228 $(dest->superview, replaceSubview, dest, view);
229 }
230 release(dest);
231 }
232
233 *(View **) inlet->dest = view;
234
235 } else if (dest) {
236 $(dest, awakeWithDictionary, dictionary);
237 } else {
238 MVC_LogWarn("Inlet %s has NULL destination and no className specified\n", inlet->name);
239 }
240}
241
245static void bindStyle(const Inlet *inlet, ident obj) {
246 $(cast(View, *((View **) inlet->dest))->style, addAttributes, cast(Dictionary, obj));
247}
248
252static void bindSubviews_enumerate(const Array *array, ident obj, ident data) {
253
254 View *subview = NULL;
255
256 const Inlet inlet = MakeInlet(NULL, InletTypeView, &subview, NULL);
257
258 bindView(&inlet, obj);
259
260 $(cast(View, data), addSubview, subview);
261
262 release(subview);
263}
264
268static void bindSubviews(const Inlet *inlet, ident obj) {
269 $(cast(Array, obj), enumerate, bindSubviews_enumerate, *(View **) inlet->dest);
270}
271
275static void bindApplicationDefined(const Inlet *inlet, ident obj) {
276
277 assert(inlet->data);
278
279 ((InletBinding) inlet->data)(inlet, obj);
280}
281
302
303bool bindInlets(const Inlet *inlets, const Dictionary *dictionary) {
304
305 assert(inlets);
306 assert(dictionary);
307
308 bool didBindInlets = false;
309
310 for (const Inlet *inlet = inlets; inlet->name; inlet++) {
311 const ident obj = $(dictionary, objectForKeyPath, inlet->name);
312 if (obj) {
313 BindInlet(inlet, obj);
314 didBindInlets = true;
315 }
316 }
317
318 return didBindInlets;
319}
320
321#undef _Class
static View * init(View *self)
Definition Box.c:67
static void awakeWithDictionary(View *self, const Dictionary *dictionary)
Definition Box.c:50
SDL_Color MVC_ColorForName(const char *name)
Definition Colors.c:181
SDL_Color MVC_HexToRGBA(const char *hex)
Definition Colors.c:639
#define MVC_LogWarn(fmt,...)
Definition Log.h:54
ObjectivelyMVC: Object oriented MVC framework for SDL3 and C.
static void addSubview(View *self, View *subview)
Definition PageView.c:49
static void addAttributes(Style *self, const Dictionary *attributes)
Definition Style.c:221
static void bindColor(const Inlet *inlet, ident obj)
InletBinding for InletTypeColor.
Definition View+JSON.c:67
static void bindEnum(const Inlet *inlet, ident obj)
InletBinding for InletTypeEnum.
Definition View+JSON.c:120
static void bindPoint(const Inlet *inlet, ident obj)
InletBinding for InletTypePoint.
Definition View+JSON.c:141
static void bindApplicationDefined(const Inlet *inlet, ident obj)
InletBinding for InletTypeApplicationDefined.
Definition View+JSON.c:275
static void bindClassNames_enumerate(const Array *array, ident obj, ident data)
ArrayEnumerator for bindClassNames.
Definition View+JSON.c:53
static void bindSubviews_enumerate(const Array *array, ident obj, ident data)
ArrayEnumerator for bind subview recursion.
Definition View+JSON.c:252
static void bindDouble(const Inlet *inlet, ident obj)
InletBinding for InletTypeDouble.
Definition View+JSON.c:113
static void bindClassNames(const Inlet *inlet, ident obj)
InletBinding for InletTypeClassNames.
Definition View+JSON.c:60
static void bindInteger(const Inlet *inlet, ident obj)
InletBinding for InletTypeInteger.
Definition View+JSON.c:134
bool bindInlets(const Inlet *inlets, const Dictionary *dictionary)
Binds each Inlet specified in inlets to the data provided in dictionary.
Definition View+JSON.c:303
static void bindFloat(const Inlet *inlet, ident obj)
InletBinding for InletTypeFloat.
Definition View+JSON.c:127
#define ScaleColor(c)
static void bindRectangle(const Inlet *inlet, ident obj)
InletBinding for InletTypeRectangle.
Definition View+JSON.c:156
static void bindSize(const Inlet *inlet, ident obj)
InletBinding for InletTypeSize.
Definition View+JSON.c:179
static void bindBool(const Inlet *inlet, ident obj)
InletBinding for InletTypeBool.
Definition View+JSON.c:32
static void bindView(const Inlet *inlet, ident obj)
Binds the given View with the specified Dictionary.
Definition View+JSON.c:194
static void bindCharacters(const Inlet *inlet, ident obj)
InletBinding for InletTypeCharacters.
Definition View+JSON.c:39
const InletBinding inletBindings[]
The array of InletBinding functions, indexed by InletType.
Definition View+JSON.c:285
static void bindSubviews(const Inlet *inlet, ident obj)
InletBinding for InletTypeSubviews.
Definition View+JSON.c:268
static void bindStyle(const Inlet *inlet, ident obj)
InletBinding for InletTypeStyle.
Definition View+JSON.c:245
@ InletTypeView
Definition View+JSON.h:133
#define BindInlet(inlet, obj)
Binds the Inlet to obj by invoking the appropriate InletBinding function.
Definition View+JSON.h:238
void(* InletBinding)(const Inlet *inlet, ident obj)
A function pointer for Inlet binding.
Definition View+JSON.h:180
#define MakeInlet(name, type, dest, data)
Creates an Inlet with the specified parameters.
Definition View+JSON.h:210
static void addClassName(View *self, const char *className)
Definition View.c:183
Class * _View(void)
Definition View.c:2336
static void replaceSubview(View *self, View *subview, View *replacement)
Definition View.c:1663
static void enumerate(View *self, ViewEnumerator enumerator, ident data)
Definition View.c:807
W3C Color constants.
Definition Colors.h:37
SDL_Color Black
Definition Colors.h:46
Inlets enable inbound data binding of View attributes through JSON.
Definition View+JSON.h:149
const char * name
The Inlet name, e.g. "alignment".
Definition View+JSON.h:154
ident data
Type-specific data, e.g. an array of EnumNames.
Definition View+JSON.h:169
ident dest
The Inlet destination.
Definition View+JSON.h:164
Views are the fundamental building blocks of ObjectivelyMVC user interfaces.
Definition View.h:225
View * superview
The super View.
Definition View.h:454
View * init(View *self)
Initializes this View.
Definition Box.c:67