quakeforge/ruamoko/qwaq/ui/scrollbar.r
Bill Currie 6d5ffa9f8e [build] Move to non-recursive make
There's still some cleanup to do, but everything seems to be working
nicely: `make -j` works, `make distcheck` passes. There is probably
plenty of bitrot in the package directories (RPM, debian), though.

The vc project files have been removed since those versions are way out
of date and quakeforge is pretty much dependent on gcc now anyway.

Most of the old Makefile.am files  are now Makemodule.am.  This should
allow for new Makefile.am files that allow local building (to be added
on an as-needed bases).  The current remaining Makefile.am files are for
standalone sub-projects.a

The installable bins are currently built in the top-level build
directory. This may change if the clutter gets to be too much.

While this does make a noticeable difference in build times, the main
reason for the switch was to take care of the growing dependency issues:
now it's possible to build tools for code generation (eg, using qfcc and
ruamoko programs for code-gen).
2020-06-25 11:35:37 +09:00

247 lines
4.9 KiB
R

#include "ruamoko/qwaq/ui/button.h"
#include "ruamoko/qwaq/ui/group.h"
#include "ruamoko/qwaq/ui/listener.h"
#include "ruamoko/qwaq/ui/scrollbar.h"
@implementation ScrollBar
-initWithRect:(Rect)rect
{
if (!(self = [super initWithRect:rect])) {
return nil;
}
options = ofRelativeEvents;
buffer = [[DrawBuffer buffer:size] retain];
objects = [[Group withContext:buffer owner:self] retain];
onScrollBarModified = [[ListenerGroup listener] retain];
vertical = xlen == 1;
DrawBuffer *icons[3] = {
[DrawBuffer buffer:{1, 1}],
[DrawBuffer buffer:{1, 1}],
[DrawBuffer buffer:{1, 1}],
};
[icons[2] addch:acs_char (ACS_DIAMOND)];
Point thumbPos;
SEL thumbSel;
growMode = gfGrowAll;
if (vertical) {
[icons[0] addch:acs_char (ACS_UARROW)];
[icons[1] addch:acs_char (ACS_DARROW)];
thumbPos = {0, 1};
thumbSel = @selector(verticalSlide:);
growMode &= ~gfGrowLoY;
} else {
[icons[0] addch:acs_char (ACS_LARROW)];
[icons[1] addch:acs_char (ACS_RARROW)];
thumbPos = {1, 0};
thumbSel = @selector(horizontalSlide:);
growMode &= ~gfGrowLoX;
}
bgchar = acs_char (ACS_CKBOARD);
backButton = [Button withPos:{0, 0}
releasedIcon:icons[0] pressedIcon:icons[0]];
forwardButton = [Button withPos:{xlen - 1, ylen - 1}
releasedIcon:icons[1] pressedIcon:icons[1]];
thumbTab = [Button withPos:thumbPos
releasedIcon:icons[2] pressedIcon:icons[2]];
[[backButton onClick] addListener:self :@selector(scrollBack:)];
[[forwardButton onClick] addListener:self :@selector(scrollForward:)];
[[thumbTab onPress] addListener:self :thumbSel];
singleStep = 1;
[objects insert:backButton];
[objects insert:forwardButton];
[objects insert:thumbTab];
return self;
}
-(void)dealloc
{
[objects release];
[buffer release];
[onScrollBarModified release];
[super dealloc];
}
+(ScrollBar *)horizontal:(unsigned)len at:(Point)pos
{
if (len == 1) {
[self error:"can't make scrollbar of length 1"];
}
return [[[self alloc] initWithRect:{pos, {len, 1}}] autorelease];
}
+(ScrollBar *)vertical:(unsigned)len at:(Point)pos
{
if (len == 1) {
[self error:"can't make scrollbar of length 1"];
}
return [[[self alloc] initWithRect:{pos, {1, len}}] autorelease];
}
-(ListenerGroup *)onScrollBarModified
{
return onScrollBarModified;
}
-draw
{
[super draw];
if (vertical) {
[buffer mvvline:{0,0}, bgchar, ylen];
} else {
[buffer mvhline:{0,0}, bgchar, xlen];
}
[objects draw];
[textContext blitFromBuffer:buffer to:pos from:[buffer rect]];
return self;
}
static void
position_tab (ScrollBar *self)
{
Point p = {0, 0};
Point o = [self.thumbTab origin];
if (self.range > 0) {
if (self.vertical) {
p.y = 1 + self.index * (self.ylen - 2) / (self.range - 1);
} else {
p.x = 1 + self.index * (self.xlen - 2) / (self.range - 1);
}
}
[self.thumbTab move:{p.x - o.x, p.y - o.y}];
[self redraw];
}
-resize:(Extent)delta
{
Extent size = self.size;
[super resize:delta];
delta = {self.size.width - size.width, self.size.height - size.height};
[objects resize:delta];
[buffer resizeTo:self.size];
position_tab (self);
return self;
}
-page:(unsigned)step dir:(unsigned) dir
{
unsigned oind = index;
if (dir) {
if (range - 1 - index < step) {
step = range - 1 - index;
}
index += step;
} else {
if (index < step) {
step = index;
}
index -= step;
}
if (index != oind) {
[onScrollBarModified respond:self];
position_tab (self);
}
return self;
}
static void
page (ScrollBar *self, Point pos, Point thumb)
{
unsigned pageDir = 0;
if (self.vertical) {
if (pos.y < thumb.y) {
pageDir = 0;
} else {
pageDir = 1;
}
} else {
if (pos.x < thumb.x) {
pageDir = 0;
} else {
pageDir = 1;
}
}
[self page:self.pageStep dir:pageDir];
}
-(void)scrollBack:(id)sender
{
[self page:singleStep dir:0];
}
-(void)scrollForward:(id)sender
{
[self page:singleStep dir:1];
}
-(void)horizontalSlide:(id)sender
{
}
-(void)verticalSlide:(id)sender
{
}
-handleEvent:(qwaq_event_t *)event
{
[super handleEvent: event];
[objects handleEvent: event];
if (event.what == qe_mousedown) {
[self grabMouse];
mouseTime = event.when;
mouseStart = {event.mouse.x, event.mouse.y};
tabStart = [thumbTab origin];
page(self, mouseStart, tabStart);
event.what = qe_none;
} else if (event.what==qe_mouseauto) {
if (event.when - mouseTime > 0.1) {
mouseTime = event.when;
page(self, mouseStart, tabStart);
}
event.what = qe_none;
} else if (event.what == qe_mouseup) {
[self releaseMouse];
event.what = qe_none;
}
return self;
}
-setRange:(unsigned)range
{
self.range = range;
return self;
}
-setPageStep:(unsigned)pageStep
{
self.pageStep = pageStep;
return self;
}
-setSingleStep:(unsigned)singleStep
{
self.singleStep = singleStep;
return self;
}
-setIndex:(unsigned)index
{
if (index > self.index) {
[self page:index - self.index dir:1];
} else {
[self page:self.index - index dir:0];
}
return self;
}
-(unsigned)index
{
return index;
}
@end