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 bindFont(const Inlet *inlet, ident obj) {
135
136 release(*(Font **) inlet->dest);
137
138 // TODO
139
140 //*((Font **) inlet->dest) = $(alloc(Font), initWithName, cast(String, obj)->chars);
141}
142
146static void bindImage(const Inlet *inlet, ident obj) {
147
148 release(*(Image **) inlet->dest);
149
150 *((Image **) inlet->dest) = $(alloc(Image), initWithResourceName, cast(String, obj)->chars);
151}
152
156static void bindInteger(const Inlet *inlet, ident obj) {
157 *((int *) inlet->dest) = cast(Number, obj)->value;
158}
159
163static void bindPoint(const Inlet *inlet, ident obj) {
164
165 const Array *array = cast(Array, obj);
166
167 assert(array->count == 2);
168
169 const Number *x = $(array, objectAtIndex, 0);
170 const Number *y = $(array, objectAtIndex, 1);
171
172 *((SDL_Point *) inlet->dest) = MakePoint(x->value, y->value);
173}
174
178static void bindRectangle(const Inlet *inlet, ident obj) {
179
180 if ($((Object *) obj, isKindOfClass, _Number())) {
181 const Number *n = obj;
182
183 *((SDL_Rect *) inlet->dest) = MakeRect(n->value, n->value, n->value, n->value);
184 } else {
185 const Array *array = cast(Array, obj);
186
187 assert(array->count == 4);
188
189 const Number *x = $(array, objectAtIndex, 0);
190 const Number *y = $(array, objectAtIndex, 1);
191 const Number *w = $(array, objectAtIndex, 2);
192 const Number *h = $(array, objectAtIndex, 3);
193
194 *((SDL_Rect *) inlet->dest) = MakeRect(x->value, y->value, w->value, h->value);
195 }
196}
197
201static void bindSize(const Inlet *inlet, ident obj) {
202
203 const Array *array = cast(Array, obj);
204
205 assert(array->count == 2);
206
207 const Number *w = $(array, objectAtIndex, 0);
208 const Number *h = $(array, objectAtIndex, 1);
209
210 *((SDL_Size *) inlet->dest) = MakeSize(w->value, h->value);
211}
212
216static void bindView(const Inlet *inlet, ident obj) {
217
218 View *dest = *(View **) inlet->dest;
219
220 const Dictionary *dictionary = cast(Dictionary, obj);
221
222 const String *className = $(dictionary, objectForKeyPath, "class");
223 if (className || dest == NULL) {
224
225 Class *clazz = className ? classForName(className->chars) : _View();
226 assert(clazz);
227
228 const Class *c = clazz;
229 while (c) {
230 if (c == _View()) {
231 break;
232 }
233 c = c->def.superclass;
234 }
235 assert(c);
236
237 if (clazz != _View()) {
238 if (interfaceof(View, clazz)->init == interfaceof(View, clazz->def.superclass)->init) {
239 MVC_LogWarn("%s does not implement View::init\n", clazz->def.name);
240 }
241 }
242
243 View *view = $((View *) _alloc(clazz), init);
244 assert(view);
245
246 $(view, awakeWithDictionary, dictionary);
247
248 if (dest) {
249 if (dest->superview) {
250 $(dest->superview, replaceSubview, dest, view);
251 }
252 release(dest);
253 }
254
255 *(View **) inlet->dest = view;
256
257 } else if (dest) {
258 $(dest, awakeWithDictionary, dictionary);
259 } else {
260 MVC_LogWarn("Inlet %s has NULL destination and no className specified\n", inlet->name);
261 }
262}
263
267static void bindStyle(const Inlet *inlet, ident obj) {
268 $(cast(View, *((View **) inlet->dest))->style, addAttributes, cast(Dictionary, obj));
269}
270
274static void bindSubviews_enumerate(const Array *array, ident obj, ident data) {
275
276 View *subview = NULL;
277
278 const Inlet inlet = MakeInlet(NULL, InletTypeView, &subview, NULL);
279
280 bindView(&inlet, obj);
281
282 $(cast(View, data), addSubview, subview);
283
284 release(subview);
285}
286
290static void bindSubviews(const Inlet *inlet, ident obj) {
291 $(cast(Array, obj), enumerate, bindSubviews_enumerate, *(View **) inlet->dest);
292}
293
297static void bindApplicationDefined(const Inlet *inlet, ident obj) {
298
299 assert(inlet->data);
300
301 ((InletBinding) inlet->data)(inlet, obj);
302}
303
326
327bool bindInlets(const Inlet *inlets, const Dictionary *dictionary) {
328
329 assert(inlets);
330 assert(dictionary);
331
332 bool didBindInlets = false;
333
334 for (const Inlet *inlet = inlets; inlet->name; inlet++) {
335 const ident obj = $(dictionary, objectForKeyPath, inlet->name);
336 if (obj) {
337 BindInlet(inlet, obj);
338 didBindInlets = true;
339 }
340 }
341
342 return didBindInlets;
343}
344
345#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
static Image * initWithResourceName(Image *self, const char *name)
Definition Image.c:142
#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:119
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:163
static void bindApplicationDefined(const Inlet *inlet, ident obj)
InletBinding for InletTypeApplicationDefined.
Definition View+JSON.c:297
static void bindImage(const Inlet *inlet, ident obj)
InletBinding for InletTypeImage.
Definition View+JSON.c:146
static void bindFont(const Inlet *inlet, ident obj)
InletBinding for InletTypeFont.
Definition View+JSON.c:134
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:274
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:156
bool bindInlets(const Inlet *inlets, const Dictionary *dictionary)
Binds each Inlet specified in inlets to the data provided in dictionary.
Definition View+JSON.c:327
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:178
static void bindSize(const Inlet *inlet, ident obj)
InletBinding for InletTypeSize.
Definition View+JSON.c:201
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:216
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:307
static void bindSubviews(const Inlet *inlet, ident obj)
InletBinding for InletTypeSubviews.
Definition View+JSON.c:290
static void bindStyle(const Inlet *inlet, ident obj)
InletBinding for InletTypeStyle.
Definition View+JSON.c:267
@ InletTypeView
Definition View+JSON.h:139
#define BindInlet(inlet, obj)
Binds the Inlet to obj by invoking the appropriate InletBinding function.
Definition View+JSON.h:244
void(* InletBinding)(const Inlet *inlet, ident obj)
A function pointer for Inlet binding.
Definition View+JSON.h:186
#define MakeInlet(name, type, dest, data)
Creates an Inlet with the specified parameters.
Definition View+JSON.h:216
static void addClassName(View *self, const char *className)
Definition View.c:159
Class * _View(void)
Definition View.c:2067
static void replaceSubview(View *self, View *subview, View *replacement)
Definition View.c:1482
static void enumerate(View *self, ViewEnumerator enumerator, ident data)
Definition View.c:749
W3C Color constants.
Definition Colors.h:37
SDL_Color Black
Definition Colors.h:46
TrueType fonts.
Definition Font.h:63
Image loading.
Definition Image.h:38
Inlets enable inbound data binding of View attributes through JSON.
Definition View+JSON.h:155
const char * name
The Inlet name, e.g. "alignment".
Definition View+JSON.h:160
ident data
Type-specific data, e.g. an array of EnumNames.
Definition View+JSON.h:175
ident dest
The Inlet destination.
Definition View+JSON.h:170
Views are the fundamental building blocks of ObjectivelyMVC user interfaces.
Definition View.h:134
View * superview
The super View.
Definition View.h:259
View * init(View *self)
Initializes this View.
Definition Box.c:67