mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-14 17:01:22 +00:00
2572011a4b
The editor now uses the vertical scrollbar for handling mouse wheel scrolling, thus keeping the scrollbar in sync. Scrollbar index can now cover the full range (not sure why I had that -1), and the potential divide by zero is avoided properly. Thumb-tab now positioned properly when the range is 0.
261 lines
5 KiB
R
261 lines
5 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]];
|
|
|
|
[forwardButton setGrowMode:gfGrowAll];
|
|
|
|
[[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;
|
|
}
|
|
|
|
-updateAbsPos: (Point) absPos
|
|
{
|
|
[super updateAbsPos: absPos];
|
|
[objects updateAbsPos: absRect.offset];
|
|
return self;
|
|
}
|
|
|
|
-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};
|
|
if (self.range > 0) {
|
|
if (self.vertical) {
|
|
p.y = 1 + self.index * (self.ylen - 3) / self.range;
|
|
} else {
|
|
p.x = 1 + self.index * (self.xlen - 3) / self.range;
|
|
}
|
|
} else {
|
|
if (self.vertical) {
|
|
p.y = 1;
|
|
} else {
|
|
p.x = 1;
|
|
}
|
|
}
|
|
[self.thumbTab moveTo:p];
|
|
[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 - index < step) {
|
|
step = range - 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
|