engine/quakec/menusys/menusys/mitem_grid.qc

211 lines
5.4 KiB
Plaintext

#ifndef MITEM_GRID_QC__
#define MITEM_GRID_QC__
//simple key/value grid (with editing).
class mitem_grid : mitem
{
//virtual void(mitem newfocus, float changedflag) item_focuschange;
virtual float(vector pos, float scan, float char, float down) item_keypress;
virtual void(vector pos) item_draw;
virtual void() item_resized;
//first child is determined from the vslider.
float grid_numchildren;
float grid_mactive;
float grid_kactive;
mitem_vslider vslider; //displayed if any client item's max[y] > our item_size[y]
virtual void(vector pos, float idx) grid_draw = 0;
virtual float(vector pos, float scan, float char, float down, float idx) grid_keypress = {return FALSE;};
virtual void(float olditem, float newitem) grid_selectionchanged = {}; //just key focus
};
//does NOT wrap.
//does NOT pass go.
static mitem(mitem item, float upwards) menu_simplenextitem =
{
mitem_frame menu = item.item_parent;
mitem prev;
if (upwards)
{
if (item)
{
item = item.item_next;
if (!item)
return __NULL__;
return item;
}
else
return __NULL__;
}
else
{
for(prev = menu.item_children; prev.item_next; prev = prev.item_next)
{
if (prev.item_next == item)
return prev;
}
return __NULL__;
}
};
float(vector pos, float scan, float char, float down) mitem_grid::item_keypress =
{
float ch;
float handled = FALSE;
if (scan >= K_MOUSE1 && scan <= K_MOUSE5 && scan != K_MWHEELUP && scan != K_MWHEELDOWN)
{
ch = grid_mactive;
if (ch != grid_kactive)
if (down && scan == K_MOUSE1) //keyboard focus follows on mouse click.
{
item_focuschange((ch>=0)?__NULL__:vslider, IF_KFOCUSED);
grid_selectionchanged(grid_kactive, ch);
grid_kactive = ch;
handled = TRUE;
}
}
else
{
ch = grid_kactive;
if (ch<0 && down)
{
//if there's no key child active, then go and pick one so you can just start using keyboard access etc.
if (grid_mactive)
ch = grid_mactive;
else
ch = 0;
item_focuschange((ch>=0)?__NULL__:vslider, IF_KFOCUSED);
grid_selectionchanged(grid_kactive, ch);
grid_kactive = ch;
}
}
if (vslider)
pos[1] -= vslider.val;
if (ch<0&&vslider)
{
if (vslider.item_keypress)
handled = vslider.item_keypress(pos + vslider.item_position, scan, char, down);
}
else if (!handled && ch >= 0 && ch < grid_numchildren)
handled = grid_keypress(pos + vslider.item_position + [0,ch]*item_scale, scan, char, down, ch);
if (!handled && down)
{
ch = grid_kactive;
switch(scan)
{
case K_MWHEELUP:
case K_MWHEELDOWN:
if (vslider) //give mwheel to the slider if its visible.
handled = vslider.item_keypress(pos + vslider.item_position, scan, char, down);
break;
case K_HOME:
ch = 0;
break;
case K_END:
ch = grid_numchildren-1;
break;
case K_PGUP:
ch = max(0, grid_kactive-5);
break;
case K_PGDN:
ch = min(grid_numchildren-1, grid_kactive+5);
break;
case K_UPARROW:
ch = max(grid_kactive-1, 0);
break;
case K_DOWNARROW:
ch = min(grid_kactive+1, grid_numchildren-1);
break;
}
if (ch != grid_kactive)
{
grid_selectionchanged(grid_kactive, ch);
grid_kactive = ch;
handled = TRUE;
}
}
return handled;
};
void() mitem_grid::item_resized =
{
float clientheight = grid_numchildren * item_scale;
if (clientheight > item_size[1])
{
if (!vslider)
vslider = spawn(mitem_vslider, val:0, stride:8);
vslider.maxv = clientheight - item_size[1];
}
else if (vslider)
{
vslider.item_remove();
vslider = (mitem_vslider)__NULL__;
}
}
void(vector pos) mitem_grid::item_draw =
{
local vector omin = ui.drawrectmin, omax = ui.drawrectmax;
local vector clientpos;
local vector clientsize;
clientpos = pos;
clientsize = this.item_size;
if (vslider)
{
//scroll+shrink the client area to fit the slider on it.
clientpos[1] -= vslider.val;
clientsize[0] -= vslider.item_size[0];
}
if (ui.mousepos != ui.oldmousepos)
{
local mitem newfocus = __NULL__;
grid_mactive = floor((ui.mousepos[1]-clientpos_y)/item_scale);
if (vslider)
if (mouseinbox(pos + [clientsize[0], 0], vslider.item_size))
{
newfocus = vslider;
grid_mactive = -1;
}
this.item_focuschange(newfocus, IF_MFOCUSED);
}
//clip the draw rect to our area, so children don't draw outside it. don't draw if its inverted.
if (pos_x > ui.drawrectmin[0])
ui.drawrectmin[0] = pos_x;
if (pos_y > ui.drawrectmin[1])
ui.drawrectmin[1] = pos_y;
if (pos_x+clientsize_x < ui.drawrectmax[0])
ui.drawrectmax[0] = pos_x+clientsize_x;
if (pos_y+clientsize_y < ui.drawrectmax[1])
ui.drawrectmax[1] = pos_y+clientsize[1];
if (ui.drawrectmax[0] > ui.drawrectmin[0] && ui.drawrectmax[1] > ui.drawrectmin[1])
{
ui.setcliparea(ui.drawrectmin[0], ui.drawrectmin[1], ui.drawrectmax[0] - ui.drawrectmin[0], ui.drawrectmax[1] - ui.drawrectmin[1]);
float c = max(0,floor((ui.drawrectmin[1]-clientpos_y)/item_scale)); //calculate how many we can skip
for (clientpos_y += item_scale * c; c < grid_numchildren; c++, clientpos_y += item_scale)
{
if (clientpos_y >= ui.drawrectmax[1])
break;
grid_draw(clientpos, c);
}
ui.setcliparea(omin_x, omin_y, omax_x - omin_x, omax_y - omin_y);
if (vslider)
{
vslider.item_size[1] = clientsize[1];
vslider.item_draw(pos + [clientsize[0], 0]);
}
}
ui.drawrectmin = omin;
ui.drawrectmax = omax;
};
#endif