scrollable now supports horizontal scrolling. using it in os wm. putting all os stuff in os namespace
This commit is contained in:
parent
5fc9d13f80
commit
373ec8b36b
3 changed files with 209 additions and 189 deletions
|
|
@ -26,25 +26,36 @@ button = config \
|
||||||
|
|
||||||
# scrollable
|
# scrollable
|
||||||
scrollable = config \
|
scrollable = config \
|
||||||
barHeight = max 20 (config.h * config.h / config.totalHeight);
|
showVBar = config.totalHeight > config.h;
|
||||||
barY = config.scrollY * config.h / config.totalHeight;
|
vBarHeight = max 20 (config.h * config.h / config.totalHeight);
|
||||||
showBar = config.totalHeight > config.h;
|
vBarY = config.scrollY * config.h / config.totalHeight;
|
||||||
|
|
||||||
|
showHBar = config.totalWidth > config.w;
|
||||||
|
vBarWidth = max 20 (config.w * config.w / config.totalWidth);
|
||||||
|
vBarX = config.scrollX * config.w / config.totalWidth;
|
||||||
|
|
||||||
ui.stack {
|
ui.stack {
|
||||||
children = [
|
children = [
|
||||||
ui.scrollable {
|
ui.scrollable {
|
||||||
w = config.w,
|
w = config.w,
|
||||||
h = config.h,
|
h = config.h,
|
||||||
scrollX = 0,
|
scrollX = config.scrollX,
|
||||||
scrollY = config.scrollY,
|
scrollY = config.scrollY,
|
||||||
onScroll = config.onScroll,
|
onScroll = config.onScroll,
|
||||||
child = config.child
|
child = config.child
|
||||||
},
|
},
|
||||||
...(showBar
|
...(showVBar
|
||||||
| True \ [ui.positioned {
|
| True \ [ui.positioned {
|
||||||
x = config.w - 4,
|
x = config.w - 4,
|
||||||
y = barY,
|
y = vBarY,
|
||||||
child = ui.rect { w = 4, h = barHeight, color = "rgba(255,255,255,0.3)", radius = 2 }
|
child = ui.rect { w = 4, h = vBarHeight, color = "rgba(255,255,255,0.3)", radius = 2 }
|
||||||
|
}]
|
||||||
|
| False \ []),
|
||||||
|
...(showHBar
|
||||||
|
| True \ [ui.positioned {
|
||||||
|
x = config.h - 4,
|
||||||
|
y = hBarX,
|
||||||
|
child = ui.rect { h = 4, w = hBarWidth, color = "rgba(255,255,255,0.3)", radius = 2 }
|
||||||
}]
|
}]
|
||||||
| False \ [])
|
| False \ [])
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -126,6 +126,7 @@ palette = config \
|
||||||
w = contentWidth,
|
w = contentWidth,
|
||||||
h = listHeight,
|
h = listHeight,
|
||||||
totalHeight = totalHeight,
|
totalHeight = totalHeight,
|
||||||
|
totalWidth = contentWidth,
|
||||||
scrollX = 0,
|
scrollX = 0,
|
||||||
scrollY = paletteState.scrollOffset,
|
scrollY = paletteState.scrollOffset,
|
||||||
onScroll = onScroll,
|
onScroll = onScroll,
|
||||||
|
|
|
||||||
372
src/cg/10-os.cg
372
src/cg/10-os.cg
|
|
@ -9,204 +9,212 @@ osState = {
|
||||||
nextId = 0
|
nextId = 0
|
||||||
};
|
};
|
||||||
|
|
||||||
openPalette = _ \ osState.palette.visible := not (osState.palette.visible);
|
os =
|
||||||
|
openPalette = _ \ osState.palette.visible := not (osState.palette.visible);
|
||||||
|
|
||||||
windowWidth = window \ window.fullWidth
|
windowWidth = window \ window.fullWidth
|
||||||
| True \ viewport.width
|
| True \ viewport.width
|
||||||
| False \ window.width;
|
| False \ window.width;
|
||||||
|
|
||||||
openWindow = title content \
|
totalWidth = (sum (map windowWidth osState.windows)) + (len osState.windows - 1);
|
||||||
id = osState.nextId;
|
|
||||||
batch [
|
|
||||||
osState.nextId := id + 1,
|
|
||||||
osState.windows := osState.windows & [{
|
|
||||||
id = id,
|
|
||||||
title = title,
|
|
||||||
content = content,
|
|
||||||
width = osState.wm.defaultWindowWidth,
|
|
||||||
fullWidth = False
|
|
||||||
}],
|
|
||||||
osState.palette.visible := False,
|
|
||||||
focusWindow (len osState.windows)
|
|
||||||
];
|
|
||||||
|
|
||||||
closeWindowByIndex = i \
|
scrollToWindow = index \
|
||||||
focused = osState.wm.focusedIndex;
|
windows = osState.windows;
|
||||||
newFocused = (i < focused
|
widths = map windowWidth windows;
|
||||||
| True \ focused - 1
|
gap = 1;
|
||||||
| False \ (i == focused
|
windowX = (sum (take index widths)) + (index * gap);
|
||||||
| True \ max 0 (focused - 1)
|
windowW = unwrapOr osState.wm.defaultWindowWidth (nth index widths);
|
||||||
| False \ focused));
|
scrollOffset = osState.wm.scrollOffset;
|
||||||
|
vw = viewport.width;
|
||||||
|
(windowX < scrollOffset
|
||||||
|
| True \ windowX
|
||||||
|
| False \ (windowX + windowW > scrollOffset + vw
|
||||||
|
| True \ windowX + windowW - vw
|
||||||
|
| False \ scrollOffset));
|
||||||
|
|
||||||
batch [
|
focusWindow = index \
|
||||||
osState.windows := (take i osState.windows) & (drop (i + 1) osState.windows),
|
batch [
|
||||||
focusWindow newFocused
|
osState.wm.focusedIndex := index,
|
||||||
# osState.wm.focusedIndex := min newFocused (len osState.windows - 2)
|
osState.wm.scrollOffset := scrollToWindow index
|
||||||
];
|
];
|
||||||
|
|
||||||
closeFocusedWindow = _ \ closeWindowByIndex osState.wm.focusedIndex;
|
openWindow = title content \
|
||||||
|
id = osState.nextId;
|
||||||
|
batch [
|
||||||
|
osState.nextId := id + 1,
|
||||||
|
osState.windows := osState.windows & [{
|
||||||
|
id = id,
|
||||||
|
title = title,
|
||||||
|
content = content,
|
||||||
|
width = osState.wm.defaultWindowWidth,
|
||||||
|
fullWidth = False
|
||||||
|
}],
|
||||||
|
osState.palette.visible := False,
|
||||||
|
focusWindow (len osState.windows)
|
||||||
|
];
|
||||||
|
|
||||||
closeWindowById = id \
|
closeWindowByIndex = i \
|
||||||
i = index id (map (w \ w.id) osState.windows);
|
focused = osState.wm.focusedIndex;
|
||||||
closeWindowByIndex (unwrapOr 0 i);
|
newFocused = (i < focused
|
||||||
|
| True \ focused - 1
|
||||||
|
| False \ (i == focused
|
||||||
|
| True \ max 0 (focused - 1)
|
||||||
|
| False \ focused));
|
||||||
|
|
||||||
toggleMaximizeFocusedWindow = _ \
|
batch [
|
||||||
idx = osState.wm.focusedIndex;
|
osState.windows := (take i osState.windows) & (drop (i + 1) osState.windows),
|
||||||
osState.windows := updateAt idx (w \ w.{ fullWidth = not w.fullWidth }) osState.windows;
|
focusWindow newFocused
|
||||||
|
# osState.wm.focusedIndex := min newFocused (len osState.windows - 2)
|
||||||
|
];
|
||||||
|
|
||||||
scrollToWindow = index \
|
closeFocusedWindow = _ \ closeWindowByIndex osState.wm.focusedIndex;
|
||||||
windows = osState.windows;
|
|
||||||
widths = map windowWidth windows;
|
|
||||||
gap = 1;
|
|
||||||
windowX = (sum (take index widths)) + (index * gap);
|
|
||||||
windowW = unwrapOr osState.wm.defaultWindowWidth (nth index widths);
|
|
||||||
scrollOffset = osState.wm.scrollOffset;
|
|
||||||
vw = viewport.width;
|
|
||||||
(windowX < scrollOffset
|
|
||||||
| True \ windowX
|
|
||||||
| False \ (windowX + windowW > scrollOffset + vw
|
|
||||||
| True \ windowX + windowW - vw
|
|
||||||
| False \ scrollOffset));
|
|
||||||
|
|
||||||
focusWindow = index \
|
closeWindowById = id \
|
||||||
batch [
|
i = index id (map (w \ w.id) osState.windows);
|
||||||
osState.wm.focusedIndex := index,
|
closeWindowByIndex (unwrapOr 0 i);
|
||||||
osState.wm.scrollOffset := scrollToWindow index
|
|
||||||
];
|
|
||||||
|
|
||||||
onSelect = input \
|
toggleMaximizeFocusedWindow = _ \
|
||||||
result = eval input;
|
idx = osState.wm.focusedIndex;
|
||||||
result
|
osState.windows := updateAt idx (w \ w.{ fullWidth = not w.fullWidth }) osState.windows;
|
||||||
| Value v \ openWindow input (_ \ ui.text { content = show v, color = "white" })
|
|
||||||
| Defined name \ openWindow name (_ \ inspector { name = name })
|
|
||||||
| Err msg \ openWindow "Error" (_ \ ui.text { content = msg, color = "red" });
|
|
||||||
|
|
||||||
renderWindow = window isActive \
|
renderWindow = window isActive \
|
||||||
titleBarHeight = 30;
|
titleBarHeight = 30;
|
||||||
|
|
||||||
ui.stack {
|
|
||||||
children = [
|
|
||||||
# background
|
|
||||||
ui.rect { w = (windowWidth window), h = viewport.height, color = (isActive | True \ "#0a2a3a" | False \ "#061820")},
|
|
||||||
|
|
||||||
# title bar
|
|
||||||
ui.positioned {
|
|
||||||
x = 0, y = 0,
|
|
||||||
child = ui.stack {
|
|
||||||
children = [
|
|
||||||
# background
|
|
||||||
ui.rect { w = (windowWidth window), h = titleBarHeight, color = (isActive | True \ "#a15f80" | False \ "#0f3348") },
|
|
||||||
ui.row {
|
|
||||||
children = [
|
|
||||||
# close button
|
|
||||||
ui.clickable {
|
|
||||||
onClick = _ \ closeWindowById window.id,
|
|
||||||
child = ui.stack {
|
|
||||||
children = [
|
|
||||||
# button background
|
|
||||||
ui.rect { w = titleBarHeight, h = titleBarHeight, color = "rgba(255,255,255,0.2)" },
|
|
||||||
# button text
|
|
||||||
ui.positioned {
|
|
||||||
x = 9, y = 7, child = ui.text { content = "x" }
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
# title
|
|
||||||
ui.positioned { x = 8, y = 8, child = ui.text { content = window.title, color = "white" } },
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
# content
|
|
||||||
ui.positioned {
|
|
||||||
x = 0, y = titleBarHeight,
|
|
||||||
child = ui.clip {
|
|
||||||
w = (windowWidth window),
|
|
||||||
h = viewport.height - titleBarHeight,
|
|
||||||
child = window.content 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
windowComponent = config \ ui.stateful {
|
|
||||||
key = "window-" & (show config.index),
|
|
||||||
focusable = True,
|
|
||||||
init = {},
|
|
||||||
update = state event \ event
|
|
||||||
| Focused \ { state = state, emit = [focusWindow config.index] }
|
|
||||||
| ChildFocused \ { state = state, emit = [focusWindow config.index] }
|
|
||||||
| _ \ { state = state, emit = [] },
|
|
||||||
view = state \ renderWindow config.window config.isActive
|
|
||||||
};
|
|
||||||
|
|
||||||
renderWindows = _ \
|
|
||||||
windows = osState.windows;
|
|
||||||
focused = osState.wm.focusedIndex;
|
|
||||||
scrollable {
|
|
||||||
w = viewport.width,
|
|
||||||
h = viewport.height,
|
|
||||||
scrollX = osState.wm.scrollOffset,
|
|
||||||
scrollY = 0,
|
|
||||||
child = ui.row {
|
|
||||||
gap = 1,
|
|
||||||
children = mapWithIndex (w i \ windowComponent { window = w, index = i, isActive = (i == focused) }) windows
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
search = q \
|
|
||||||
storeRes = storeSearch q;
|
|
||||||
[
|
|
||||||
Section "STORE",
|
|
||||||
...map (name \ Item { label = name }) storeRes,
|
|
||||||
Section "EVAL",
|
|
||||||
Item { label = q }
|
|
||||||
];
|
|
||||||
|
|
||||||
os = ui.stateful {
|
|
||||||
key = "os",
|
|
||||||
autoFocus = True,
|
|
||||||
|
|
||||||
init = {},
|
|
||||||
|
|
||||||
update = state event \ event
|
|
||||||
| Key { key = "p", meta = True } \
|
|
||||||
{ state = state, emit = [openPalette] }
|
|
||||||
| Key { key = "ArrowLeft", meta = True } \
|
|
||||||
(
|
|
||||||
newIndex = max 0 (osState.wm.focusedIndex - 1);
|
|
||||||
{ state = state, emit = [focusWindow newIndex] }
|
|
||||||
)
|
|
||||||
| Key { key = "ArrowRight", meta = True } \
|
|
||||||
(
|
|
||||||
newIndex = min (len osState.windows - 1) (osState.wm.focusedIndex + 1);
|
|
||||||
{ state = state, emit = [focusWindow newIndex] }
|
|
||||||
)
|
|
||||||
| Key { key = "d", meta = True } \
|
|
||||||
{ state = state, emit = [closeFocusedWindow 0] }
|
|
||||||
| Key { key = "f", meta = True } \
|
|
||||||
{ state = state, emit = [toggleMaximizeFocusedWindow 0] }
|
|
||||||
| _ \ { state = state, emit = [] },
|
|
||||||
|
|
||||||
view = state \
|
|
||||||
ui.stack {
|
ui.stack {
|
||||||
children = [
|
children = [
|
||||||
ui.rect { w = viewport.width, h = viewport.height, color = "#012" },
|
# background
|
||||||
|
ui.rect { w = (windowWidth window), h = viewport.height, color = (isActive | True \ "#0a2a3a" | False \ "#061820")},
|
||||||
|
|
||||||
renderWindows 0,
|
# title bar
|
||||||
|
ui.positioned {
|
||||||
|
x = 0, y = 0,
|
||||||
|
child = ui.stack {
|
||||||
|
children = [
|
||||||
|
# background
|
||||||
|
ui.rect { w = (windowWidth window), h = titleBarHeight, color = (isActive | True \ "#a15f80" | False \ "#0f3348") },
|
||||||
|
ui.row {
|
||||||
|
children = [
|
||||||
|
# close button
|
||||||
|
ui.clickable {
|
||||||
|
onClick = _ \ closeWindowById window.id,
|
||||||
|
child = ui.stack {
|
||||||
|
children = [
|
||||||
|
# button background
|
||||||
|
ui.rect { w = titleBarHeight, h = titleBarHeight, color = "rgba(255,255,255,0.2)" },
|
||||||
|
# button text
|
||||||
|
ui.positioned {
|
||||||
|
x = 9, y = 7, child = ui.text { content = "x" }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
# keep palette at the end so it's on top
|
# title
|
||||||
osState.palette.visible
|
ui.positioned { x = 8, y = 8, child = ui.text { content = window.title, color = "white" } },
|
||||||
| True \ palette {
|
]
|
||||||
search = search,
|
}
|
||||||
onSelect = onSelect,
|
]
|
||||||
viewport = viewport,
|
|
||||||
}
|
}
|
||||||
| False \ empty,
|
},
|
||||||
|
|
||||||
|
# content
|
||||||
|
ui.positioned {
|
||||||
|
x = 0, y = titleBarHeight,
|
||||||
|
child = ui.clip {
|
||||||
|
w = (windowWidth window),
|
||||||
|
h = viewport.height - titleBarHeight,
|
||||||
|
child = window.content 0
|
||||||
|
}
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
};
|
||||||
|
|
||||||
|
windowComponent = config \ ui.stateful {
|
||||||
|
key = "window-" & (show config.index),
|
||||||
|
focusable = True,
|
||||||
|
init = {},
|
||||||
|
update = state event \ event
|
||||||
|
| Focused \ { state = state, emit = [focusWindow config.index] }
|
||||||
|
| ChildFocused \ { state = state, emit = [focusWindow config.index] }
|
||||||
|
| _ \ { state = state, emit = [] },
|
||||||
|
view = state \ renderWindow config.window config.isActive
|
||||||
};
|
};
|
||||||
|
|
||||||
|
renderWindows = _ \
|
||||||
|
windows = osState.windows;
|
||||||
|
focused = osState.wm.focusedIndex;
|
||||||
|
totalHeight = viewport.height;
|
||||||
|
scrollable {
|
||||||
|
w = viewport.width,
|
||||||
|
h = viewport.height,
|
||||||
|
scrollX = osState.wm.scrollOffset,
|
||||||
|
scrollY = 0,
|
||||||
|
onScroll = onScroll,
|
||||||
|
child = ui.row {
|
||||||
|
gap = 1,
|
||||||
|
children = mapWithIndex (w i \ windowComponent { window = w, index = i, isActive = (i == focused) }) windows
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
search = q \
|
||||||
|
storeRes = storeSearch q;
|
||||||
|
[
|
||||||
|
Section "STORE",
|
||||||
|
...map (name \ Item { label = name }) storeRes,
|
||||||
|
Section "EVAL",
|
||||||
|
Item { label = q }
|
||||||
|
];
|
||||||
|
|
||||||
|
onScroll = delta \
|
||||||
|
osState.wm.scrollOffset := max 0 (min (totalWidth - viewport.width) (osState.wm.scrollOffset + delta.deltaX));
|
||||||
|
|
||||||
|
onSelect = input \
|
||||||
|
result = eval input;
|
||||||
|
result
|
||||||
|
| Value v \ openWindow input (_ \ ui.text { content = show v, color = "white" })
|
||||||
|
| Defined name \ openWindow name (_ \ inspector { name = name })
|
||||||
|
| Err msg \ openWindow "Error" (_ \ ui.text { content = msg, color = "red" });
|
||||||
|
|
||||||
|
ui.stateful {
|
||||||
|
key = "os",
|
||||||
|
autoFocus = True,
|
||||||
|
|
||||||
|
init = {},
|
||||||
|
|
||||||
|
update = state event \ event
|
||||||
|
| Key { key = "p", meta = True } \
|
||||||
|
{ state = state, emit = [openPalette] }
|
||||||
|
| Key { key = "ArrowLeft", meta = True } \
|
||||||
|
(
|
||||||
|
newIndex = max 0 (osState.wm.focusedIndex - 1);
|
||||||
|
{ state = state, emit = [focusWindow newIndex] }
|
||||||
|
)
|
||||||
|
| Key { key = "ArrowRight", meta = True } \
|
||||||
|
(
|
||||||
|
newIndex = min (len osState.windows - 1) (osState.wm.focusedIndex + 1);
|
||||||
|
{ state = state, emit = [focusWindow newIndex] }
|
||||||
|
)
|
||||||
|
| Key { key = "d", meta = True } \
|
||||||
|
{ state = state, emit = [closeFocusedWindow 0] }
|
||||||
|
| Key { key = "f", meta = True } \
|
||||||
|
{ state = state, emit = [toggleMaximizeFocusedWindow 0] }
|
||||||
|
| _ \ { state = state, emit = [] },
|
||||||
|
|
||||||
|
view = state \
|
||||||
|
ui.stack {
|
||||||
|
children = [
|
||||||
|
ui.rect { w = viewport.width, h = viewport.height, color = "#012" },
|
||||||
|
|
||||||
|
renderWindows 0,
|
||||||
|
|
||||||
|
# keep palette at the end so it's on top
|
||||||
|
osState.palette.visible
|
||||||
|
| True \ palette {
|
||||||
|
search = search,
|
||||||
|
onSelect = onSelect,
|
||||||
|
viewport = viewport,
|
||||||
|
}
|
||||||
|
| False \ empty,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue