Make Catalog browsers focusable with shortcuts

- Category and scenario list views can now be focused with
  ctrl+a/ctrl+s.
- Bind all keys with ctrl modifier
- Add "shortcut" concept to views which currently hooks to
  hot keys.
- In a catalog app by using a "shortcut" then takes the key
  event as a hot key, as it consumes resulting behaviour
  is to focus.
- Move view initInternal away from constructor call to
  require user to call init() which is not in a
  View interface
- Relates #826
This commit is contained in:
Janne Valkealahti
2023-11-12 16:43:11 +00:00
parent a9b1675595
commit 2d29050c34
10 changed files with 53 additions and 7 deletions

View File

@@ -190,6 +190,7 @@ public class TerminalUI implements ViewService {
* @param view the view to configure
*/
public void configure(View view) {
view.init();
view.setEventLoop(eventLoop);
view.setThemeResolver(themeResolver);
view.setThemeName(themeName);

View File

@@ -60,10 +60,7 @@ public abstract class AbstractView extends AbstractControl implements View {
private Map<Integer, KeyBindingValue> keyBindings = new HashMap<>();
private Map<Integer, KeyBindingValue> hotKeyBindings = new HashMap<>();
private Map<Integer, MouseBindingValue> mouseBindings = new HashMap<>();
public AbstractView() {
init();
}
private boolean init = false;
/**
* Register {@link Disposable} to get disposed when view terminates.
@@ -88,8 +85,20 @@ public abstract class AbstractView extends AbstractControl implements View {
*
* @see #initInternal()
*/
protected final void init() {
@Override
public final void init() {
if (init) {
return;
}
initInternal();
init = true;
}
private Integer shortcutKey;
private Runnable shortcutAction;
public void shortcut(Integer key, Runnable runnable) {
this.shortcutKey = key;
this.shortcutAction = runnable;
}
/**
@@ -97,6 +106,9 @@ public abstract class AbstractView extends AbstractControl implements View {
* usefull. Typically key and mousebindings are registered from this method.
*/
protected void initInternal() {
if (shortcutKey != null && shortcutAction != null) {
registerHotKeyBinding(shortcutKey, shortcutAction);
}
}
@Override

View File

@@ -261,6 +261,28 @@ public class GridView extends BoxView {
return super.getKeyHandler();
}
@Override
public KeyHandler getHotKeyHandler() {
log.trace("getHotKeyHandler()");
KeyHandler handler = null;
for (GridItem i : gridItems) {
if (handler == null) {
handler = i.view.getHotKeyHandler();
}
else {
handler = handler.thenIfNotConsumed(i.view.getHotKeyHandler());
}
// handler = i.view.getHotKeyHandler();
// if (i.view.hasFocus()) {
// handler = i.view.getHotKeyHandler();
// break;
// }
}
if (handler != null) {
return handler.thenIfNotConsumed(super.getHotKeyHandler());
}
return super.getHotKeyHandler();
}
@Override
public boolean hasFocus() {

View File

@@ -100,6 +100,7 @@ public class ListView<T> extends BoxView {
@Override
protected void initInternal() {
super.initInternal();
registerViewCommand(ViewCommand.LINE_UP, () -> up());
registerViewCommand(ViewCommand.LINE_DOWN, () -> down());

View File

@@ -247,9 +247,11 @@ public class MenuBarView extends BoxView {
private MenuView buildMenuView(MenuBarItem item) {
MenuView menuView = new MenuView(item.getItems());
menuView.init();
menuView.setEventLoop(getEventLoop());
menuView.setThemeResolver(getThemeResolver());
menuView.setThemeName(getThemeName());
menuView.setViewService(getViewService());
menuView.setShowBorder(true);
menuView.setLayer(1);
Rectangle rect = getInnerRect();

View File

@@ -30,6 +30,8 @@ import org.springframework.shell.component.view.event.MouseHandler;
*/
public interface View extends Control {
void init();
/**
* Sets a layer index this {@code View} operates on.
*

View File

@@ -47,6 +47,7 @@ public class KeyBinder {
for (char i = KeyEvent.Key.a; i <= KeyEvent.Key.z; i++) {
keyMap.bind(i | KeyEvent.KeyMask.AltMask, alt(i));
keyMap.bind(i | KeyEvent.KeyMask.CtrlMask, ctrl(i));
}
keyMap.bind(KeyEvent.Key.q | KeyEvent.KeyMask.CtrlMask, ctrl('q'));

View File

@@ -66,6 +66,7 @@ public class AbstractViewTests {
}
protected void configure(View view) {
view.init();
if (eventLoop != null) {
if (view instanceof AbstractView v) {
v.setEventLoop(eventLoop);

View File

@@ -38,6 +38,7 @@ class TerminalUiSnippets {
void sample() {
TerminalUI ui = builder.build();
BoxView view = new BoxView();
ui.configure(view);
view.setDrawFunction((screen, rect) -> {
screen.writerBuilder()
.build()
@@ -59,6 +60,7 @@ class TerminalUiSnippets {
void sample() {
TerminalUI ui = new TerminalUI(terminal);
BoxView view = new BoxView();
ui.configure(view);
ui.setRoot(view, true);
EventLoop eventLoop = ui.getEventLoop();
eventLoop.keyEvents()

View File

@@ -207,11 +207,12 @@ public class Catalog {
private ListView<String> buildCategorySelector() {
ListView<String> categories = new ListView<>();
categories.shortcut(Key.a | KeyMask.CtrlMask, () -> {});
ui.configure(categories);
List<String> items = List.copyOf(categoryMap.keySet());
categories.setItems(items);
categories.setTitle("Categories");
categories.setTitle("Categories (CTRL+A)");
categories.setFocusedTitleStyle(ScreenItem.STYLE_BOLD);
categories.setShowBorder(true);
return categories;
@@ -242,8 +243,9 @@ public class Catalog {
private ListView<ScenarioData> buildScenarioSelector() {
ListView<ScenarioData> scenarios = new ListView<>();
scenarios.shortcut(Key.s | KeyMask.CtrlMask, () -> {});
ui.configure(scenarios);
scenarios.setTitle("Scenarios");
scenarios.setTitle("Scenarios (CTRL+S)");
scenarios.setFocusedTitleStyle(ScreenItem.STYLE_BOLD);
scenarios.setShowBorder(true);
scenarios.setCellFactory((list, item) -> new ScenarioListCell(item));