Overhaul StatusBar for better text use

- Can change item text
- Can position items by priority(true left, false right)
  and primary(sort for draw attempt)
- Fixes #1112
This commit is contained in:
Janne Valkealahti
2024-08-09 07:40:34 +01:00
parent 02011c898c
commit 9021238ede
2 changed files with 276 additions and 6 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2023 the original author or authors.
* Copyright 2023-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,12 +17,14 @@ package org.springframework.shell.component.view.control;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.ListIterator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.lang.Nullable;
import org.springframework.shell.component.message.ShellMessageBuilder;
import org.springframework.shell.component.view.event.MouseEvent;
import org.springframework.shell.component.view.event.MouseHandler;
@@ -30,17 +32,24 @@ import org.springframework.shell.component.view.screen.Screen;
import org.springframework.shell.component.view.screen.Screen.Writer;
import org.springframework.shell.geom.Rectangle;
import org.springframework.shell.style.StyleSettings;
import org.springframework.util.StringUtils;
/**
* {@link StatusBarView} shows {@link StatusItem items} horizontally and is
* typically used in layouts which builds complete terminal UI's.
*
* {@link StatusItem item} {@code primary} denotes if item is drawn to left
* or right, {@code priority} on which order items are drawn until bar runs
* out of space. Default {@code primary} is {@code true} and {@code priority}
* is {@code 0}.
*
* @author Janne Valkealahti
*/
public class StatusBarView extends BoxView {
private final Logger log = LoggerFactory.getLogger(StatusBarView.class);
private final List<StatusItem> items = new ArrayList<>();
private String itemSeparator = " | ";
public StatusBarView() {
this(new StatusItem[0]);
@@ -59,18 +68,64 @@ public class StatusBarView extends BoxView {
return StyleSettings.TAG_STATUSBAR_BACKGROUND;
}
/**
* Gets the item separator.
*
* @return a separator
*/
@Nullable
public String getItemSeparator() {
return itemSeparator;
}
/**
* Sets the item separator. Separator can be {@code null} or empty which
* essentially disables it.
*
* @param itemSeparator the item separator
*/
public void setItemSeparator(@Nullable String itemSeparator) {
this.itemSeparator = itemSeparator;
}
@Override
protected void drawInternal(Screen screen) {
Rectangle rect = getInnerRect();
log.debug("Drawing status bar to {}", rect);
Writer writer = screen.writerBuilder().build();
int x = rect.x();
int primaryX = rect.x();
int nonprimaryX = rect.x() + rect.width();
boolean primaryWritten = false;
boolean nonprimaryWritten = false;
ListIterator<StatusItem> iter = items.listIterator();
while (iter.hasNext()) {
StatusItem item = iter.next();
String text = String.format(" %s%s", item.getTitle(), iter.hasNext() ? " |" : "");
writer.text(text, x, rect.y());
x += text.length();
String text = item.getTitle();
if (text == null) {
continue;
}
String sep = getItemSeparator();
if (nonprimaryX - primaryX < (text.length() + (sep != null ? sep.length() : 0))) {
break;
}
if (item.primary) {
if (primaryWritten && StringUtils.hasText(sep)) {
text = sep + text;
}
writer.text(text, primaryX, rect.y());
primaryX += text.length();
primaryWritten = true;
}
else {
if (nonprimaryWritten && StringUtils.hasText(sep)) {
text = text + sep;
}
writer.text(text, nonprimaryX - text.length(), rect.y());
nonprimaryX -= text.length();
nonprimaryWritten = true;
}
}
super.drawInternal(screen);
}
@@ -121,6 +176,19 @@ public class StatusBarView extends BoxView {
public void setItems(List<StatusItem> items) {
this.items.clear();
this.items.addAll(items);
Collections.sort(this.items, (o1, o2) -> {
int ret = o1.priority - o2.priority;
if (ret == 0) {
if (o1.primary && !o2.primary) {
ret = -1;
}
else if (!o1.primary && o2.primary) {
ret = 1;
}
}
return ret;
});
// this.items.sort(null);
registerHotKeys();
}
@@ -152,6 +220,8 @@ public class StatusBarView extends BoxView {
private String title;
private Runnable action;
private Integer hotKey;
private boolean primary = true;
private int priority = 0;
public StatusItem(String title) {
this(title, null);
@@ -167,6 +237,14 @@ public class StatusBarView extends BoxView {
this.hotKey = hotKey;
}
public StatusItem(String title, Runnable action, Integer hotKey, boolean primary, int priority) {
this.title = title;
this.action = action;
this.hotKey = hotKey;
this.primary = primary;
this.priority = priority;
}
public static StatusItem of(String title) {
return new StatusItem(title);
}
@@ -179,10 +257,18 @@ public class StatusBarView extends BoxView {
return new StatusItem(title, action, hotKey);
}
public static StatusItem of(String title, Runnable action, Integer hotKey, boolean primary, int priority) {
return new StatusItem(title, action, hotKey, primary, priority);
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Runnable getAction() {
return action;
}
@@ -201,6 +287,22 @@ public class StatusBarView extends BoxView {
return this;
}
public int getPriority() {
return priority;
}
public void setPriority(int priority) {
this.priority = priority;
}
public boolean isPrimary() {
return primary;
}
public void setPrimary(boolean primary) {
this.primary = primary;
}
}
/**