ObjectivelyMVC 0.1.0
Object oriented MVC framework for OpenGL, SDL2 and GNU C
Text.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 <stdarg.h>
26#include <string.h>
27
28#include "Text.h"
29
30#define _Class _Text
31
32#pragma mark - ObjectInterface
33
37static void dealloc(Object *self) {
38
39 Text *this = (Text *) self;
40
41 release(this->font);
42
43 free(this->text);
44
45 if (this->texture) {
46 glDeleteTextures(1, &this->texture);
47 }
48
49 super(Object, self, dealloc);
50}
51
55static String *description(const Object *self) {
56
57 View *this = (View *) self;
58
59 String *classNames = $((Object *) this->classNames, description);
60 String *description = str("%s@%p \"%s\" %s [%d, %d, %d, %d]",
61 this->identifier ?: classnameof(self),
62 self,
63 ((Text *) self)->text,
64 classNames->chars,
65 this->frame.x, this->frame.y, this->frame.w, this->frame.h);
66
67 release(classNames);
68 return description;
69}
70
71#pragma mark - View
72
76static void applyStyle(View *self, const Style *style) {
77
78 super(View, self, applyStyle, style);
79
80 Text *this = (Text *) self;
81
82 const Inlet inlets[] = MakeInlets(
83 MakeInlet("color", InletTypeColor, &this->color, NULL)
84 );
85
86 $(self, bind, inlets, style->attributes);
87
88 char *fontFamily = NULL;
89 int fontSize = -1, fontStyle = -1;
90
91 const Inlet fontInlets[] = MakeInlets(
92 MakeInlet("font-family", InletTypeCharacters, &fontFamily, NULL),
93 MakeInlet("font-size", InletTypeInteger, &fontSize, NULL),
94 MakeInlet("font-style", InletTypeEnum, &fontStyle, (ident) FontStyleNames)
95 );
96
97 if ($(self, bind, fontInlets, style->attributes)) {
98
99 Font *font = $$(Font, cachedFont, fontFamily , fontSize, fontStyle);
100 assert(font);
101
102 $(this, setFont, font);
103
104 if (fontFamily) {
105 free(fontFamily);
106 }
107 }
108}
109
113static void awakeWithDictionary(View *self, const Dictionary *dictionary) {
114
115 super(View, self, awakeWithDictionary, dictionary);
116
117 Text *this = (Text *) self;
118
119 const Inlet inlets[] = MakeInlets(
120 MakeInlet("color", InletTypeColor, &this->color, NULL),
121 MakeInlet("font", InletTypeFont, &this->font, NULL),
122 MakeInlet("lineWrap", InletTypeBool, &this->lineWrap, NULL),
123 MakeInlet("text", InletTypeCharacters, &this->text, NULL)
124 );
125
126 $(self, bind, inlets, dictionary);
127}
128
132static View *init(View *self) {
133 return (View *) $((Text *) self, initWithText, NULL, NULL);
134}
135
139static void render(View *self, Renderer *renderer) {
140
141 super(View, self, render, renderer);
142
143 Text *this = (Text *) self;
144
145 assert(this->font);
146
147 if (this->text) {
148
149 const SDL_Rect frame = $(self, renderFrame);
150
151 if (this->texture == 0) {
152 SDL_Surface *surface = $(this->font, renderCharacters,
153 this->text,
154 this->color,
155 this->lineWrap ? frame.w : 0);
156 assert(surface);
157
158 this->texture = $(renderer, createTexture, surface);
159
160 SDL_FreeSurface(surface);
161 }
162
163 assert(this->texture);
164
165 $(renderer, drawTexture, this->texture, &frame);
166 }
167}
168
172static void renderDeviceDidReset(View *self) {
173
174 Text *this = (Text *) self;
175
176 $(this->font, renderDeviceDidReset);
177
178 super(View, self, renderDeviceDidReset);
179}
180
184static void renderDeviceWillReset(View *self) {
185
186 Text *this = (Text *) self;
187
188 if (this->texture) {
189 glDeleteTextures(1, &this->texture);
190 this->texture = 0;
191 }
192
193 super(View, self, renderDeviceWillReset);
194}
195
199static SDL_Size sizeThatFits(const View *self) {
200 return $((Text *) self, naturalSize);
201}
202
203#pragma mark - Text
204
209static Text *initWithText(Text *self, const char *text, Font *font) {
210
211 self = (Text *) super(View, self, initWithFrame, NULL);
212 if (self) {
213 $(self, setFont, font);
214 $(self, setText, text);
215 }
216
217 return self;
218}
219
224static SDL_Size naturalSize(const Text *self) {
225
226 SDL_Size size = MakeSize(0, 0);
227
228 if (self->font) {
229 $(self->font, sizeCharacters, self->text ?: "", &size.w, &size.h);
230 }
231
232 return size;
233}
234
239static void setFont(Text *self, Font *font) {
240
241 font = font ?: $$(Font, defaultFont);
242
243 if (font != self->font) {
244
245 release(self->font);
246 self->font = retain(font);
247
248 if (self->texture) {
249 glDeleteTextures(1, &self->texture);
250 self->texture = 0;
251 }
252
253 $((View *) self, sizeToFit);
254 }
255}
256
261static void setText(Text *self, const char *text) {
262
263 if (strcmp(self->text ?: "", text ?: "")) {
264
265 free(self->text);
266
267 if (text && strlen(text)) {
268 self->text = strdup(text);
269 } else {
270 self->text = NULL;
271 }
272
273 if (self->texture) {
274 glDeleteTextures(1, &self->texture);
275 self->texture = 0;
276 }
277
278 $((View *) self, sizeToFit);
279 }
280}
281
289static void setTextWithFormat(Text *self, const char *fmt, ...) {
290
291 va_list args;
292 va_start(args, fmt);
293
294 char *text;
295 const int len = vasprintf(&text, fmt, args);
296 if (len >= 0) {
297 $(self, setText, text);
298 }
299
300 free(text);
301 va_end(args);
302}
303
304#pragma mark - Class lifecycle
305
309static void initialize(Class *clazz) {
310
311 ((ObjectInterface *) clazz->interface)->dealloc = dealloc;
312 ((ObjectInterface *) clazz->interface)->description = description;
313
314 ((ViewInterface *) clazz->interface)->applyStyle = applyStyle;
315 ((ViewInterface *) clazz->interface)->awakeWithDictionary = awakeWithDictionary;
316 ((ViewInterface *) clazz->interface)->init = init;
317 ((ViewInterface *) clazz->interface)->render = render;
318 ((ViewInterface *) clazz->interface)->renderDeviceDidReset = renderDeviceDidReset;
319 ((ViewInterface *) clazz->interface)->renderDeviceWillReset = renderDeviceWillReset;
320 ((ViewInterface *) clazz->interface)->sizeThatFits = sizeThatFits;
321
322 ((TextInterface *) clazz->interface)->initWithText = initWithText;
323 ((TextInterface *) clazz->interface)->naturalSize = naturalSize;
324 ((TextInterface *) clazz->interface)->setFont = setFont;
325 ((TextInterface *) clazz->interface)->setText = setText;
326 ((TextInterface *) clazz->interface)->setTextWithFormat = setTextWithFormat;
327}
328
333Class *_Text(void) {
334 static Class *clazz;
335 static Once once;
336
337 do_once(&once, {
338 clazz = _initialize(&(const ClassDef) {
339 .name = "Text",
340 .superclass = _View(),
341 .instanceSize = sizeof(Text),
342 .interfaceOffset = offsetof(Text, interface),
343 .interfaceSize = sizeof(TextInterface),
345 });
346 });
347
348 return clazz;
349}
350
351#undef _Class
const EnumName FontStyleNames[]
Definition: Font.c:38
static String * description(const Object *self)
Definition: Text.c:55
static void dealloc(Object *self)
Definition: Text.c:37
static void initialize(Class *clazz)
Definition: Text.c:309
Text rendered with TrueType fonts.
#define MakeSize(w, h)
Creates an SDL_Size with the given dimensions.
Definition: Types.h:79
@ InletTypeEnum
Definition: View+JSON.h:75
@ InletTypeCharacters
Definition: View+JSON.h:52
@ InletTypeBool
Definition: View+JSON.h:46
@ InletTypeFont
Definition: View+JSON.h:85
@ InletTypeInteger
Definition: View+JSON.h:95
@ InletTypeColor
Definition: View+JSON.h:62
#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
Box * initWithFrame(Box *self, const SDL_Rect *frame)
Initializes this Box with the given frame.
Definition: Box.c:92
SDL_Size naturalSize(const CollectionView *self)
CollectionView * init(CollectionView *self, const SDL_Rect *frame)
Initializes this CollectionView with the specified frame and style.
TrueType fonts.
Definition: Font.h:63
Font * cachedFont(const char *family, int size, int style)
Resolves the cached Font with the given attributes.
Definition: Font.c:124
void renderCharacters(const Font *self, const char *chars, SDL_Color color, int wrapWidth)
Renders the given characters in this Font.
Definition: Font.c:223
void renderDeviceDidReset(Font *self)
This method should be invoked when the render context is invalidated.
Definition: Font.c:247
Font * defaultFont(void)
Definition: Font.c:178
void sizeCharacters(const Font *self, const char *chars, int *w, int *h)
Definition: Font.c:272
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
Label * initWithText(Label *self, const char *text, Font *font)
Initializes this Label with the given text and Font.
Definition: Label.c:96
The Renderer is responsible for rasterizing the View hierarchy of a WindowController.
Definition: Renderer.h:50
GLuint createTexture(const Renderer *self, const SDL_Surface *surface)
Generates and binds to an OpenGL texture object, uploading the given surface.
Definition: Renderer.c:56
void renderDeviceWillReset(Renderer *self)
This method is invoked when the render device will become reset.
Definition: Renderer.c:252
void drawTexture(const Renderer *self, GLuint texture, const SDL_Rect *dest)
Draws a textured GL_QUAD in the given rectangle.
Definition: Renderer.c:155
The SDL_Size type.
Definition: Types.h:62
int w
Definition: Types.h:63
int h
Definition: Types.h:63
The Style type.
Definition: Style.h:43
Dictionary * attributes
Definition: Style.h:59
Text rendered with TrueType fonts.
Definition: Text.h:41
Class * _Text(void)
Definition: Text.c:333
void setFont(Text *self, Font *font)
Sets this Text's font.
Definition: Text.c:239
void setTextWithFormat(Text *self, const char *fmt,...)
Sets this Text's text with the given format string.
Definition: Text.c:289
GLuint texture
The rendered texture.
Definition: Text.h:82
void setText(Text *self, const char *text)
Sets this Text's text.
Definition: Text.c:261
Font * font
The Font.
Definition: Text.h:64
char * text
The text.
Definition: Text.h:76
Views are the fundamental building blocks of ObjectivelyMVC user interfaces.
Definition: View.h:133
_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
void applyStyle(View *self, const Style *style)
Applies the given Style to this View.
void sizeThatFits(const View *self)
void awakeWithDictionary(View *self, const Dictionary *dictionary)
Wakes this View with the specified Dictionary.
Definition: Box.c:50
SDL_Rect renderFrame(const View *self)
Definition: View.c:1275
void render(View *self, Renderer *renderer)
Renders this View using the given renderer.
Definition: Control.c:131
void sizeToFit(View *self)
Resizes this View to fit its subviews.
Definition: View.c:1496