|
30 | 30 | drawChecker, drawCheckerBox |
31 | 31 | getElement, getElementAt, getWidgetAt, findParent |
32 | 32 | getTopmostActiveModal |
| 33 | + getVisibleAreaInLocalSpace |
33 | 34 | isElementVisible |
34 | 35 | isInsideElement, isOverGui |
35 | 36 | onKeyPressed, onKeyReleased, onTextInput |
@@ -181,6 +182,7 @@ export State :: struct { |
181 | 182 | getElementAt :: _getElementAt, |
182 | 183 | getScrollOffset :: _getScrollOffset, |
183 | 184 | getTopmostActiveModal :: _getTopmostActiveModal, |
| 185 | + getVisibleAreaInLocalSpace :: _getVisibleAreaInLocalSpace, |
184 | 186 | getWidgetAt :: _getWidgetAt, |
185 | 187 | hideContextMenu :: _hideContextMenu, |
186 | 188 | isElementVisible :: _isElementVisible, |
@@ -219,6 +221,7 @@ local _getElement :: getElement |
219 | 221 | local _getElementAt :: getElementAt |
220 | 222 | local _getScrollOffset :: getScrollOffset |
221 | 223 | local _getTopmostActiveModal :: getTopmostActiveModal |
| 224 | +local _getVisibleAreaInLocalSpace :: getVisibleAreaInLocalSpace |
222 | 225 | local _getWidgetAt :: getWidgetAt |
223 | 226 | local _hideContextMenu :: hideContextMenu |
224 | 227 | local _isElementVisible :: isElementVisible |
@@ -601,26 +604,66 @@ export onKeyPressed :: (state:State, key:LK.KeyConstant, scancode:LK.Scancode, i |
601 | 604 | ? ((i-1+dir) % #buttons.buttons + 1) |
602 | 605 | : (dir < 0 ? #buttons.buttons : 1) |
603 | 606 |
|
604 | | - for buttons.buttons it.selected = (itIndex == i) |
| 607 | + local anyChange = false |
| 608 | + |
| 609 | + for buttons.buttons { |
| 610 | + local isSelected = (itIndex == i) |
| 611 | + |
| 612 | + if it.selected ~= isSelected { |
| 613 | + it.selected = isSelected |
| 614 | + anyChange = true |
| 615 | + } |
| 616 | + } |
605 | 617 | state.scrollIntoView!(buttons, i) |
606 | 618 |
|
| 619 | + if not anyChange return true |
| 620 | + |
607 | 621 | triggerBeginEvent (state, buttons, buttons.buttons[i].name, i) |
608 | 622 | triggerActionEvent(state, buttons, buttons.buttons[i].name, i, .KEYBOARD, alsoEnd=true) |
609 | 623 |
|
610 | 624 | } elseif key == "pageup" or key == "pagedown" { |
611 | | - -- @Incomplete |
| 625 | + if not buttons.buttons return true |
| 626 | + |
| 627 | + local dir = (key == "pagedown") ? 1 : -1 |
| 628 | + local x, y, w, h = state.getVisibleAreaInLocalSpace!(buttons) |
| 629 | + local visibleCount = math.max(math.floor(h/buttons.buttonHeight), 1) |
| 630 | + local step = math.max(visibleCount-1, 1) |
| 631 | + local found, i = indexWith(buttons.buttons, "selected", true) |
| 632 | + |
| 633 | + i = found |
| 634 | + ? math.clamp(i+step*dir, 1, #buttons.buttons) |
| 635 | + : 1 |
| 636 | + |
| 637 | + local anyChange = false |
| 638 | + |
| 639 | + for buttons.buttons { |
| 640 | + local isSelected = (itIndex == i) |
| 641 | + |
| 642 | + if it.selected ~= isSelected { |
| 643 | + it.selected = isSelected |
| 644 | + anyChange = true |
| 645 | + } |
| 646 | + } |
| 647 | + state.scrollIntoView!(buttons, i) |
| 648 | + |
| 649 | + if not anyChange return true |
| 650 | + |
| 651 | + triggerBeginEvent (state, buttons, buttons.buttons[i].name, i) |
| 652 | + triggerActionEvent(state, buttons, buttons.buttons[i].name, i, .KEYBOARD, alsoEnd=true) |
612 | 653 |
|
613 | 654 | } elseif key == "end" or key == "home" { |
| 655 | + if not buttons.buttons return true |
| 656 | + |
614 | 657 | local iTarget = (key == "end") ? #buttons.buttons : 1 |
615 | 658 | local found, i = indexWith(buttons.buttons, "selected", true) |
616 | 659 |
|
617 | | - if found and i == iTarget return true |
| 660 | + if found and i == iTarget return true -- @Incomplete: Don't return if the target button is selected, but there are also others selected. |
618 | 661 |
|
619 | 662 | for buttons.buttons it.selected = (itIndex == iTarget) |
620 | 663 | state.scrollIntoView!(buttons, iTarget) |
621 | 664 |
|
622 | | - triggerBeginEvent (state, buttons, buttons.buttons[i].name, i) |
623 | | - triggerActionEvent(state, buttons, buttons.buttons[i].name, i, .KEYBOARD, alsoEnd=true) |
| 665 | + triggerBeginEvent (state, buttons, buttons.buttons[iTarget].name, iTarget) |
| 666 | + triggerActionEvent(state, buttons, buttons.buttons[iTarget].name, iTarget, .KEYBOARD, alsoEnd=true) |
624 | 667 | } |
625 | 668 | } |
626 | 669 |
|
@@ -3790,6 +3833,34 @@ export scrollIntoView :: (state:State, el:Element, subid:int) { |
3790 | 3833 |
|
3791 | 3834 |
|
3792 | 3835 |
|
| 3836 | +local getVisibleAreaInLocalSpace :: (state:State, el0:Element) -> (x,y,w,h:int) { |
| 3837 | + -- @Incomplete: Check isElementVisible(). |
| 3838 | + local el = el0 |
| 3839 | + local x1 = el.layoutX |
| 3840 | + local y1 = el.layoutY |
| 3841 | + local x2 = x1 + el.layoutWidth |
| 3842 | + local y2 = y1 + el.layoutHeight |
| 3843 | + local offset = 0 |
| 3844 | + |
| 3845 | + while true { |
| 3846 | + el = el.parent |
| 3847 | + if el == NULL break |
| 3848 | + |
| 3849 | + if el.type == Scrollable { |
| 3850 | + local scrollable = cast(Scrollable) el |
| 3851 | + x1 = math.max(x1, scrollable.layoutX) |
| 3852 | + y1 = math.max(y1, scrollable.layoutY) |
| 3853 | + x2 = math.min(x2, scrollable.layoutX+scrollable.layoutWidth) |
| 3854 | + y2 = math.min(y2, scrollable.layoutY+scrollable.layoutHeight) |
| 3855 | + offset += math.round(scrollable.scroll) |
| 3856 | + } |
| 3857 | + } |
| 3858 | + |
| 3859 | + return x1-el0.layoutX, y1-el0.layoutY+offset, x2-x1, y2-y1 |
| 3860 | +} |
| 3861 | + |
| 3862 | + |
| 3863 | + |
3793 | 3864 | export getButtonLayout :: (state:State, buttons:Buttons, i:int) -> (x,y,w,h:int) { |
3794 | 3865 | updateLayoutIfNeeded(state) |
3795 | 3866 |
|
|
0 commit comments