diff --git a/.gitignore b/.gitignore index 44b9d505..6e52d510 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ package-lock.json *.flippy wasm *.html +nimbledeps diff --git a/examples/minimal_scroll/minimal_scroll.nim b/examples/minimal_scroll/minimal_scroll.nim new file mode 100644 index 00000000..1b7d9f52 --- /dev/null +++ b/examples/minimal_scroll/minimal_scroll.nim @@ -0,0 +1,23 @@ +## This minimal example shows 5 blue squares in a scroll box + +import fidget + +proc drawMain() = + frame "main": + box 0, 0, 620, 140 + frame "scrollBox": + box 5, 5, 610, 130 + stroke "#000" + strokeWeight 1 + clipContent true + scrollable true, true + fill "#FFF" + for i in 0 .. 4: + group "blockA" & $i: + scrollSpeed (i + 1) * 2 - 6 + box 15 + (float i) * 120, 15, 100, 100 + fill "#2B9FEA" + stroke "#000" + strokeWeight 1 + +startFidget(drawMain, w = 620, h = 140) diff --git a/fidget.nimble b/fidget.nimble index fcc2bc4f..7efa958f 100644 --- a/fidget.nimble +++ b/fidget.nimble @@ -10,7 +10,7 @@ srcDir = "src" requires "nim >= 1.0.0" requires "chroma >= 0.1.3" -requires "typography >= 0.4.0" +requires "typography >= 0.6.0" requires "pixie >= 0.0.2" requires "vmath >= 0.3.1" requires "print >= 0.1.0" diff --git a/src/fidget.nim b/src/fidget.nim index dad32066..d0d7f300 100644 --- a/src/fidget.nim +++ b/src/fidget.nim @@ -266,7 +266,7 @@ proc image*(imageName: string) = ## Sets image fill. current.imageName = imageName -proc orgBox*(x, y, w, h: int|float32|float32) = +proc orgBox*(x, y, w, h: int|float32|float64) = ## Sets the box dimensions of the original element for constraints. current.orgBox.x = float32 x current.orgBox.y = float32 y @@ -280,6 +280,13 @@ proc box*(x, y, w, h: float32) = current.box.w = w current.box.h = h + ## Apply scroll + if not parent.isNil: + if parent.scrollable.x: + current.box.x += parent.scroll.x * current.scrollSpeed.x + if parent.scrollable.y: + current.box.y += parent.scroll.y * current.scrollSpeed.y + proc box*( x: int|float32|float64, y: int|float32|float64, @@ -358,6 +365,35 @@ proc scrollBars*(scrollBars: bool) = ## Causes the parent to clip the children and draw scroll bars. current.scrollBars = scrollBars +proc scrollable*(value: tuple[x: bool, y:bool]) = + ## Causes the parent to let scroll its children. + current.scrollable = value + + ## Accumulate scroll value + if current.scrollable.x or current.scrollable.y: + onHover: + current.scroll += mouse.wheelDelta + +proc scrollable*(xValue: bool, yValue: bool) = + ## Causes the parent to let scroll its children. + scrollable((x: xValue, y: yValue)) + +proc scrollable*(yValue: bool) = + ## Causes the parent to let scroll its children. + scrollable((x: false, y: yValue)) + +proc scrollSpeed*(value: Vec2) = + ## Sets the speed at which a child is scrolled inside its parent's box + current.scrollSpeed = value + +proc scrollSpeed*(value: int|float32|float64) = + ## Sets the speed at which a child is scrolled inside its parent's box + scrollSpeed(vec2(float32 value, float32 value)) + +proc scrollSpeed*(xValue, yValue: int|float32|float64) = + ## Sets the speed at which a child is scrolled inside its parent's box + scrollSpeed(vec2(float32 xValue, float32 yValue)) + proc cursorColor*(color: Color) = ## Sets the color of the text cursor. current.cursorColor = color diff --git a/src/fidget/common.nim b/src/fidget/common.nim index f35cecdc..8425527d 100644 --- a/src/fidget/common.nim +++ b/src/fidget/common.nim @@ -142,6 +142,9 @@ type textLayoutWidth*: float32 ## Can the text be selected. selectable*: bool + scrollable*: tuple[x: bool, y: bool] + scroll*: Vec2 + scrollSpeed*: Vec2 scrollBars*: bool ## Should it have scroll bars if children are clipped. KeyState* = enum @@ -160,7 +163,7 @@ type Mouse* = ref object pos*, delta*, prevPos*: Vec2 pixelScale*: float32 - wheelDelta*: float32 + wheelDelta*: Vec2 cursorStyle*: MouseCursorStyle ## Sets the mouse cursor icon prevCursorStyle*: MouseCursorStyle @@ -320,6 +323,7 @@ proc resetToDefault*(node: Node)= node.clipContent = false node.diffIndex = 0 node.selectable = false + node.scrollSpeed = vec2(1, 1) proc setupRoot*() = if root == nil: @@ -335,7 +339,7 @@ proc setupRoot*() = proc clearInputs*() = - mouse.wheelDelta = 0 + mouse.wheelDelta = vec2(0, 0) # Reset key and mouse press to default state for i in 0 ..< buttonPress.len: diff --git a/src/fidget/dom2.nim b/src/fidget/dom2.nim index 536f566d..45ea1e20 100644 --- a/src/fidget/dom2.nim +++ b/src/fidget/dom2.nim @@ -1154,6 +1154,13 @@ type screenX*, screenY*: int x*, y*: int + WheelEvent* = ref WheelEventObj ## see `docs` + WheelEventObj {.importc.} = object of MouseEvent + deltaX*: float64 + deltaY*: float64 + deltaZ*: float64 + deltaMode*: uint32 + DataTransferItemKind* {.pure.} = enum File = "file", String = "string" diff --git a/src/fidget/htmlbackend.nim b/src/fidget/htmlbackend.nim index cf826fda..b975f939 100644 --- a/src/fidget/htmlbackend.nim +++ b/src/fidget/htmlbackend.nim @@ -519,6 +519,12 @@ proc startFidget*(draw: proc(), load: proc() = nil, w = 0, h = 0) = ## Scroll does not need to do anything special in HTML mode refresh() + dom.window.addEventListener "wheel", proc(event: Event) = + ## When wheel is used + let event = cast[WheelEvent](event) + mouse.wheelDelta += vec2(event.deltaX, event.deltaY) + refresh() + dom.window.addEventListener "mousedown", proc(event: Event) = ## When mouse button is pressed let event = cast[MouseEvent](event) diff --git a/src/fidget/opengl/base.nim b/src/fidget/opengl/base.nim index 2ba086c6..1352900c 100644 --- a/src/fidget/opengl/base.nim +++ b/src/fidget/opengl/base.nim @@ -274,7 +274,7 @@ proc onScroll(window: staticglfw.Window, xoffset, yoffset: float64) {.cdecl.} = if keyboard.focusNode != nil: textBox.scrollBy(-yoffset * 50) else: - mouse.wheelDelta += yoffset + mouse.wheelDelta += vec2(xoffset, yoffset) proc onMouseButton( window: staticglfw.Window, button, action, modifiers: cint