Change build scripts
[jvcard.git] / src / com / googlecode / lanterna / gui2 / DefaultWindowManager.java
CommitLineData
a3b510ab
NR
1package com.googlecode.lanterna.gui2;
2
3import com.googlecode.lanterna.TerminalPosition;
4import com.googlecode.lanterna.TerminalSize;
5
6import java.util.List;
7
8/**
9 * The default window manager implementation used by Lanterna. New windows will be generally added in a tiled manner,
10 * starting in the top-left corner and moving down-right as new windows are added. By using the various window hints
11 * that are available you have some control over how the window manager will place and size the windows.
12 *
13 * @author Martin
14 */
15public class DefaultWindowManager implements WindowManager {
16
17 private final WindowDecorationRenderer windowDecorationRenderer;
18 private TerminalSize lastKnownScreenSize;
19
20 /**
21 * Default constructor, will create a window manager that uses {@code DefaultWindowDecorationRenderer} for drawing
22 * window decorations. Any size calculations done before the text GUI has actually been started and displayed on
23 * the terminal will assume the terminal size is 80x24.
24 */
25 public DefaultWindowManager() {
26 this(new DefaultWindowDecorationRenderer());
27 }
28
29 /**
30 * Creates a new {@code DefaultWindowManager} with a specific window decoration renderer. Any size calculations done
31 * before the text GUI has actually been started and displayed on the terminal will assume the terminal size is
32 * 80x24.
33 *
34 * @param windowDecorationRenderer Window decoration renderer to use when drawing windows
35 */
36 public DefaultWindowManager(WindowDecorationRenderer windowDecorationRenderer) {
37 this(windowDecorationRenderer, null);
38 }
39
40 /**
41 * Creates a new {@code DefaultWindowManager} using a {@code DefaultWindowDecorationRenderer} for drawing window
42 * decorations. Any size calculations done before the text GUI has actually been started and displayed on the
43 * terminal will use the size passed in with the {@code initialScreenSize} parameter
44 *
45 * @param initialScreenSize Size to assume the terminal has until the text GUI is started and can be notified of the
46 * correct size
47 */
48 public DefaultWindowManager(TerminalSize initialScreenSize) {
49 this(new DefaultWindowDecorationRenderer(), initialScreenSize);
50 }
51
52 /**
53 * Creates a new {@code DefaultWindowManager} using a specified {@code windowDecorationRenderer} for drawing window
54 * decorations. Any size calculations done before the text GUI has actually been started and displayed on the
55 * terminal will use the size passed in with the {@code initialScreenSize} parameter
56 *
57 * @param windowDecorationRenderer Window decoration renderer to use when drawing windows
58 * @param initialScreenSize Size to assume the terminal has until the text GUI is started and can be notified of the
59 * correct size
60 */
61 public DefaultWindowManager(WindowDecorationRenderer windowDecorationRenderer, TerminalSize initialScreenSize) {
62 this.windowDecorationRenderer = windowDecorationRenderer;
63 if(initialScreenSize != null) {
64 this.lastKnownScreenSize = initialScreenSize;
65 }
66 else {
67 this.lastKnownScreenSize = new TerminalSize(80, 24);
68 }
69 }
70
71 @Override
72 public boolean isInvalid() {
73 return false;
74 }
75
76 @Override
77 public WindowDecorationRenderer getWindowDecorationRenderer(Window window) {
78 if(window.getHints().contains(Window.Hint.NO_DECORATIONS)) {
79 return new EmptyWindowDecorationRenderer();
80 }
81 return windowDecorationRenderer;
82 }
83
84 @Override
85 public void onAdded(WindowBasedTextGUI textGUI, Window window, List<Window> allWindows) {
86 WindowDecorationRenderer decorationRenderer = getWindowDecorationRenderer(window);
87 TerminalSize expectedDecoratedSize = decorationRenderer.getDecoratedSize(window, window.getPreferredSize());
88 window.setDecoratedSize(expectedDecoratedSize);
89
90 if(window.getHints().contains(Window.Hint.FIXED_POSITION)) {
91 //Don't place the window, assume the position is already set
92 }
93 else if(allWindows.isEmpty()) {
94 window.setPosition(TerminalPosition.OFFSET_1x1);
95 }
96 else if(window.getHints().contains(Window.Hint.CENTERED)) {
97 int left = (lastKnownScreenSize.getColumns() - expectedDecoratedSize.getColumns()) / 2;
98 int top = (lastKnownScreenSize.getRows() - expectedDecoratedSize.getRows()) / 2;
99 window.setPosition(new TerminalPosition(left, top));
100 }
101 else {
102 TerminalPosition nextPosition = allWindows.get(allWindows.size() - 1).getPosition().withRelative(2, 1);
103 if(nextPosition.getColumn() + expectedDecoratedSize.getColumns() > lastKnownScreenSize.getColumns() ||
104 nextPosition.getRow() + expectedDecoratedSize.getRows() > lastKnownScreenSize.getRows()) {
105 nextPosition = TerminalPosition.OFFSET_1x1;
106 }
107 window.setPosition(nextPosition);
108 }
109
110 // Finally, run through the usual calculations so the window manager's usual prepare method can have it's say
111 prepareWindow(lastKnownScreenSize, window);
112 }
113
114 @Override
115 public void onRemoved(WindowBasedTextGUI textGUI, Window window, List<Window> allWindows) {
116 //NOP
117 }
118
119 @Override
120 public void prepareWindows(WindowBasedTextGUI textGUI, List<Window> allWindows, TerminalSize screenSize) {
121 this.lastKnownScreenSize = screenSize;
122 for(Window window: allWindows) {
123 prepareWindow(screenSize, window);
124 }
125 }
126
127 /**
128 * Called by {@link DefaultWindowManager} when iterating through all windows to decide their size and position. If
129 * you override {@link DefaultWindowManager} to add your own logic to how windows are placed on the screen, you can
130 * override this method and selectively choose which window to interfere with. Note that the two key properties that
131 * are read by the GUI system after preparing all windows are the position and decorated size. Your custom
132 * implementation should set these two fields directly on the window. You can infer the decorated size from the
133 * content size by using the window decoration renderer that is attached to the window manager.
134 *
135 * @param screenSize Size of the terminal that is available to draw on
136 * @param window Window to prepare decorated size and position for
137 */
138 protected void prepareWindow(TerminalSize screenSize, Window window) {
139 WindowDecorationRenderer decorationRenderer = getWindowDecorationRenderer(window);
140 TerminalSize contentAreaSize;
141 if(window.getHints().contains(Window.Hint.FIXED_SIZE)) {
142 contentAreaSize = window.getSize();
143 }
144 else {
145 contentAreaSize = window.getPreferredSize();
146 }
147 TerminalSize size = decorationRenderer.getDecoratedSize(window, contentAreaSize);
148 TerminalPosition position = window.getPosition();
149
150 if(window.getHints().contains(Window.Hint.FULL_SCREEN)) {
151 position = TerminalPosition.TOP_LEFT_CORNER;
152 size = screenSize;
153 }
154 else if(window.getHints().contains(Window.Hint.EXPANDED)) {
155 position = TerminalPosition.OFFSET_1x1;
156 size = screenSize.withRelative(
157 -Math.min(4, screenSize.getColumns()),
158 -Math.min(3, screenSize.getRows()));
159 if(!size.equals(window.getDecoratedSize())) {
160 window.invalidate();
161 }
162 }
163 else if(window.getHints().contains(Window.Hint.FIT_TERMINAL_WINDOW) ||
164 window.getHints().contains(Window.Hint.CENTERED)) {
165 //If the window is too big for the terminal, move it up towards 0x0 and if that's not enough then shrink
166 //it instead
167 while(position.getRow() > 0 && position.getRow() + size.getRows() > screenSize.getRows()) {
168 position = position.withRelativeRow(-1);
169 }
170 while(position.getColumn() > 0 && position.getColumn() + size.getColumns() > screenSize.getColumns()) {
171 position = position.withRelativeColumn(-1);
172 }
173 if(position.getRow() + size.getRows() > screenSize.getRows()) {
174 size = size.withRows(screenSize.getRows() - position.getRow());
175 }
176 if(position.getColumn() + size.getColumns() > screenSize.getColumns()) {
177 size = size.withColumns(screenSize.getColumns() - position.getColumn());
178 }
179 if(window.getHints().contains(Window.Hint.CENTERED)) {
180 int left = (lastKnownScreenSize.getColumns() - size.getColumns()) / 2;
181 int top = (lastKnownScreenSize.getRows() - size.getRows()) / 2;
182 position = new TerminalPosition(left, top);
183 }
184 }
185
186 window.setPosition(position);
187 window.setDecoratedSize(size);
188 }
189}