ObjectivelyMVC
Object oriented MVC framework for SDL3 and GNU C
Loading...
Searching...
No Matches
Button.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 "Button.h"
27
28#define _Class _Button
29
30#pragma mark - Object
31
35static void dealloc(Object *self) {
36
37 Button *this = (Button *) self;
38
39 memset(&this->delegate, 0, sizeof(this->delegate));
40
41 release(this->image);
42 release(this->title);
43
44 super(Object, self, dealloc);
45}
46
47#pragma mark - View
48
52static void awakeWithDictionary(View *self, const Dictionary *dictionary) {
53
54 super(View, self, awakeWithDictionary, dictionary);
55
56 Button *this = (Button *) self;
57
58 const Inlet inlets[] = MakeInlets(
59 MakeInlet("title", InletTypeView, &this->title, NULL),
60 MakeInlet("image", InletTypeImage, &this->image->image, NULL)
61 );
62
63 $(self, bind, inlets, dictionary);
64}
65
69static View *init(View *self) {
70 return (View *) $((Button *) self, initWithFrame, NULL);
71}
72
73#pragma mark - Control
74
78static bool captureEvent(Control *self, const SDL_Event *event) {
79
80 Button *this = (Button *) self;
81
82 View *view = (View *) self;
83
84 const bool didReceiveEvent = $(view, didReceiveEvent, event);
85
86 if (event->type == SDL_EVENT_MOUSE_BUTTON_DOWN) {
87 if (didReceiveEvent) {
89 }
90 return true;
91 }
92
93 if (event->type == SDL_EVENT_MOUSE_BUTTON_UP) {
94 $(view, resignKeyResponder);
95
96 self->state &= ~ControlStateHighlighted;
97 if (didReceiveEvent) {
98 if (event->button.clicks) {
99 if (this->delegate.didClick) {
100 this->delegate.didClick(this);
101 }
102 $(view, emitViewEvent, ViewEventClick, NULL);
103 }
104 }
105 return true;
106 }
107
108 if (event->type == SDL_EVENT_MOUSE_MOTION) {
109 if (self->state & ControlStateHighlighted) {
110 return true;
111 }
112 }
113
114 if (event->type == SDL_EVENT_KEY_DOWN) {
115 switch (event->key.key) {
116 case SDLK_SPACE:
117 case SDLK_KP_SPACE:
118 case SDLK_RETURN:
119 case SDLK_KP_ENTER:
120 if (this->delegate.didClick) {
121 this->delegate.didClick(this);
122 }
123 $(view, emitViewEvent, ViewEventClick, NULL);
124 return true;
125 default:
126 break;
127 }
128 }
129
130 return super(Control, self, captureEvent, event);
131}
132
133#pragma mark - Button
134
139static Button *initWithFrame(Button *self, const SDL_Rect *frame) {
140
141 self = (Button *) super(Control, self, initWithFrame, frame);
142 if (self) {
143
144 self->image = $(alloc(ImageView), initWithFrame, frame);
145 assert(self->image);
146
147 $((View *) self, addSubview, (View *) self->image);
148
149 self->title = $(alloc(Text), initWithText, NULL, NULL);
150 assert(self->title);
151
152 $((View *) self, addSubview, (View *) self->title);
153 }
154
155 return self;
156}
157
162static Button *initWithImage(Button *self, Image *image) {
163
164 self = $(self, initWithFrame, NULL);
165 if (self) {
166 $(self->image, setImage, image);
167 }
168 return self;
169}
170
175static Button *initWithTitle(Button *self, const char *title) {
176
177 self = $(self, initWithFrame, NULL);
178 if (self) {
179 $(self->title, setText, title);
180 }
181 return self;
182}
183
184#pragma mark - Class lifecycle
185
189static void initialize(Class *clazz) {
190
191 ((ObjectInterface *) clazz->interface)->dealloc = dealloc;
192
193 ((ViewInterface *) clazz->interface)->awakeWithDictionary = awakeWithDictionary;
194 ((ViewInterface *) clazz->interface)->init = init;
195
196 ((ControlInterface *) clazz->interface)->captureEvent = captureEvent;
197
198 ((ButtonInterface *) clazz->interface)->initWithFrame = initWithFrame;
199 ((ButtonInterface *) clazz->interface)->initWithImage = initWithImage;
200 ((ButtonInterface *) clazz->interface)->initWithTitle = initWithTitle;
201}
202
207Class *_Button(void) {
208 static Class *clazz;
209 static Once once;
210
211 do_once(&once, {
212 clazz = _initialize(&(const ClassDef) {
213 .name = "Button",
214 .superclass = _Control(),
215 .instanceSize = sizeof(Button),
216 .interfaceOffset = offsetof(Button, interface),
217 .interfaceSize = sizeof(ButtonInterface),
219 });
220 });
221
222 return clazz;
223}
224
225#undef _Class
static View * init(View *self)
Definition Button.c:69
static void awakeWithDictionary(View *self, const Dictionary *dictionary)
Definition Button.c:52
static Button * initWithTitle(Button *self, const char *title)
Definition Button.c:175
static bool captureEvent(Control *self, const SDL_Event *event)
Definition Button.c:78
static void dealloc(Object *self)
Definition Button.c:35
static Button * initWithImage(Button *self, Image *image)
Definition Button.c:162
static Button * initWithFrame(Button *self, const SDL_Rect *frame)
Definition Button.c:139
static void initialize(Class *clazz)
Definition Button.c:189
Class * _Button(void)
Definition Button.c:207
Buttons are Controls that respond to click events.
Class * _Control(void)
Definition Control.c:391
static void resignKeyResponder(View *self)
Definition Control.c:248
@ ControlStateHighlighted
Definition Control.h:67
static void setImage(ImageView *self, Image *image)
Definition ImageView.c:165
static Label * initWithText(Label *self, const char *text, Font *font)
Definition Label.c:97
static void addSubview(View *self, View *subview)
Definition PageView.c:49
static void setText(Text *self, const char *text)
Definition Text.c:534
@ ViewEventClick
A Control received one or more click events.
Definition Types.h:115
@ InletTypeImage
Definition View+JSON.h:90
@ InletTypeView
Definition View+JSON.h:139
#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
static bool didReceiveEvent(const View *self, const SDL_Event *event)
Definition View.c:657
static void emitViewEvent(View *self, ViewEvent code, ident data)
Definition View.c:725
Buttons are Controls that respond to click events.
Definition Button.h:68
Text * title
The title.
Definition Button.h:94
Button * initWithImage(Button *self, Image *image)
Initializes this Button with the sopecified Image.
Definition Button.c:162
Button * initWithTitle(Button *self, const char *title)
Initializes this Button with the specified title.
Definition Button.c:175
ImageView * image
The image.
Definition Button.h:89
Controls are Views which capture and respond to events.
Definition Control.h:83
unsigned int state
The bit mask of ControlState.
Definition Control.h:104
Image loading.
Definition Image.h:38
ImageViews render an Image in the context of a View hierarchy.
Definition ImageView.h:45
Inlets enable inbound data binding of View attributes through JSON.
Definition View+JSON.h:155
Text rendered with TrueType fonts.
Definition Text.h:69
Views are the fundamental building blocks of ObjectivelyMVC user interfaces.
Definition View.h:134
void awakeWithDictionary(View *, const Dictionary *)
Wakes this View with the specified Dictionary.
Definition Box.c:50
View * initWithFrame(View *self, const SDL_Rect *frame)
Initializes this View with the specified frame.
Definition View.c:978