362 lines
8.0 KiB
ActionScript
362 lines
8.0 KiB
ActionScript
import elements.BaseGuiElement;
|
|
import elements.GuiListbox;
|
|
import elements.GuiMarkupText;
|
|
from gui import clearTooltip;
|
|
|
|
export GuiContextOption, GuiSubMenu, GuiContextMenu;
|
|
export GuiMarkupContextOption;
|
|
|
|
const uint CTX_LEFT_OFF = 12;
|
|
const uint CTX_RIGHT_OFF = 12;
|
|
|
|
class GuiContextOption : GuiListElement {
|
|
Sprite icon;
|
|
Color color;
|
|
string text;
|
|
int height = -1;
|
|
int value = 0;
|
|
bool selectable = true;
|
|
bool separator = false;
|
|
|
|
GuiContextOption() {
|
|
}
|
|
|
|
GuiContextOption(const string& txt, int val = 0) {
|
|
text = txt;
|
|
value = val;
|
|
}
|
|
|
|
void set(const string& txt) {
|
|
text = txt;
|
|
height = -1;
|
|
}
|
|
|
|
string get() {
|
|
return text;
|
|
}
|
|
|
|
bool get_isSelectable() {
|
|
return selectable;
|
|
}
|
|
|
|
void call(GuiContextMenu@ menu) {
|
|
}
|
|
|
|
int getWidth(GuiListbox@ ele) {
|
|
const Font@ font = ele.skin.getFont(ele.TextFont);
|
|
int w = font.getDimension(text).x + ele.horizPadding * 2;
|
|
if(height == -1)
|
|
height = font.getDimension(text).height;
|
|
if(icon.valid) {
|
|
vec2i iconSize = icon.size;
|
|
if(iconSize.y > height + 8) {
|
|
iconSize.x = double(height + 8) / double(iconSize.y) * double(iconSize.x);
|
|
iconSize.y = height + 8;
|
|
}
|
|
w += iconSize.x + 8;
|
|
}
|
|
return w;
|
|
}
|
|
|
|
void draw(GuiListbox@ ele, uint flags, const recti& absPos) override {
|
|
const Font@ font = ele.skin.getFont(ele.TextFont);
|
|
|
|
if(height == -1)
|
|
height = font.getDimension(text).height;
|
|
|
|
vec2i textOffset(ele.horizPadding, (ele.lineHeight - height) / 2);
|
|
|
|
if(icon.valid) {
|
|
vec2i iconSize = icon.size;
|
|
if(iconSize.y > height + 8) {
|
|
iconSize.x = double(height + 8) / double(iconSize.y) * double(iconSize.x);
|
|
iconSize.y = height + 8;
|
|
}
|
|
vec2i iconOffset(ele.horizPadding, (ele.lineHeight - iconSize.height) / 2);
|
|
icon.draw(recti_area(absPos.topLeft + iconOffset, iconSize));
|
|
textOffset.x += iconSize.width + 8;
|
|
}
|
|
font.draw(absPos.topLeft + textOffset, text, color);
|
|
if(separator)
|
|
drawRectangle(
|
|
recti_area(absPos.topLeft + vec2i(6, absPos.size.height / 2 - 1),
|
|
vec2i(absPos.size.width - 12, 2)),
|
|
Color(0x88888888));
|
|
}
|
|
};
|
|
|
|
class GuiMarkupContextOption : GuiContextOption {
|
|
MarkupRenderer renderer;
|
|
|
|
GuiMarkupContextOption() {
|
|
}
|
|
|
|
GuiMarkupContextOption(const string& txt, int val = 0) {
|
|
set(txt);
|
|
value = val;
|
|
}
|
|
|
|
void set(const string& txt) {
|
|
text = txt;
|
|
height = -1;
|
|
|
|
renderer.parseTree(txt);
|
|
}
|
|
|
|
int getWidth(GuiListbox@ ele) {
|
|
renderer.update(ele.skin, recti_area(0,0,3000,100));
|
|
return renderer.width + 24;
|
|
}
|
|
|
|
void draw(GuiListbox@ ele, uint flags, const recti& absPos) override {
|
|
const Font@ font = ele.skin.getFont(ele.TextFont);
|
|
|
|
if(height == -1)
|
|
height = ele.lineHeight;
|
|
vec2i textOffset(ele.horizPadding, (ele.lineHeight - height) / 2);
|
|
|
|
if(icon.valid) {
|
|
vec2i iconSize = icon.size;
|
|
if(iconSize.y > height + 8) {
|
|
iconSize.x = double(height + 8) / double(iconSize.y) * double(iconSize.x);
|
|
iconSize.y = height + 8;
|
|
}
|
|
vec2i iconOffset(ele.horizPadding, (ele.lineHeight - iconSize.height) / 2);
|
|
icon.draw(recti_area(absPos.topLeft + iconOffset, iconSize));
|
|
textOffset.x += iconSize.width + 8;
|
|
}
|
|
renderer.draw(ele.skin, absPos.padded(textOffset.x, textOffset.y, 4, 4));
|
|
}
|
|
};
|
|
|
|
class GuiSubMenu : GuiContextOption {
|
|
GuiContextMenu@ menu;
|
|
|
|
GuiSubMenu(GuiContextMenu@ parent, const string& txt) {
|
|
@menu = GuiContextMenu(parent);
|
|
text = txt;
|
|
}
|
|
|
|
void set(const string& txt) {
|
|
text = txt;
|
|
}
|
|
|
|
string get() {
|
|
return text;
|
|
}
|
|
|
|
void call(GuiContextMenu@ m) {
|
|
menu.open();
|
|
}
|
|
};
|
|
|
|
class GuiContextMenu : BaseGuiElement {
|
|
GuiListbox@ list;
|
|
GuiContextMenu@ parentMenu;
|
|
vec2i origin;
|
|
bool flexWidth = true;
|
|
|
|
GuiContextMenu(const vec2i& orig, int width = 200, bool Flex = true) {
|
|
origin = orig;
|
|
flexWidth = Flex;
|
|
super(null, Alignment_Fill());
|
|
@list = GuiListbox(this, recti_area(orig, vec2i(width, 0)));
|
|
list.style = SS_ContextMenu;
|
|
list.itemStyle = SS_ContextMenuItem;
|
|
list.itemHeight = 28;
|
|
setGuiAbsorb(this);
|
|
clearTooltip();
|
|
}
|
|
|
|
GuiContextMenu(GuiContextMenu@ parent) {
|
|
super(null, Alignment_Fill());
|
|
@parentMenu = parent;
|
|
@list = GuiListbox(parent.top, recti());
|
|
list.style = SS_ContextMenu;
|
|
list.itemStyle = SS_ContextMenuItem;
|
|
list.itemHeight = parent.list.itemHeight;
|
|
visible = false;
|
|
}
|
|
|
|
GuiContextMenu@ get_top() {
|
|
GuiContextMenu@ p = this;
|
|
while(p.parentMenu !is null)
|
|
@p = p.parentMenu;
|
|
return p;
|
|
}
|
|
|
|
void open() {
|
|
visible = true;
|
|
int hov = parentMenu.list.hovered;
|
|
vec2i offset = parentMenu.list.getItemOffset(hov);
|
|
|
|
list.size = vec2i(parentMenu.list.size.width, 0);
|
|
list.position = parentMenu.position + offset + vec2i(parentMenu.list.size.width);
|
|
}
|
|
|
|
void set_width(int width) {
|
|
list.size = vec2i(width, list.size.height);
|
|
}
|
|
|
|
void clear() {
|
|
list.clearItems();
|
|
}
|
|
|
|
void addOption(const string& text, int value = 0) {
|
|
list.addItem(GuiContextOption(text, value));
|
|
}
|
|
|
|
void addOption(GuiContextOption@ opt) {
|
|
list.addItem(opt);
|
|
}
|
|
|
|
void addOption(GuiContextOption@ opt, const string& text, int value = 0) {
|
|
opt.text = text;
|
|
opt.value = value;
|
|
opt.set(text);
|
|
list.addItem(opt);
|
|
}
|
|
|
|
void addOption(GuiContextOption@ opt, const string& text, const Sprite& sprt, int value = 0) {
|
|
opt.text = text;
|
|
opt.value = value;
|
|
opt.icon = sprt;
|
|
opt.set(text);
|
|
list.addItem(opt);
|
|
}
|
|
|
|
void finalize() {
|
|
if(list.itemCount == 0)
|
|
remove();
|
|
else
|
|
updateAbsolutePosition();
|
|
}
|
|
|
|
void addLabel(const string& text) {
|
|
GuiContextOption opt(text);
|
|
opt.selectable = false;
|
|
list.addItem(opt);
|
|
}
|
|
|
|
void addSeparator() {
|
|
GuiContextOption opt;
|
|
opt.selectable = false;
|
|
opt.separator = true;
|
|
list.addItem(opt);
|
|
}
|
|
|
|
GuiContextMenu@ addSubMenu(const string& text) {
|
|
GuiSubMenu sub(this, text);
|
|
addOption(sub);
|
|
return sub.menu;
|
|
}
|
|
|
|
void remove() {
|
|
if(parentMenu !is null)
|
|
parentMenu.remove();
|
|
list.remove();
|
|
BaseGuiElement::remove();
|
|
}
|
|
|
|
bool onMouseEvent(const MouseEvent& event, IGuiElement@ source) {
|
|
if(event.type == MET_Button_Up && source is this) {
|
|
remove();
|
|
return true;
|
|
}
|
|
return BaseGuiElement::onMouseEvent(event, source);
|
|
}
|
|
|
|
bool onKeyEvent(const KeyboardEvent& event, IGuiElement@ source) {
|
|
switch(event.type) {
|
|
case KET_Key_Down:
|
|
if(event.key == KEY_ESC)
|
|
return true;
|
|
break;
|
|
case KET_Key_Up:
|
|
if(event.key == KEY_ESC) {
|
|
remove();
|
|
return true;
|
|
}
|
|
break;
|
|
}
|
|
return BaseGuiElement::onKeyEvent(event, source);
|
|
}
|
|
|
|
bool onGuiEvent(const GuiEvent& evt) {
|
|
switch(evt.type) {
|
|
case GUI_Changed:
|
|
if(evt.caller is list) {
|
|
int sel = list.selected;
|
|
if(sel != -1) {
|
|
GuiContextOption@ opt = cast<GuiContextOption>(list.getItemElement(sel));
|
|
opt.call(this);
|
|
emitClicked();
|
|
}
|
|
|
|
remove();
|
|
return true;
|
|
}
|
|
break;
|
|
}
|
|
return BaseGuiElement::onGuiEvent(evt);
|
|
}
|
|
|
|
void set_itemHeight(int value) {
|
|
list.itemHeight = value;
|
|
}
|
|
|
|
void updateAbsolutePosition() {
|
|
BaseGuiElement::updateAbsolutePosition();
|
|
|
|
//Calculate correct width
|
|
int width = list.size.width;
|
|
int wantWidth = width;
|
|
if(flexWidth) {
|
|
for(uint i = 0, cnt = list.itemCount; i < cnt; ++i) {
|
|
int w = cast<GuiContextOption>(list.getItemElement(i)).getWidth(list);
|
|
if(w > wantWidth)
|
|
wantWidth = w;
|
|
}
|
|
}
|
|
|
|
//Calculate correct height
|
|
int height = list.size.height;
|
|
int wantHeight = list.itemCount * list.lineHeight;
|
|
if(wantHeight > parent.size.height - 40) {
|
|
wantWidth += 20;
|
|
wantHeight = parent.size.height - 40;
|
|
}
|
|
if(height == wantHeight && width == wantWidth)
|
|
return;
|
|
|
|
//Resize it to the correct height
|
|
list.size = vec2i(wantWidth, wantHeight);
|
|
width = wantWidth;
|
|
height = wantHeight;
|
|
|
|
//Position on the horizontal axis
|
|
vec2i pos;
|
|
vec2i psize = size;
|
|
if(origin.x + CTX_RIGHT_OFF + width > psize.width &&
|
|
origin.x - width - CTX_LEFT_OFF > 0)
|
|
pos.x = origin.x - width - CTX_LEFT_OFF;
|
|
else
|
|
pos.x = origin.x + CTX_RIGHT_OFF;
|
|
|
|
//Position on the vertical axis
|
|
if(origin.y + height > psize.y) {
|
|
if(origin.y - height > 0) {
|
|
pos.y = origin.y - height;
|
|
}
|
|
else {
|
|
pos.y = psize.y - height;
|
|
}
|
|
}
|
|
else {
|
|
pos.y = origin.y;
|
|
}
|
|
|
|
list.position = pos;
|
|
}
|
|
};
|