Files
starruler-linux/scripts/toolkit/elements/GuiScrollbar.as
T
2018-07-17 14:15:37 +02:00

317 lines
7.7 KiB
ActionScript

import elements.BaseGuiElement;
import elements.GuiButton;
export ScrollOrientation, GuiScrollbar;
enum ScrollOrientation {
SO_Vertical,
SO_Horizontal,
};
class GuiScrollbar : BaseGuiElement {
bool Focused;
bool Dragging;
int Orientation;
vec2i DragFrom;
GuiButton@ up;
GuiButton@ down;
SkinStyle style;
SkinStyle handleStyle;
double start;
double end;
double page;
double scroll;
double pos;
double bar;
GuiScrollbar(IGuiElement@ ParentElement, const recti& Rectangle) {
super(ParentElement, Rectangle);
start = 0.0;
end = 1.0;
page = 0.0;
bar = 0.2;
pos = 0.5;
scroll = 40.0;
Focused = false;
Dragging = false;
@up = GuiButton(this, recti());
@down = GuiButton(this, recti());
Orientation = SO_Vertical;
updateAbsolutePosition();
}
void set_orientation(int orient) {
Orientation = orient;
if(orient == SO_Vertical) {
up.alignment.top.set(AS_Top, 0.0, 0);
up.alignment.left.set(AS_Left, 0.0, 0);
up.alignment.right.set(AS_Right, 0.0, 0);
up.alignment.bottom.set(AS_Top, 0.0, AbsolutePosition.width);
down.alignment.top.set(AS_Bottom, 0.0, AbsolutePosition.width);
down.alignment.left.set(AS_Left, 0.0, 0);
down.alignment.right.set(AS_Right, 0.0, 0);
down.alignment.bottom.set(AS_Bottom, 0.0, 0);
up.style = SS_ScrollUp;
down.style = SS_ScrollDown;
style = SS_ScrollVert;
handleStyle = SS_ScrollVertHandle;
}
else {
up.alignment.top.set(AS_Top, 0.0, 0);
up.alignment.left.set(AS_Left, 0.0, 0);
up.alignment.right.set(AS_Left, 0.0, AbsolutePosition.height);
up.alignment.bottom.set(AS_Bottom, 0.0, 0);
down.alignment.top.set(AS_Top, 0.0, 0);
down.alignment.left.set(AS_Right, 0.0, AbsolutePosition.height);
down.alignment.right.set(AS_Right, 0.0, 0);
down.alignment.bottom.set(AS_Bottom, 0.0, 0);
up.style = SS_ScrollLeft;
down.style = SS_ScrollRight;
style = SS_ScrollHoriz;
handleStyle = SS_ScrollHorizHandle;
}
up.updateAbsolutePosition();
down.updateAbsolutePosition();
}
int get_orientation() {
return Orientation;
}
void emitChange() {
GuiEvent evt;
evt.type = GUI_Changed;
@evt.caller = this;
onGuiEvent(evt);
}
bool onGuiEvent(const GuiEvent& event) {
if(event.caller is this) {
switch(event.type) {
case GUI_Focused:
Focused = true;
break;
case GUI_Focus_Lost:
Focused = false;
Dragging = false;
break;
}
}
else if(event.type == GUI_Clicked) {
if(event.caller is up) {
if(shiftKey)
pos = max(start, pos - page);
else
pos = max(start, pos - scroll);
emitChange();
}
else if(event.caller is down) {
if(shiftKey)
pos = min(end - page, pos + page);
else
pos = min(end - page, pos + scroll);
emitChange();
}
}
return BaseGuiElement::onGuiEvent(event);
}
bool onMouseEvent(const MouseEvent& event, IGuiElement@ source) {
if(source is this) {
vec2i mouse = vec2i(event.x, event.y);
switch(event.type) {
case MET_Button_Down: {
recti handlePos = getBarPosition();
vec2i offset = mouse - AbsolutePosition.topLeft;
Dragging = true;
DragFrom = mouse;
if(!handlePos.isWithin(offset)) {
pos = min(end - page, max(start, getOffsetPosition(offset)));
emitChange();
}
} return true;
case MET_Moved: {
if(Dragging) {
vec2i diff = mouse - DragFrom;
if(Orientation == SO_Vertical) {
int barSize = getBarPosition().height;
pos += double(diff.y) * (end - start - page) / double(AbsolutePosition.height - barSize - 2 * AbsolutePosition.width);
}
else {
int barSize = getBarPosition().width;
pos += double(diff.x) * (end - start - page) / double(AbsolutePosition.width - barSize - 2 * AbsolutePosition.height);
}
if(pos < start)
pos = start;
else if(pos > end)
pos = end;
DragFrom = vec2i(clamp(mouse.x, AbsolutePosition.topLeft.x+size.height, AbsolutePosition.botRight.x-size.height),
clamp(mouse.y, AbsolutePosition.topLeft.y+size.width, AbsolutePosition.botRight.y-size.width));
emitChange();
return true;
}
} break;
case MET_Button_Up:
if(Focused) {
Dragging = false;
return true;
}
break;
case MET_Scrolled:
pos = min(max(end - page, start), max(start, pos + double(-event.y) * scroll));
emitChange();
return true;
}
}
return BaseGuiElement::onMouseEvent(event, source);
}
bool onKeyEvent(const KeyboardEvent& event, IGuiElement@ source) {
switch(event.type) {
case KET_Key_Down:
switch(event.key) {
case KEY_LEFT:
case KEY_UP:
pos = max(start, pos - scroll);
emitChange();
break;
case KEY_RIGHT:
case KEY_DOWN:
pos = min(end - page, pos + scroll);
emitChange();
break;
case KEY_PAGEUP:
pos = max(start, pos - page);
emitChange();
break;
case KEY_PAGEDOWN:
pos = min(end - page, pos + page);
emitChange();
break;
}
break;
}
return BaseGuiElement::onKeyEvent(event, source);
}
void updateAbsolutePosition() {
BaseGuiElement::updateAbsolutePosition();
orientation = Orientation;
}
double getOffsetPosition(vec2i offset) {
double range = end - start;
if(range < page || range <= 0.0)
return start;
if(Orientation == SO_Vertical) {
int buttonsize = AbsolutePosition.width;
int space = AbsolutePosition.height - buttonsize * 2;
int barsize = max(int(space * (bar / range)), 16);
return (double(offset.y - barsize - buttonsize) / double(space - barsize)) * range + start;
}
else {
int buttonsize = AbsolutePosition.height;
int space = AbsolutePosition.width - buttonsize * 2;
int barsize = max(int(space * (bar / range)), 16);
return (double(offset.x - barsize - buttonsize) / double(space - barsize)) * range + start;
}
}
recti getBarPosition() {
//Initial scrollbar space
double range = end - start;
if(range <= page || range <= 0.0)
return recti();
if(Orientation == SO_Vertical) {
int buttonsize = AbsolutePosition.width;
int space = AbsolutePosition.height - buttonsize * 2;
//Remove space for bar
int barsize = max(int(space * (bar / range)), 16);
space -= barsize;
//Draw bar at correct position
int barpos = ((pos - start) / (range - page)) * space;
vec2i barcoord = vec2i(0, barpos + buttonsize);
return recti(barcoord, barcoord + vec2i(AbsolutePosition.width, barsize));
}
else {
int buttonsize = AbsolutePosition.height;
int space = AbsolutePosition.width - buttonsize * 2;
//Remove space for bar
int barsize = max(int(space * (bar / range)), 16);
space -= barsize;
//Draw bar at correct position
int barpos = ((pos - start) / (range - page)) * space;
vec2i barcoord = vec2i(barpos + buttonsize, 0);
return recti(barcoord, barcoord + vec2i(barsize, AbsolutePosition.height));
}
}
void draw() {
recti barPos = getBarPosition() + AbsolutePosition.topLeft;
recti bgPos;
bool enabled = (end - start > page);
uint handleFlags = SF_Normal;
uint flags = SF_Normal;
if(!enabled)
flags |= SF_Disabled;
if(Dragging)
handleFlags |= SF_Active;
if(barPos.isWithin(mousePos))
handleFlags |= SF_Hovered;
if(Orientation == SO_Vertical) {
bgPos = recti(AbsolutePosition.topLeft + vec2i(0, AbsolutePosition.width),
AbsolutePosition.botRight - vec2i(0, AbsolutePosition.width));
}
else {
bgPos = recti(AbsolutePosition.topLeft + vec2i(AbsolutePosition.height, 0),
AbsolutePosition.botRight - vec2i(AbsolutePosition.height, 0));
}
skin.draw(style, flags, bgPos);
if(enabled)
skin.draw(handleStyle, handleFlags, barPos);
up.disabled = !enabled;
down.disabled = !enabled;
BaseGuiElement::draw();
}
};