ObjectivelyMVC 0.1.0
Object oriented MVC framework for OpenGL, SDL2 and GNU C
Style.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#include <stdlib.h>
26#include <string.h>
27
28#include <Objectively.h>
29
30#include "Style.h"
31
32#define _Class _Style
33
34#pragma mark - Object
35
39static void dealloc(Object *self) {
40
41 Style *this = (Style *) self;
42
43 release(this->attributes);
44 release(this->selectors);
45
46 super(Object, self, dealloc);
47}
48
52static String *description(const Object *self) {
53
54 const Style *this = (Style *) self;
55
56 return $((Array *) this->selectors, componentsJoinedByCharacters, ", ");
57}
58
62static int hash(const Object *self) {
63
64 Style *this = (Style *) self;
65
66 int hash = HASH_SEED;
67
68 hash = HashForObject(hash, this->attributes);
69 hash = HashForObject(hash, this->selectors);
70
71 return hash;
72}
73
77static _Bool isEqual(const Object *self, const Object *other) {
78
79 if (super(Object, self, isEqual, other)) {
80 return true;
81 }
82
83 if (other && $(other, isKindOfClass, _Style())) {
84
85 const Style *this = (Style *) self;
86 const Style *that = (Style *) other;
87
88 if ($((Object *) this->selectors, isEqual, (Object *) that->selectors)) {
89 return $((Object *) this->attributes, isEqual, (Object *) that->attributes);
90 }
91 }
92
93 return false;
94}
95
96#pragma mark - Style
97
102static void addAttribute(Style *self, const char *attr, ident value) {
103
104 assert(attr);
105 assert(value);
106
107 char *key = strtrim(attr);
108 assert(key);
109
110 $((MutableDictionary *) self->attributes, setObjectForKeyPath, value, key);
111
112 free(key);
113}
114
119static void addAttributes(Style *self, const Dictionary *attributes) {
120
121 assert(attributes);
122
123 $((MutableDictionary *) self->attributes, addEntriesFromDictionary, attributes);
124}
125
130static void addBoolAttribute(Style *self, const char *attr, _Bool value) {
131 $(self, addAttribute, attr, $$(Boole, valueof, value));
132}
133
138static void addCharactersAttribute(Style *self, const char *attr, const char *value) {
139
140 String *string = $$(String, stringWithCharacters, value);
141
142 $(self, addAttribute, attr, string);
143
144 release(string);
145}
146
151static void addColorAttribute(Style *self, const char *attr, const SDL_Color *color) {
152
153 Number *r = $$(Number, numberWithValue, color->r);
154 Number *g = $$(Number, numberWithValue, color->g);
155 Number *b = $$(Number, numberWithValue, color->b);
156 Number *a = $$(Number, numberWithValue, color->a);
157
158 Array *array = $$(Array, arrayWithObjects, r, g, b, a, NULL);
159
160 $(self, addAttribute, attr, array);
161
162 release(array);
163 release(r);
164 release(g);
165 release(b);
166 release(a);
167}
168
173static void addDoubleAttribute(Style *self, const char *attr, double value) {
174
175 Number *number = $$(Number, numberWithValue, value);
176
177 $(self, addAttribute, attr, number);
178
179 release(number);
180}
181
186static void addEnumAttribute(Style *self, const char *attr, const EnumName *names, int value) {
187
188 String *string = nameof(names, value);
189
190 $(self, addAttribute, attr, string);
191
192 release(string);
193}
194
199static void addFloatAttribute(Style *self, const char *attr, float value) {
200 $(self, addDoubleAttribute, attr, value);
201}
202
207static void addIntegerAttribute(Style *self, const char *attr, int value) {
208 $(self, addDoubleAttribute, attr, value);
209}
210
215static void addPointAttribute(Style *self, const char *attr, const SDL_Point *value) {
216
217 Number *x = $$(Number, numberWithValue, value->x);
218 Number *y = $$(Number, numberWithValue, value->y);
219
220 Array *array = $$(Array, arrayWithObjects, x, y, NULL);
221
222 $(self, addAttribute, attr, array);
223
224 release(array);
225 release(x);
226 release(y);
227}
228
233static void addRectangleAttribute(Style *self, const char *attr, const SDL_Rect *value) {
234
235 Number *x = $$(Number, numberWithValue, value->x);
236 Number *y = $$(Number, numberWithValue, value->y);
237 Number *w = $$(Number, numberWithValue, value->w);
238 Number *h = $$(Number, numberWithValue, value->h);
239
240 Array *array = $$(Array, arrayWithObjects, x, y, w, h, NULL);
241
242 $(self, addAttribute, attr, array);
243
244 release(array);
245 release(x);
246 release(y);
247 release(w);
248 release(h);
249}
250
255static void addSelector(Style *self, Selector *selector) {
256
257 assert(selector);
258
259 $((MutableArray *) self->selectors, addObject, selector);
260}
261
266static void addSizeAttribute(Style *self, const char *attr, const SDL_Size *value) {
267
268 Number *w = $$(Number, numberWithValue, value->w);
269 Number *h = $$(Number, numberWithValue, value->h);
270
271 Array *array = $$(Array, arrayWithObjects, w, h, NULL);
272
273 $(self, addAttribute, attr, array);
274
275 release(array);
276 release(w);
277 release(h);
278}
279
284static ident attributeValue(const Style *self, const char *attr) {
285 return $((Dictionary *) self->attributes, objectForKeyPath, attr);
286}
287
292static Style *initWithAttributes(Style *self, const Dictionary *attributes) {
293
294 self = $(self, initWithRules, NULL);
295 if (self) {
296 if (attributes) {
297 $(self, addAttributes, attributes);
298 }
299 }
300
301 return self;
302}
303
308static Style *initWithRules(Style *self, const char *rules) {
309
310 self = (Style *) super(Object, self, init);
311 if (self) {
312
313 self->selectors = $$(Selector, parse, rules);
314 assert(self->selectors);
315
316 for (size_t i = 0; i < self->selectors->count; i++) {
317 ((Selector *) self->selectors->elements[i])->style = self;
318 }
319
320 self->attributes = (Dictionary *) $$(MutableDictionary, dictionaryWithCapacity, 4);
321 assert(self->attributes);
322 }
323
324 return self;
325}
326
331static _Bool isComputedEqual(const Style *self, const Style *other) {
332
333 assert(other);
334
335 if (self->selectors->count == other->selectors->count) {
336
337 for (size_t i = 0; i < self->selectors->count; i++) {
338
339 const Selector *this = $(self->selectors, objectAtIndex, i);
340 const Selector *that = $(other->selectors, objectAtIndex, i);
341
342 if (strcmp(this->rule, that->rule)) {
343 return false;
344 }
345 }
346
347 return true;
348 }
349
350 return false;
351}
352
356static ident parseValue(String *string) {
357
358 ident value = NULL;
359
360 assert(string);
361
362 String *trimmed = $(string, trimmedString);
363 assert(trimmed);
364
365 StringReader *reader = $(alloc(StringReader), initWithString, trimmed);
366 assert(reader);
367
368 const Unicode *charset = L", \n\t";
369 Unicode stop;
370
371 String *token = $(reader, readToken, charset, &stop);
372 if (token) {
373
374 NumberFormatter *formatter = $(alloc(NumberFormatter), initWithFormat, NULL);
375 assert(formatter);
376
377 Number *number = $(formatter, numberFromString, token);
378
379 if (stop == READER_EOF) {
380
381 if (number) {
382 value = retain(number);
383 } else if (strcmp("true", token->chars) == 0) {
384 value = $$(Boole, True);
385 } else if (strcmp("false", token->chars) == 0) {
386 value = $$(Boole, False);
387 } else {
388 value = $((Object *) token, copy);
389 }
390
391 } else if (number) {
392 value = $$(MutableArray, arrayWithCapacity, 4);
393
394 while (token) {
395
396 $((MutableArray *) value, addObject, parseValue(token));
397 release(token);
398
399 token = $(reader, readToken, charset, NULL);
400 }
401 } else {
402 value = retain(trimmed);
403 }
404
405 release(number);
406 release(formatter);
407 release(token);
408 }
409
410 release(reader);
411 release(trimmed);
412
413 return value;
414}
415
420static Array *parse(const char *css) {
421
422 MutableArray *styles = $$(MutableArray, array);
423 assert(styles);
424
425 if (css) {
426
427 StringReader *reader = $(alloc(StringReader), initWithCharacters, css);
428 assert(reader);
429
430 Style *style = NULL;
431 char *attr = NULL;
432
433 while (true) {
434
435 const Unicode *charset = style ? L"{:;}" : L"{}";
436 Unicode stop;
437
438 String *token = $(reader, readToken, charset, &stop);
439 if (token) {
440 switch (stop) {
441 case '{':
442 style = $(alloc(Style), initWithRules, token->chars);
443 assert(style);
444 break;
445 case ':':
446 if (style) {
447 attr = strtrim(token->chars);
448 assert(attr);
449 }
450 break;
451 case ';':
452 if (style && attr) {
453
454 ident value = parseValue(token);
455 $(style, addAttribute, attr, value);
456
457 free(attr);
458 attr = NULL;
459
460 release(value);
461 }
462 break;
463 case '}':
464 if (style) {
465 $(styles, addObject, style);
466 style = release(style);
467 }
468 break;
469 }
470
471 release(token);
472 } else {
473 break;
474 }
475 }
476
477 release(reader);
478 }
479
480 return (Array *) styles;
481}
482
487static void removeAttribute(Style *self, const char *attr) {
488 $((MutableDictionary *) self->attributes, removeObjectForKeyPath, attr);
489}
490
495static void removeAllAttributes(Style *self) {
496 $((MutableDictionary *) self->attributes, removeAllObjects);
497}
498
499#pragma mark - Class lifecycle
500
504static void initialize(Class *clazz) {
505
506 ((ObjectInterface *) clazz->interface)->dealloc = dealloc;
507 ((ObjectInterface *) clazz->interface)->description = description;
508 ((ObjectInterface *) clazz->interface)->hash = hash;
509 ((ObjectInterface *) clazz->interface)->isEqual = isEqual;
510
511 ((StyleInterface *) clazz->interface)->addAttribute = addAttribute;
512 ((StyleInterface *) clazz->interface)->addAttributes = addAttributes;
513 ((StyleInterface *) clazz->interface)->addBoolAttribute = addBoolAttribute;
514 ((StyleInterface *) clazz->interface)->addCharactersAttribute = addCharactersAttribute;
515 ((StyleInterface *) clazz->interface)->addColorAttribute = addColorAttribute;
516 ((StyleInterface *) clazz->interface)->addDoubleAttribute = addDoubleAttribute;
517 ((StyleInterface *) clazz->interface)->addEnumAttribute = addEnumAttribute;
518 ((StyleInterface *) clazz->interface)->addFloatAttribute = addFloatAttribute;
519 ((StyleInterface *) clazz->interface)->addIntegerAttribute = addIntegerAttribute;
520 ((StyleInterface *) clazz->interface)->addPointAttribute = addPointAttribute;
521 ((StyleInterface *) clazz->interface)->addRectangleAttribute = addRectangleAttribute;
522 ((StyleInterface *) clazz->interface)->addSelector = addSelector;
523 ((StyleInterface *) clazz->interface)->addSizeAttribute = addSizeAttribute;
524 ((StyleInterface *) clazz->interface)->attributeValue = attributeValue;
525 ((StyleInterface *) clazz->interface)->initWithAttributes = initWithAttributes;
526 ((StyleInterface *) clazz->interface)->initWithRules = initWithRules;
527 ((StyleInterface *) clazz->interface)->isComputedEqual = isComputedEqual;
528 ((StyleInterface *) clazz->interface)->parse = parse;
529 ((StyleInterface *) clazz->interface)->removeAllAttributes = removeAllAttributes;
530 ((StyleInterface *) clazz->interface)->removeAttribute = removeAttribute;
531}
532
537Class *_Style(void) {
538 static Class *clazz;
539 static Once once;
540
541 do_once(&once, {
542 clazz = _initialize(&(const ClassDef) {
543 .name = "Style",
544 .superclass = _Object(),
545 .instanceSize = sizeof(Style),
546 .interfaceOffset = offsetof(Style, interface),
547 .interfaceSize = sizeof(StyleInterface),
549 });
550 });
551
552 return clazz;
553}
554
555#undef _Class
static String * description(const Object *self)
Definition: Style.c:52
static _Bool isEqual(const Object *self, const Object *other)
Definition: Style.c:77
static void dealloc(Object *self)
Definition: Style.c:39
static void initialize(Class *clazz)
Definition: Style.c:504
static ident parseValue(String *string)
Definition: Style.c:356
static int hash(const Object *self)
Definition: Style.c:62
The Style type.
CollectionView * init(CollectionView *self, const SDL_Rect *frame)
Initializes this CollectionView with the specified frame and style.
The SDL_Size type.
Definition: Types.h:62
int w
Definition: Types.h:63
int h
Definition: Types.h:63
Selectors are comprised of one or more SelectorSequences.
Definition: Selector.h:49
char * rule
The rule, as provided by the user.
Definition: Selector.h:70
Array * parse(const char *rules)
Parses the null-terminated C string of Selector rules into an Array of Selectors.
Definition: Selector.c:274
The Style type.
Definition: Style.h:43
void addSelector(Style *self, Selector *selector)
Adds the given Selector to this Style.
Definition: Style.c:255
Style * initWithAttributes(Style *self, const Dictionary *attributes)
Initializes this Style with the given attributes.
Definition: Style.c:292
_Bool isComputedEqual(const Style *self, const Style *other)
Performs a fast, rule-based comparison of this Style to the given Style.
Definition: Style.c:331
void addIntegerAttribute(Style *self, const char *attr, int value)
Adds or replaces the given attribute with value.
Definition: Style.c:207
void addSizeAttribute(Style *self, const char *attr, const SDL_Size *value)
Adds or replaces the given attribute with value.
Definition: Style.c:266
void removeAttribute(Style *self, const char *attr)
Removes the attribute with the given name.
Definition: Style.c:487
Array * selectors
The Selectors.
Definition: Style.h:64
void addEnumAttribute(Style *self, const char *attr, const EnumName *names, int value)
Adds or replaces the given attribute with value.
Definition: Style.c:186
void addPointAttribute(Style *self, const char *attr, const SDL_Point *value)
Adds or replaces the given attribute with value.
Definition: Style.c:215
void addRectangleAttribute(Style *self, const char *attr, const SDL_Rect *value)
Adds or replaces the given attribute with value.
Definition: Style.c:233
Style * initWithRules(Style *self, const char *rules)
Initializes this Style with the given CSS selector rules.
Definition: Style.c:308
void removeAllAttributes(Style *self)
Removes all attributes from this Style.
Definition: Style.c:495
void addFloatAttribute(Style *self, const char *attr, float value)
Adds or replaces the given attribute with value.
Definition: Style.c:199
void addAttribute(Style *self, const char *attr, ident value)
Adds or replaces the given attribute with value.
Definition: Style.c:102
Dictionary * attributes
Definition: Style.h:59
void addCharactersAttribute(Style *self, const char *attr, const char *value)
Adds or replaces the given attribute with value.
Definition: Style.c:138
void addAttributes(Style *self, const Dictionary *attributes)
Adds or replaces the attribtues in attributes to this Style.
Definition: Style.c:119
void addDoubleAttribute(Style *self, const char *attr, double value)
Adds or replaces the given attribute with value.
Definition: Style.c:173
Class * _Style(void)
The Style archetype.
Definition: Style.c:537
void addBoolAttribute(Style *self, const char *attr, _Bool value)
Adds or replaces the given attribute with value.
Definition: Style.c:130
ident attributeValue(const Style *self, const char *attr)
Definition: Style.c:284
void addColorAttribute(Style *self, const char *attr, const SDL_Color *value)
Adds or replaces the given attribute with value.
Definition: Style.c:151
Stylesheet * initWithCharacters(Stylesheet *self, const char *chars)
Initializes this Stylesheet with the given CSS definitions.
Definition: Stylesheet.c:124
Stylesheet * initWithString(Stylesheet *self, const String *string)
Initializes this Stylesheet with the CSS definitions in string.
Definition: Stylesheet.c:195