cg/src/cg/palette.cg

170 lines
6 KiB
Text

@palette
paletteState = {
query = "",
focusedIndex = 0,
scrollOffset = 0,
opacity = 0.95,
scrollIndex = 0
};
palette = config \
windowHeight = 400;
windowWidth = 600;
results = take 100 (config.search paletteState.query);
nextSelectable = items index direction \
next = index + direction;
nth next items
| (Some (Section _)) \ nextSelectable items next direction
| (Some (Item _)) \ next
| None \ index;
effectiveIndex = nth paletteState.focusedIndex results
| (Some (Section _)) \ nextSelectable results paletteState.focusedIndex 1
| _ \ paletteState.focusedIndex;
dialogPadding = 0;
itemGap = 1;
textInputHeight = 40;
sectionHeight = 30;
contentWidth = windowWidth - (dialogPadding * 2);
contentHeight = windowHeight - (dialogPadding * 2);
listHeight = contentHeight - 40;
itemHeight = entry \
entry
| (Section _) \ sectionHeight
| (Item _) \ textInputHeight
| _ \ 0;
totalHeight = (sum (map itemHeight results)) + (itemGap * ((len results) - 1));
itemY = i \ (sum (map itemHeight (take i results))) + i;
onScroll = delta \ paletteState.scrollOffset := max 0 (min (totalHeight - listHeight) (paletteState.scrollOffset + delta.deltaY));
scrollTo = index \
y = itemY index;
h = unwrapOr 0 (nth index (map itemHeight results));
offset = paletteState.scrollOffset;
y < offset
| True \ y
| False \ ((y + h) > (offset + listHeight)
| True \ (y + h) - listHeight
| False \ offset);
onSelect = text \ batch [
paletteState.query := "",
paletteState.focusedIndex := 0,
paletteState.scrollOffset := 0,
config.onSelect text
];
paletteRow = config \
color = config.selected
| True \ "rgba(255,255,255,0.2)"
| False \ "transparent";
ui.clickable {
onClick = config.onClick,
child = ui.stack { children = [
ui.rect { w = config.w, h = config.h, color = color },
ui.positioned { x = 6, y = 12, child = text config.child }
] }
};
ui.stateful {
key = "palette",
focusable = False,
init = { },
update = state event \
event
| (Key {printable = True}) \ {
state = state,
emit = [
paletteState.focusedIndex := nextSelectable results 0 1,
paletteState.scrollIndex := 0
]
}
| (Key {key = "ArrowUp"}) \ (newIndex = nextSelectable results effectiveIndex (0 - 1);
{
state = state,
emit = [
paletteState.focusedIndex := newIndex,
paletteState.scrollOffset := scrollTo newIndex
]
})
| (Key {key = "ArrowDown"}) \ (newIndex = nextSelectable results effectiveIndex 1;
{
state = state,
emit = [
paletteState.focusedIndex := newIndex,
paletteState.scrollOffset := scrollTo newIndex
]
})
| (Key {key = "Enter"}) \ (nth effectiveIndex results
| (Some (Item data)) \ { state = state, emit = [onSelect data.label] }
| _ \ { state = state, emit = [] })
| (Key {key = "Tab"}) \ (newQuery = nth effectiveIndex results
| (Some (Item data)) \ data.label
| None \ paletteState.query;
{ state = state, emit = [paletteState.query := newQuery] })
| (Key {key = "Escape"}) \ { state = state, emit = [osState.palette.visible := False] }
| _ \ { state = state, emit = [] },
view = state emit \ ui.positioned {
x = (config.viewport.width - windowWidth) / 2,
y = (config.viewport.height - windowHeight) / 2,
child = ui.opacity {
opacity = paletteState.opacity,
child = ui.stack { children = [
ui.rect {
w = windowWidth,
h = windowHeight,
color = "#063351",
radius = 0,
strokeWidth = 1,
strokeColor = "#1A5F80"
},
ui.padding {
amount = dialogPadding,
child = ui.column {
gap = 0,
children = [
textInput {
key = "palette-query",
value = paletteState.query,
autoFocus = True,
color = "white",
backgroundColor = "rgba(0,0,0,0.2)",
w = contentWidth,
h = textInputHeight,
onChange = text \ batch [paletteState.query := text]
},
scrollable {
w = contentWidth,
h = listHeight,
totalHeight = totalHeight,
totalWidth = contentWidth,
scrollX = 0,
scrollY = paletteState.scrollOffset,
onScroll = onScroll,
child = ui.column {
gap = itemGap,
children = [...mapWithIndex (entry i \
entry
| (Section title) \ box {
w = contentWidth,
h = sectionHeight,
color = "transparent",
paddingLeft = 6,
paddingTop = 8,
child = renderText { content = title, color = "#bbb" }
}
| (Item data) \ paletteRow {
child = data.label,
w = contentWidth,
h = textInputHeight,
selected = effectiveIndex == i,
onClick = _ \ onSelect data.label
}
| _ \ empty) results]
}
}
]
}
}
] }
}
}
};
@