ObjectivelyMVC
Object oriented MVC framework for SDL3 and GNU C
Loading...
Searching...
No Matches
DebugViewController.c
Go to the documentation of this file.
1/*
2 * ObjectivelyMVC: Object oriented MVC framework for SDL3 and 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
26#include <Objectively/String.h>
27
28#include "DebugViewController.h"
29#include "WindowController.h"
30
31#include "../Assets/debug.css.h"
32#include "../Assets/debug.json.h"
33
34#define _Class _DebugViewController
35
36#pragma mark - Selectors
37
41static size_t selectors_numberOfRows(const TableView *tableView) {
42
43 const DebugViewController *this = tableView->dataSource.self;
44 if (this->debug) {
45 return this->debug->computedStyle->selectors->count;
46 } else {
47 return 0;
48 }
49}
50
54static ident selectors_valueForColumnAndRow(const TableView *tableView, const TableColumn *column, size_t row) {
55
56 const DebugViewController *this = tableView->dataSource.self;
57 if (this->debug) {
58 return $(this->debug->computedStyle->selectors, objectAtIndex, row);
59 } else {
60 return NULL;
61 }
62}
63
67static TableCellView *selectors_cellForColumnAndRow(const TableView *tableView, const TableColumn *column, size_t row) {
68
69 const Selector *selector = tableView->dataSource.valueForColumnAndRow(tableView, column, row);
70 assert(selector);
71
72 TableCellView *cell = $(alloc(TableCellView), initWithFrame, NULL);
73 $(cell->text, setText, selector->rule);
74
75 return cell;
76}
77
78#pragma mark - Computed Style
79
83static size_t computedStyle_numberOfRows(const TableView *tableView) {
84
85 const DebugViewController *this = tableView->dataSource.self;
86 if (this->debug) {
87 return this->debug->computedStyle->attributes->count;
88 } else {
89 return 0;
90 }
91}
92
96static ident computedStyle_valueForColumnAndRow(const TableView *tableView, const TableColumn *column, size_t row) {
97
98 ident value = NULL;
99
100 const DebugViewController *this = tableView->dataSource.self;
101 if (this->debug) {
102
103 Array *array;
104 if (strcmp("Attribute", column->identifier) == 0) {
105 array = $(this->debug->computedStyle->attributes, allKeys);
106 } else {
107 array = $(this->debug->computedStyle->attributes, allObjects);
108 }
109
110 value = $(array, objectAtIndex, row);
111 release(array);
112 }
113
114 return value;
115}
116
120static TableCellView *computedStyle_cellForColumnAndRow(const TableView *tableView, const TableColumn *column, size_t row) {
121
122 ident value = tableView->dataSource.valueForColumnAndRow(tableView, column, row);
123 assert(value);
124
125 TableCellView *cell = $(alloc(TableCellView), initWithFrame, NULL);
126 String *description = $((Object *) value, description);
127 $(cell->text, setText, description->chars);
128 release(description);
129
130 return cell;
131}
132
133#pragma mark - Warnings
134
138static size_t warnings_numberOfRows(const TableView *tableView) {
139
140 const DebugViewController *this = tableView->dataSource.self;
141 if (this->debug) {
142 return this->debug->warnings->count;
143 } else {
144 return 0;
145 }
146}
147
151static ident warnings_valueForColumnAndRow(const TableView *tableView, const TableColumn *column, size_t row) {
152
153 ident value = NULL;
154
155 const DebugViewController *this = tableView->dataSource.self;
156 if (this->debug) {
157 value = $((Array *) this->debug->warnings, objectAtIndex, row);
158 }
159
160 return value;
161}
162
166static TableCellView *warnings_cellForColumnAndRow(const TableView *tableView, const TableColumn *column, size_t row) {
167
168 Warning *warning = tableView->dataSource.valueForColumnAndRow(tableView, column, row);
169 assert(warning);
170
171 TableCellView *cell = $(alloc(TableCellView), initWithFrame, NULL);
172 $(cell->text, setText, warning->message->chars);
173
174 return cell;
175}
176
177#pragma mark - ViewController
178
182static void loadView(ViewController *self) {
183
184 super(ViewController, self, loadView);
185
187
188 Outlet outlets[] = MakeOutlets(
189 MakeOutlet("statistics", &this->statistics),
190 MakeOutlet("description", &this->description),
191 MakeOutlet("path", &this->path),
192 MakeOutlet("selectors", &this->selectors),
193 MakeOutlet("computedStyle", &this->computedStyle),
194 MakeOutlet("warnings", &this->warnings)
195 );
196
197 View *view = $$(View, viewWithCharacters, (char *) debug_json, outlets);
198 view->stylesheet = $$(Stylesheet, stylesheetWithCharacters, (char *) debug_css);
199
200 $(self, setView, view);
201 release(view);
202
203 this->selectors->dataSource.self = self;
204 this->selectors->dataSource.numberOfRows = selectors_numberOfRows;
205 this->selectors->dataSource.valueForColumnAndRow = selectors_valueForColumnAndRow;
206 this->selectors->delegate.self = self;
207 this->selectors->delegate.cellForColumnAndRow = selectors_cellForColumnAndRow;
208
209 this->computedStyle->dataSource.self = self;
210 this->computedStyle->dataSource.numberOfRows = computedStyle_numberOfRows;
211 this->computedStyle->dataSource.valueForColumnAndRow = computedStyle_valueForColumnAndRow;
212 this->computedStyle->delegate.self = self;
213 this->computedStyle->delegate.cellForColumnAndRow = computedStyle_cellForColumnAndRow;
214
215 this->warnings->dataSource.self = self;
216 this->warnings->dataSource.numberOfRows = warnings_numberOfRows;
217 this->warnings->dataSource.valueForColumnAndRow = warnings_valueForColumnAndRow;
218 this->warnings->delegate.self = self;
219 this->warnings->delegate.cellForColumnAndRow = warnings_cellForColumnAndRow;
220}
221
222#pragma mark - DebugViewController
223
227static void debugEnumerate(View *view, ident data) {
228
229 DebugViewController *this = data;
230
231 if (view == this->debug) {
232 const SDL_Rect frame = $(view, renderFrame);
233
234 $(this->renderer, setClippingFrame, NULL);
235 $(this->renderer, drawRectFilled, &frame, &MakeColor(0x22, 0x66, 0x99, 0x88));
236 }
237
238 if ($(view, isVisible)) {
239 this->visibleViews++;
240
241 // FIXME: This is a bit gaff. But hasOverflow produces false positives if called at the
242 // FIXME: end of layoutSubviews, because containers have not yet been resized to fill their
243 // FIXME: parent (e.g. autoresizing-mask: contain | width).
244 // FIXME: Ideally, warnings are accumulated during layoutSubviews and applyTheme, instead
245 // FIXME: of attempting to collect them here.
246
247 $(view, clearWarnings, (WarningType) 0xff);
248 $(view, hasOverflow);
249
250 const Array *warnings = (Array *) view->warnings;
251 if (warnings->count) {
252 const SDL_Rect frame = $(view, renderFrame);
253
254 $(this->renderer, setClippingFrame, NULL);
255 $(this->renderer, drawRect, &frame, &Colors.DarkGoldenRod);
256 }
257 }
258}
259
264static void debug(DebugViewController *self, const View *view, Renderer *renderer) {
265
266 if (view != self->debug) {
267 self->debug = view;
268
269 if (self->debug) {
270 self->root = self->debug;
271 while (self->root->superview) {
272 self->root = self->root->superview;
273 }
274
275 String *path = $(self->debug, path);
276 $(self->path, setText, path->chars);
277 release(path);
278
279 String *description = $((Object *) view, description);
280 $(self->description, setText, description->chars);
281 release(description);
282 } else {
283 $(self->path, setText, NULL);
284 $(self->description, setText, NULL);
285 }
286
287 $(self->selectors, reloadData);
288 $((View *) self->selectors, sizeToFit);
289
290 $(self->computedStyle, reloadData);
291 $((View *) self->computedStyle, sizeToFit);
292
293 $(self->warnings, reloadData);
294 $((View *) self->warnings, sizeToFit);
295 }
296
297 self->renderer = renderer;
298 assert(self->renderer);
299
300 self->visibleViews = 0;
301
302 if (self->root) {
303 $((View *) self->root, enumerate, debugEnumerate, self);
304 }
305
306 self->frames++;
307 if (SDL_GetTicks() - self->timestamp >= 1000) {
308
309 $(self->statistics, setTextWithFormat, "%d views, %dfps", self->visibleViews, self->frames);
310
311 self->timestamp = SDL_GetTicks();
312 self->frames = 0;
313 }
314}
315
321 return (DebugViewController *) super(ViewController, self, init);
322}
323
324#pragma mark - Class lifecycle
325
329static void initialize(Class *clazz) {
330
331 ((ViewControllerInterface *) clazz->interface)->loadView = loadView;
332
333 ((DebugViewControllerInterface *) clazz->interface)->debug = debug;
334 ((DebugViewControllerInterface *) clazz->interface)->init = init;
335}
336
342 static Class *clazz;
343 static Once once;
344
345 do_once(&once, {
346 clazz = _initialize(&(const ClassDef) {
347 .name = "DebugViewController",
348 .superclass = _ViewController(),
349 .instanceSize = sizeof(DebugViewController),
350 .interfaceOffset = offsetof(DebugViewController, interface),
351 .interfaceSize = sizeof(DebugViewControllerInterface),
353 });
354 });
355
356 return clazz;
357}
358
359#undef _Class
static Box * initWithFrame(Box *self, const SDL_Rect *frame)
Definition Box.c:92
static void reloadData(CollectionView *self)
Class * _DebugViewController(void)
static void debugEnumerate(View *view, ident data)
static void loadView(ViewController *self)
static TableCellView * selectors_cellForColumnAndRow(const TableView *tableView, const TableColumn *column, size_t row)
static ident warnings_valueForColumnAndRow(const TableView *tableView, const TableColumn *column, size_t row)
static ident computedStyle_valueForColumnAndRow(const TableView *tableView, const TableColumn *column, size_t row)
static TableCellView * warnings_cellForColumnAndRow(const TableView *tableView, const TableColumn *column, size_t row)
static DebugViewController * init(DebugViewController *self)
static size_t computedStyle_numberOfRows(const TableView *tableView)
static TableCellView * computedStyle_cellForColumnAndRow(const TableView *tableView, const TableColumn *column, size_t row)
static void debug(DebugViewController *self, const View *view, Renderer *renderer)
static size_t selectors_numberOfRows(const TableView *tableView)
static void initialize(Class *clazz)
static ident selectors_valueForColumnAndRow(const TableView *tableView, const TableColumn *column, size_t row)
static size_t warnings_numberOfRows(const TableView *tableView)
The DebugViewController type.
static String * description(const Object *self)
Definition Label.c:47
static void setClippingFrame(Renderer *self, const SDL_Rect *clippingFrame)
Definition Renderer.c:482
static void drawRectFilled(const Renderer *self, const SDL_Rect *rect, const SDL_Color *color)
Definition Renderer.c:188
static void drawRect(const Renderer *self, const SDL_Rect *rect, const SDL_Color *color)
Definition Renderer.c:169
static Stylesheet * stylesheetWithCharacters(const char *chars)
Definition Stylesheet.c:206
static void setTextWithFormat(Text *self, const char *fmt,...)
Definition Text.c:558
static void setText(Text *self, const char *text)
Definition Text.c:532
#define MakeOutlet(identifier, view)
Creates an Outlet with the specified parameters.
Definition View+JSON.h:230
#define MakeOutlets(...)
Creates a NULL-termianted array of Outlets.
Definition View+JSON.h:235
static String * path(const View *self)
Definition View.c:1277
static void clearWarnings(const View *self, WarningType type)
Definition View.c:538
static bool isVisible(const View *self)
Definition View.c:1093
static bool hasOverflow(const View *self)
Definition View.c:939
static SDL_Rect renderFrame(const View *self)
Definition View.c:1455
static View * viewWithCharacters(const char *chars, Outlet *outlets)
Definition View.c:1829
static void enumerate(View *self, ViewEnumerator enumerator, ident data)
Definition View.c:749
static void sizeToFit(View *self)
Definition View.c:1767
Class * _ViewController(void)
static void setView(ViewController *self, View *view)
WarningType
Warning types.
Definition Warning.h:33
A WindowController manages a ViewController and its descendants within an SDL_Window.
W3C Color constants.
Definition Colors.h:37
SDL_Color DarkGoldenRod
Definition Colors.h:63
The DebugViewController type.
TableView * selectors
The CSS selectors matching the View.
const View * debug
The View to debug.
TableView * computedStyle
The computed style of the View.
int visibleViews
The count of visibile Views.
Renderer * renderer
A weak referece to the current WindowController's renderer.
TableView * warnings
The warnings generated by the View.
Text * description
The View description.
const View * root
The root ancestor of the debug View.
Text * path
The path to the debug View.
Outlets enable outbound data binding of Views through JSON.
Definition View+JSON.h:200
Renderer extends Object with ObjectivelyMVC's UI rendering layer.
Definition Renderer.h:70
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
Stylesheets are comprised of Selectors and Styles.
Definition Stylesheet.h:44
Each row in a TableView is comprised of TableCellViews.
Text * text
The text.
Columns provide alignment, spacing and sorting hints for TableView instances.
Definition TableColumn.h:45
char * identifier
The identifier.
Definition TableColumn.h:66
ident self
The data source self-reference.
Definition TableView.h:61
ident(* valueForColumnAndRow)(const TableView *tableView, const TableColumn *column, size_t row)
Called by the TableView for the associated value of a cell.
Definition TableView.h:76
TableViews provide sortable, tabular presentations of data.
Definition TableView.h:122
TableViewDataSource dataSource
The data source.
Definition TableView.h:148
A ViewController manages a View and its descendants.
Views are the fundamental building blocks of ObjectivelyMVC user interfaces.
Definition View.h:134
Stylesheet * stylesheet
An optional Stylesheet.
Definition View.h:248
View * superview
The super View.
Definition View.h:259
Array * warnings
The Warnings this View generated.
Definition View.h:271
The Warning type.
Definition Warning.h:50
String * message
The message.
Definition Warning.h:71