# HG changeset patch # User Sam # Date 1707574771 -25200 # Node ID 10267da04fba736e47ec887142bf5791790e63e8 # Parent 2aa26c23cc6099a9ed6cfd4bea7132ea19ab9191 add: input-processing for panels diff -r 2aa26c23cc60 -r 10267da04fba semicongine/engine.nim --- a/semicongine/engine.nim Sat Feb 10 15:55:05 2024 +0700 +++ b/semicongine/engine.nim Sat Feb 10 21:19:31 2024 +0700 @@ -218,3 +218,25 @@ func limits*(engine: Engine): VkPhysicalDeviceLimits = engine.gpuDevice().physicalDevice.properties.limits + +proc processEventsFor*(engine: Engine, panel: var Panel) = + let hasMouseNow = panel.contains(engine.mousePositionNormalized()) + + # enter/leave events + if hasMouseNow: + if panel.hasMouse: + if panel.onMouseMove != nil: panel.onMouseMove(panel) + else: + if panel.onMouseEnter != nil: panel.onMouseEnter(panel) + else: + if panel.hasMouse: + if panel.onMouseLeave != nil: panel.onMouseLeave(panel) + + # button events + if hasMouseNow: + if engine.input.mouseWasPressed.len > 0: + if panel.onMouseDown != nil: panel.onMouseDown(panel, engine.input.mouseWasPressed) + if engine.input.mouseWasReleased.len > 0: + if panel.onMouseUp != nil: panel.onMouseUp(panel, engine.input.mouseWasReleased) + + panel.hasMouse = hasMouseNow diff -r 2aa26c23cc60 -r 10267da04fba semicongine/panel.nim --- a/semicongine/panel.nim Sat Feb 10 15:55:05 2024 +0700 +++ b/semicongine/panel.nim Sat Feb 10 21:19:31 2024 +0700 @@ -5,6 +5,7 @@ import ./mesh import ./material import ./vulkan/shader +import ./events const # font shader @@ -45,13 +46,19 @@ Panel* = object position: Vec2f size: Vec2f - texture: Texture horizontalAlignment: HorizontalAlignment = Center verticalAlignment: VerticalAlignment = Center aspect_ratio: float32 dirty: bool mesh: Mesh + # input handling + onMouseDown*: proc(panel: var Panel, buttons: set[MouseButton]) + onMouseUp*: proc(panel: var Panel, buttons: set[MouseButton]) + onMouseEnter*: proc(panel: var Panel) + onMouseMove*: proc(panel: var Panel) + onMouseLeave*: proc(panel: var Panel) + hasMouse*: bool proc `$`*(panel: Panel): string = &"Panel {panel.position} (size {panel.size})" @@ -89,9 +96,33 @@ panel.dirty = false -proc initPanel*(position = newVec2f(), size = newVec2f(), color = newVec4f(1, 1, 1, 1), texture = EMPTY_TEXTURE, horizontalAlignment = HorizontalAlignment.Center, verticalAlignment = VerticalAlignment.Center): Panel = +proc initPanel*( + position = newVec2f(), + size = newVec2f(), + color = newVec4f(1, 1, 1, 1), + texture = EMPTY_TEXTURE, + horizontalAlignment = HorizontalAlignment.Center, + verticalAlignment = VerticalAlignment.Center, + onMouseDown: proc(panel: var Panel, buttons: set[MouseButton]) = nil, + onMouseUp: proc(panel: var Panel, buttons: set[MouseButton]) = nil, + onMouseEnter: proc(panel: var Panel) = nil, + onMouseMove: proc(panel: var Panel) = nil, + onMouseLeave: proc(panel: var Panel) = nil, +): Panel = - result = Panel(position: position, size: size, texture: texture, horizontalAlignment: horizontalAlignment, verticalAlignment: verticalAlignment, aspect_ratio: 1) + result = Panel( + position: position, + size: size, + texture: texture, + horizontalAlignment: horizontalAlignment, + verticalAlignment: verticalAlignment, + aspect_ratio: 1, + onMouseDown: onMouseDown, + onMouseUp: onMouseUp, + onMouseEnter: onMouseEnter, + onMouseMove: onMouseMove, + onMouseLeave: onMouseLeave, + ) result.mesh = newMesh( positions = newSeq[Vec3f](4), @@ -151,3 +182,14 @@ if value != panel.aspect_ratio: panel.aspect_ratio = value panel.dirty = true + +proc contains*(panel: Panel, p: Vec2f): bool = + let cursor = panel.mesh.transform * p.toVec3 + let p1 = panel.mesh[POSITION_ATTRIB, 0, Vec3f] + let p2 = panel.mesh[POSITION_ATTRIB, 2, Vec3f] + let + left = min(p1.x, p2.x) + right = max(p1.x, p2.x) + top = min(p1.y, p2.y) + bottom = max(p1.y, p2.y) + return left <= cursor.x and cursor.x <= right and top <= cursor.y and cursor.y <= bottom diff -r 2aa26c23cc60 -r 10267da04fba tests/test_panel.nim --- a/tests/test_panel.nim Sat Feb 10 15:55:05 2024 +0700 +++ b/tests/test_panel.nim Sat Feb 10 21:19:31 2024 +0700 @@ -2,18 +2,44 @@ import semicongine +var counter = 0 +var counterText: Text + +proc click(panel: var Panel, buttons: set[MouseButton]) = + if buttons.contains(Mouse1): + counter.inc + if buttons.contains(Mouse3): + counter.dec + counterText.text = $counter +proc enter(panel: var Panel) = + panel.size = newVec2f(0.22, 0.22) +proc leave(panel: var Panel) = + panel.size = newVec2f(0.2, 0.2) proc main() = # setup engine var engine = initEngine("Test panels") engine.initRenderer([]) + const B = [0'u8, 0'u8, 0'u8, 255'u8] + const T = [0'u8, 0'u8, 0'u8, 0'u8] # build scene + # var font = loadFont("DejaVuSans.ttf", lineHeightPixels = 210'f32) scene = Scene(name: "main") - origin = initPanel(size = newVec2f(0.01, 0.01), color = newVec4f(0, 0, 0, 1)) - panel = initPanel(size = newVec2f(0.2, 0.2), color = newVec4f(1, 0, 0, 1)) + origin = initPanel( + size = newVec2f(0.02, 0.02), + color = newVec4f(1, 1, 1, 1), + texture = Texture(isGrayscale: false, colorImage: newImage[RGBAPixel](3, 3, [T, B, T, B, B, B, T, B, T]), sampler: NEAREST_SAMPLER), + ) + panel = initPanel( + size = newVec2f(0.2, 0.2), + color = newVec4f(1, 0, 0, 0.5), + onMouseDown = click, + onMouseEnter = enter, + onMouseLeave = leave + ) help_text = font.initText("""Controls Horizontal alignment: @@ -25,6 +51,9 @@ F5: Center F6: Bottom""", scale = 0.0002, position = newVec2f(-0.9, -0.9), horizontalAlignment = Left, verticalAlignment = Top) + counterText = font.initText($counter, maxLen = 99, scale = 0.0004) + + scene.add counterText scene.add panel scene.add help_text scene.add origin @@ -34,17 +63,33 @@ if engine.windowWasResized(): var winSize = engine.getWindow().size panel.aspect_ratio = winSize[0] / winSize[1] + counterText.aspect_ratio = winSize[0] / winSize[1] origin.aspect_ratio = winSize[0] / winSize[1] help_text.aspect_ratio = winSize[0] / winSize[1] - if engine.keyWasPressed(F1): panel.horizontalAlignment = Left - elif engine.keyWasPressed(F2): panel.horizontalAlignment = Center - elif engine.keyWasPressed(F3): panel.horizontalAlignment = Right - elif engine.keyWasPressed(F4): panel.verticalAlignment = Top - elif engine.keyWasPressed(F5): panel.verticalAlignment = Center - elif engine.keyWasPressed(F6): panel.verticalAlignment = Bottom + if engine.keyWasPressed(F1): + panel.horizontalAlignment = Left + counterText.horizontalAlignment = Left + elif engine.keyWasPressed(F2): + panel.horizontalAlignment = Center + counterText.horizontalAlignment = Center + elif engine.keyWasPressed(F3): + panel.horizontalAlignment = Right + counterText.horizontalAlignment = Right + elif engine.keyWasPressed(F4): + panel.verticalAlignment = Top + counterText.verticalAlignment = Top + elif engine.keyWasPressed(F5): + panel.verticalAlignment = Center + counterText.verticalAlignment = Center + elif engine.keyWasPressed(F6): + panel.verticalAlignment = Bottom + counterText.verticalAlignment = Bottom + + engine.processEventsFor(panel) panel.refresh() + counterText.refresh() origin.refresh() help_text.refresh()