Open source Star Ruler 2 source code!
This commit is contained in:
@@ -0,0 +1,845 @@
|
||||
import elements.IGuiElement;
|
||||
RootElement gui_root;
|
||||
|
||||
int next_gui_id = 1;
|
||||
int get_nextGuiID() {
|
||||
return next_gui_id++;
|
||||
}
|
||||
|
||||
IGuiElement@ getRootGuiElement() {
|
||||
return gui_root;
|
||||
}
|
||||
|
||||
void setGuiFocus(IGuiElement@ elem) {
|
||||
@gui_root.focus = elem;
|
||||
}
|
||||
|
||||
void clearGuiHovered() {
|
||||
@gui_root.hovered = null;
|
||||
}
|
||||
|
||||
void setGuiAbsorb(IGuiElement@ elem) {
|
||||
@gui_root.AbsorbTo = elem;
|
||||
@gui_root.focus = elem;
|
||||
}
|
||||
|
||||
IGuiElement@ getGuiFocus() {
|
||||
return gui_root.Focus;
|
||||
}
|
||||
|
||||
bool isGuiFocusIn(IGuiElement@ elem) {
|
||||
if(gui_root.Focus is null)
|
||||
return false;
|
||||
return gui_root.Focus is elem || gui_root.Focus.isChildOf(elem);
|
||||
}
|
||||
|
||||
bool isGuiHovered() {
|
||||
if(gui_root.AbsorbTo !is null)
|
||||
return true;
|
||||
if(gui_root.Hovered is null)
|
||||
return false;
|
||||
return !gui_root.Hovered.isRoot;
|
||||
}
|
||||
|
||||
void animate_speed(IGuiElement@ ele, const recti& dest, double speed, int value = 0) {
|
||||
GuiAnim@ anim;
|
||||
uint len = animations.length();
|
||||
for(uint i = 0; i < len; ++i) {
|
||||
if(animations[i].ele is ele) {
|
||||
@anim = animations[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(anim is null) {
|
||||
animations.resize(len+1);
|
||||
@anim = animations[len];
|
||||
}
|
||||
|
||||
@anim.ele = @ele;
|
||||
recti startRect = ele.rect;
|
||||
anim.from = rectf(startRect);
|
||||
anim.to = dest;
|
||||
anim.byTime = false;
|
||||
anim.arg = speed;
|
||||
anim.value = value;
|
||||
anim.completed = false;
|
||||
}
|
||||
|
||||
void animate_time(IGuiElement@ ele, const recti& dest, double time, int value = 0) {
|
||||
GuiAnim@ anim;
|
||||
uint len = animations.length();
|
||||
for(uint i = 0; i < len; ++i) {
|
||||
if(animations[i].ele is ele) {
|
||||
@anim = animations[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(anim is null) {
|
||||
animations.resize(len+1);
|
||||
@anim = animations[len];
|
||||
}
|
||||
|
||||
@anim.ele = @ele;
|
||||
recti startRect = ele.rect;
|
||||
anim.from = rectf(startRect);
|
||||
anim.to = dest;
|
||||
anim.byTime = true;
|
||||
anim.arg = time;
|
||||
anim.value = value;
|
||||
anim.completed = false;
|
||||
}
|
||||
|
||||
void animate_retarget(IGuiElement@ ele, const recti& dest) {
|
||||
uint len = animations.length();
|
||||
for(uint i = 0; i < len; ++i) {
|
||||
if(animations[i].ele is ele) {
|
||||
animations[i].to = dest;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void animate_remove(IGuiElement@ ele) {
|
||||
for(int i = animations.length()-1; i >= 0; --i)
|
||||
if(animations[i].ele is ele)
|
||||
animations.removeAt(i);
|
||||
}
|
||||
|
||||
void animate_snap(IGuiElement@ ele) {
|
||||
uint len = animations.length();
|
||||
for(uint i = 0; i < len; ++i) {
|
||||
if(animations[i].ele is ele) {
|
||||
ele.rect = animations[i].to;
|
||||
animations.removeAt(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ITooltip@ getTooltip(IGuiElement@ ele) {
|
||||
ITooltip@ tt;
|
||||
while(tt is null && ele !is null) {
|
||||
@tt = ele.tooltipObject;
|
||||
@ele = ele.parent;
|
||||
}
|
||||
return tt;
|
||||
}
|
||||
|
||||
void clearTooltip() {
|
||||
if(gui_root.Tooltip !is null) {
|
||||
gui_root.Tooltip.hide(gui_root.skin, gui_root.Hovered);
|
||||
@gui_root.Tooltip = null;
|
||||
gui_root.updateHover();
|
||||
}
|
||||
}
|
||||
|
||||
void tick(double time) {
|
||||
if(gui_root.AbsorbTo !is null && gui_root.AbsorbTo.parent is null)
|
||||
@gui_root.AbsorbTo = null;
|
||||
|
||||
if(gui_root.Hovered !is null && gui_root.Tooltip is null && gui_root.AbsorbTo is null) {
|
||||
@gui_root.Tooltip = getTooltip(gui_root.Hovered);
|
||||
if(gui_root.Tooltip !is null) {
|
||||
gui_root.showTooltipDelay = gui_root.Tooltip.delay;
|
||||
if(gui_root.showTooltipDelay <= 0.f)
|
||||
gui_root.Tooltip.show(gui_root.skin, gui_root.Hovered);
|
||||
}
|
||||
}
|
||||
|
||||
if(gui_root.Tooltip !is null) {
|
||||
if(gui_root.showTooltipDelay > 0.f) {
|
||||
gui_root.showTooltipDelay = max(gui_root.showTooltipDelay - float(time), 0.f);
|
||||
if(gui_root.showTooltipDelay <= 0.f)
|
||||
gui_root.Tooltip.show(gui_root.skin, gui_root.Hovered);
|
||||
}
|
||||
}
|
||||
|
||||
if(gui_root.Hovered !is null) {
|
||||
if(gui_root.Hovered.parent is null)
|
||||
gui_root.updateHover();
|
||||
}
|
||||
}
|
||||
|
||||
void draw() {
|
||||
for(int i = animations.length()-1; i >= 0; --i)
|
||||
if(animations[i].update(frameLength))
|
||||
animations.removeAt(i);
|
||||
gui_root.draw();
|
||||
}
|
||||
|
||||
bool onGuiEvent(const GuiEvent& evt) {
|
||||
return gui_root.postGuiEvent(evt);
|
||||
}
|
||||
|
||||
bool onMouseEvent(const MouseEvent& event) {
|
||||
return gui_root.postMouseEvent(event);
|
||||
}
|
||||
|
||||
bool onKeyboardEvent(const KeyboardEvent& event) {
|
||||
return gui_root.postKeyEvent(event);
|
||||
}
|
||||
|
||||
void onGuiNavigate(vec2d direction) {
|
||||
gui_root.navigateTo(direction);
|
||||
}
|
||||
|
||||
IGuiElement@ getNavChild(IGuiElement@ ele, NavigationMode mode) {
|
||||
for(uint i = 0, cnt = ele.childCount; i < cnt; ++i) {
|
||||
IGuiElement@ child = ele.getChild(i);
|
||||
if(!child.visible)
|
||||
continue;
|
||||
if(child.isNavigable(mode))
|
||||
return child;
|
||||
|
||||
@child = getNavChild(child, mode);
|
||||
if(child !is null)
|
||||
return child;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
void navigateInto(IGuiElement@ elem) {
|
||||
if(elem.isNavigable(gui_root.NavMode)) {
|
||||
setGuiFocus(elem);
|
||||
}
|
||||
else {
|
||||
IGuiElement@ child = getNavChild(elem, gui_root.NavMode);
|
||||
if(child !is null)
|
||||
setGuiFocus(child);
|
||||
else
|
||||
setGuiFocus(elem);
|
||||
}
|
||||
}
|
||||
|
||||
//A special element that has only children, no parent
|
||||
//Acts as the parent of all elements
|
||||
class RootElement : IGuiElement {
|
||||
IGuiElement@[] Children;
|
||||
IGuiElement@ Focus;
|
||||
IGuiElement@ Hovered;
|
||||
IGuiElement@ AbsorbTo;
|
||||
recti absRect;
|
||||
ITooltip@ Tooltip;
|
||||
const Skin@ skin = getSkin(settings::sSkinName);
|
||||
float showTooltipDelay = -1;
|
||||
IGuiElement@ prevTabFocus;
|
||||
bool Visible = true;
|
||||
bool NoClip = true;
|
||||
NavigationMode NavMode = NM_None;
|
||||
GuiEvent guiEvent;
|
||||
|
||||
RootElement() {
|
||||
updateAbsolutePosition();
|
||||
}
|
||||
|
||||
bool onMouseEvent(const MouseEvent& event, IGuiElement@ source) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool onKeyEvent(const KeyboardEvent& event, IGuiElement@ source) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool onGuiEvent(const GuiEvent& event) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int get_id() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool postGuiEvent(const GuiEvent& event) {
|
||||
if(Focus !is null && Focus.actuallyVisible && Focus.onGuiEvent(event))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void updateHover() {
|
||||
vec2i pos = mousePos;
|
||||
@hovered = elementFromPosition(vec2i(pos.x, pos.y));
|
||||
}
|
||||
|
||||
bool postMouseEvent(const MouseEvent& event) {
|
||||
if(Tooltip !is null) {
|
||||
if(Tooltip.persist) {
|
||||
if(event.type == MET_Moved && showTooltipDelay > 0.f)
|
||||
showTooltipDelay = Tooltip.delay;
|
||||
}
|
||||
else {
|
||||
if(showTooltipDelay <= 0.f)
|
||||
Tooltip.hide(skin, Hovered);
|
||||
if(event.type == MET_Moved)
|
||||
showTooltipDelay = Tooltip.delay;
|
||||
else
|
||||
@Tooltip = null;
|
||||
}
|
||||
}
|
||||
|
||||
if(event.type == MET_Moved)
|
||||
@hovered = elementFromPosition(vec2i(event.x, event.y));
|
||||
|
||||
if(event.type == MET_Button_Down) {
|
||||
if(NavMode != NM_None)
|
||||
NavMode = NM_None;
|
||||
@focus = elementFromPosition(vec2i(event.x, event.y));
|
||||
}
|
||||
|
||||
if(Hovered !is null && Hovered !is Focus && Hovered.onMouseEvent(event,Hovered)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if(Focus !is null && Focus.actuallyVisible && Focus.onMouseEvent(event,Focus)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return Hovered !is null && !Hovered.isRoot;
|
||||
}
|
||||
|
||||
bool postKeyEvent(const KeyboardEvent& event) {
|
||||
if(Focus !is null && Focus.actuallyVisible && Focus.onKeyEvent(event,Focus))
|
||||
return true;
|
||||
|
||||
if(Hovered !is null && Hovered !is Focus && Hovered.onKeyEvent(event,Hovered))
|
||||
return true;
|
||||
|
||||
if(event.type == KET_Key_Down && event.key == KEY_TAB) {
|
||||
if(prevTabFocus !is null) {
|
||||
if(shiftKey)
|
||||
@focus = prevTabElement(prevTabFocus);
|
||||
else
|
||||
@focus = nextTabElement(prevTabFocus);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void set_focus(IGuiElement@ ele) {
|
||||
if(Focus is ele)
|
||||
return;
|
||||
|
||||
if(Focus !is null) {
|
||||
guiEvent.type = GUI_Focus_Lost;
|
||||
@guiEvent.caller = Focus;
|
||||
@guiEvent.other = ele;
|
||||
if(Focus.onGuiEvent(guiEvent))
|
||||
return;
|
||||
}
|
||||
if(ele !is null) {
|
||||
guiEvent.type = GUI_Focused;
|
||||
@guiEvent.caller = ele;
|
||||
@guiEvent.other = Focus;
|
||||
if(ele.onGuiEvent(guiEvent))
|
||||
return;
|
||||
}
|
||||
@Focus = @ele;
|
||||
|
||||
if(Focus !is null) {
|
||||
if(Focus.tabIndex >= 0) {
|
||||
@prevTabFocus = Focus;
|
||||
}
|
||||
else if(prevTabFocus !is null) {
|
||||
IGuiElement@ oldGroup = findParentGroup(prevTabFocus);
|
||||
@prevTabFocus = findParentGroup(Focus);
|
||||
if(prevTabFocus !is oldGroup)
|
||||
@prevTabFocus = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void set_hovered(IGuiElement@ ele) {
|
||||
if(Hovered is ele)
|
||||
return;
|
||||
if(Hovered !is null) {
|
||||
if(ele is null || !ele.isChildOf(Hovered)) {
|
||||
guiEvent.type = GUI_Mouse_Left;
|
||||
@guiEvent.caller = Hovered;
|
||||
@guiEvent.other = ele;
|
||||
if(Hovered.onGuiEvent(guiEvent))
|
||||
return;
|
||||
|
||||
if(ele !is null) {
|
||||
IGuiElement@ check = Hovered.parent;
|
||||
while(check !is null) {
|
||||
if(check.isAncestorOf(ele))
|
||||
break;
|
||||
|
||||
@guiEvent.caller = check;
|
||||
if(check.onGuiEvent(guiEvent))
|
||||
return;
|
||||
|
||||
@check = check.parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(ele !is null) {
|
||||
if(Hovered is null || !Hovered.isChildOf(ele)) {
|
||||
guiEvent.type = GUI_Mouse_Entered;
|
||||
@guiEvent.caller = ele;
|
||||
@guiEvent.other = Hovered;
|
||||
if(ele.onGuiEvent(guiEvent))
|
||||
return;
|
||||
|
||||
IGuiElement@ check = ele.parent;
|
||||
while(check !is null) {
|
||||
if(check.isAncestorOf(Hovered))
|
||||
break;
|
||||
|
||||
@guiEvent.caller = check;
|
||||
if(check.onGuiEvent(guiEvent))
|
||||
return;
|
||||
|
||||
@check = check.parent;
|
||||
}
|
||||
}
|
||||
|
||||
ITooltip@ prevTooltip = Tooltip;
|
||||
@Tooltip = getTooltip(ele);
|
||||
if(prevTooltip !is Tooltip) {
|
||||
if(prevTooltip !is null)
|
||||
prevTooltip.hide(skin, Hovered);
|
||||
if(Tooltip !is null) {
|
||||
showTooltipDelay = Tooltip.delay;
|
||||
if(showTooltipDelay <= 0.f)
|
||||
Tooltip.show(skin, ele);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(Tooltip !is null)
|
||||
Tooltip.hide(skin, Hovered);
|
||||
@Tooltip = null;
|
||||
}
|
||||
|
||||
@Hovered = @ele;
|
||||
}
|
||||
|
||||
IGuiElement@ get_parent() const {
|
||||
return null;
|
||||
}
|
||||
|
||||
void set_parent(IGuiElement@ NewParent) {
|
||||
throw("Attempted to set parent of Root GUI Element");
|
||||
}
|
||||
|
||||
void updateAbsolutePosition() {
|
||||
vec2i newSize = screenSize;
|
||||
if(newSize != absRect.size && newSize.width != 0 && newSize.height != 0) {
|
||||
absRect = recti_area(vec2i(0,0), screenSize);
|
||||
uint cCnt = Children.length();
|
||||
for(uint i = 0; i != cCnt; ++i)
|
||||
Children[i].updateAbsolutePosition();
|
||||
}
|
||||
}
|
||||
|
||||
IGuiElement@ elementFromPosition(const vec2i& pos) {
|
||||
uint cCnt = Children.length();
|
||||
for(int i = cCnt - 1; i >= 0; --i) {
|
||||
if(!Children[i].visible)
|
||||
continue;
|
||||
|
||||
IGuiElement@ ele = Children[i].elementFromPosition(pos);
|
||||
|
||||
if(ele !is null)
|
||||
return ele;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
recti get_absolutePosition() {
|
||||
return absRect;
|
||||
}
|
||||
|
||||
recti get_updatePosition() {
|
||||
return absRect;
|
||||
}
|
||||
|
||||
recti get_absoluteClipRect() {
|
||||
return absRect;
|
||||
}
|
||||
|
||||
string get_elementType() const {
|
||||
return "root";
|
||||
}
|
||||
|
||||
bool get_isRoot() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool get_visible() const {
|
||||
return Visible;
|
||||
}
|
||||
|
||||
bool get_actuallyVisible() const {
|
||||
return Visible;
|
||||
}
|
||||
|
||||
bool get_onScreen() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
void set_visible(bool vis) {
|
||||
Visible = vis;
|
||||
}
|
||||
|
||||
void addChild(IGuiElement@ ele) {
|
||||
Children.insertLast(ele);
|
||||
}
|
||||
|
||||
void removeChild(IGuiElement@ ele) {
|
||||
for(uint i = 0; i < Children.length(); ++i) {
|
||||
if(Children[i] is ele) {
|
||||
Children.removeAt(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void remove() {
|
||||
throw("Error: attempting to remove gui root.");
|
||||
}
|
||||
|
||||
bool isAncestorOf(const IGuiElement@ ele) const {
|
||||
while(ele !is null) {
|
||||
if(ele is this)
|
||||
return true;
|
||||
@ele = @ele.parent;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isChildOf(const IGuiElement@ ele) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isFront() { return true; }
|
||||
|
||||
void bringToFront() {}
|
||||
|
||||
void bringToFront(IGuiElement@ ele) {
|
||||
if(Children.length != 0)
|
||||
if(Children[Children.length - 1] is ele)
|
||||
return;
|
||||
Children.remove(ele);
|
||||
Children.insertLast(ele);
|
||||
}
|
||||
|
||||
bool isBack() { return true; }
|
||||
|
||||
void sendToBack() {}
|
||||
|
||||
void sendToBack(IGuiElement@ ele) {
|
||||
uint offset = 0;
|
||||
for(int i = Children.length() - 1; i >= 0; --i) {
|
||||
if(Children[i] is ele)
|
||||
offset = 1;
|
||||
else if(offset != 0)
|
||||
@Children[i + offset] = Children[i];
|
||||
}
|
||||
@Children[0] = ele;
|
||||
}
|
||||
|
||||
void draw() {
|
||||
updateAbsolutePosition();
|
||||
if(!Visible)
|
||||
return;
|
||||
|
||||
uint cCnt = Children.length();
|
||||
for(uint i = 0; i != cCnt; ++i) {
|
||||
IGuiElement@ ele = Children[i];
|
||||
if(!ele.visible || !ele.onScreen)
|
||||
continue;
|
||||
|
||||
if(ele.noClip)
|
||||
clearClip();
|
||||
else
|
||||
setClip(ele.absoluteClipRect);
|
||||
|
||||
ele.draw();
|
||||
|
||||
if(!ele.noClip)
|
||||
clearClip();
|
||||
}
|
||||
|
||||
if(Focus !is null && NavMode != NM_None && Focus.isNavigable(NavMode) && Focus.actuallyVisible) {
|
||||
clearClip();
|
||||
drawRectangle(Focus.absolutePosition.padded(-8), Color(0xffffff40));
|
||||
|
||||
setClip(Focus.absoluteClipRect);
|
||||
Focus.draw();
|
||||
clearClip();
|
||||
}
|
||||
|
||||
if(Tooltip !is null && showTooltipDelay <= 0.f)
|
||||
Tooltip.draw(skin, Hovered);
|
||||
}
|
||||
|
||||
void set_position(const vec2i& pos) {}
|
||||
void move(const vec2i& moveBy) {}
|
||||
void abs_move(const vec2i& moveBy) {}
|
||||
|
||||
vec2i get_position() const {
|
||||
return absRect.topLeft;
|
||||
}
|
||||
|
||||
void set_size(const vec2i& _size) {}
|
||||
|
||||
vec2i get_size() const {
|
||||
return absRect.get_size();
|
||||
}
|
||||
|
||||
vec2i get_desiredSize() const {
|
||||
return size;
|
||||
}
|
||||
|
||||
void set_rect(const recti& rect) {}
|
||||
|
||||
recti get_rect() const {
|
||||
return absRect;
|
||||
}
|
||||
|
||||
void set_tooltip(const string& ToolText) {
|
||||
}
|
||||
|
||||
string get_tooltip() {
|
||||
return "";
|
||||
}
|
||||
|
||||
void set_tooltipObject(ITooltip@ tp) {
|
||||
}
|
||||
|
||||
ITooltip@ get_tooltipObject() const {
|
||||
return null;
|
||||
}
|
||||
|
||||
bool get_noClip() const {
|
||||
return NoClip;
|
||||
}
|
||||
|
||||
void set_noClip(bool noclip) {
|
||||
NoClip = noclip;
|
||||
}
|
||||
|
||||
int get_tabIndex() const {
|
||||
return -1;
|
||||
}
|
||||
|
||||
void set_tabIndex(int ind) {
|
||||
}
|
||||
|
||||
IGuiElement@ getChild(uint index) {
|
||||
if(index >= Children.length())
|
||||
return null;
|
||||
return Children[index];
|
||||
}
|
||||
|
||||
uint get_childCount() const {
|
||||
return Children.length();
|
||||
}
|
||||
|
||||
//Find the first parent with a tab index (or the root)
|
||||
IGuiElement@ findParentGroup(IGuiElement@ ele) {
|
||||
IGuiElement@ parent = ele.parent;
|
||||
while(parent !is null && parent.tabIndex == -1)
|
||||
@parent = parent.parent;
|
||||
|
||||
if(parent is null)
|
||||
return this;
|
||||
else
|
||||
return parent;
|
||||
}
|
||||
|
||||
//Within the same tab group parent, find the next element to tab to
|
||||
IGuiElement@ nextTabElement(IGuiElement@ from) {
|
||||
int minIndex = from.tabIndex;
|
||||
IGuiElement@ minElement;
|
||||
|
||||
IGuiElement@ parent = findParentGroup(from);
|
||||
nextTabElement(parent, minIndex, minIndex, minElement);
|
||||
|
||||
return minElement;
|
||||
}
|
||||
|
||||
void nextTabElement(IGuiElement@ ele, int index, int& minIndex, IGuiElement@& minElement) {
|
||||
int ind = ele.tabIndex;
|
||||
if(ind >= 0) {
|
||||
if(minIndex > index) {
|
||||
if(ind > index && ind < minIndex) {
|
||||
minIndex = ind;
|
||||
@minElement = ele;
|
||||
}
|
||||
}
|
||||
else if(ind > index || ind < minIndex) {
|
||||
minIndex = ind;
|
||||
@minElement = ele;
|
||||
}
|
||||
}
|
||||
|
||||
for(uint i = 0, cnt = ele.childCount; i < cnt; ++i)
|
||||
nextTabElement(ele.getChild(i), index, minIndex, minElement);
|
||||
}
|
||||
|
||||
//Within the same tab group parent, find the previous element to tab to
|
||||
IGuiElement@ prevTabElement(IGuiElement @from) {
|
||||
int maxIndex = from.tabIndex;
|
||||
IGuiElement@ maxElement;
|
||||
|
||||
IGuiElement@ parent = findParentGroup(from);
|
||||
prevTabElement(parent, maxIndex, maxIndex, maxElement);
|
||||
|
||||
return maxElement;
|
||||
}
|
||||
|
||||
void prevTabElement(IGuiElement@ ele, int index, int& maxIndex, IGuiElement@& maxElement) {
|
||||
int ind = ele.tabIndex;
|
||||
if(ind >= 0) {
|
||||
if(maxIndex < index) {
|
||||
if(ind < index && ind > maxIndex) {
|
||||
maxIndex = ind;
|
||||
@maxElement = ele;
|
||||
}
|
||||
}
|
||||
else if(ind < index || ind > maxIndex) {
|
||||
maxIndex = ind;
|
||||
@maxElement = ele;
|
||||
}
|
||||
}
|
||||
|
||||
for(uint i = 0, cnt = ele.childCount; i < cnt; ++i)
|
||||
prevTabElement(ele.getChild(i), index, maxIndex, maxElement);
|
||||
}
|
||||
|
||||
bool isNavigable(NavigationMode mode) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void navigateTo(vec2d line) {
|
||||
//Jump into the right navigation mode
|
||||
if(NavMode != NM_Action) {
|
||||
@focus = null;
|
||||
NavMode = NM_Action;
|
||||
}
|
||||
|
||||
//Find element to navigate to
|
||||
IGuiElement@ nav;
|
||||
if(Focus !is null && Focus.actuallyVisible && Focus.parent !is null)
|
||||
@nav = Focus.navigate(NavMode, line);
|
||||
else
|
||||
@nav = navigate(NavMode, line);
|
||||
|
||||
//Focus it
|
||||
GuiEvent evt;
|
||||
if(nav !is null && nav !is Focus) {
|
||||
if(Focus !is null) {
|
||||
evt.type = GUI_Navigation_Leave;
|
||||
@evt.caller = Focus;
|
||||
@evt.other = nav;
|
||||
Focus.onGuiEvent(evt);
|
||||
}
|
||||
@focus = nav;
|
||||
|
||||
evt.type = GUI_Navigation_Enter;
|
||||
@evt.caller = Focus;
|
||||
Focus.onGuiEvent(evt);
|
||||
}
|
||||
}
|
||||
|
||||
IGuiElement@ navigate(NavigationMode mode, const vec2d& line) {
|
||||
return navigate(mode, absolutePosition, line);
|
||||
}
|
||||
|
||||
IGuiElement@ navigate(NavigationMode mode, const recti& box, const vec2d&in line) {
|
||||
float closestDist = FLOAT_INFINITY;
|
||||
IGuiElement@ closest;
|
||||
closestToLine(mode, box, line.normalized(), closestDist, closest, Focus);
|
||||
return closest;
|
||||
}
|
||||
|
||||
void closestToLine(NavigationMode mode, const recti& box, const vec2d&in line, float& closestDist, IGuiElement@& closest, IGuiElement@ skip) {
|
||||
vec2d origin = vec2d(box.center);
|
||||
for(uint i = 0, cnt = Children.length; i < cnt; ++i) {
|
||||
IGuiElement@ child = Children[i];
|
||||
if(!child.visible)
|
||||
continue;
|
||||
if(child.isNavigable(mode)) {
|
||||
if(child is skip)
|
||||
continue;
|
||||
recti pos = child.absolutePosition;
|
||||
vec2d dir = vec2d(pos.center) - origin;
|
||||
double t = (dir.x*line.x + dir.y*line.y);
|
||||
if(t < 0 && skip !is null)
|
||||
continue;
|
||||
|
||||
vec2d point = origin + line * t;
|
||||
float dist = pos.distanceTo(vec2i(point));
|
||||
dist += 0.001f * point.distanceTo(origin);
|
||||
|
||||
if(dist < closestDist) {
|
||||
closestDist = dist;
|
||||
@closest = child;
|
||||
if(dist == 0.f)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
child.closestToLine(mode, box, line, closestDist, closest, skip);
|
||||
if(closestDist == 0.f)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class GuiAnim {
|
||||
IGuiElement@ ele;
|
||||
rectf from;
|
||||
recti to;
|
||||
bool byTime;
|
||||
double arg;
|
||||
int value;
|
||||
bool completed;
|
||||
|
||||
bool update(double time) {
|
||||
double interp;
|
||||
if(byTime) {
|
||||
interp = time / arg;
|
||||
arg -= time;
|
||||
}
|
||||
else {
|
||||
rectf to_f(to);
|
||||
|
||||
float dist = max(to_f.topLeft.distanceTo(from.topLeft), to_f.topLeft.distanceTo(from.topLeft));
|
||||
if(dist > 0)
|
||||
interp = (arg * time) / dist;
|
||||
else
|
||||
interp = 1.0;
|
||||
}
|
||||
|
||||
if(interp >= 1.0) {
|
||||
ele.rect = to;
|
||||
ele.updateAbsolutePosition();
|
||||
completed = true;
|
||||
|
||||
GuiEvent evt;
|
||||
evt.type = GUI_Animation_Complete;
|
||||
evt.value = value;
|
||||
@evt.caller = ele;
|
||||
ele.onGuiEvent(evt);
|
||||
|
||||
return completed;
|
||||
}
|
||||
|
||||
from = from.interpolate(rectf(to), interp);
|
||||
ele.rect = recti(from);
|
||||
ele.updateAbsolutePosition();
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
GuiAnim[] animations;
|
||||
Reference in New Issue
Block a user