You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
335 lines
9.8 KiB
Plaintext
335 lines
9.8 KiB
Plaintext
empty = ui.rect { w = 0, h = 0 };
|
|
|
|
centerH = parentW child \
|
|
childW = (ui.measure child).width;
|
|
ui.positioned { x = (parentW - childW) / 2, y = 0, child = child };
|
|
|
|
centerV = parentH child \
|
|
childH = (ui.measure child).height;
|
|
ui.positioned { y = (parentH - childH) / 2, x = 0, child = child };
|
|
|
|
center = parentW parentH child \
|
|
childSize = ui.measure child;
|
|
ui.positioned { x = (parentW - childSize.width) / 2, y = (parentH - childSize.height) / 2, child = child };
|
|
|
|
# button : Record -> ui
|
|
button = config \
|
|
textSize = ui.measureText config.label;
|
|
|
|
defaults = {
|
|
h = 30,
|
|
w = textSize + 20,
|
|
strokeWidth = 1,
|
|
strokeColor = "#fff",
|
|
textColor = "#fff",
|
|
label = ""
|
|
};
|
|
|
|
c = { ...defaults, ...config };
|
|
|
|
ui.clickable {
|
|
onClick = config.event,
|
|
child = ui.stack {
|
|
children = [
|
|
ui.rect { w = c.w, h = c.h, strokeColor = c.strokeColor, strokeWidth = c.strokeWidth },
|
|
ui.positioned {
|
|
x = 10, y = 8,
|
|
child = ui.text { content = config.label, color = c.textColor }
|
|
}
|
|
]
|
|
}
|
|
};
|
|
|
|
# inputButton (button that turns into an input)
|
|
inputButton = config \
|
|
textSize = ui.measureText config.label;
|
|
|
|
defaults = {
|
|
h = 30,
|
|
w = textSize + 16,
|
|
strokeWidth = 1,
|
|
strokeColor = "#fff",
|
|
textColor = "#fff",
|
|
backgroundColor = "transparent",
|
|
label = ""
|
|
};
|
|
|
|
c = { ...defaults, ...config };
|
|
|
|
ui.stateful {
|
|
key = c.key,
|
|
focusable = True,
|
|
|
|
init = { editing = False },
|
|
|
|
update = state event \ event
|
|
| Activate \ { state = state.{ editing = True }, emit = [] }
|
|
| Submit text \ { state = state.{ editing = False }, emit = [c.onSubmit text] }
|
|
| Key { key = "Escape" } \ { state = state.{ editing = False }, emit = [] }
|
|
| _ \ { state = state, emit = [] },
|
|
|
|
view = state emit \
|
|
state.editing
|
|
| True \ textInput {
|
|
key = c.key & "-input",
|
|
autoFocus = True,
|
|
w = c.w, h = c.h,
|
|
strokeWidth = 1,
|
|
strokeColor = "#fff",
|
|
color = c.textColor,
|
|
backgroundColor = c.backgroundColor,
|
|
onSubmit = text \ emit (Submit text)
|
|
}
|
|
| False \ ui.clickable {
|
|
onClick = \ emit Activate,
|
|
child = ui.stack {
|
|
children = [
|
|
ui.rect { w = c.w, h = c.h, strokeColor = c.strokeColor, strokeWidth = c.strokeWidth },
|
|
ui.positioned {
|
|
x = 8, y = 8,
|
|
child = ui.text { content = config.label, color = c.textColor }
|
|
}
|
|
]
|
|
}
|
|
}
|
|
};
|
|
|
|
# scrollable
|
|
scrollable = config \
|
|
defaults = {
|
|
scrollX = 0,
|
|
scrollY = 0,
|
|
onScroll = _ \ noOp
|
|
};
|
|
c = { ...defaults, ...config };
|
|
|
|
showVBar = c.totalHeight > c.h;
|
|
vBarHeight = max 20 (c.h * c.h / c.totalHeight);
|
|
vBarY = c.scrollY * c.h / c.totalHeight;
|
|
|
|
showHBar = c.totalWidth > c.w;
|
|
vBarWidth = max 20 (c.w * c.w / c.totalWidth);
|
|
vBarX = c.scrollX * c.w / c.totalWidth;
|
|
|
|
ui.stack {
|
|
children = [
|
|
ui.scrollable {
|
|
w = c.w,
|
|
h = c.h,
|
|
scrollX = c.scrollX,
|
|
scrollY = c.scrollY,
|
|
onScroll = c.onScroll,
|
|
child = c.child
|
|
},
|
|
...(showVBar
|
|
| True \ [ui.positioned {
|
|
x = c.w - 4,
|
|
y = vBarY,
|
|
child = ui.rect { w = 4, h = vBarHeight, color = "rgba(255,255,255,0.3)", radius = 2 }
|
|
}]
|
|
| False \ []),
|
|
...(showHBar
|
|
| True \ [ui.positioned {
|
|
x = c.h - 4,
|
|
y = hBarX,
|
|
child = ui.rect { h = 4, w = hBarWidth, color = "rgba(255,255,255,0.3)", radius = 2 }
|
|
}]
|
|
| False \ [])
|
|
]
|
|
};
|
|
|
|
box = config \
|
|
defaults = {
|
|
w = 100,
|
|
h = 100,
|
|
color = "white",
|
|
borderTop = 0,
|
|
borderBottom = 0,
|
|
borderLeft = 0,
|
|
borderRight = 0,
|
|
borderColor = "transparent",
|
|
paddingTop = 0,
|
|
paddingLeft = 0
|
|
};
|
|
|
|
c = { ...defaults, ...config };
|
|
|
|
ui.stack {
|
|
children = [
|
|
# background
|
|
ui.rect { w = c.w, h = c.h, color = c.color },
|
|
# top border
|
|
ui.rect { w = c.w, h = c.borderTop, color = c.borderColor },
|
|
# bottom border
|
|
ui.positioned { x = 0, y = c.h - c.borderBottom, child =
|
|
ui.rect { w = c.w, h = c.borderBottom, color = c.borderColor }
|
|
},
|
|
# left border
|
|
ui.rect { w = c.borderLeft, h = c.h, color = c.borderColor },
|
|
# right border
|
|
ui.positioned { x = c.w - c.borderRight, y = 0, child =
|
|
ui.rect { w = c.borderRight, h = c.h, color = c.borderColor }
|
|
},
|
|
# content
|
|
ui.positioned { x = c.paddingLeft, y = c.paddingTop, child = c.child }
|
|
]
|
|
};
|
|
|
|
textInput = config \
|
|
defaults = {
|
|
onSubmit = _ \ noOp,
|
|
onChange = _ \ noOp,
|
|
initialValue = "",
|
|
autoFocus = False,
|
|
strokeWidth = 0,
|
|
strokeColor = "transparent"
|
|
};
|
|
|
|
c = { ...defaults, ...config };
|
|
|
|
insertChar = text pos char \
|
|
before = slice text 0 pos;
|
|
after = slice text pos (len text);
|
|
before & char & after;
|
|
|
|
deleteChar = text pos \
|
|
(pos == 0
|
|
| True \ text
|
|
| False \
|
|
(before = slice text 0 (pos - 1);
|
|
after = slice text pos (len text);
|
|
before & after));
|
|
|
|
calcScrollOffset = text cursorPos scrollOffset inputWidth \
|
|
textBeforeCursor = slice text 0 cursorPos;
|
|
cursorX = ui.measureText textBeforeCursor;
|
|
(cursorX < scrollOffset
|
|
| True \ max 0 (cursorX - 20)
|
|
| False \
|
|
(cursorX > (scrollOffset + inputWidth)
|
|
| True \ cursorX - inputWidth + 20
|
|
| False \ scrollOffset));
|
|
|
|
findPosHelper = text targetX index \
|
|
(index >= len text)
|
|
| True \ len text
|
|
| False \ (
|
|
widthSoFar = ui.measureText (slice text 0 index);
|
|
widthNext = ui.measureText (slice text 0 (index + 1));
|
|
midpoint = (widthSoFar + widthNext) / 2;
|
|
(targetX < midpoint
|
|
| True \ index
|
|
| False \ findPosHelper text targetX (index + 1))
|
|
);
|
|
|
|
findCursorPos = text clickX scrollOffset inputPadding \
|
|
adjustedX = clickX + scrollOffset - inputPadding;
|
|
findPosHelper text adjustedX 0;
|
|
|
|
ui.stateful {
|
|
key = c.key,
|
|
focusable = True,
|
|
autoFocus = c.autoFocus,
|
|
|
|
# init : State
|
|
init = {
|
|
text = c.initialValue,
|
|
focused = c.autoFocus,
|
|
cursorPos = len c.initialValue,
|
|
scrollOffset = 0
|
|
},
|
|
|
|
# update : State \ Event \ State
|
|
update = state event \
|
|
s = (hasField "value" c
|
|
| True \ (c.value == state.text
|
|
| True \ state
|
|
| False \ state.{ text = c.value, cursorPos = len c.value, scrollOffset = 0 })
|
|
| False \ state);
|
|
event
|
|
| Key { key = key, printable = True, meta = False, ctrl = False } \ (
|
|
newText = insertChar s.text s.cursorPos key;
|
|
newCursorPos = s.cursorPos + 1;
|
|
newScroll = calcScrollOffset newText newCursorPos s.scrollOffset c.w;
|
|
newState = s.{ text = newText, cursorPos = newCursorPos, scrollOffset = newScroll };
|
|
{ state = newState, emit = [c.onChange newText] })
|
|
|
|
| Key { key = "ArrowLeft" } \ (
|
|
newCursorPos = max 0 (s.cursorPos - 1);
|
|
newScroll = calcScrollOffset s.text newCursorPos s.scrollOffset c.w;
|
|
newState = s.{ text = s.text, cursorPos = newCursorPos, scrollOffset = newScroll };
|
|
{ state = newState, emit = [] })
|
|
|
|
| Key { key = "ArrowRight" } \ (
|
|
newCursorPos = min (len s.text) (s.cursorPos + 1);
|
|
newScroll = calcScrollOffset s.text newCursorPos s.scrollOffset c.w;
|
|
newState = s.{ text = s.text, cursorPos = newCursorPos, scrollOffset = newScroll };
|
|
{ state = newState, emit = [] })
|
|
|
|
| Key { key = "Backspace" } \ (
|
|
newText = deleteChar s.text s.cursorPos;
|
|
newCursorPos = max 0 (s.cursorPos - 1);
|
|
newScroll = calcScrollOffset newText newCursorPos s.scrollOffset c.w;
|
|
newState = s.{ text = newText, cursorPos = newCursorPos, scrollOffset = newScroll };
|
|
{ state = newState, emit = [c.onChange newText] })
|
|
|
|
| Key { key = "Enter" } \ { state = s, emit = [c.onSubmit s.text] }
|
|
|
|
| Clicked coords \ (
|
|
newCursorPos = findCursorPos s.text coords.x s.scrollOffset 8;
|
|
newScroll = calcScrollOffset s.text newCursorPos s.scrollOffset c.w;
|
|
newState = s.{ text = s.text, cursorPos = newCursorPos, scrollOffset = newScroll };
|
|
{ state = newState, emit = [] })
|
|
|
|
| Focused \ { state = state.{ focused = True }, emit = [] }
|
|
| Blurred \ { state = state.{ focused = False }, emit = [] }
|
|
| SetText newText \ (
|
|
newState = s.{ text = newText, cursorPos = len newText, scrollOffset = 0 };
|
|
{ state = newState, emit = [c.onChange newText] })
|
|
| _ \ { state = s, emit = [] },
|
|
|
|
view = state emit \
|
|
text = (hasField "value" c | True \ c.value | False \ state.text);
|
|
cursorPos = (text == state.text | True \ state.cursorPos | False \ len text);
|
|
textBeforeCursor = slice text 0 cursorPos;
|
|
cursorX = ui.measureText textBeforeCursor;
|
|
padding = 8;
|
|
|
|
ui.clip {
|
|
w = c.w,
|
|
h = c.h,
|
|
child = ui.stack {
|
|
children = [
|
|
ui.rect { w = c.w, h = c.h, color = c.backgroundColor, radius = 0, strokeWidth = c.strokeWidth, strokeColor = c.strokeColor },
|
|
|
|
ui.positioned {
|
|
x = 8 - state.scrollOffset,
|
|
y = 0,
|
|
child = ui.positioned { x = 0, y = 12, child = ui.text { content = text, color = c.color } }
|
|
},
|
|
|
|
(state.focused
|
|
| True \ ui.positioned {
|
|
x = 8 + cursorX - state.scrollOffset,
|
|
y = 8,
|
|
child = ui.rect { w = 2, h = 24, color = c.color }
|
|
}
|
|
| _ \ empty)
|
|
]
|
|
}
|
|
}
|
|
};
|
|
|
|
glyphView = config \
|
|
defaults = { scale = 1, color = "#fff" };
|
|
c = { ...defaults, ...config };
|
|
ui.stack {
|
|
children = map (pixel \
|
|
ui.positioned {
|
|
x = pixel.x * c.scale,
|
|
y = pixel.y * c.scale,
|
|
child = ui.rect { w = c.scale, h = c.scale, color = c.color }
|
|
}
|
|
) c.glyph.map
|
|
};
|