Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
46bdfe1
rough cut of ScrollPanel
ginkoblongata Jun 14, 2020
10d7663
added comment, fiddled with test
ginkoblongata Jun 14, 2020
5373335
steps toward ScrollerPanel with interactable ScrollBar
ginkoblongata Jun 16, 2020
beb3e62
set cursor position to null for ScrollBar
ginkoblongata Jun 16, 2020
1e90571
preparing ScrollBar renderer to handle mouse clicks
ginkoblongata Jun 16, 2020
768e100
calculate page-less and page-more rectangles, simplify usage surface …
ginkoblongata Jun 16, 2020
f28496a
mouse click in page-less and page-more action working
ginkoblongata Jun 16, 2020
ec205c4
ScrollBar now can be clicked on arrows and on page more and less gaps
ginkoblongata Jun 18, 2020
7287014
limit selected index to within range for arrow and page ScrollBar clicks
ginkoblongata Jun 18, 2020
98c33bf
ScrollBar mouse drag hooked up, not proportional yet
ginkoblongata Jun 18, 2020
7bd9b7e
ScrollBar mouse drag now uses ratio
ginkoblongata Jun 18, 2020
91b1d2c
draft 2, clearing out ScrollableBox interface
ginkoblongata Jun 21, 2020
7be7d5f
rough cut of ScrollPanel
ginkoblongata Jun 14, 2020
3070260
added comment, fiddled with test
ginkoblongata Jun 14, 2020
18abb8f
steps toward ScrollerPanel with interactable ScrollBar
ginkoblongata Jun 16, 2020
a89b314
preparing ScrollBar renderer to handle mouse clicks
ginkoblongata Jun 16, 2020
1dffed1
calculate page-less and page-more rectangles, simplify usage surface …
ginkoblongata Jun 16, 2020
7f426ed
mouse click in page-less and page-more action working
ginkoblongata Jun 16, 2020
6064513
ScrollBar now can be clicked on arrows and on page more and less gaps
ginkoblongata Jun 18, 2020
1729a20
limit selected index to within range for arrow and page ScrollBar clicks
ginkoblongata Jun 18, 2020
02e1026
ScrollBar mouse drag hooked up, not proportional yet
ginkoblongata Jun 18, 2020
117fedd
ScrollBar mouse drag now uses ratio
ginkoblongata Jun 18, 2020
e57fce9
draft 2, clearing out ScrollableBox interface
ginkoblongata Jun 21, 2020
41b6295
correct layout manager engagement regarding preferredSize
ginkoblongata Jun 21, 2020
5773750
now that drag events stay with mouse_down'd component, added more cli…
ginkoblongata Jun 21, 2020
7715ed2
ScrollableBox interface surfaces selectedIndex functionality to Scrol…
ginkoblongata Jun 21, 2020
63eaffd
page up page down arrow up arrow down working for ScrollPanel with Sc…
ginkoblongata Jun 21, 2020
6e9575e
getting scroll up scroll down working to follow selection with viewport
ginkoblongata Jun 22, 2020
1d0aba9
similar to MouseDrag, now MouseUp only routes to same interactable as…
ginkoblongata Jun 22, 2020
ee26926
getting TextBox to work within a ScrollPanel while still preserving s…
ginkoblongata Jun 22, 2020
7708295
keep scrollPanel offset up to date with moving caret when TextBox is …
ginkoblongata Jun 22, 2020
c0870de
pull caret around into viewport when ScrollPanel is adjusted via Scro…
ginkoblongata Jun 22, 2020
3abfc11
preliminary SplitPanel component
ginkoblongata Jun 22, 2020
84c319c
hooked up mouse listener to SplitPanel
ginkoblongata Jun 22, 2020
787770f
prevent attempts to make negative sized components
ginkoblongata Jun 22, 2020
29642c2
MouseDown on non active window causes it to become active and event i…
ginkoblongata Jun 23, 2020
83af1d6
added theme selection window to TestBase, so can be used across vario…
ginkoblongata Jun 23, 2020
94c9956
Now can drag Windo via title decoration rectangle
ginkoblongata Jun 23, 2020
c3f01f3
mouse CLICK outside of popup MENU (& others) to be treated same/simil…
ginkoblongata Jun 24, 2020
2b66ca0
minor tweaks from review
ginkoblongata Jun 28, 2020
7f04664
remove line diff
ginkoblongata Jul 25, 2020
4786d23
added sdk config
ginkoblongata Nov 30, 2022
2a409ee
remotes
ginkoblongata Nov 30, 2022
3c2a677
LANTERNA-491--2024 rebased over master from March 1, 2024, trying to …
ginkoblongata Mar 2, 2024
3ace986
remove misc cruft files
ginkoblongata Mar 2, 2024
d5593bf
LANTERNA-491--2024 extraneous line changes reduction
ginkoblongata Mar 2, 2024
3521b94
LANTERNA-490--2024 minimizing changes
ginkoblongata Mar 2, 2024
4a84dad
LANTERNA-491--2024 reduce line changes
ginkoblongata Mar 2, 2024
5e5c052
LANTERNA-491--2024 reduce extraneous changes
ginkoblongata Mar 2, 2024
2e01b7f
LANTERNA-491--2024 conforming SplitPanel to interim changes since thi…
ginkoblongata Mar 2, 2024
c83d518
LANTERNA-491--2024 conforming SplitPanel to interim changes since thi…
ginkoblongata Mar 2, 2024
e28b087
LANTERNA-491--2024 conforming SplitPanel to interim changes since thi…
ginkoblongata Mar 2, 2024
b5e7b6c
LANTERNA-491--2024 conforming SplitPanel to interim changes since thi…
ginkoblongata Mar 2, 2024
1b99c8c
LANTERNA-491--2024 conforming SplitPanel to interim changes since thi…
ginkoblongata Mar 2, 2024
e363ba6
LANTERNA-491--2024 conforming SplitPanel to interim changes since thi…
ginkoblongata Mar 2, 2024
7b7fe8a
LANTERNA-491--2024 conforming SplitPanel to interim changes since thi…
ginkoblongata Mar 2, 2024
7ebf4ca
LANTERNA-491--2024 conforming SplitPanel to interim changes since thi…
ginkoblongata Mar 2, 2024
c8796ea
LANTERNA-491--2024 conforming SplitPanel to interim changes since thi…
ginkoblongata Mar 2, 2024
dd92f59
LANTERNA-491--2024 conforming SplitPanel to interim changes since thi…
ginkoblongata Mar 2, 2024
d33c158
LANTERNA-491--2024 conforming SplitPanel to interim changes since thi…
ginkoblongata Mar 2, 2024
f216d11
LANTERNA-491--2024 conforming SplitPanel to interim changes since thi…
ginkoblongata Mar 2, 2024
315c9f2
LANTERNA-491--2024 conforming SplitPanel to interim changes since thi…
ginkoblongata Mar 2, 2024
d1c56cb
LANTERNA-491--2024 conforming SplitPanel to interim changes since thi…
ginkoblongata Mar 2, 2024
ba1ed8b
LANTERNA-491--2024 conforming SplitPanel to interim changes since thi…
ginkoblongata Mar 2, 2024
e5bed46
LANTERNA-491--2024 conforming SplitPanel to interim changes since thi…
ginkoblongata Mar 2, 2024
1391419
LANTERNA-491--2024 conforming SplitPanel to interim changes since thi…
ginkoblongata Mar 2, 2024
6044f74
LANTERNA-491--2024 conforming SplitPanel to interim changes since thi…
ginkoblongata Mar 3, 2024
b4464db
LANTERNA-491--2024 conforming SplitPanel to interim changes since thi…
ginkoblongata Mar 3, 2024
9c56e31
LANTERNA-491--2024 conforming SplitPanel to interim changes since thi…
ginkoblongata Mar 3, 2024
14564ab
LANTERNA-491--2024 conforming SplitPanel to interim changes since thi…
ginkoblongata Mar 3, 2024
94ed77b
LANTERNA-491--2024 conforming SplitPanel to interim changes since thi…
ginkoblongata Mar 3, 2024
da26aca
moteToTop method added
ginkoblongata Mar 5, 2024
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
140 changes: 119 additions & 21 deletions src/main/java/com/googlecode/lanterna/gui2/AbstractListBox.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,12 @@
* @param <V> Type of items this list box contains
* @author Martin
*/
public abstract class AbstractListBox<V, T extends AbstractListBox<V, T>> extends AbstractInteractableComponent<T> {
public abstract class AbstractListBox<V, T extends AbstractListBox<V, T>> extends AbstractInteractableComponent<T> implements ScrollableBox<T> {
private final List<V> items;
private int selectedIndex;
private ListItemRenderer<V,T> listItemRenderer;

protected ScrollPanel scrollPanel = null;
protected TerminalPosition scrollOffset = new TerminalPosition(0, 0);

/**
Expand All @@ -65,6 +67,90 @@ protected AbstractListBox(TerminalSize size) {
setListItemRenderer(createDefaultListItemRenderer());
}

@Override
public void setIsWithinScrollPanel(ScrollPanel scrollPanel) {
this.scrollPanel = scrollPanel;
}
boolean isWithinScrollPanel() {
return scrollPanel != null;
}
void ifScrollPanelRedoOffset() {
if (isWithinScrollPanel()) {
scrollPanel.redoOffset();
}
}

@Override
public boolean isVerticalScrollCapable() {
return true;
}

private void doPageKeyboard(boolean isLess) {
if (scrollPanel != null) {
scrollPanel.doPageKeyboard(true, isLess);
} else {
doOffsetAmount(isLess, getSize().getRows());
}
}
private void doOffsetAmount(boolean isLess, int desiredMagnitude) {
int priorOffset = scrollOffset.getRow();
if (isLess && getSize() != null) {
adjustScrollOffset(desiredMagnitude);
} else if (!isLess && getSize() != null) {
adjustScrollOffset(-desiredMagnitude);
}
if (priorOffset == scrollOffset.getRow()) {
// scrolling stopped, start moving selection more
setSelectedIndex(selectedIndex + desiredMagnitude * (isLess ? -1 : 1));
}
pullSelectionIntoView();
}
@Override
public void pullSelectionIntoView() {
int offset = getScrollOffset();
int viewedRows = scrollPanel != null ? scrollPanel.getViewportSize().getRows() : getSize().getRows();

int minViewableSelection = Math.max(0, -offset);
int maxViewableSelection = minViewableSelection + viewedRows;
if (selectedIndex < minViewableSelection) {
setSelectedIndex(minViewableSelection);
} else if(selectedIndex >= maxViewableSelection) {
setSelectedIndex(maxViewableSelection -1);
}
}
public void pullViewportToOverlapSelection() {
if (scrollPanel != null) {
int vOffset = scrollPanel.getScrollOffset().getRow();
TerminalSize vp = scrollPanel.getViewportSize();
if (selectedIndex < -vOffset) {
int distance = -vOffset - selectedIndex;
scrollPanel.doOffsetAmount(new TerminalPosition(0, distance));
} else if (-vOffset + vp.getRows() -1 < selectedIndex) {
int distance = selectedIndex - (-vOffset + vp.getRows() -1);
scrollPanel.doOffsetAmount(new TerminalPosition(0, -distance));
}
} else {
// TODO: not in ScrollPanel
}
}
int getScrollOffset() {
if (scrollPanel != null) {
return scrollPanel.getScrollOffset().getRow();
} else {
return scrollOffset.getRow();
}
}

private void adjustScrollOffset(int verticalAmount) {
// scrollerOffset is negative
int min = Math.min(0, getSize().getRows() - getItemCount());
int max = 0;

int goal = scrollOffset.getRow() + verticalAmount;
int offset = Math.max(min, Math.min(goal, max));
scrollOffset = scrollOffset.withRow(offset);
}

@Override
protected InteractableRenderer<T> createDefaultRenderer() {
return new DefaultListBoxRenderer<>();
Expand Down Expand Up @@ -121,34 +207,36 @@ public synchronized Result handleKeyStroke(KeyStroke keyStroke) {
if(items.isEmpty() || selectedIndex == items.size() - 1) {
return Result.MOVE_FOCUS_DOWN;
}
selectedIndex++;
setSelectedIndex(getSelectedIndex() +1);
pullViewportToOverlapSelection();
return Result.HANDLED;

case ARROW_UP:
if(items.isEmpty() || selectedIndex == 0) {
return Result.MOVE_FOCUS_UP;
}
selectedIndex--;
setSelectedIndex(getSelectedIndex() -1);
pullViewportToOverlapSelection();
return Result.HANDLED;

case HOME:
selectedIndex = 0;
setSelectedIndex(0);
pullViewportToOverlapSelection();
return Result.HANDLED;

case END:
selectedIndex = items.size() - 1;
setSelectedIndex(items.size() - 1);
pullViewportToOverlapSelection();
return Result.HANDLED;

case PAGE_UP:
if(getSize() != null) {
setSelectedIndex(getSelectedIndex() - getSize().getRows());
}
doPageKeyboard(true);
pullViewportToOverlapSelection();
return Result.HANDLED;

case PAGE_DOWN:
if(getSize() != null) {
setSelectedIndex(getSelectedIndex() + getSize().getRows());
}
doPageKeyboard(false);
pullViewportToOverlapSelection();
return Result.HANDLED;

case CHARACTER:
Expand All @@ -161,7 +249,7 @@ public synchronized Result handleKeyStroke(KeyStroke keyStroke) {
MouseActionType actionType = mouseAction.getActionType();
if (isMouseMove(keyStroke)) {
takeFocus();
selectedIndex = getIndexByMouseAction(mouseAction);
setSelectedIndex(getIndexByMouseAction(mouseAction));
return Result.HANDLED;
}

Expand All @@ -171,14 +259,16 @@ public synchronized Result handleKeyStroke(KeyStroke keyStroke) {
} else if (actionType == MouseActionType.SCROLL_UP) {
// relying on setSelectedIndex(index) to clip the index to valid values within range
setSelectedIndex(getSelectedIndex() -1);
pullViewportToOverlapSelection();
return Result.HANDLED;
} else if (actionType == MouseActionType.SCROLL_DOWN) {
// relying on setSelectedIndex(index) to clip the index to valid values within range
setSelectedIndex(getSelectedIndex() +1);
pullViewportToOverlapSelection();
return Result.HANDLED;
}

selectedIndex = getIndexByMouseAction(mouseAction);
setSelectedIndex(getIndexByMouseAction(mouseAction));
return super.handleKeyStroke(keyStroke);
default:
}
Expand All @@ -198,7 +288,7 @@ public synchronized Result handleKeyStroke(KeyStroke keyStroke) {
protected int getIndexByMouseAction(MouseAction click) {
int index = click.getPosition().getRow() - getGlobalPosition().getRow() - scrollOffset.getRow();

return Math.min(index, items.size() -1);
return Math.max(-1, Math.min(index, items.size() -1));
}

private boolean selectByCharacter(Character character) {
Expand Down Expand Up @@ -249,6 +339,7 @@ public synchronized T addItem(V item) {
if(selectedIndex == -1) {
selectedIndex = 0;
}
ifScrollPanelRedoOffset();
invalidate();
return self();
}
Expand All @@ -268,6 +359,7 @@ public synchronized V removeItem(int index) {
while(selectedIndex >= items.size()) {
selectedIndex--;
}
ifScrollPanelRedoOffset();
invalidate();
return existing;
}
Expand All @@ -279,6 +371,7 @@ public synchronized V removeItem(int index) {
public synchronized T clearItems() {
items.clear();
selectedIndex = -1;
ifScrollPanelRedoOffset();
invalidate();
return self();
}
Expand Down Expand Up @@ -345,6 +438,7 @@ public synchronized List<V> getItems() {
* @param index Index of the item that should be currently selected
* @return Itself
*/
@Override
public synchronized T setSelectedIndex(int index) {
selectedIndex = Math.max(0, Math.min(index, items.size() -1));

Expand All @@ -358,6 +452,7 @@ public synchronized T setSelectedIndex(int index) {
* implementations such as {@code CheckBoxList} where individual items have a certain checked/unchecked state.
* @return The index of the currently selected row in the list box, or -1 if there are no items
*/
@Override
public int getSelectedIndex() {
return selectedIndex;
}
Expand All @@ -369,11 +464,12 @@ public int getSelectedIndex() {
* @return The currently selected item in the list box, or {@code null} if there are no items
*/
public synchronized V getSelectedItem() {
if (selectedIndex == -1) {
return null;
} else {
return items.get(selectedIndex);
List<V> theItems = items;
int index = getSelectedIndex();
if (0 <= index && index < theItems.size()) {
return theItems.get(index);
}
return null;
}

/**
Expand Down Expand Up @@ -417,11 +513,13 @@ public TerminalSize getPreferredSize(T listBox) {
maxWidth = stringLengthInColumns;
}
}
return new TerminalSize(maxWidth + 1, listBox.getItemCount());
int additionalWidth = listBox.isWithinScrollPanel() ? 0 : 1;
return new TerminalSize(maxWidth + additionalWidth, listBox.getItemCount());
}

@Override
public void drawComponent(TextGUIGraphics graphics, T listBox) {
scrollTopIndex = - listBox.scrollOffset.getRow();
//update the page size, used for page up and page down keys
ThemeDefinition themeDefinition = listBox.getTheme().getDefinition(AbstractListBox.class);
int componentHeight = graphics.getSize().getRows();
Expand Down Expand Up @@ -465,7 +563,7 @@ else if(selectedIndex >= componentHeight + scrollTopIndex)
}

graphics.applyThemeStyle(themeDefinition.getNormal());
if(items.size() > componentHeight) {
if(!listBox.isWithinScrollPanel() && items.size() > componentHeight) {
verticalScrollBar.onAdded(listBox.getParent());
verticalScrollBar.setViewSize(componentHeight);
verticalScrollBar.setScrollMaximum(items.size());
Expand Down Expand Up @@ -523,7 +621,7 @@ public String getLabel(T listBox, int index, V item) {
*/
public void drawItem(TextGUIGraphics graphics, T listBox, int index, V item, boolean selected, boolean focused) {
ThemeDefinition themeDefinition = listBox.getTheme().getDefinition(AbstractListBox.class);
if(selected && focused) {
if (selected) {
graphics.applyThemeStyle(themeDefinition.getSelected());
}
else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,7 @@ protected void ifMouseDownPossiblyStartTitleDrag(KeyStroke keyStroke) {
titleBarDragWindow = window;
originWindowPosition = titleBarDragWindow.getPosition();
dragStart = mouse.getPosition();
moveToTop(window);
});
}

Expand Down
Loading