45 memset(&this->delegate, 0,
sizeof(this->delegate));
48 release(this->handle);
51 free(this->labelFormat);
67 double value = this->value;
81 $(self, bind, inlets, dictionary);
102 if (this->max > this->min) {
104 if (((
View *) this->label)->hidden ==
false) {
105 int minWidth, maxWidth;
110 snprintf(text,
sizeof(text), this->labelFormat, this->min);
113 snprintf(text,
sizeof(text), this->labelFormat, this->max);
116 this->bar->frame.w -= max(minWidth, maxWidth) + label->
view.
padding.
left;
119 const double fraction = clamp((this->value - this->min) / (this->max - this->min), 0.0, 1.0);
122 View *handle = (
View *) this->handle;
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 }
148#pragma mark - Control
159 if (event->type == SDL_EVENT_MOUSE_BUTTON_DOWN) {
168 const int x =
event->button.x - frame.x;
169 const double step = this->step ?: (this->max - this->min) / 20.0;
171 $(
this,
setValue, this->value + (x > this->handle->
frame.x ? step : -step));
173 if (this->delegate.didSetValue) {
174 this->delegate.didSetValue(
this, this->value);
180 else if (event->type == SDL_EVENT_MOUSE_BUTTON_UP) {
182 self->
state &= ~ControlStateHighlighted;
187 else if (event->type == SDL_EVENT_MOUSE_MOTION) {
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);
194 if (this->snapToStep && this->step) {
195 value = clamp(round(value / this->step) * this->step, this->min, this->max);
198 const double delta = fabs(this->value - value);
199 if (delta > __DBL_EPSILON__) {
202 if (this->delegate.didSetValue) {
203 this->delegate.didSetValue(
this, this->value);
212 if (event->type == SDL_EVENT_KEY_DOWN) {
215 switch (event->key.key) {
217 step = -this->step ?: -(this->max - this->min) / 20.0;
220 step = this->step ?: (this->max - this->min) / 20.0;
225 $(
this,
setValue, this->value + step);
227 if (this->delegate.didSetValue) {
228 this->delegate.didSetValue(
this, this->value);
268 assert(self->handle);
307 value = clamp(value, self->
min, self->
max);
309 const double delta = fabs(self->
value - value);
310 if (delta > __DBL_EPSILON__) {
318#pragma mark - Class lifecycle
325 ((ObjectInterface *) clazz->interface)->dealloc =
dealloc;
328 ((ViewInterface *) clazz->interface)->init =
init;
330 ((ViewInterface *) clazz->interface)->render =
render;
332 ((ControlInterface *) clazz->interface)->captureEvent =
captureEvent;
334 ((SliderInterface *) clazz->interface)->formatLabel =
formatLabel;
335 ((SliderInterface *) clazz->interface)->initWithFrame =
initWithFrame;
337 ((SliderInterface *) clazz->interface)->setLabelFormat =
setLabelFormat;
349 clazz = _initialize(&(
const ClassDef) {
352 .instanceSize =
sizeof(
Slider),
353 .interfaceOffset = offsetof(
Slider, interface),
354 .interfaceSize =
sizeof(SliderInterface),
@ ControlStateHighlighted
static void sizeCharacters(const Font *self, const char *chars, int *w, int *h)
static Label * initWithText(Label *self, const char *text, Font *font)
View logging facilities via SDL_Log.
#define MVC_LogWarn(fmt,...)
static void addSubview(View *self, View *subview)
static void drawLine(const Renderer *self, const SDL_Point *points, const SDL_Color *color)
static void setValue(Slider *self, double value)
static void setLabelFormat(Slider *self, const char *labelFormat)
static View * init(View *self)
static void awakeWithDictionary(View *self, const Dictionary *dictionary)
static bool captureEvent(Control *self, const SDL_Event *event)
static void render(View *self, Renderer *renderer)
static Slider * initWithFrame(Slider *self, const SDL_Rect *frame)
static void dealloc(Object *self)
static void initialize(Class *clazz)
static void layoutSubviews(View *self)
static void formatLabel(Slider *self)
A Control allowing users to drag a handle to select a numeric value.
static void setText(Text *self, const char *text)
#define MakeInlets(...)
Creates a null-termianted array of Inlets.
#define MakeInlet(name, type, dest, data)
Creates an Inlet with the specified parameters.
static void addClassName(View *self, const char *className)
static bool didReceiveEvent(const View *self, const SDL_Event *event)
static SDL_Rect renderFrame(const View *self)
static SDL_Rect bounds(const View *self)
Controls are Views which capture and respond to events.
unsigned int state
The bit mask of ControlState.
Inlets enable inbound data binding of View attributes through JSON.
Renderer extends Object with ObjectivelyMVC's UI rendering layer.
A Control allowing users to drag a handle to select a numeric value.
double min
The slider bounds.
View * bar
The slider bar.
Text * label
The Text displaying the current value.
char * labelFormat
The label format, e.g. "%0.01f".
double value
The slider value.
void setValue(Slider *self, double value)
Sets this Slider's value, invalidating its layout and notifying the delegate.
Control control
The superclass.
Text rendered with TrueType fonts.
Views are the fundamental building blocks of ObjectivelyMVC user interfaces.
bool needsLayout
If true, this View will layout its subviews before it is drawn.
ViewPadding padding
The padding.
layoutSubviews(View *self)
Performs layout for this View's immediate subviews.
SDL_Rect frame
The frame, relative to the superview.