Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add state for active objects to GUI #201

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/engine/menus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -638,7 +638,9 @@ void ui_body(uint *contents, char *action, char *altact, uint *onhover)
cgui->pushlist(action && *action ? true : false);
execute(contents);
int ret = cgui->poplist();
if(ret&GUI_UP)
if(guilayoutpass) return;
bool active = cgui->unique_object_active(ret & GUI_ROLLOVER);
if(ret&GUI_UP && active)
{
char *act = NULL;
if(ret&GUI_ALT && altact && *altact) act = altact;
Expand Down
85 changes: 76 additions & 9 deletions src/engine/ui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,44 @@ struct gui : guient
static int curdepth, curlist, xsize, ysize, curx, cury, fontdepth, mergelist, mergedepth;
static bool hitfx, skinfx, cursorfx;

// Example: {3, 2} means that the current object (button/slider/whatever) is the 2nd child of the 3rd top-level child.
// The exact numbers don't matter as long as they are unique for each object.
static vector<int> curchildpath;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not use std::vector?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because vector is used in other places. It could be confusing to mix the two.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We wanna switch to using STL datatypes and functions instead of the custom implementation, IIRC the custom vector has severe memory problems, but also it's way easier to use the STL for everybody because everybody usually knows how it behaves, if you look at PRs that have been merged so far, they all use std::vector instead of vector unless it has a serious advantage to use vector


// This is a copy of curchildpath made when pressing down a mouse button on an object.
// It's used to remember what item is interacted with (on the previous frame).
static vector<int> activechildpath;

// This is used to set activechildpath on the next frame.
// The reason we don't set activechildpath directly is that then it will be half set in the middle of each frame.
static vector<int> nextactivechildpath;

bool current_is_active()
{
if(activechildpath.size() != curchildpath.size()) return false;
for(int i = 0; i < curchildpath.size(); i++)
{
if(curchildpath[i] != activechildpath[i]) return false;
}
return true;
}

// Registers current object as unique and returns whether it's active (pressed with mouse).
bool unique_object_active(bool hit)
{
bool active = current_is_active();
if(active && mouse_action[0] & GUI_UP)
{
nextactivechildpath.clear();
}
else if(hit && mouse_action[0] & GUI_DOWN)
{
nextactivechildpath = curchildpath;
}
curchildpath.last()++;
return active;
}

static void reset()
{
if(statusstr) DELETEA(statusstr);
Expand Down Expand Up @@ -212,9 +250,11 @@ struct gui : guient
int x1 = curx+tx, x2 = x1 + width + ui_size_spacer, y1 = cury - ui_size_spacer - height, y2 = cury - ui_size_spacer * 3 / 4, alpha = ui_blend_text, border = -1;
if(!visibletab())
{
if(tcurrent && !passthrough && fieldmode != FIELDKEY && hitx>=x1 && hity>=y1 && hitx<x2 && hity<y2)
bool hit = hitx >= x1 && hity >= y1 && hitx < x2 && hity < y2;
bool active = unique_object_active(hit);
if(tcurrent && !passthrough && fieldmode != FIELDKEY && hit)
{
if(!ui_click_tab || mouse_action[0] & GUI_UP) *tcurrent = tpos; // switch tab
if(active && (!ui_click_tab || mouse_action[0] & GUI_UP)) *tcurrent = tpos; // switch tab
tcolor = ui_color_active;
alpha = max(alpha, ui_fade_text);
if(ui_tab_border) border = tcolor;
Expand Down Expand Up @@ -245,11 +285,11 @@ struct gui : guient
#define uibtn(a,b) \
{ \
int border = -1; \
bool hit = false; \
if(!passthrough && fieldmode != FIELDKEY && hitx>=x1 && hity>=y1 && hitx<x2 && hity<y2) \
bool hit = !passthrough && fieldmode != FIELDKEY && hitx>=x1 && hity>=y1 && hitx<x2 && hity<y2; \
bool active = unique_object_active(hit); \
if(hit) \
{ \
if(mouse_action[0]&GUI_UP) { b; } \
hit = true; \
if(active && mouse_action[0]&GUI_UP) { b; } \
if(ui_tab_border) border = ui_color_active; \
} \
else if(ui_tab_border == 2) border = vec::hexcolor(ui_color_border).mul(0.25f).tohexcolor(); \
Expand Down Expand Up @@ -313,10 +353,13 @@ struct gui : guient
mergelist = curlist;
mergedepth = curdepth;
}
if(!curchildpath.empty()) curchildpath.last()++;
curchildpath.emplace_back(0);
}

int poplist()
{
if(curchildpath.size()) curchildpath.pop_back();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please write if (int(curchildpath.size()) != 0) instead of if (curchildpath.size())

if(!lists.inrange(curlist)) return 0;
list &l = lists[curlist];
if(guilayoutpass)
Expand Down Expand Up @@ -440,7 +483,15 @@ struct gui : guient
{
if(scale == 0) scale = 1;
int size = (int)(scale*2*FONTH) - ui_shadow;
if(visible()) icon_(t, overlaid, curx, cury, size, ishit(size + ui_shadow, size + ui_shadow), icolour, o, ocolour);
bool hit = ishit(size + ui_shadow, size + ui_shadow);
if(visible())
{
bool active = unique_object_active(hit);
icon_(t, overlaid, curx, cury, size, hit, icolour, o, ocolour);
int ret = layout(size + ui_shadow, size + ui_shadow);
if(!active) ret &= ~GUI_UP;
return ret;
}
return layout(size + ui_shadow, size + ui_shadow);
}

Expand All @@ -459,6 +510,7 @@ struct gui : guient
if(visible())
{
bool hit = ishit(size + ui_shadow, size + ui_shadow);
bool active = unique_object_active(hit);
float xs = size, ys = size, xi = curx, yi = cury, xpad = 0, ypad = 0;
if(overlaid)
{
Expand Down Expand Up @@ -486,6 +538,10 @@ struct gui : guient
rect_(xi - xpad, yi - ypad, xs + 2*xpad, ys + 2*ypad, 0);
}
if(hit && hitfx && cursorfx && !ui_cursor_type) ui_cursor_type = 1;

int ret = layout(size + ui_shadow, size + ui_shadow);
if(!active) ret &= ~GUI_UP;
return ret;
}
return layout(size + ui_shadow, size + ui_shadow);
}
Expand Down Expand Up @@ -603,12 +659,13 @@ struct gui : guient
int space = slider_(ui_size_slider, percent, ishorizontal() ? FONTW * 3 : FONTH, hit, style, scolour);
if(visible())
{
if(hit)
bool active = unique_object_active(hit);
if((hit && activechildpath.empty()) || active)
{
if(!label) label = intstr(val);
settooltip("\f[%d]%s", -1, colour, label);
tooltipforce = true;
if(mouse_action[0] & GUI_PRESSED)
if(active)
{
int vnew = vmax-vmin+1;
if(ishorizontal()) vnew = int((vnew*(reverse ? hity - y - ui_size_slider / 2 : y + ysize - ui_size_slider / 2 - hity)) / (ysize - ui_size_slider));
Expand Down Expand Up @@ -1136,6 +1193,8 @@ struct gui : guient
if(visible())
{
bool hit = ishit(w, h);
bool active = unique_object_active(hit);

int x = curx;
if((icon && *icon) || (oicon && *oicon))
{
Expand All @@ -1148,6 +1207,10 @@ struct gui : guient
}
if(text && *text) text_(text, x, cury, color, (hit && hitfx) || !faded || !clickable ? ui_blend_text : ui_fade_text, hit && clickable, wrap > 0 ? wrap : -1);
if(clickable && hit && hitfx && cursorfx && !ui_cursor_type) ui_cursor_type = 1;

int ret = layout(w, h);
if(!active) ret &= ~GUI_UP;
return ret;
}
return layout(w, h);
}
Expand All @@ -1172,6 +1235,7 @@ struct gui : guient

void start(int starttime, int *tab, bool allowinput, bool wantstitle, bool wantsbgfx)
{
if(!guilayoutpass) activechildpath = nextactivechildpath;
fontdepth = 0;
gui::pushfont("default");
basescale = ui_scale;
Expand Down Expand Up @@ -1285,6 +1349,9 @@ float gui::basescale, gui::maxscale = 1, gui::hitx, gui::hity;
bool gui::passthrough, gui::hitfx = true, gui::cursorfx = true, gui::skinfx = true;
int gui::curdepth, gui::fontdepth, gui::curlist, gui::xsize, gui::ysize, gui::curx, gui::cury, gui::mergelist, gui::mergedepth;
int gui::ty, gui::tx, gui::tpos, *gui::tcurrent, gui::tcolor;
vector<int> gui::curchildpath;
vector<int> gui::activechildpath;
vector<int> gui::nextactivechildpath;
static vector<gui> guis;

namespace UI
Expand Down
2 changes: 2 additions & 0 deletions src/shared/iengine.h
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,8 @@ struct guient
virtual void start(int starttime, int *tab = NULL, bool allowinput = true, bool wantstitle = true, bool wantsbgfx = true) = 0;
virtual void end() = 0;

virtual bool unique_object_active(bool hit) = 0;

virtual int text(const char *text, int color = 0xFFFFFF, const char *icon = NULL, int icolour = 0xFFFFFF, int wrap = -1, bool faded = false, const char *oicon = NULL, int ocolor = 0xFFFFFF) = 0;
int textf(const char *fmt, int color = 0xFFFFFF, const char *icon = NULL, int icolour = 0xFFFFFF, int wrap = -1, bool faded = false, const char *oicon = NULL, int ocolor = 0xFFFFFF, ...) PRINTFARGS(2, 10)
{
Expand Down