Move Canvas and game ui to armory.ui package

This commit is contained in:
Lubos Lenco 2021-05-07 15:24:03 +02:00
parent 4db37ea1c1
commit 2f1fe4ef0b
4 changed files with 872 additions and 4 deletions

View file

@ -3,7 +3,7 @@ package armory.trait.internal;
import iron.Trait;
#if arm_ui
import zui.Zui;
import zui.Canvas;
import armory.ui.Canvas;
#end
class CanvasScript extends Trait {
@ -62,7 +62,7 @@ class CanvasScript extends Trait {
notifyOnRender2D(function(g: kha.graphics2.Graphics) {
if (canvas == null) return;
setCanvasDimensions(kha.System.windowWidth(), kha.System.windowHeight());
var events = Canvas.draw(cui, canvas, g);
@ -121,7 +121,7 @@ class CanvasScript extends Trait {
public function setCanvasVisibility(visible: Bool){
for (e in canvas.elements) e.visible = visible;
}
/**
* Set dimensions of canvas
* @param x Width
@ -140,7 +140,7 @@ class CanvasScript extends Trait {
}
// Contains data
@:access(zui.Canvas)
@:access(armory.ui.Canvas)
@:access(zui.Handle)
public function getHandle(name: String): Handle {
// Consider this a temporary solution

410
Sources/armory/ui/Canvas.hx Normal file
View file

@ -0,0 +1,410 @@
package armory.ui;
import zui.Zui;
using kha.graphics2.GraphicsExtension;
@:access(zui.Zui)
class Canvas {
public static var assetMap = new Map<Int, Dynamic>(); // kha.Image | kha.Font
public static var themes = new Array<zui.Themes.TTheme>();
static var events:Array<String> = [];
public static var screenW = -1;
public static var screenH = -1;
public static var locale = "en";
static var _ui: Zui;
static var h = new zui.Zui.Handle(); // TODO: needs one handle per canvas
public static function draw(ui: Zui, canvas: TCanvas, g: kha.graphics2.Graphics): Array<String> {
screenW = kha.System.windowWidth();
screenH = kha.System.windowHeight();
events.resize(0);
_ui = ui;
g.end();
ui.begin(g); // Bake elements
g.begin(false);
ui.g = g;
for (elem in canvas.elements) {
if (elem.parent == null) drawElement(ui, canvas, elem);
}
g.end();
ui.end(); // Finish drawing
g.begin(false);
return events;
}
static function drawElement(ui: Zui, canvas: TCanvas, element: TElement, px = 0.0, py = 0.0) {
if (element == null || element.visible == false) return;
var anchorOffset = getAnchorOffset(canvas, element);
px += anchorOffset[0];
py += anchorOffset[1];
ui._x = canvas.x + scaled(element.x) + px;
ui._y = canvas.y + scaled(element.y) + py;
ui._w = scaled(element.width);
var rotated = element.rotation != null && element.rotation != 0;
if (rotated) ui.g.pushRotation(element.rotation, ui._x + scaled(element.width) / 2, ui._y + scaled(element.height) / 2);
switch (element.type) {
case Text:
var font = ui.ops.font;
var size = ui.fontSize;
var fontAsset = element.asset != null && StringTools.endsWith(element.asset, ".ttf");
if (fontAsset) ui.ops.font = getAsset(canvas, element.asset);
ui.fontSize = scaled(element.height);
ui.t.TEXT_COL = getColor(element.color_text, getTheme(canvas.theme).TEXT_COL);
ui.text(getText(canvas, element), element.alignment);
ui.ops.font = font;
ui.fontSize = size;
case Button:
var eh = ui.t.ELEMENT_H;
var bh = ui.t.BUTTON_H;
ui.t.ELEMENT_H = element.height;
ui.t.BUTTON_H = element.height;
ui.t.BUTTON_COL = getColor(element.color, getTheme(canvas.theme).BUTTON_COL);
ui.t.BUTTON_TEXT_COL = getColor(element.color_text, getTheme(canvas.theme).BUTTON_TEXT_COL);
ui.t.BUTTON_HOVER_COL = getColor(element.color_hover, getTheme(canvas.theme).BUTTON_HOVER_COL);
ui.t.BUTTON_PRESSED_COL = getColor(element.color_press, getTheme(canvas.theme).BUTTON_PRESSED_COL);
if (ui.button(getText(canvas, element), element.alignment)) {
var e = element.event;
if (e != null && e != "") events.push(e);
}
ui.t.ELEMENT_H = eh;
ui.t.BUTTON_H = bh;
case Image:
var image = getAsset(canvas, element.asset);
var fontAsset = element.asset != null && StringTools.endsWith(element.asset, ".ttf");
if (image != null && !fontAsset) {
ui.imageScrollAlign = false;
var tint = element.color != null ? element.color : 0xffffffff;
if (ui.image(image, tint, scaled(element.height)) == zui.Zui.State.Released) {
var e = element.event;
if (e != null && e != "") events.push(e);
}
ui.imageScrollAlign = true;
}
case FRectangle:
var col = ui.g.color;
ui.g.color = getColor(element.color, getTheme(canvas.theme).BUTTON_COL);
ui.g.fillRect(ui._x, ui._y, ui._w, scaled(element.height));
ui.g.color = col;
case FCircle:
var col = ui.g.color;
ui.g.color = getColor(element.color, getTheme(canvas.theme).BUTTON_COL);
ui.g.fillCircle(ui._x + (scaled(element.width) / 2), ui._y + (scaled(element.height) / 2), ui._w / 2);
ui.g.color = col;
case Rectangle:
var col = ui.g.color;
ui.g.color = getColor(element.color, getTheme(canvas.theme).BUTTON_COL);
ui.g.drawRect(ui._x, ui._y, ui._w, scaled(element.height), element.strength);
ui.g.color = col;
case Circle:
var col = ui.g.color;
ui.g.color = getColor(element.color, getTheme(canvas.theme).BUTTON_COL);
ui.g.drawCircle(ui._x+(scaled(element.width) / 2), ui._y + (scaled(element.height) / 2), ui._w / 2, element.strength);
ui.g.color = col;
case FTriangle:
var col = ui.g.color;
ui.g.color = getColor(element.color, getTheme(canvas.theme).BUTTON_COL);
ui.g.fillTriangle(ui._x + (ui._w / 2), ui._y, ui._x, ui._y + scaled(element.height), ui._x + ui._w, ui._y + scaled(element.height));
ui.g.color = col;
case Triangle:
var col = ui.g.color;
ui.g.color = getColor(element.color, getTheme(canvas.theme).BUTTON_COL);
ui.g.drawLine(ui._x + (ui._w / 2), ui._y, ui._x, ui._y + scaled(element.height), element.strength);
ui.g.drawLine(ui._x, ui._y + scaled(element.height), ui._x + ui._w, ui._y + scaled(element.height), element.strength);
ui.g.drawLine(ui._x + ui._w, ui._y + scaled(element.height), ui._x + (ui._w / 2), ui._y, element.strength);
ui.g.color = col;
case Check:
ui.t.TEXT_COL = getColor(element.color_text, getTheme(canvas.theme).TEXT_COL);
ui.t.ACCENT_COL = getColor(element.color, getTheme(canvas.theme).BUTTON_COL);
ui.t.ACCENT_HOVER_COL = getColor(element.color_hover, getTheme(canvas.theme).BUTTON_HOVER_COL);
ui.check(h.nest(element.id), getText(canvas, element));
case Radio:
ui.t.TEXT_COL = getColor(element.color_text, getTheme(canvas.theme).TEXT_COL);
ui.t.ACCENT_COL = getColor(element.color, getTheme(canvas.theme).BUTTON_COL);
ui.t.ACCENT_HOVER_COL = getColor(element.color_hover, getTheme(canvas.theme).BUTTON_HOVER_COL);
zui.Ext.inlineRadio(ui, h.nest(element.id), getText(canvas, element).split(";"));
case Combo:
ui.t.TEXT_COL = getColor(element.color_text, getTheme(canvas.theme).TEXT_COL);
ui.t.LABEL_COL = getColor(element.color_text, getTheme(canvas.theme).TEXT_COL);
ui.t.ACCENT_COL = getColor(element.color, getTheme(canvas.theme).BUTTON_COL);
ui.t.SEPARATOR_COL = getColor(element.color, getTheme(canvas.theme).BUTTON_COL);
ui.t.ACCENT_HOVER_COL = getColor(element.color_hover, getTheme(canvas.theme).BUTTON_HOVER_COL);
ui.combo(h.nest(element.id), getText(canvas, element).split(";"));
case Slider:
ui.t.TEXT_COL = getColor(element.color_text, getTheme(canvas.theme).TEXT_COL);
ui.t.LABEL_COL = getColor(element.color_text, getTheme(canvas.theme).TEXT_COL);
ui.t.ACCENT_COL = getColor(element.color, getTheme(canvas.theme).BUTTON_COL);
ui.t.ACCENT_HOVER_COL = getColor(element.color_hover, getTheme(canvas.theme).BUTTON_HOVER_COL);
ui.slider(h.nest(element.id), getText(canvas, element), 0.0, 1.0, true, 100, true, element.alignment);
case TextInput:
ui.t.TEXT_COL = getColor(element.color_text, getTheme(canvas.theme).TEXT_COL);
ui.t.LABEL_COL = getColor(element.color_text, getTheme(canvas.theme).TEXT_COL);
ui.t.ACCENT_COL = getColor(element.color, getTheme(canvas.theme).BUTTON_COL);
ui.t.ACCENT_HOVER_COL = getColor(element.color_hover, getTheme(canvas.theme).BUTTON_HOVER_COL);
ui.textInput(h.nest(element.id), getText(canvas, element), element.alignment);
if (h.nest(element.id).changed) {
var e = element.event;
if (e != null && e != "") events.push(e);
}
case TextArea:
ui.t.TEXT_COL = getColor(element.color_text, getTheme(canvas.theme).TEXT_COL);
ui.t.LABEL_COL = getColor(element.color_text, getTheme(canvas.theme).TEXT_COL);
ui.t.ACCENT_COL = getColor(element.color, getTheme(canvas.theme).BUTTON_COL);
ui.t.ACCENT_HOVER_COL = getColor(element.color_hover, getTheme(canvas.theme).BUTTON_HOVER_COL);
h.nest(element.id).text = getText(canvas, element);
zui.Ext.textArea(ui,h.nest(element.id), element.alignment,element.editable);
if (h.nest(element.id).changed) {
var e = element.event;
if (e != null && e != "") events.push(e);
}
case KeyInput:
ui.t.TEXT_COL = getColor(element.color_text, getTheme(canvas.theme).TEXT_COL);
ui.t.LABEL_COL = getColor(element.color_text, getTheme(canvas.theme).TEXT_COL);
ui.t.ACCENT_COL = getColor(element.color, getTheme(canvas.theme).BUTTON_COL);
ui.t.ACCENT_HOVER_COL = getColor(element.color_hover, getTheme(canvas.theme).BUTTON_HOVER_COL);
Ext.keyInput(ui, h.nest(element.id), getText(canvas, element));
case ProgressBar:
var col = ui.g.color;
var progress = element.progress_at;
var totalprogress = element.progress_total;
ui.g.color = getColor(element.color_progress, getTheme(canvas.theme).TEXT_COL);
ui.g.fillRect(ui._x, ui._y, ui._w / totalprogress * Math.min(progress, totalprogress), scaled(element.height));
ui.g.color = getColor(element.color, getTheme(canvas.theme).BUTTON_COL);
ui.g.drawRect(ui._x, ui._y, ui._w, scaled(element.height), element.strength);
ui.g.color = col;
case CProgressBar:
var col = ui.g.color;
var progress = element.progress_at;
var totalprogress = element.progress_total;
ui.g.color = getColor(element.color_progress, getTheme(canvas.theme).TEXT_COL);
ui.g.drawArc(ui._x + (scaled(element.width) / 2), ui._y + (scaled(element.height) / 2), ui._w / 2, -Math.PI / 2, ((Math.PI * 2) / totalprogress * progress) - Math.PI / 2, element.strength);
ui.g.color = getColor(element.color, getTheme(canvas.theme).BUTTON_COL);
ui.g.fillCircle(ui._x + (scaled(element.width) / 2), ui._y + (scaled(element.height) / 2), (ui._w / 2) - 10);
ui.g.color = col;
case Empty:
}
if (element.children != null) {
for (id in element.children) {
drawElement(ui, canvas, elemById(canvas, id), scaled(element.x) + px, scaled(element.y) + py);
}
}
if (rotated) ui.g.popTransformation();
}
static inline function getText(canvas: TCanvas, e: TElement): String {
return e.text;
}
public static function getAsset(canvas: TCanvas, asset: String): Dynamic { // kha.Image | kha.Font {
for (a in canvas.assets) if (a.name == asset) return assetMap.get(a.id);
return null;
}
static var elemId = -1;
public static function getElementId(canvas: TCanvas): Int {
if (elemId == -1) for (e in canvas.elements) if (elemId < e.id) elemId = e.id;
return ++elemId;
}
static var assetId = -1;
public static function getAssetId(canvas: TCanvas): Int {
if (assetId == -1) for (a in canvas.assets) if (assetId < a.id) assetId = a.id;
return ++assetId;
}
static function elemById(canvas: TCanvas, id: Int): TElement {
for (e in canvas.elements) if (e.id == id) return e;
return null;
}
static inline function scaled(f: Float): Int {
return Std.int(f * _ui.SCALE());
}
public static inline function getColor(color: Null<Int>, defaultColor: Int): Int {
return color != null ? color : defaultColor;
}
public static function getTheme(theme: String): zui.Themes.TTheme {
for (t in Canvas.themes) {
if (t.NAME == theme) return t;
}
return null;
}
/**
Returns the positional scaled offset of the given element based on its anchor setting.
@param canvas The canvas object
@param element The element
@return Array<Float> [xOffset, yOffset]
**/
public static function getAnchorOffset(canvas: TCanvas, element: TElement): Array<Float> {
var boxWidth, boxHeight: Float;
var offsetX = 0.0;
var offsetY = 0.0;
if (element.parent == null) {
boxWidth = canvas.width;
boxHeight = canvas.height;
}
else {
var parent = elemById(canvas, element.parent);
boxWidth = scaled(parent.width);
boxHeight = scaled(parent.height);
}
switch (element.anchor) {
case Top:
offsetX += boxWidth / 2 - scaled(element.width) / 2;
case TopRight:
offsetX += boxWidth - scaled(element.width);
case CenterLeft:
offsetY += boxHeight / 2 - scaled(element.height) / 2;
case Center:
offsetX += boxWidth / 2 - scaled(element.width) / 2;
offsetY += boxHeight / 2 - scaled(element.height) / 2;
case CenterRight:
offsetX += boxWidth - scaled(element.width);
offsetY += boxHeight / 2 - scaled(element.height) / 2;
case BottomLeft:
offsetY += boxHeight - scaled(element.height);
case Bottom:
offsetX += boxWidth / 2 - scaled(element.width) / 2;
offsetY += boxHeight - scaled(element.height);
case BottomRight:
offsetX += boxWidth - scaled(element.width);
offsetY += boxHeight - scaled(element.height);
}
return [offsetX, offsetY];
}
}
typedef TCanvas = {
var name: String;
var x: Float;
var y: Float;
var width: Int;
var height: Int;
var elements: Array<TElement>;
var theme: String;
@:optional var assets: Array<TAsset>;
@:optional var locales: Array<TLocale>;
}
typedef TElement = {
var id: Int;
var type: ElementType;
var name: String;
var x: Float;
var y: Float;
var width: Int;
var height: Int;
@:optional var rotation: Null<kha.FastFloat>;
@:optional var text: String;
@:optional var event: String;
// null = follow theme settings
@:optional var color: Null<Int>;
@:optional var color_text: Null<Int>;
@:optional var color_hover: Null<Int>;
@:optional var color_press: Null<Int>;
@:optional var color_progress: Null<Int>;
@:optional var progress_at: Null<Int>;
@:optional var progress_total: Null<Int>;
@:optional var strength: Null<Int>;
@:optional var alignment: Null<Int>;
@:optional var anchor: Null<Int>;
@:optional var parent: Null<Int>; // id
@:optional var children: Array<Int>; // ids
@:optional var asset: String;
@:optional var visible: Null<Bool>;
@:optional var editable: Null<Bool>;
}
typedef TAsset = {
var id: Int;
var name: String;
var file: String;
}
typedef TLocale = {
var name: String; // "en"
var texts: Array<TTranslatedText>;
}
typedef TTranslatedText = {
var id: Int; // element id
var text: String;
}
@:enum abstract ElementType(Int) from Int to Int {
var Text = 0;
var Image = 1;
var Button = 2;
var Empty = 3;
// var HLayout = 4;
// var VLayout = 5;
var Check = 6;
var Radio = 7;
var Combo = 8;
var Slider = 9;
var TextInput = 10;
var KeyInput = 11;
var FRectangle = 12;
var Rectangle = 13;
var FCircle = 14;
var Circle = 15;
var FTriangle = 16;
var Triangle = 17;
var ProgressBar = 18;
var CProgressBar = 19;
var TextArea = 20;
}
@:enum abstract Anchor(Int) from Int to Int {
var TopLeft = 0;
var Top = 1;
var TopRight = 2;
var CenterLeft = 3;
var Center = 4;
var CenterRight = 5;
var BottomLeft = 6;
var Bottom = 7;
var BottomRight = 8;
}

331
Sources/armory/ui/Ext.hx Normal file
View file

@ -0,0 +1,331 @@
package armory.ui;
import zui.Zui;
import kha.input.Keyboard;
import kha.input.KeyCode;
typedef ListOpts = {
?addCb: String->Void,
?removeCb: Int->Void,
?getNameCb: Int->String,
?setNameCb: Int->String->Void,
?getLabelCb: Int->String,
?itemDrawCb: Handle->Int->Void,
?showRadio: Bool, // false
?editable: Bool, // true
?showAdd: Bool, // true
?addLabel: String // 'Add'
}
@:access(zui.Zui)
class Ext {
public static function keyInput(ui: Zui, handle: Handle, label = "", align: Align = Left): Int {
if (!ui.isVisible(ui.ELEMENT_H())) {
ui.endElement();
return Std.int(handle.value);
}
var hover = ui.getHover();
if (hover && Zui.onTextHover != null) Zui.onTextHover();
ui.g.color = hover ? ui.t.ACCENT_HOVER_COL : ui.t.ACCENT_COL; // Text bg
ui.drawRect(ui.g, ui.t.FILL_ACCENT_BG, ui._x + ui.buttonOffsetY, ui._y + ui.buttonOffsetY, ui._w - ui.buttonOffsetY * 2, ui.BUTTON_H());
var startEdit = ui.getReleased() || ui.tabPressed;
if (ui.textSelectedHandle != handle && startEdit) ui.startTextEdit(handle);
if (ui.textSelectedHandle == handle) Ext.listenToKey(ui, handle);
else handle.changed = false;
if (label != "") {
ui.g.color = ui.t.LABEL_COL; // Label
var labelAlign = align == Align.Right ? Align.Left : Align.Right;
var xOffset = labelAlign == Align.Left ? 7 : 0;
ui.drawString(ui.g, label, xOffset, 0, labelAlign);
}
handle.text = Ext.keycodeToString(Std.int(handle.value));
ui.g.color = ui.t.TEXT_COL; // Text
ui.textSelectedHandle != handle ? ui.drawString(ui.g, handle.text, null, 0, align) : ui.drawString(ui.g, ui.textSelected, null, 0, align);
ui.endElement();
return Std.int(handle.value);
}
static function listenToKey(ui: Zui, handle: Handle) {
if (ui.isKeyDown) {
handle.value = ui.key;
handle.changed = ui.changed = true;
ui.textSelectedHandle = null;
ui.isTyping = false;
if (Keyboard.get() != null) Keyboard.get().hide();
}
else {
ui.textSelected = "Press a key...";
}
}
public static function list(ui: Zui, handle: Handle, ar: Array<Dynamic>, ?opts: ListOpts ): Int {
var selected = 0;
if (opts == null) opts = {};
var addCb = opts.addCb != null ? opts.addCb : function(name: String) ar.push(name);
var removeCb = opts.removeCb != null ? opts.removeCb : function(i: Int) ar.splice(i, 1);
var getNameCb = opts.getNameCb != null ? opts.getNameCb : function(i: Int) return ar[i];
var setNameCb = opts.setNameCb != null ? opts.setNameCb : function(i: Int, name: String) ar[i] = name;
var getLabelCb = opts.getLabelCb != null ? opts.getLabelCb : function(i: Int) return "";
var itemDrawCb = opts.itemDrawCb;
var showRadio = opts.showRadio != null ? opts.showRadio : false;
var editable = opts.editable != null ? opts.editable : true;
var showAdd = opts.showAdd != null ? opts.showAdd : true;
var addLabel = opts.addLabel != null ? opts.addLabel : "Add";
var i = 0;
while (i < ar.length) {
if (showRadio) { // Prepend ratio button
ui.row([0.12, 0.68, 0.2]);
if (ui.radio(handle.nest(0), i, "")) {
selected = i;
}
}
else ui.row([0.8, 0.2]);
var itemHandle = handle.nest(i);
itemHandle.text = getNameCb(i);
editable ? setNameCb(i, ui.textInput(itemHandle, getLabelCb(i))) : ui.text(getNameCb(i));
if (ui.button("X")) removeCb(i);
else i++;
if (itemDrawCb != null) itemDrawCb(itemHandle.nest(i), i - 1);
}
if (showAdd && ui.button(addLabel)) addCb("untitled");
return selected;
}
public static function panelList(ui: Zui, handle: Handle, ar: Array<Dynamic>,
addCb: String->Void = null,
removeCb: Int->Void = null,
getNameCb: Int->String = null,
setNameCb: Int->String->Void = null,
itemDrawCb: Handle->Int->Void = null,
editable = true,
showAdd = true,
addLabel: String = "Add") {
if (addCb == null) addCb = function(name: String) { ar.push(name); };
if (removeCb == null) removeCb = function(i: Int) { ar.splice(i, 1); };
if (getNameCb == null) getNameCb = function(i: Int) { return ar[i]; };
if (setNameCb == null) setNameCb = function(i: Int, name: String) { ar[i] = name; };
var i = 0;
while (i < ar.length) {
ui.row([0.12, 0.68, 0.2]);
var expanded = ui.panel(handle.nest(i), "");
var itemHandle = handle.nest(i);
editable ? setNameCb(i, ui.textInput(itemHandle, getNameCb(i))) : ui.text(getNameCb(i));
if (ui.button("X")) removeCb(i);
else i++;
if (itemDrawCb != null && expanded) itemDrawCb(itemHandle.nest(i), i - 1);
}
if (showAdd && ui.button(addLabel)) {
addCb("untitled");
}
}
public static function colorField(ui: Zui, handle:Handle, alpha = false): Int {
ui.g.color = handle.color;
ui.drawRect(ui.g, true, ui._x + 2, ui._y + ui.buttonOffsetY, ui._w - 4, ui.BUTTON_H());
ui.g.color = ui.getHover() ? ui.t.ACCENT_HOVER_COL : ui.t.ACCENT_COL;
ui.drawRect(ui.g, false, ui._x + 2, ui._y + ui.buttonOffsetY, ui._w - 4, ui.BUTTON_H(), 1.0);
if (ui.getStarted()) {
Popup.showCustom(
new Zui(ui.ops),
function(ui:Zui) {
zui.Ext.colorWheel(ui, handle, alpha);
},
Std.int(ui.inputX), Std.int(ui.inputY), 200, 500);
}
ui.endElement();
return handle.color;
}
public static function colorPicker(ui: Zui, handle: Handle, alpha = false): Int {
var r = ui.slider(handle.nest(0, {value: handle.color.R}), "R", 0, 1, true);
var g = ui.slider(handle.nest(1, {value: handle.color.G}), "G", 0, 1, true);
var b = ui.slider(handle.nest(2, {value: handle.color.B}), "B", 0, 1, true);
var a = handle.color.A;
if (alpha) a = ui.slider(handle.nest(3, {value: a}), "A", 0, 1, true);
var col = kha.Color.fromFloats(r, g, b, a);
ui.text("", Right, col);
return col;
}
/**
Keycodes can be found here: http://api.kha.tech/kha/input/KeyCode.html
**/
static function keycodeToString(keycode: Int): String {
switch (keycode) {
case -1: return "None";
case KeyCode.Unknown: return "Unknown";
case KeyCode.Back: return "Back";
case KeyCode.Cancel: return "Cancel";
case KeyCode.Help: return "Help";
case KeyCode.Backspace: return "Backspace";
case KeyCode.Tab: return "Tab";
case KeyCode.Clear: return "Clear";
case KeyCode.Return: return "Return";
case KeyCode.Shift: return "Shift";
case KeyCode.Control: return "Ctrl";
case KeyCode.Alt: return "Alt";
case KeyCode.Pause: return "Pause";
case KeyCode.CapsLock: return "CapsLock";
case KeyCode.Kana: return "Kana";
// case KeyCode.Hangul: return "Hangul"; // Hangul == Kana
case KeyCode.Eisu: return "Eisu";
case KeyCode.Junja: return "Junja";
case KeyCode.Final: return "Final";
case KeyCode.Hanja: return "Hanja";
// case KeyCode.Kanji: return "Kanji"; // Kanji == Hanja
case KeyCode.Escape: return "Esc";
case KeyCode.Convert: return "Convert";
case KeyCode.NonConvert: return "NonConvert";
case KeyCode.Accept: return "Accept";
case KeyCode.ModeChange: return "ModeChange";
case KeyCode.Space: return "Space";
case KeyCode.PageUp: return "PageUp";
case KeyCode.PageDown: return "PageDown";
case KeyCode.End: return "End";
case KeyCode.Home: return "Home";
case KeyCode.Left: return "Left";
case KeyCode.Up: return "Up";
case KeyCode.Right: return "Right";
case KeyCode.Down: return "Down";
case KeyCode.Select: return "Select";
case KeyCode.Print: return "Print";
case KeyCode.Execute: return "Execute";
case KeyCode.PrintScreen: return "PrintScreen";
case KeyCode.Insert: return "Insert";
case KeyCode.Delete: return "Delete";
case KeyCode.Colon: return "Colon";
case KeyCode.Semicolon: return "Semicolon";
case KeyCode.LessThan: return "LessThan";
case KeyCode.Equals: return "Equals";
case KeyCode.GreaterThan: return "GreaterThan";
case KeyCode.QuestionMark: return "QuestionMark";
case KeyCode.At: return "At";
case KeyCode.Win: return "Win";
case KeyCode.ContextMenu: return "ContextMenu";
case KeyCode.Sleep: return "Sleep";
case KeyCode.Numpad0: return "Numpad0";
case KeyCode.Numpad1: return "Numpad1";
case KeyCode.Numpad2: return "Numpad2";
case KeyCode.Numpad3: return "Numpad3";
case KeyCode.Numpad4: return "Numpad4";
case KeyCode.Numpad5: return "Numpad5";
case KeyCode.Numpad6: return "Numpad6";
case KeyCode.Numpad7: return "Numpad7";
case KeyCode.Numpad8: return "Numpad8";
case KeyCode.Numpad9: return "Numpad9";
case KeyCode.Multiply: return "Multiply";
case KeyCode.Add: return "Add";
case KeyCode.Separator: return "Separator";
case KeyCode.Subtract: return "Subtract";
case KeyCode.Decimal: return "Decimal";
case KeyCode.Divide: return "Divide";
case KeyCode.F1: return "F1";
case KeyCode.F2: return "F2";
case KeyCode.F3: return "F3";
case KeyCode.F4: return "F4";
case KeyCode.F5: return "F5";
case KeyCode.F6: return "F6";
case KeyCode.F7: return "F7";
case KeyCode.F8: return "F8";
case KeyCode.F9: return "F9";
case KeyCode.F10: return "F10";
case KeyCode.F11: return "F11";
case KeyCode.F12: return "F12";
case KeyCode.F13: return "F13";
case KeyCode.F14: return "F14";
case KeyCode.F15: return "F15";
case KeyCode.F16: return "F16";
case KeyCode.F17: return "F17";
case KeyCode.F18: return "F18";
case KeyCode.F19: return "F19";
case KeyCode.F20: return "F20";
case KeyCode.F21: return "F21";
case KeyCode.F22: return "F22";
case KeyCode.F23: return "F23";
case KeyCode.F24: return "F24";
case KeyCode.NumLock: return "NumLock";
case KeyCode.ScrollLock: return "ScrollLock";
case KeyCode.WinOemFjJisho: return "WinOemFjJisho";
case KeyCode.WinOemFjMasshou: return "WinOemFjMasshou";
case KeyCode.WinOemFjTouroku: return "WinOemFjTouroku";
case KeyCode.WinOemFjLoya: return "WinOemFjLoya";
case KeyCode.WinOemFjRoya: return "WinOemFjRoya";
case KeyCode.Circumflex: return "Circumflex";
case KeyCode.Exclamation: return "Exclamation";
case KeyCode.DoubleQuote: return "DoubleQuote";
case KeyCode.Hash: return "Hash";
case KeyCode.Dollar: return "Dollar";
case KeyCode.Percent: return "Percent";
case KeyCode.Ampersand: return "Ampersand";
case KeyCode.Underscore: return "Underscore";
case KeyCode.OpenParen: return "OpenParen";
case KeyCode.CloseParen: return "CloseParen";
case KeyCode.Asterisk: return "Asterisk";
case KeyCode.Plus: return "Plus";
case KeyCode.Pipe: return "Pipe";
case KeyCode.HyphenMinus: return "HyphenMinus";
case KeyCode.OpenCurlyBracket: return "OpenCurlyBracket";
case KeyCode.CloseCurlyBracket: return "CloseCurlyBracket";
case KeyCode.Tilde: return "Tilde";
case KeyCode.VolumeMute: return "VolumeMute";
case KeyCode.VolumeDown: return "VolumeDown";
case KeyCode.VolumeUp: return "VolumeUp";
case KeyCode.Comma: return "Comma";
case KeyCode.Period: return "Period";
case KeyCode.Slash: return "Slash";
case KeyCode.BackQuote: return "BackQuote";
case KeyCode.OpenBracket: return "OpenBracket";
case KeyCode.BackSlash: return "BackSlash";
case KeyCode.CloseBracket: return "CloseBracket";
case KeyCode.Quote: return "Quote";
case KeyCode.Meta: return "Meta";
case KeyCode.AltGr: return "AltGr";
case KeyCode.WinIcoHelp: return "WinIcoHelp";
case KeyCode.WinIco00: return "WinIco00";
case KeyCode.WinIcoClear: return "WinIcoClear";
case KeyCode.WinOemReset: return "WinOemReset";
case KeyCode.WinOemJump: return "WinOemJump";
case KeyCode.WinOemPA1: return "WinOemPA1";
case KeyCode.WinOemPA2: return "WinOemPA2";
case KeyCode.WinOemPA3: return "WinOemPA3";
case KeyCode.WinOemWSCTRL: return "WinOemWSCTRL";
case KeyCode.WinOemCUSEL: return "WinOemCUSEL";
case KeyCode.WinOemATTN: return "WinOemATTN";
case KeyCode.WinOemFinish: return "WinOemFinish";
case KeyCode.WinOemCopy: return "WinOemCopy";
case KeyCode.WinOemAuto: return "WinOemAuto";
case KeyCode.WinOemENLW: return "WinOemENLW";
case KeyCode.WinOemBackTab: return "WinOemBackTab";
case KeyCode.ATTN: return "ATTN";
case KeyCode.CRSEL: return "CRSEL";
case KeyCode.EXSEL: return "EXSEL";
case KeyCode.EREOF: return "EREOF";
case KeyCode.Play: return "Play";
case KeyCode.Zoom: return "Zoom";
case KeyCode.PA1: return "PA1";
case KeyCode.WinOemClear: return "WinOemClear";
}
return String.fromCharCode(keycode);
}
}

127
Sources/armory/ui/Popup.hx Normal file
View file

@ -0,0 +1,127 @@
package armory.ui;
import zui.Zui;
import kha.System;
@:access(zui.Zui)
class Popup {
public static var show = false;
static var ui: Zui = null;
static var hwnd = new Handle();
static var boxTitle = "";
static var boxText = "";
static var boxCommands: Zui->Void = null;
static var modalX = 0;
static var modalY = 0;
static var modalW = 400;
static var modalH = 160;
public static function render(g: kha.graphics2.Graphics) {
if (boxCommands == null) {
ui.begin(g);
if (ui.window(hwnd, modalX, modalY, modalW, modalH)) {
drawTitle(g);
for (line in boxText.split("\n")) {
ui.text(line);
}
ui._y = ui._h - ui.t.BUTTON_H - 10;
ui.row([1/3, 1/3, 1/3]);
ui.endElement();
if (ui.button("OK")) {
show = false;
}
}
ui.end();
}
else {
ui.begin(g);
if (ui.window(hwnd, modalX, modalY, modalW, modalH)) {
drawTitle(g);
ui._y += 10;
boxCommands(ui);
}
ui.end();
}
}
public static function drawTitle(g: kha.graphics2.Graphics) {
if (boxTitle != "") {
g.color = ui.t.SEPARATOR_COL;
ui.drawRect(g, true, ui._x, ui._y, ui._w, ui.t.BUTTON_H);
g.color = ui.t.TEXT_COL;
ui.text(boxTitle);
}
}
public static function update() {
var inUse = ui.comboSelectedHandle != null;
// Close popup
if (ui.inputStarted && !inUse) {
if (ui.inputX < modalX || ui.inputX > modalX + modalW || ui.inputY < modalY || ui.inputY > modalY + modalH) {
show = false;
}
}
}
/**
Displays a message box with a title, a text body and a centered "OK" button.
@param ui the Zui instance for the popup
@param title the title to display
@param text the text to display
**/
public static function showMessage(ui: Zui, title: String, text: String) {
Popup.ui = ui;
init();
boxTitle = title;
boxText = text;
boxCommands = null;
}
/**
Displays a popup box with custom drawing code.
@param ui the Zui instance for the popup
@param commands the function for drawing the popup's content
@param mx the x position of the popup. -1 = screen center (defaults to -1)
@param my the y position of the popup. -1 = screen center (defaults to -1)
@param mw the width of the popup (defaults to 400)
@param mh the height of the popup (defaults to 160)
**/
public static function showCustom(ui: Zui, commands: Zui->Void = null, mx = -1, my = -1, mw = 400, mh = 160) {
Popup.ui = ui;
init(mx, my, mw, mh);
boxTitle = "";
boxText = "";
boxCommands = commands;
}
static function init(mx = -1, my = -1, mw = 400, mh = 160) {
var appW = System.windowWidth();
var appH = System.windowHeight();
modalX = mx;
modalY = my;
modalW = Std.int(mw * ui.SCALE());
modalH = Std.int(mh * ui.SCALE());
// Center popup window if no value is given
if (mx == -1) modalX = Std.int(appW / 2 - modalW / 2);
if (my == -1) modalY = Std.int(appH / 2 - modalH / 2);
// Limit popup position to screen
modalX = Std.int(Math.max(0, Math.min(modalX, appW - modalW)));
modalY = Std.int(Math.max(0, Math.min(modalY, appH - modalH)));
hwnd.dragX = 0;
hwnd.dragY = 0;
hwnd.scrollOffset = 0.0;
show = true;
}
}