Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions packages/core/src/Renderable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,7 @@ export abstract class Renderable extends BaseRenderable {
if (this._zIndex !== value) {
this._zIndex = value
this.parent?.requestZIndexSort()
this.requestRender()
}
}

Expand Down Expand Up @@ -983,13 +984,15 @@ export abstract class Renderable extends BaseRenderable {

const oldX = this._x
const oldY = this._y
const oldWidth = this._widthValue
const oldHeight = this._heightValue

this._x = layout.left
this._y = layout.top

const newWidth = Math.max(layout.width, 1)
const newHeight = Math.max(layout.height, 1)
const sizeChanged = this.width !== newWidth || this.height !== newHeight
const sizeChanged = oldWidth !== newWidth || oldHeight !== newHeight

this._widthValue = newWidth
this._heightValue = newHeight
Expand All @@ -998,7 +1001,8 @@ export abstract class Renderable extends BaseRenderable {
this.onLayoutResize(newWidth, newHeight)
}

if (oldX !== this._x || oldY !== this._y) {
const positionChanged = oldX !== this._x || oldY !== this._y
if (positionChanged) {
if (this.parent) this.parent.childrenPrimarySortDirty = true
}
}
Expand Down
14 changes: 14 additions & 0 deletions packages/core/src/examples/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ import * as keypressDebugDemo from "./keypress-debug-demo"
import * as linkDemo from "./link-demo"
import * as extmarksDemo from "./extmarks-demo"
import * as opacityExample from "./opacity-example"
import * as scrollboxOverlayHitTest from "./scrollbox-overlay-hit-test"
import * as scrollboxMouseTest from "./scrollbox-mouse-test"
import { setupCommonDemoKeys } from "./lib/standalone-keys"

interface Example {
Expand Down Expand Up @@ -245,6 +247,18 @@ const examples: Example[] = [
run: stickyScrollExample.run,
destroy: stickyScrollExample.destroy,
},
{
name: "Scrollbox Mouse Test",
description: "Test scrollbox mouse hit detection with hover and click events",
run: scrollboxMouseTest.run,
destroy: scrollboxMouseTest.destroy,
},
{
name: "Scrollbox Overlay Hit Test",
description: "Test scrollbox hit detection with overlays and dialogs",
run: scrollboxOverlayHitTest.run,
destroy: scrollboxOverlayHitTest.destroy,
},
{
name: "Shader Cube",
description: "3D cube with custom shaders",
Expand Down
53 changes: 53 additions & 0 deletions packages/core/src/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,7 @@ export class CliRenderer extends EventEmitter implements RenderContext {
private _capabilities: any | null = null
private _latestPointer: { x: number; y: number } = { x: 0, y: 0 }
private _hasPointer: boolean = false
private _lastPointerModifiers: RawMouseEvent["modifiers"] = { shift: false, alt: false, ctrl: false }

private _currentFocusedRenderable: Renderable | null = null
private lifecyclePasses: Set<Renderable> = new Set()
Expand Down Expand Up @@ -1088,6 +1089,7 @@ export class CliRenderer extends EventEmitter implements RenderContext {
this._latestPointer.x = mouseEvent.x
this._latestPointer.y = mouseEvent.y
this._hasPointer = true
this._lastPointerModifiers = mouseEvent.modifiers

if (this._console.visible) {
const consoleBounds = this._console.bounds
Expand Down Expand Up @@ -1233,6 +1235,52 @@ export class CliRenderer extends EventEmitter implements RenderContext {
return false
}

/**
* Recheck hover state after hit grid changes.
* Called after render when native code detects the hit grid changed.
* Fires out/over events if the element under the cursor changed.
*/
private recheckHoverState(): void {
if (this._isDestroyed || !this._hasPointer) return
if (this.capturedRenderable) return

const hitId = this.hitTest(this._latestPointer.x, this._latestPointer.y)
const hitRenderable = Renderable.renderablesByNumber.get(hitId)
const lastOver = this.lastOverRenderable

// No change
if (lastOver?.num === hitId) {
this.lastOverRenderableNum = hitId
return
}

const baseEvent: RawMouseEvent = {
type: "move",
button: 0,
x: this._latestPointer.x,
y: this._latestPointer.y,
modifiers: this._lastPointerModifiers,
}

// Fire out on old element
if (lastOver) {
const event = new MouseEvent(lastOver, { ...baseEvent, type: "out" })
lastOver.processMouseEvent(event)
}

this.lastOverRenderable = hitRenderable
this.lastOverRenderableNum = hitId

// Fire over on new element
if (hitRenderable) {
const event = new MouseEvent(hitRenderable, {
...baseEvent,
type: "over",
})
hitRenderable.processMouseEvent(event)
}
}

public hitTest(x: number, y: number): number {
return this.lib.checkHit(this.rendererPtr, x, y)
}
Expand Down Expand Up @@ -1753,6 +1801,11 @@ export class CliRenderer extends EventEmitter implements RenderContext {
if (!this._isDestroyed) {
this.renderNative()

// Check if hit grid changed and recheck hover state if needed
if (this._useMouse && this.lib.getHitGridDirty(this.rendererPtr)) {
this.recheckHoverState()
}

const overallFrameTime = performance.now() - overallStart

// TODO: Add animationRequestTime to stats
Expand Down
Loading
Loading