@@ -41,16 +41,19 @@ open class Layout(
4141
4242 // ToDo: impl alignmentLayout: Layout, instead of being able to align to the owner only
4343 // Position of the component
44+ @UIRenderPr0p3rty
4445 var position: Vec2d
4546 get() = Vec2d (positionX, positionY)
4647 set(value) { positionX = value.x; positionY = value.y }
4748
49+ @UIRenderPr0p3rty
4850 var positionX: Double
4951 get() = ownerX + (relativePosX + dockingOffsetX).let {
5052 if (! properties.clampPosition) return @let it
5153 it.coerceAtMost(ownerWidth - width).coerceAtLeast(0.0 )
5254 }; set(value) { relativePosX = value - ownerX - dockingOffsetX }
5355
56+ @UIRenderPr0p3rty
5457 var positionY: Double
5558 get() = ownerY + (relativePosY + dockingOffsetY).let {
5659 if (! properties.clampPosition) return @let it
@@ -66,12 +69,13 @@ open class Layout(
6669 private var relativePosY = 0.0
6770
6871 // Size of the component
72+ @UIRenderPr0p3rty
6973 var size: Vec2d
7074 get() = Vec2d (width, height)
7175 set(value) { width = value.x; height = value.y }
7276
73- var width = 0.0
74- var height = 0.0
77+ @UIRenderPr0p3rty var width = 0.0
78+ @UIRenderPr0p3rty var height = 0.0
7579
7680 // Horizontal alignment
7781 var horizontalAlignment = HAlign .LEFT ; set(to) {
@@ -118,9 +122,22 @@ open class Layout(
118122 protected open val scissorRect get() = rect
119123
120124 // Inputs
121- protected var mousePosition = Vec2d .ZERO
125+ protected var mousePosition = Vec2d .ZERO ; set(value) {
126+ if (field == value) return
127+ field = value
128+
129+ selectedChild = if (isHovered) children.lastOrNull {
130+ if (it.properties.interactionPassthrough) return @lastOrNull false
131+ val xh = (value.x - it.positionX) in 0.0 .. it.width
132+ val yh = (value.y - it.positionY) in 0.0 .. it.height
133+ xh && yh
134+ } else null
135+ }
122136 open val isHovered get() = owner?.let { it.selectedChild == this } ? : true
123137
138+ var pressedButton: Mouse .Button ? = null
139+ protected val isPressed get() = pressedButton != null
140+
124141 // Actions
125142 private val showActions = mutableListOf<Layout .() - > Unit > ()
126143 private val hideActions = mutableListOf<Layout .() - > Unit > ()
@@ -130,6 +147,7 @@ open class Layout(
130147 private val keyPressActions = mutableListOf<Layout .(key: KeyCode ) - > Unit > ()
131148 private val charTypedActions = mutableListOf<Layout .(char: Char ) - > Unit > ()
132149 private val mouseClickActions = mutableListOf<Layout .(button: Mouse .Button , action: Mouse .Action ) - > Unit > ()
150+ private val mouseActions = mutableListOf<Layout .(button: Mouse .Button ) - > Unit > ()
133151 private val mouseMoveActions = mutableListOf<Layout .(mouse: Vec2d ) - > Unit > ()
134152 private val mouseScrollActions = mutableListOf<Layout .(delta: Double ) - > Unit > ()
135153
@@ -180,6 +198,7 @@ open class Layout(
180198 */
181199 @LayoutBuilder
182200 fun <T : Layout > T.onUpdate (action : T .() -> Unit ) {
201+ action(this )
183202 updateActions + = { action() }
184203 }
185204
@@ -219,19 +238,21 @@ open class Layout(
219238 * @param action The action to be performed.
220239 */
221240 @LayoutBuilder
222- fun <T : Layout > T.onMouseClick (action : T .(button: Mouse .Button , action: Mouse .Action ) -> Unit ) {
223- mouseClickActions + = { button, mouseAction -> action(button, mouseAction) }
241+ fun <T : Layout > T.onMouse (button : Mouse .Button ? = null, action : Mouse .Action ? = null, block : T .(Mouse .Button ) -> Unit ) {
242+ mouseClickActions + = { butt, act ->
243+ if ((butt == button || button == null ) && (act == action || action == null )) block(butt)
244+ }
224245 }
225246
226247 /* *
227- * Sets the action to be performed when mouse button gets clicked.
248+ * Sets the action to be performed when mouse button gets released and this layout was clicked.
228249 *
229250 * @param action The action to be performed.
230251 */
231252 @LayoutBuilder
232- fun <T : Layout > T.onMouseClick (button : Mouse .Button , action : Mouse . Action , block : T .() -> Unit ) {
233- onMouseClick { butt, act ->
234- if (butt == button && act == action) block( )
253+ fun <T : Layout > T.onMouseAction (button : Mouse .Button ? = null, acceptNotHovered : Boolean = false, action : T .(Mouse . Button ) -> Unit ) {
254+ mouseActions + = {
255+ if (it == button || button == null && (isHovered || ! acceptNotHovered)) action(it )
235256 }
236257 }
237258
@@ -255,72 +276,6 @@ open class Layout(
255276 mouseScrollActions + = { delta -> action(delta) }
256277 }
257278
258- /* *
259- * Force overrides drawn x position of the layout
260- */
261- @LayoutBuilder
262- fun overrideX (transform : () -> Double ) {
263- positionX = transform()
264-
265- onUpdate {
266- positionX = transform()
267- }
268- }
269-
270- /* *
271- * Force overrides drawn y position of the layout
272- */
273- @LayoutBuilder
274- fun overrideY (transform : () -> Double ) {
275- positionY = transform()
276-
277- onUpdate {
278- positionY = transform()
279- }
280- }
281-
282- /* *
283- * Force overrides drawn position of the layout
284- */
285- @LayoutBuilder
286- fun overridePosition (x : () -> Double , y : () -> Double ) {
287- overrideX(x)
288- overrideY(y)
289- }
290-
291- /* *
292- * Force overrides drawn width of the layout
293- */
294- @LayoutBuilder
295- fun overrideWidth (transform : () -> Double ) {
296- width = transform()
297-
298- onUpdate {
299- width = transform()
300- }
301- }
302-
303- /* *
304- * Force overrides drawn height of the layout
305- */
306- @LayoutBuilder
307- fun overrideHeight (transform : () -> Double ) {
308- height = transform()
309-
310- onUpdate {
311- height = transform()
312- }
313- }
314-
315- /* *
316- * Force overrides drawn size of the layout
317- */
318- @LayoutBuilder
319- fun overrideSize (width : () -> Double , height : () -> Double ) {
320- overrideWidth(width)
321- overrideHeight(height)
322- }
323-
324279 /* *
325280 * Removes this layout from its parent
326281 */
@@ -343,21 +298,15 @@ open class Layout(
343298 ownerY = owner?.positionY ? : ownerY
344299 ownerWidth = owner?.width ? : screenSize.x
345300 ownerHeight = owner?.height ? : screenSize.y
346-
347- // Select an element that's on foreground
348- selectedChild = if (isHovered) children.lastOrNull {
349- if (it.properties.interactionPassthrough) return @lastOrNull false
350- val xh = (mousePosition.x - it.positionX) in 0.0 .. it.width
351- val yh = (mousePosition.y - it.positionY) in 0.0 .. it.height
352- xh && yh
353- } else null
354301 }
355302 }
356303
357304 fun onEvent (e : GuiEvent ) {
358305 // Update self
359306 when (e) {
360307 is GuiEvent .Show -> {
308+ pressedButton = null
309+ selectedChild = null
361310 mousePosition = Vec2d .ONE * - 1000.0
362311 showActions.forEach { it(this ) }
363312 }
@@ -381,16 +330,29 @@ open class Layout(
381330 }
382331 is GuiEvent .MouseMove -> {
383332 mousePosition = e.mouse
333+
384334 mouseMoveActions.forEach { it(this , e.mouse) }
385335 }
386336 is GuiEvent .MouseScroll -> {
387- if (! isHovered) return
388337 mousePosition = e.mouse
338+
339+ if (! isHovered) return
389340 mouseScrollActions.forEach { it(this , e.delta) }
390341 }
391342 is GuiEvent .MouseClick -> {
392343 mousePosition = e.mouse
344+
393345 val action = if (isHovered) e.action else Mouse .Action .Release
346+
347+ val prevPressed = pressedButton
348+ pressedButton = e.button.takeIf { action == Mouse .Action .Click }
349+
350+ if (pressedButton == null ) prevPressed?.let { button ->
351+ mouseActions.forEach {
352+ it.invoke(this , button)
353+ }
354+ }
355+
394356 mouseClickActions.forEach { it(this , e.button, action) }
395357 }
396358 }
@@ -434,6 +396,34 @@ open class Layout(
434396 ) = Layout (this )
435397 .apply (children::add).apply (block)
436398
399+ /* *
400+ * Creates an empty [Layout] behind given [layout]
401+ *
402+ * @param block Actions to perform within this component.
403+ *
404+ * Check [Layout] description for more info about batching.
405+ */
406+ @UIBuilder
407+ fun Layout.layoutBehind (
408+ layout : Layout ,
409+ block : Layout .() -> Unit = {},
410+ ) = Layout (this )
411+ .insertLayout(this , layout, false ).apply (block)
412+
413+ /* *
414+ * Creates an empty [Layout] over given [layout].
415+ *
416+ * @param block Actions to perform within this component.
417+ *
418+ * Check [Layout] description for more info about batching.
419+ */
420+ @UIBuilder
421+ fun Layout.layoutOver (
422+ layout : Layout ,
423+ block : Layout .() -> Unit = {},
424+ ) = Layout (this )
425+ .insertLayout(this , layout, true ).apply (block)
426+
437427 /* *
438428 * Creates new [AnimationTicker].
439429 *
0 commit comments