From 6d794f18a25710c7227ffb37ae0cd2ea10df96a7 Mon Sep 17 00:00:00 2001 From: levovix Date: Sat, 14 Sep 2024 10:07:46 +0300 Subject: [PATCH] add: scroll in ScrollArea using scrollbar --- src/sigui/animations.nim | 12 ++++-- src/sigui/scrollArea.nim | 65 +++++++++++++++++++++++++++-- src/sigui/uibase.nim | 6 +-- tests/t_todoapp.nim | 89 +++++++++++++++++----------------------- 4 files changed, 110 insertions(+), 62 deletions(-) diff --git a/src/sigui/animations.nim b/src/sigui/animations.nim index 146eaa2..290c29d 100644 --- a/src/sigui/animations.nim +++ b/src/sigui/animations.nim @@ -165,13 +165,19 @@ template transition*[T](prop: var AnyProperty[T], dur: Duration): Animation[T] = ), duration: dur.property ) - a.a{} = prop.unsafeVal - a.b{} = prop.unsafeVal + a.a{} = prop[] + a.b{} = prop[] + + var prevPropVal = prop[] + prop.changed.connect(a.eventHandler, proc() = - a.a{} = a.currentValue + a.a{} = prevPropVal a.b{} = prop[] start a , flags = {EventConnectionFlag.transition}) + + prop.changed.connect(a.eventHandler, proc() = prevPropVal = prop[]) + a diff --git a/src/sigui/scrollArea.nim b/src/sigui/scrollArea.nim index 0b0ec5d..11c0a5b 100644 --- a/src/sigui/scrollArea.nim +++ b/src/sigui/scrollArea.nim @@ -1,6 +1,6 @@ import std/[sequtils] import pkg/fusion/[matching] -import ./[uibase, animations, mouseArea] +import ./[uibase, events {.all.}, animations, mouseArea, dolars] type ScrollAreaSetting* = enum @@ -12,8 +12,8 @@ type shrinkScrollBarWhenNotHovered hideScrollBarWhenNotHoveredOrScrolled - # disableAnimationsWhenScrollingUsingBar - # immediateScrollWhenClickedOnScrollBarArea + disableAnimationsWhenScrollingUsingBar + instantScrollWhenClickedOnScrollBarArea ScrollArea* = ref object of Uiobj @@ -156,6 +156,59 @@ method init*(this: ScrollArea) = not(scrollArea.horizontalScrollBarArea.hovered[] or scrollArea.horizontalScrollBarArea.pressed[]) ): scrollArea.horizontalScrollBarShouldBeVisible[] = false + + + template makeScrollBar3( + this, mouseY, scrollY, targetY, scrollH, y, h, verticalScrollbarObj, verticalScrollOverFit, verticalScrollSpeed + ) = + var isDraggingScrollbar: bool + var prevMouseY: float + + proc moveVerticalScrollbarToMouse(mouseY: float) = + proc setScrollY(scrollArea: ScrollArea, newScrollY: float) = + if disableAnimationsWhenScrollingUsingBar in scrollArea.settings[]: + scrollArea.scrollY{} = newScrollY + scrollArea.scrollY.changed.emit({EventConnectionFlag.transition}) + scrollArea.targetY[] = newScrollY + else: + scrollArea.targetY[] = newScrollY + + if isDraggingScrollbar: + let d = mouseY - prevMouseY + prevMouseY = mouseY + scrollArea.setScrollY ( + scrollArea.targetY[] + (d / this.h[] * (scrollArea.scrollH[] + scrollArea.verticalScrollOverFit[])) + ).min(scrollArea.scrollH[] + scrollArea.verticalScrollOverFit[] - scrollArea.h[]).max(0) + + else: + if instantScrollWhenClickedOnScrollBarArea in scrollArea.settings[]: + scrollArea.setScrollY ( + (this.mouseY[] - scrollArea.verticalScrollbarObj[].h[] / 2) / (this.h[] - scrollArea.verticalScrollbarObj[].h[]) * + (scrollArea.scrollH[] + scrollArea.verticalScrollOverFit[] - scrollArea.h[]) + ).min(scrollArea.scrollH[] + scrollArea.verticalScrollOverFit[] - scrollArea.h[]).max(0) + + else: + if this.mouseY[] notin ( + scrollArea.verticalScrollbarObj[].y[] .. + (scrollArea.verticalScrollbarObj[].y[] + scrollArea.verticalScrollbarObj[].h[]) + ): + scrollArea.setScrollY ( + scrollArea.targetY[] + + scrollArea.verticalScrollSpeed[] * (if this.mouseY[] < scrollArea.verticalScrollbarObj[].y[]: -1 else: 1) + ).min(scrollArea.scrollH[] + scrollArea.verticalScrollOverFit[] - scrollArea.h[]).max(0) + + + this.pressed.changed.connectTo scrollArea: + isDraggingScrollbar = this.mouseY[] in ( + scrollArea.verticalScrollbarObj[].y[] .. + (scrollArea.verticalScrollbarObj[].y[] + scrollArea.verticalScrollbarObj[].h[]) + ) + prevMouseY = this.mouseY[] + if (hasScrollBar in scrollArea.settings[]) and this.pressed[]: moveVerticalScrollbarToMouse(this.mouseY[]) + + this.mouseY.changed.connectTo scrollArea: + if (hasScrollBar in scrollArea.settings[]) and this.pressed[]: moveVerticalScrollbarToMouse(this.mouseY[]) + # actual scroll area @@ -205,7 +258,7 @@ method init*(this: ScrollArea) = w = binding: if ( shrinkScrollBarWhenNotHovered in scrollArea.settings[] and - (not scrollArea.verticalScrollBarArea.hovered[] or scrollArea.verticalScrollBarArea.pressed[]) + not (scrollArea.verticalScrollBarArea.hovered[] or scrollArea.verticalScrollBarArea.pressed[]) ): scrollArea.verticalScrollBarShrinkedWidth[] else: @@ -219,6 +272,8 @@ method init*(this: ScrollArea) = - this.w.transition(0.2's): easing = outSquareEasing + + makeScrollBar3(this, mouseY, scrollY, targetY, scrollH, y, h, verticalScrollBarObj, verticalScrollOverFit, verticalScrollSpeed) - scrollArea.horizontalScrollBarArea: @@ -246,6 +301,8 @@ method init*(this: ScrollArea) = - this.h.transition(0.2's): easing = outSquareEasing + + makeScrollBar3(this, mouseX, scrollX, targetX, scrollW, x, w, horizontalScrollbarObj, horizontalScrollOverFit, horizontalScrollSpeed) this.newChildsObject = container diff --git a/src/sigui/uibase.nim b/src/sigui/uibase.nim index 74e16ea..593baa0 100644 --- a/src/sigui/uibase.nim +++ b/src/sigui/uibase.nim @@ -706,7 +706,7 @@ method addChangableChildUntyped*(parent: Uiobj, child: Uiobj): CustomProperty[Ui parent.childs[i] = v v.parent = parent v.recieve(ParentChanged(newParentInTree: parent)) - parent.recieve(ChildAdded(child: child)) + parent.recieve(ChildAdded(child: v)) ), ) @@ -1594,8 +1594,8 @@ macro makeLayout*(obj: Uiobj, body: untyped) = genSym(nskLabel, "changableChildInitializationBlock") stmtList: discard checkCtor ctor - let - updateProc = genSym(nskProc) + + let updateProc = genSym(nskProc) asgn: prop diff --git a/tests/t_todoapp.nim b/tests/t_todoapp.nim index 73d17b5..7aa5939 100644 --- a/tests/t_todoapp.nim +++ b/tests/t_todoapp.nim @@ -78,62 +78,47 @@ test "todo app": taskName.pushState() taskName.text[] = "" - - ClipRect(): + - ScrollArea(): this.fillHorizontal(parent, 20) bottom = parent.bottom - 20 top = taskAdder.bottom + 20 - - MouseArea(): - this.fill parent - - - Uiobj(): - w := parent.w[] - - - this.y.transition(0.2's): - easing = outSquareEasing - - var targetY = 0'f32.property - this.binding y: targetY[] - - parent.scrolled.connectTo this, delta: - targetY[] = (targetY[] - delta.y * 56).min(0).max(-(app.layout[].h[] - 56).max(0)) - - app.layout --- Layout(): - this.binding w: parent.w[] - - orientation = vertical - gap = 5 - - for i in 0..app.tasks.high: - template task: auto = app.tasks[i] - - - Layout(): - spacing = 10 - align = center - - - Switch(isOn: task.complete[].property): - color = color(0.43, 0.15, 0.76) - - isOn := task.complete[] - this.bindingValue task.complete[]: this.isOn[] - - - UiText(): - text = task.name - - this.binding font: - let it = typeface.withSize(24) - it.strikethrough = task.complete[] - it - - this.binding color: - if mouse.pressed[]: color(0.2, 0.2, 0.2) - elif mouse.hovered[]: color(0.4, 0.4, 0.4) - else: color(0, 0, 0) - - - MouseArea() as mouse: - this.fill parent - this.mouseDownAndUpInside.connectTo this: - task.complete[] = not task.complete[] + app.layout --- Layout(): + this.binding w: parent.w[] + + orientation = vertical + gap = 5 + + for i in 0..app.tasks.high: + template task: auto = app.tasks[i] + + - Layout(): + spacing = 10 + align = center + + - Switch(isOn: task.complete[].property): + color = color(0.43, 0.15, 0.76) + + isOn := task.complete[] + this.bindingValue task.complete[]: this.isOn[] + + - UiText(): + text = task.name + + this.binding font: + let it = typeface.withSize(24) + it.strikethrough = task.complete[] + it + + this.binding color: + if mouse.pressed[]: color(0.2, 0.2, 0.2) + elif mouse.hovered[]: color(0.4, 0.4, 0.4) + else: color(0, 0, 0) + + - MouseArea() as mouse: + this.fill parent + this.mouseDownAndUpInside.connectTo this: + task.complete[] = not task.complete[] app.tasksChanged.connectTo app: app.layout[] = Layout()