29#define _Class _ScrollBar
37#pragma mark - Delegate callbacks
48 const SDL_Rect track = $((
View *) self,
bounds);
49 const SDL_Size content = $((
View *) self->scrollView->contentView,
size);
50 const SDL_Rect visible = $((
View *) self->scrollView,
bounds);
52 const int scrollRange = content.h - visible.h;
53 const int travel = track.h - ((
View *) self->handle)->frame.h;
55 if (scrollRange > 0 && travel > 0) {
57 SDL_Point offset = self->scrollView->contentOffset;
58 offset.y -= (int) (delta * ((
float) scrollRange / travel));
60 $(self->scrollView, scrollToOffset, &offset);
61 ((
View *) self)->needsLayout =
true;
75 release(this->handle);
98 if (this->scrollView == NULL || this->scrollView->contentView == NULL) {
102 const SDL_Rect track = $(self,
bounds);
103 const SDL_Size content = $(this->scrollView->contentView,
size);
104 const SDL_Rect visible = $((
View *) this->scrollView,
bounds);
106 View *handle = (
View *) this->handle;
108 if (content.h <= visible.h || track.h <= 0) {
109 handle->
frame = (SDL_Rect) { 0, 0, track.w, track.h };
112 const int scrollRange = content.h - visible.h;
114 int handleH = (int) ((
float) track.h * visible.h / content.h);
115 handleH = clamp(handleH, handle->
minSize.h, track.h);
117 const int travel = track.h - handleH;
118 const float fraction = clamp((
float) (-this->scrollView->contentOffset.y) / scrollRange, 0.f, 1.f);
120 handle->
frame = (SDL_Rect) { 0, (int) (fraction * travel), track.w, handleH };
131 switch (event->type) {
133 case SDL_EVENT_MOUSE_BUTTON_DOWN:
134 if (this->scrollView) {
136 const SDL_Point point = MakePoint(event->button.x, event->button.y);
138 const SDL_Rect visible = $((
View *) this->scrollView,
bounds);
140 SDL_Point offset = this->scrollView->contentOffset;
142 if (point.y < handleFrame.y) {
143 offset.y += visible.h;
144 }
else if (point.y > handleFrame.y + handleFrame.h) {
145 offset.y -= visible.h;
148 $(this->scrollView, scrollToOffset, &offset);
153 case SDL_EVENT_MOUSE_BUTTON_UP:
157 case SDL_EVENT_MOUSE_MOTION:
167#pragma mark - ScrollBar
179 ((
View *) self)->clipsSubviews =
true;
182 assert(self->handle);
183 self->handle->delegate.self = self;
204#pragma mark - Class lifecycle
211 ((ObjectInterface *) clazz->interface)->dealloc =
dealloc;
213 ((ViewInterface *) clazz->interface)->init =
init;
215 ((ViewInterface *) clazz->interface)->respondToEvent =
respondToEvent;
230 clazz = _initialize(&(
const ClassDef) {
232 .superclass =
_View(),
234 .interfaceOffset = offsetof(
ScrollBar, interface),
235 .interfaceSize =
sizeof(ScrollBarInterface),
static Box * initWithFrame(Box *self, const SDL_Rect *frame)
static SDL_Size size(const Image *self)
static void addSubview(View *self, View *subview)
static void addClassName(View *self, const char *className)
static void resignTouchResponder(View *self)
static SDL_Rect renderFrame(const View *self)
static SDL_Rect bounds(const View *self)
Views are the fundamental building blocks of ObjectivelyMVC user interfaces.
bool needsLayout
If true, this View will layout its subviews before it is drawn.
SDL_Size minSize
The minimum size this View may be resized to during layout.
layoutSubviews(View *self)
Performs layout for this View's immediate subviews.
SDL_Rect frame
The frame, relative to the superview.