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 );
61
62 $(self, bind, inlets, dictionary);
63}
64
68static View *init(View *self) {
69 return (View *) $((Button *) self, initWithFrame, NULL);
70}
71
72#pragma mark - Control
73
77static bool captureEvent(Control *self, const SDL_Event *event) {
78
79 Button *this = (Button *) self;
80
81 View *view = (View *) self;
82
83 const bool didReceiveEvent = $(view, didReceiveEvent, event);
84
85 if (event->type == SDL_EVENT_MOUSE_BUTTON_DOWN) {
86 if (didReceiveEvent) {
88 }
89 return true;
90 }
91
92 if (event->type == SDL_EVENT_MOUSE_BUTTON_UP) {
93 $(view, resignKeyResponder);
94
95 self->state &= ~ControlStateHighlighted;
96 if (didReceiveEvent) {
97 if (event->button.clicks) {
98 if (this->delegate.didClick) {
99 this->delegate.didClick(this);
100 }
101 $(view, emitViewEvent, ViewEventClick, NULL);
102 }
103 }
104 return true;
105 }
106
107 if (event->type == SDL_EVENT_MOUSE_MOTION) {
108 if (self->state & ControlStateHighlighted) {
109 return true;
110 }
111 }
112
113 if (event->type == SDL_EVENT_KEY_DOWN) {
114 switch (event->key.key) {
115 case SDLK_SPACE:
116 case SDLK_KP_SPACE:
117 case SDLK_RETURN:
118 case SDLK_KP_ENTER:
119 if (this->delegate.didClick) {
120 this->delegate.didClick(this);
121 }
122 $(view, emitViewEvent, ViewEventClick, NULL);
123 return true;
124 default:
125 break;
126 }
127 }
128
129 return super(Control, self, captureEvent, event);
130}
131
132#pragma mark - Button
133
138static Button *initWithFrame(Button *self, const SDL_Rect *frame) {
139
140 self = (Button *) super(Control, self, initWithFrame, frame);
141 if (self) {
142
143 self->image = $(alloc(ImageView), initWithFrame, frame);
144 assert(self->image);
145
146 $((View *) self, addSubview, (View *) self->image);
147
148 self->title = $(alloc(Text), initWithText, NULL, NULL);
149 assert(self->title);
150
151 $((View *) self, addSubview, (View *) self->title);
152 }
153
154 return self;
155}
156
161static Button *initWithImage(Button *self, Image *image) {
162
163 self = $(self, initWithFrame, NULL);
164 if (self) {
165 $(self->image, setImage, image);
166 }
167 return self;
168}
169
174static Button *initWithTitle(Button *self, const char *title) {
175
176 self = $(self, initWithFrame, NULL);
177 if (self) {
178 $(self->title, setText, title);
179 }
180 return self;
181}
182
183#pragma mark - Class lifecycle
184
188static void initialize(Class *clazz) {
189
190 ((ObjectInterface *) clazz->interface)->dealloc = dealloc;
191
192 ((ViewInterface *) clazz->interface)->awakeWithDictionary = awakeWithDictionary;
193 ((ViewInterface *) clazz->interface)->init = init;
194
195 ((ControlInterface *) clazz->interface)->captureEvent = captureEvent;
196
197 ((ButtonInterface *) clazz->interface)->initWithFrame = initWithFrame;
198 ((ButtonInterface *) clazz->interface)->initWithImage = initWithImage;
199 ((ButtonInterface *) clazz->interface)->initWithTitle = initWithTitle;
200}
201
206Class *_Button(void) {
207 static Class *clazz;
208 static Once once;
209
210 do_once(&once, {
211 clazz = _initialize(&(const ClassDef) {
212 .name = "Button",
213 .superclass = _Control(),
214 .instanceSize = sizeof(Button),
215 .interfaceOffset = offsetof(Button, interface),
216 .interfaceSize = sizeof(ButtonInterface),
218 });
219 });
220
221 return clazz;
222}
223
224#undef _Class
static View * init(View *self)
Definition Button.c:68
static void awakeWithDictionary(View *self, const Dictionary *dictionary)
Definition Button.c:52
static Button * initWithTitle(Button *self, const char *title)
Definition Button.c:174
static bool captureEvent(Control *self, const SDL_Event *event)
Definition Button.c:77
static void dealloc(Object *self)
Definition Button.c:35
static Button * initWithImage(Button *self, Image *image)
Definition Button.c:161
static Button * initWithFrame(Button *self, const SDL_Rect *frame)
Definition Button.c:138
static void initialize(Class *clazz)
Definition Button.c:188
Class * _Button(void)
Definition Button.c:206
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:532
@ ViewEventClick
A Control received one or more click events.
Definition Types.h:115
@ 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:668
static void emitViewEvent(View *self, ViewEvent code, ident data)
Definition View.c:736
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:161
Button * initWithTitle(Button *self, const char *title)
Initializes this Button with the specified title.
Definition Button.c:174
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:989