ObjectivelyMVC
Object oriented MVC framework for SDL3 and GNU C
Loading...
Searching...
No Matches
Slider.c File Reference
#include <assert.h>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "Colors.h"
#include "Log.h"
#include "Slider.h"

Go to the source code of this file.

Macros

#define _Class   _Slider
 

Functions

Class * _Slider (void)
 
static void awakeWithDictionary (View *self, const Dictionary *dictionary)
 
static bool captureEvent (Control *self, const SDL_Event *event)
 
static void dealloc (Object *self)
 
static void formatLabel (Slider *self)
 
static Viewinit (View *self)
 
static void initialize (Class *clazz)
 
static SliderinitWithFrame (Slider *self, const SDL_Rect *frame)
 
static void layoutSubviews (View *self)
 
static void render (View *self, Renderer *renderer)
 
static void setLabelFormat (Slider *self, const char *labelFormat)
 
static void setValue (Slider *self, double value)
 

Macro Definition Documentation

◆ _Class

#define _Class   _Slider

Definition at line 34 of file Slider.c.

Function Documentation

◆ _Slider()

Class * _Slider ( void  )

Definition at line 344 of file Slider.c.

344 {
345 static Class *clazz;
346 static Once once;
347
348 do_once(&once, {
349 clazz = _initialize(&(const ClassDef) {
350 .name = "Slider",
351 .superclass = _Control(),
352 .instanceSize = sizeof(Slider),
353 .interfaceOffset = offsetof(Slider, interface),
354 .interfaceSize = sizeof(SliderInterface),
356 });
357 });
358
359 return clazz;
360}
Class * _Control(void)
Definition Control.c:391
static void initialize(Class *clazz)
Definition Slider.c:323
A Control allowing users to drag a handle to select a numeric value.
Definition Slider.h:62

◆ awakeWithDictionary()

static void awakeWithDictionary ( View self,
const Dictionary *  dictionary 
)
static
See also
View::awakeWithDictionary(View *, const Dictionary *)

Definition at line 61 of file Slider.c.

61 {
62
63 super(View, self, awakeWithDictionary, dictionary);
64
65 Slider *this = (Slider *) self;
66
67 double value = this->value;
68
69 const Inlet inlets[] = MakeInlets(
70 MakeInlet("bar", InletTypeView, &this->bar, NULL),
71 MakeInlet("handle", InletTypeView, &this->handle, NULL),
72 MakeInlet("label", InletTypeView, &this->label, NULL),
73 MakeInlet("labelFormat", InletTypeCharacters, &this->labelFormat, NULL),
74 MakeInlet("min", InletTypeDouble, &this->min, NULL),
75 MakeInlet("max", InletTypeDouble, &this->max, NULL),
76 MakeInlet("snapToStep", InletTypeBool, &this->snapToStep, NULL),
77 MakeInlet("step", InletTypeDouble, &this->step, NULL),
78 MakeInlet("value", InletTypeDouble, &value, NULL)
79 );
80
81 $(self, bind, inlets, dictionary);
82
83 $(this, setValue, value);
84}
static void setValue(Slider *self, double value)
Definition Slider.c:305
static void awakeWithDictionary(View *self, const Dictionary *dictionary)
Definition Slider.c:61
@ InletTypeDouble
Definition View+JSON.h:67
@ InletTypeCharacters
Definition View+JSON.h:52
@ InletTypeBool
Definition View+JSON.h:46
@ 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
Inlets enable inbound data binding of View attributes through JSON.
Definition View+JSON.h:155
Views are the fundamental building blocks of ObjectivelyMVC user interfaces.
Definition View.h:134

◆ captureEvent()

static bool captureEvent ( Control self,
const SDL_Event *  event 
)
static
See also
Control::captureEvent(Control *, const SDL_Event *)

Definition at line 153 of file Slider.c.

153 {
154
155 Slider *this = (Slider *) self;
156
157 const SDL_Rect frame = $((View *) this->bar, renderFrame);
158
159 if (event->type == SDL_EVENT_MOUSE_BUTTON_DOWN) {
160
161 // The handle captures mouse motion events allowing the user to drag it
162 // However, the user may also click left or right of the handle to decrement
163 // or increment the value
164
165 if ($((View *) this->handle, didReceiveEvent, event)) {
167 } else {
168 const int x = event->button.x - frame.x;
169 const double step = this->step ?: (this->max - this->min) / 20.0;
170
171 $(this, setValue, this->value + (x > this->handle->frame.x ? step : -step));
172
173 if (this->delegate.didSetValue) {
174 this->delegate.didSetValue(this, this->value);
175 }
176 }
177 return true;
178 }
179
180 else if (event->type == SDL_EVENT_MOUSE_BUTTON_UP) {
181 if (self->state & ControlStateHighlighted) {
182 self->state &= ~ControlStateHighlighted;
183 }
184 return true;
185 }
186
187 else if (event->type == SDL_EVENT_MOUSE_MOTION) {
188 if (self->state & ControlStateHighlighted) {
189 if (frame.w) {
190
191 const double fraction = (double) (event->motion.x - frame.x) / (double) frame.w;
192 double value = this->min + (this->max - this->min) * clamp(fraction, 0.0, 1.0);
193
194 if (this->snapToStep && this->step) {
195 value = clamp(round(value / this->step) * this->step, this->min, this->max);
196 }
197
198 const double delta = fabs(this->value - value);
199 if (delta > __DBL_EPSILON__) {
200 $(this, setValue, value);
201
202 if (this->delegate.didSetValue) {
203 this->delegate.didSetValue(this, this->value);
204 }
205 }
206
207 }
208 }
209 return true;
210 }
211
212 if (event->type == SDL_EVENT_KEY_DOWN) {
213
214 double step = 0.0;
215 switch (event->key.key) {
216 case SDLK_LEFT:
217 step = -this->step ?: -(this->max - this->min) / 20.0;
218 break;
219 case SDLK_RIGHT:
220 step = this->step ?: (this->max - this->min) / 20.0;
221 break;
222 }
223
224 if (step) {
225 $(this, setValue, this->value + step);
226
227 if (this->delegate.didSetValue) {
228 this->delegate.didSetValue(this, this->value);
229 }
230 return true;
231 }
232 }
233
234 return super(Control, self, captureEvent, event);
235}
@ ControlStateHighlighted
Definition Control.h:67
static bool captureEvent(Control *self, const SDL_Event *event)
Definition Slider.c:153
static bool didReceiveEvent(const View *self, const SDL_Event *event)
Definition View.c:668
static SDL_Rect renderFrame(const View *self)
Definition View.c:1455
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
SDL_Rect frame
The frame, relative to the superview.
Definition View.h:191

◆ dealloc()

static void dealloc ( Object *  self)
static
See also
Object::dealloc(Object *)

Definition at line 41 of file Slider.c.

41 {
42
43 Slider *this = (Slider *) self;
44
45 memset(&this->delegate, 0, sizeof(this->delegate));
46
47 release(this->bar);
48 release(this->handle);
49 release(this->label);
50
51 free(this->labelFormat);
52
53 super(Object, self, dealloc);
54}
static void dealloc(Object *self)
Definition Slider.c:41

◆ formatLabel()

static void formatLabel ( Slider self)
static

Definition at line 243 of file Slider.c.

243 {
244
245 char text[64];
246 snprintf(text, sizeof(text), self->labelFormat, self->value);
247
248 $(self->label, setText, text);
249}
static void setText(Text *self, const char *text)
Definition Text.c:532
Text * label
The Text displaying the current value.
Definition Slider.h:94
char * labelFormat
The label format, e.g. "%0.01f".
Definition Slider.h:99
double value
The slider value.
Definition Slider.h:119

◆ init()

static View * init ( View self)
static
See also
View::init(View *)

Definition at line 89 of file Slider.c.

89 {
90 return (View *) $((Slider *) self, initWithFrame, NULL);
91}
static Slider * initWithFrame(Slider *self, const SDL_Rect *frame)
Definition Slider.c:255

◆ initialize()

static void initialize ( Class *  clazz)
static
See also
Class::initialize(Class *)

Definition at line 323 of file Slider.c.

323 {
324
325 ((ObjectInterface *) clazz->interface)->dealloc = dealloc;
326
327 ((ViewInterface *) clazz->interface)->awakeWithDictionary = awakeWithDictionary;
328 ((ViewInterface *) clazz->interface)->init = init;
329 ((ViewInterface *) clazz->interface)->layoutSubviews = layoutSubviews;
330 ((ViewInterface *) clazz->interface)->render = render;
331
332 ((ControlInterface *) clazz->interface)->captureEvent = captureEvent;
333
334 ((SliderInterface *) clazz->interface)->formatLabel = formatLabel;
335 ((SliderInterface *) clazz->interface)->initWithFrame = initWithFrame;
336 ((SliderInterface *) clazz->interface)->setValue = setValue;
337 ((SliderInterface *) clazz->interface)->setLabelFormat = setLabelFormat;
338}
static void setLabelFormat(Slider *self, const char *labelFormat)
Definition Slider.c:291
static View * init(View *self)
Definition Slider.c:89
static void render(View *self, Renderer *renderer)
Definition Slider.c:132
static void layoutSubviews(View *self)
Definition Slider.c:96
static void formatLabel(Slider *self)
Definition Slider.c:243
void setValue(Slider *self, double value)
Sets this Slider's value, invalidating its layout and notifying the delegate.
Definition Slider.c:305
layoutSubviews(View *self)
Performs layout for this View's immediate subviews.
Definition Box.c:74

◆ initWithFrame()

static Slider * initWithFrame ( Slider self,
const SDL_Rect *  frame 
)
static

Definition at line 255 of file Slider.c.

255 {
256
257 self = (Slider *) super(Control, self, initWithFrame, frame);
258 if (self) {
259
260 self->bar = $(alloc(View), initWithFrame, frame);
261 assert(self->bar);
262
263 $(self->bar, addClassName, "bar");
264
265 $((View *) self, addSubview, self->bar);
266
267 self->handle = $(alloc(View), initWithFrame, NULL);
268 assert(self->handle);
269
270 $((View *) self->handle, addClassName, "handle");
271
272 $(self->bar, addSubview, (View *) self->handle);
273
274 self->label = $(alloc(Text), initWithText, NULL, NULL);
275 assert(self->label);
276
277 $((View *) self->label, addClassName, "label");
278
279 $((View *) self, addSubview, (View *) self->label);
280
281 $(self, setLabelFormat, "%0.1f");
282 }
283
284 return self;
285}
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 addClassName(View *self, const char *className)
Definition View.c:159
View * bar
The slider bar.
Definition Slider.h:78
Text rendered with TrueType fonts.
Definition Text.h:69

◆ layoutSubviews()

static void layoutSubviews ( View self)
static
See also
View::layoutSubviews(View *)

Definition at line 96 of file Slider.c.

96 {
97
98 super(View, self, layoutSubviews);
99
100 Slider *this = (Slider *) self;
101
102 if (this->max > this->min) {
103
104 if (((View *) this->label)->hidden == false) {
105 int minWidth, maxWidth;
106 char text[64];
107
108 Text *label = (Text *) this->label;
109
110 snprintf(text, sizeof(text), this->labelFormat, this->min);
111 $(label->font, sizeCharacters, text, &minWidth, NULL);
112
113 snprintf(text, sizeof(text), this->labelFormat, this->max);
114 $(label->font, sizeCharacters, text, &maxWidth, NULL);
115
116 this->bar->frame.w -= max(minWidth, maxWidth) + label->view.padding.left;
117 }
118
119 const double fraction = clamp((this->value - this->min) / (this->max - this->min), 0.0, 1.0);
120 const SDL_Rect bounds = $(this->bar, bounds);
121
122 View *handle = (View *) this->handle;
123 handle->frame.x = (bounds.w * fraction) - handle->frame.w * 0.5;
124 } else {
125 MVC_LogWarn("max > min");
126 }
127}
static void sizeCharacters(const Font *self, const char *chars, int *w, int *h)
Definition Font.c:273
#define MVC_LogWarn(fmt,...)
Definition Log.h:54
static SDL_Rect bounds(const View *self)
Definition View.c:492
View view
The superclass.
Definition Text.h:74
Font * font
The Font.
Definition Text.h:92
ViewPadding padding
The padding.
Definition View.h:234
int left
Definition View.h:101

◆ render()

static void render ( View self,
Renderer renderer 
)
static
See also
View::render(View *, Renderer *)

Definition at line 132 of file Slider.c.

132 {
133
134 super(View, self, render, renderer);
135
136 Slider *this = (Slider *) self;
137
138 const SDL_Rect frame = $(this->bar, renderFrame);
139
140 const SDL_Point points[] = {
141 { frame.x, frame.y + frame.h * 0.5 },
142 { frame.x + frame.w, frame.y + frame.h * 0.5 }
143 };
144
145 $(renderer, drawLine, points, &Colors.White);
146}
static void drawLine(const Renderer *self, const SDL_Point *points, const SDL_Color *color)
Definition Renderer.c:114
W3C Color constants.
Definition Colors.h:37
SDL_Color White
Definition Colors.h:185

◆ setLabelFormat()

static void setLabelFormat ( Slider self,
const char *  labelFormat 
)
static

Definition at line 291 of file Slider.c.

291 {
292
293 if (self->labelFormat) {
294 free(self->labelFormat);
295 }
296
297 self->labelFormat = strdup(labelFormat);
298 $(self, formatLabel);
299}

◆ setValue()

static void setValue ( Slider self,
double  value 
)
static

Definition at line 305 of file Slider.c.

305 {
306
307 value = clamp(value, self->min, self->max);
308
309 const double delta = fabs(self->value - value);
310 if (delta > __DBL_EPSILON__) {
311 self->value = value;
312 self->control.view.needsLayout = true;
313
314 $(self, formatLabel);
315 }
316}
View view
The superclass.
Definition Control.h:88
double max
Definition Slider.h:104
double min
The slider bounds.
Definition Slider.h:104
Control control
The superclass.
Definition Slider.h:67
bool needsLayout
If true, this View will layout its subviews before it is drawn.
Definition View.h:222