Skip to content

Commit

Permalink
feat(imgui): non-destructive value updates, local state
Browse files Browse the repository at this point in the history
- update all components to return new values (if edited) or else undefined
- store local state (dropdown, textfield) in IMGUI state cache
  • Loading branch information
postspectacular committed Aug 14, 2019
1 parent c2ef036 commit b499c8c
Show file tree
Hide file tree
Showing 14 changed files with 282 additions and 203 deletions.
2 changes: 2 additions & 0 deletions packages/imgui/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { Predicate } from "@thi.ng/api";

export type Color = string | number | number[];

export type Hash = number | string;

export interface GUITheme {
globalBg?: Color;
font?: string;
Expand Down
15 changes: 5 additions & 10 deletions packages/imgui/src/behaviors/slider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,14 @@ export const slider1Val = (x: number, min: number, max: number, prec: number) =>
clamp(roundTo(x, prec), min, max);

export const slider2Val = (v: Vec, min: Vec, max: Vec, prec: number) =>
clamp2(v, round2(v, v, prec), min, max);
clamp2(null, round2([], v, prec), min, max);

export const handleSlider1Keys = (
gui: IMGUI,
min: number,
max: number,
prec: number,
val: number[],
i = 0
val: number
) => {
switch (gui.key) {
case Key.TAB:
Expand All @@ -40,9 +39,7 @@ export const handleSlider1Keys = (
const step =
(gui.key === Key.UP ? prec : -prec) *
(gui.isShiftDown() ? 5 : 1);
val[i] = slider1Val(val[i] + step, min, max, prec);
gui.isAltDown() && val.fill(val[i]);
return true;
return slider1Val(val + step, min, max, prec);
}
default:
}
Expand All @@ -65,17 +62,15 @@ export const handleSlider2Keys = (
const step =
(gui.key === Key.RIGHT ? prec : -prec) *
(gui.isShiftDown() ? 5 : 1);
slider2Val(add2(val, val, [step, 0]), min, max, prec);
return true;
return slider2Val(add2([], val, [step, 0]), min, max, prec);
}
case Key.UP:
case Key.DOWN: {
const step =
(gui.key === Key.UP ? prec : -prec) *
(yUp ? 1 : -1) *
(gui.isShiftDown() ? 5 : 1);
slider2Val(add2(val, val, [0, step]), min, max, prec);
return true;
return slider2Val(add2([], val, [0, step]), min, max, prec);
}
default:
}
Expand Down
9 changes: 7 additions & 2 deletions packages/imgui/src/components/button.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import { rect } from "@thi.ng/geom";
import { IShape } from "@thi.ng/geom-api";
import { hash, ZERO2 } from "@thi.ng/vectors";
import { Color, IGridLayout, LayoutBox } from "../api";
import {
Color,
Hash,
IGridLayout,
LayoutBox
} from "../api";
import { handleButtonKeys, isHoverButton } from "../behaviors/button";
import { IMGUI } from "../gui";
import { isLayout } from "../layout";
Expand Down Expand Up @@ -92,7 +97,7 @@ export const buttonRaw = (
gui: IMGUI,
id: string,
shape: IShape,
hash: number | string,
hash: Hash,
label?: any,
labelHover?: any,
info?: string
Expand Down
26 changes: 13 additions & 13 deletions packages/imgui/src/components/dial.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ export const dial = (
min: number,
max: number,
prec: number,
val: number[],
i: number,
val: number,
label?: string,
fmt?: Fn<number, string>,
info?: string
Expand All @@ -40,7 +39,6 @@ export const dial = (
max,
prec,
val,
i,
gui.theme.pad,
h + ch / 2 + gui.theme.baseLine,
label,
Expand All @@ -59,8 +57,7 @@ export const dialRaw = (
min: number,
max: number,
prec: number,
val: number[],
i: number,
val: number,
lx: number,
ly: number,
label?: string,
Expand All @@ -75,11 +72,13 @@ export const dialRaw = (
gui.registerID(id, key);
const bgShape = gui.resource(id, key, () => circle(pos, r, {}));
const hover = isHoverSlider(gui, id, bgShape);
let v: number | undefined = val;
let res: number | undefined;
if (hover) {
gui.hotID = id;
if (gui.isMouseDown()) {
gui.activeID = id;
val[i] = dialVal(
res = v = dialVal(
gui.mouse,
pos,
startTheta,
Expand All @@ -88,17 +87,15 @@ export const dialRaw = (
max,
prec
);
gui.isAltDown() && val.fill(val[i]);
}
info && tooltipRaw(gui, info);
}
const focused = gui.requestFocus(id);
const v = val[i];
const valShape = gui.resource(id, v, () =>
line(
cartesian2(
null,
[r, startTheta + (TAU - thetaGap) * norm(v, min, max)],
[r, startTheta + (TAU - thetaGap) * norm(v!, min, max)],
pos
),
pos,
Expand All @@ -109,17 +106,20 @@ export const dialRaw = (
textLabelRaw(
[x + lx, y + ly],
gui.textColor(false),
(label ? label + " " : "") + (fmt ? fmt(v) : v)
(label ? label + " " : "") + (fmt ? fmt(v!) : v)
)
);
bgShape.attribs.fill = gui.bgColor(hover || focused);
bgShape.attribs.stroke = gui.focusColor(id);
valShape.attribs.stroke = gui.fgColor(hover);
valShape.attribs.weight = 2;
gui.add(bgShape, valShape, valLabel);
if (focused && handleSlider1Keys(gui, min, max, prec, val, i)) {
return true;
if (
focused &&
(v = handleSlider1Keys(gui, min, max, prec, v)) !== undefined
) {
return v;
}
gui.lastID = id;
return gui.activeID === id;
return res;
};
71 changes: 36 additions & 35 deletions packages/imgui/src/components/dropdown.ts
Original file line number Diff line number Diff line change
@@ -1,86 +1,87 @@
import { polygon } from "@thi.ng/geom";
import { hash } from "@thi.ng/vectors";
import { IGridLayout, Key } from "../api";
import { IMGUI } from "../gui";
import { buttonH } from "./button";

/**
*
* @param gui
* @param layout
* @param id
* @param sel
* @param items
* @param title
* @param info
*/
export const dropdown = (
gui: IMGUI,
layout: IGridLayout,
id: string,
state: [number, boolean],
sel: number,
items: string[],
title: string,
info?: string
) => {
const nested = layout.nest(1, [1, state[1] ? items.length : 1]);
let res = false;
const sel = state[0];
const open = gui.state<boolean>(id, () => false);
const nested = layout.nest(1, [1, open ? items.length : 1]);
let res: number | undefined;
const box = nested.next();
const { x, y, w, h } = box;
const key = hash([x, y, w, h]);
const tx = x + w - gui.theme.pad - 4;
const ty = y + h / 2;
if (state[1]) {
if (open) {
const bt = buttonH(gui, box, `${id}-title`, title);
gui.add(
polygon([[tx - 4, ty + 2], [tx + 4, ty + 2], [tx, ty - 2]], {
fill: gui.textColor(false)
})
gui.resource(id, "o" + key, () =>
polygon([[tx - 4, ty + 2], [tx + 4, ty + 2], [tx, ty - 2]], {
fill: gui.textColor(false)
})
)
);
if (bt) {
state[1] = false;
gui.setState(id, false);
} else {
for (let i = 0, n = items.length; i < n; i++) {
if (buttonH(gui, nested, `${id}-${i}`, items[i])) {
if (i !== sel) {
state[0] = i;
res = true;
}
state[1] = false;
i !== sel && (res = i);
gui.setState(id, false);
}
}
if (gui.focusID.startsWith(`${id}-`)) {
switch (gui.key) {
case Key.ESC:
state[1] = false;
gui.setState(id, false);
break;
case Key.UP:
return update(
gui,
state,
id,
Math.max(0, state[0] - 1)
);
return update(gui, id, Math.max(0, sel - 1));
case Key.DOWN:
return update(
gui,
state,
id,
Math.min(items.length - 1, state[0] + 1)
Math.min(items.length - 1, sel + 1)
);
default:
}
}
}
} else {
if (buttonH(gui, box, `${id}-${sel}`, items[sel], title, info)) {
state[1] = true;
gui.setState(id, true);
}
gui.add(
polygon([[tx - 4, ty - 2], [tx + 4, ty - 2], [tx, ty + 2]], {
fill: gui.textColor(false)
})
gui.resource(id, "c" + key, () =>
polygon([[tx - 4, ty - 2], [tx + 4, ty - 2], [tx, ty + 2]], {
fill: gui.textColor(false)
})
)
);
}
return res;
};

const update = (
gui: IMGUI,
state: [number, boolean?],
id: string,
next: number
) => {
const update = (gui: IMGUI, id: string, next: number) => {
gui.focusID = `${id}-${next}`;
state[0] = next;
return true;
return next;
};
2 changes: 1 addition & 1 deletion packages/imgui/src/components/radial-menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export const radialMenu = (
];
}, triFan(vertices(circle([x, y], r), n)))
]);
let res = -1;
let res: number | undefined;
for (let i = 0; i < n; i++) {
const cell = cells[i];
buttonRaw(gui, id + i, cell[0], cell[1], cell[2], cell[3], info[i]) &&
Expand Down
22 changes: 11 additions & 11 deletions packages/imgui/src/components/radio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,24 @@ export const radio = (
layout: IGridLayout,
id: string,
horizontal: boolean,
val: number[],
idx: number,
sel: number,
square: boolean,
labels: string[],
info: string[] = []
) => {
const n = labels.length;
const nested = horizontal ? layout.nest(n, [n, 1]) : layout.nest(1, [1, n]);
let res = false;
const tmp: boolean[] = [];
const sel = val[idx];
let res: number | undefined;
for (let i = 0; i < n; i++) {
tmp[0] = sel === i;
// prettier-ignore
if (toggle(gui, nested, `${id}-${i}`, tmp, 0, square, labels[i], info[i])) {
val[idx] = i;
res = true;
}
toggle(
gui,
nested,
`${id}-${i}`,
sel === i,
square,
labels[i],
info[i]
) !== undefined && (res = i);
}
return res;
};
Loading

0 comments on commit b499c8c

Please sign in to comment.