TerminalUI can define rootView rect
- Add functions to calculate Rectangle for fullscreen/nonfullscreen modes. - Fixes for rendering so that nonfullscreen works better with views. - Add some basic samples - isEmpty method for Rectangle - Fixes #872
This commit is contained in:
@@ -18,6 +18,7 @@ package org.springframework.shell.component.view;
|
||||
import java.io.IOError;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import org.jline.keymap.BindingReader;
|
||||
import org.jline.keymap.KeyMap;
|
||||
@@ -148,36 +149,75 @@ public class TerminalUI implements ViewService {
|
||||
}
|
||||
}
|
||||
|
||||
private void render(int rows, int columns) {
|
||||
private void render(Rectangle rect) {
|
||||
if (rootView != null) {
|
||||
rootView.setRect(0, 0, columns, rows);
|
||||
rootView.setRect(rect.x(), rect.y(), rect.width(), rect.height());
|
||||
rootView.draw(virtualDisplay);
|
||||
}
|
||||
if (modalView != null) {
|
||||
modalView.setLayer(1);
|
||||
modalView.setRect(0, 0, columns, rows);
|
||||
modalView.setRect(rect.x(), rect.y(), rect.width(), rect.height());
|
||||
modalView.draw(virtualDisplay);
|
||||
}
|
||||
}
|
||||
|
||||
private BiFunction<Terminal, View, Rectangle> fullScreenViewRect = (terminal, view) -> {
|
||||
Size s = terminal.getSize();
|
||||
return new Rectangle(0, 0, s.getColumns(), s.getRows());
|
||||
};
|
||||
|
||||
private BiFunction<Terminal, View, Rectangle> nonfullScreenViewRect = (terminal, view) -> {
|
||||
Size s = terminal.getSize();
|
||||
Rectangle rect = view.getRect();
|
||||
if (!rect.isEmpty()) {
|
||||
return rect;
|
||||
}
|
||||
return new Rectangle(0, 0, s.getColumns(), 5);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets a view rect function for full screen mode. Default behaviour uses {@link Rectangle}
|
||||
* area equal to terminal size.
|
||||
*
|
||||
* @param fullScreenViewRect the view rect function
|
||||
*/
|
||||
public void setFullScreenViewRect(BiFunction<Terminal, View, Rectangle> fullScreenViewRect) {
|
||||
Assert.notNull(fullScreenViewRect, "view rect function must be set");
|
||||
this.fullScreenViewRect = fullScreenViewRect;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a view rect function for full screen mode. Default behaviour uses {@link Rectangle}
|
||||
* from {@code rootView} if it's not empty, otherwise uses zero based area with
|
||||
* width matching terminal columns and height matching 5.
|
||||
*
|
||||
* @param nonfullScreenViewRect the view rect function
|
||||
*/
|
||||
public void setNonfullScreenViewRect(BiFunction<Terminal, View, Rectangle> nonfullScreenViewRect) {
|
||||
Assert.notNull(nonfullScreenViewRect, "view rect function must be set");
|
||||
this.nonfullScreenViewRect = nonfullScreenViewRect;
|
||||
}
|
||||
|
||||
private void display() {
|
||||
log.trace("display()");
|
||||
log.trace("display() start");
|
||||
size.copy(terminal.getSize());
|
||||
if (fullScreen) {
|
||||
display.clear();
|
||||
display.resize(size.getRows(), size.getColumns());
|
||||
display.reset();
|
||||
rootView.setRect(0, 0, size.getColumns(), size.getRows());
|
||||
display.resize(size.getRows(), size.getColumns());
|
||||
Rectangle rect = fullScreenViewRect.apply(terminal, rootView);
|
||||
rootView.setRect(rect.x(), rect.y(), rect.width(), rect.height());
|
||||
virtualDisplay.resize(size.getRows(), size.getColumns());
|
||||
virtualDisplay.setShowCursor(false);
|
||||
render(size.getRows(), size.getColumns());
|
||||
render(rect);
|
||||
}
|
||||
else {
|
||||
Rectangle rect = nonfullScreenViewRect.apply(terminal, rootView);
|
||||
display.reset();
|
||||
display.resize(size.getRows(), size.getColumns());
|
||||
Rectangle rect = rootView.getRect();
|
||||
virtualDisplay.resize(rect.height(), rect.width());
|
||||
virtualDisplay.setShowCursor(false);
|
||||
render(rect.height(), rect.width());
|
||||
render(rect);
|
||||
}
|
||||
|
||||
List<AttributedString> newLines = virtualDisplay.getScreenLines();
|
||||
@@ -192,6 +232,7 @@ public class TerminalUI implements ViewService {
|
||||
terminal.puts(Capability.cursor_invisible);
|
||||
}
|
||||
display.update(newLines, targetCursorPos);
|
||||
log.trace("display() end");
|
||||
}
|
||||
|
||||
private void dispatchWinch() {
|
||||
|
||||
@@ -36,4 +36,15 @@ public record Rectangle(int x, int y, int width, int height) {
|
||||
h += y;
|
||||
return ((w < x || w > X) && (h < y || h > Y));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the {@code Rectangle} is empty. When the {@code Rectangle}
|
||||
* is empty, it encloses no area.
|
||||
*
|
||||
* @return {@code true} if the {@code Rectangle} is empty; {@code false}
|
||||
* otherwise.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return width <= 0 || height <= 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2023 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.shell.component.view.geom;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class RectangleTests {
|
||||
|
||||
private Rectangle rect;
|
||||
|
||||
@Test
|
||||
void isEmpty() {
|
||||
rect = new Rectangle(0, 0, 0, 0);
|
||||
assertThat(rect.isEmpty()).isTrue();
|
||||
rect = new Rectangle(1, 0, 0, 0);
|
||||
assertThat(rect.isEmpty()).isTrue();
|
||||
rect = new Rectangle(0, 1, 0, 0);
|
||||
assertThat(rect.isEmpty()).isTrue();
|
||||
rect = new Rectangle(1, 1, 0, 0);
|
||||
assertThat(rect.isEmpty()).isTrue();
|
||||
rect = new Rectangle(0, 0, 1, 0);
|
||||
assertThat(rect.isEmpty()).isTrue();
|
||||
rect = new Rectangle(0, 0, 0, 1);
|
||||
assertThat(rect.isEmpty()).isTrue();
|
||||
rect = new Rectangle(1, 1, 1, 1);
|
||||
assertThat(rect.isEmpty()).isFalse();
|
||||
}
|
||||
}
|
||||
@@ -17,12 +17,62 @@ package org.springframework.shell.samples.standard;
|
||||
|
||||
import org.springframework.shell.command.annotation.Command;
|
||||
import org.springframework.shell.component.ViewComponent;
|
||||
import org.springframework.shell.component.view.TerminalUI;
|
||||
import org.springframework.shell.component.view.control.BoxView;
|
||||
import org.springframework.shell.component.view.control.InputView;
|
||||
import org.springframework.shell.component.view.geom.HorizontalAlign;
|
||||
import org.springframework.shell.component.view.geom.VerticalAlign;
|
||||
import org.springframework.shell.standard.AbstractShellComponent;
|
||||
|
||||
@Command
|
||||
public class ComponentUiCommands extends AbstractShellComponent {
|
||||
|
||||
@Command(command = "componentui tui1")
|
||||
public void tui1() {
|
||||
TerminalUI ui = new TerminalUI(getTerminal());
|
||||
BoxView view = new BoxView();
|
||||
view.setShowBorder(true);
|
||||
view.setDrawFunction((screen, rect) -> {
|
||||
screen.writerBuilder()
|
||||
.build()
|
||||
.text("Hello World", rect, HorizontalAlign.CENTER, VerticalAlign.CENTER);
|
||||
return rect;
|
||||
});
|
||||
ui.setRoot(view, true);
|
||||
ui.run();
|
||||
}
|
||||
|
||||
@Command(command = "componentui tui2")
|
||||
public void tui2() {
|
||||
TerminalUI ui = new TerminalUI(getTerminal());
|
||||
BoxView view = new BoxView();
|
||||
view.setRect(0, 0, 40, 5);
|
||||
view.setShowBorder(true);
|
||||
view.setDrawFunction((screen, rect) -> {
|
||||
screen.writerBuilder()
|
||||
.build()
|
||||
.text("Hello World", rect, HorizontalAlign.CENTER, VerticalAlign.CENTER);
|
||||
return rect;
|
||||
});
|
||||
ui.setRoot(view, false);
|
||||
ui.run();
|
||||
}
|
||||
|
||||
@Command(command = "componentui tui3")
|
||||
public void tui3() {
|
||||
TerminalUI ui = new TerminalUI(getTerminal());
|
||||
BoxView view = new BoxView();
|
||||
view.setShowBorder(true);
|
||||
view.setDrawFunction((screen, rect) -> {
|
||||
screen.writerBuilder()
|
||||
.build()
|
||||
.text("Hello World", rect, HorizontalAlign.CENTER, VerticalAlign.CENTER);
|
||||
return rect;
|
||||
});
|
||||
ui.setRoot(view, false);
|
||||
ui.run();
|
||||
}
|
||||
|
||||
@Command(command = "componentui string")
|
||||
public String stringInput() {
|
||||
InputView view = new InputView();
|
||||
|
||||
Reference in New Issue
Block a user