From d8dc8aea32a07a0653933700f1abadc7776b013f Mon Sep 17 00:00:00 2001 From: Kevin Lamonte Date: Sat, 17 Aug 2019 09:32:45 -0500 Subject: [PATCH] #46 StretchLayoutManager working --- src/jexer/TButton.java | 32 ++++++++- src/jexer/TComboBox.java | 29 +++++++-- src/jexer/TField.java | 11 ++++ src/jexer/TLabel.java | 11 ++++ src/jexer/TProgressBar.java | 11 ++++ src/jexer/TRadioButton.java | 21 ++++++ src/jexer/TRadioGroup.java | 25 ++++++- src/jexer/TWidget.java | 74 ++++++++++++++++++--- src/jexer/demos/DemoCheckBoxWindow.java | 3 + src/jexer/demos/DemoMainWindow.java | 3 + src/jexer/demos/DemoMsgBoxWindow.java | 3 + src/jexer/demos/DemoTextFieldWindow.java | 3 + src/jexer/layout/StretchLayoutManager.java | 76 +++++++++++++++++++++- 13 files changed, 282 insertions(+), 20 deletions(-) diff --git a/src/jexer/TButton.java b/src/jexer/TButton.java index 82a63892..3938c737 100644 --- a/src/jexer/TButton.java +++ b/src/jexer/TButton.java @@ -98,13 +98,20 @@ public class TButton extends TWidget { setX(x); setY(y); - setHeight(2); - setWidth(StringUtils.width(mnemonic.getRawLabel()) + 3); + super.setHeight(2); + super.setWidth(StringUtils.width(mnemonic.getRawLabel()) + 3); shadowColor = new CellAttributes(); shadowColor.setTo(getWindow().getBackground()); shadowColor.setForeColor(Color.BLACK); shadowColor.setBold(false); + + // Since we set dimensions after TWidget's constructor, we need to + // update the layout manager. + if (getParent().getLayoutManager() != null) { + getParent().getLayoutManager().remove(this); + getParent().getLayoutManager().add(this); + } } /** @@ -215,6 +222,27 @@ public class TButton extends TWidget { // TWidget ---------------------------------------------------------------- // ------------------------------------------------------------------------ + /** + * Override TWidget's width: we can only set width at construction time. + * + * @param width new widget width (ignored) + */ + @Override + public void setWidth(final int width) { + // Do nothing + } + + /** + * Override TWidget's height: we can only set height at construction + * time. + * + * @param height new widget height (ignored) + */ + @Override + public void setHeight(final int height) { + // Do nothing + } + /** * Draw a button with a shadow. */ diff --git a/src/jexer/TComboBox.java b/src/jexer/TComboBox.java index fe2fdacf..4abdd6fb 100644 --- a/src/jexer/TComboBox.java +++ b/src/jexer/TComboBox.java @@ -114,7 +114,7 @@ public class TComboBox extends TWidget { field.setText(list.getSelected()); list.setEnabled(false); list.setVisible(false); - TComboBox.this.setHeight(1); + TComboBox.super.setHeight(1); if (TComboBox.this.limitToListValue == false) { TComboBox.this.activate(field); } @@ -130,7 +130,7 @@ public class TComboBox extends TWidget { list.setEnabled(false); list.setVisible(false); - setHeight(1); + super.setHeight(1); if (limitToListValue) { field.setEnabled(false); } else { @@ -215,6 +215,27 @@ public class TComboBox extends TWidget { // TWidget ---------------------------------------------------------------- // ------------------------------------------------------------------------ + /** + * Override TWidget's width: we can only set width at construction time. + * + * @param width new widget width (ignored) + */ + @Override + public void setWidth(final int width) { + // Do nothing + } + + /** + * Override TWidget's height: we can only set height at construction + * time. + * + * @param height new widget height (ignored) + */ + @Override + public void setHeight(final int height) { + // Do nothing + } + /** * Draw the combobox down arrow. */ @@ -253,7 +274,7 @@ public class TComboBox extends TWidget { public void hideList() { list.setEnabled(false); list.setVisible(false); - setHeight(1); + super.setHeight(1); if (limitToListValue == false) { activate(field); } @@ -265,7 +286,7 @@ public class TComboBox extends TWidget { public void showList() { list.setEnabled(true); list.setVisible(true); - setHeight(list.getHeight() + 1); + super.setHeight(list.getHeight() + 1); activate(list); } diff --git a/src/jexer/TField.java b/src/jexer/TField.java index 6aaf5912..1a706b16 100644 --- a/src/jexer/TField.java +++ b/src/jexer/TField.java @@ -378,6 +378,17 @@ public class TField extends TWidget { // TWidget ---------------------------------------------------------------- // ------------------------------------------------------------------------ + /** + * Override TWidget's height: we can only set height at construction + * time. + * + * @param height new widget height (ignored) + */ + @Override + public void setHeight(final int height) { + // Do nothing + } + /** * Draw the text field. */ diff --git a/src/jexer/TLabel.java b/src/jexer/TLabel.java index 38c014c2..0c62250e 100644 --- a/src/jexer/TLabel.java +++ b/src/jexer/TLabel.java @@ -170,6 +170,17 @@ public class TLabel extends TWidget { // TWidget ---------------------------------------------------------------- // ------------------------------------------------------------------------ + /** + * Override TWidget's height: we can only set height at construction + * time. + * + * @param height new widget height (ignored) + */ + @Override + public void setHeight(final int height) { + // Do nothing + } + /** * Draw a static label. */ diff --git a/src/jexer/TProgressBar.java b/src/jexer/TProgressBar.java index b144fd27..1e3b55a3 100644 --- a/src/jexer/TProgressBar.java +++ b/src/jexer/TProgressBar.java @@ -86,6 +86,17 @@ public class TProgressBar extends TWidget { // TWidget ---------------------------------------------------------------- // ------------------------------------------------------------------------ + /** + * Override TWidget's height: we can only set height at construction + * time. + * + * @param height new widget height (ignored) + */ + @Override + public void setHeight(final int height) { + // Do nothing + } + /** * Draw a static progress bar. */ diff --git a/src/jexer/TRadioButton.java b/src/jexer/TRadioButton.java index 2d602fa3..60a62884 100644 --- a/src/jexer/TRadioButton.java +++ b/src/jexer/TRadioButton.java @@ -156,6 +156,27 @@ public class TRadioButton extends TWidget { // TWidget ---------------------------------------------------------------- // ------------------------------------------------------------------------ + /** + * Override TWidget's width: we can only set width at construction time. + * + * @param width new widget width (ignored) + */ + @Override + public void setWidth(final int width) { + // Do nothing + } + + /** + * Override TWidget's height: we can only set height at construction + * time. + * + * @param height new widget height (ignored) + */ + @Override + public void setHeight(final int height) { + // Do nothing + } + /** * Draw a radio button with label. */ diff --git a/src/jexer/TRadioGroup.java b/src/jexer/TRadioGroup.java index 7460de41..58c65e2b 100644 --- a/src/jexer/TRadioGroup.java +++ b/src/jexer/TRadioGroup.java @@ -81,6 +81,27 @@ public class TRadioGroup extends TWidget { // TWidget ---------------------------------------------------------------- // ------------------------------------------------------------------------ + /** + * Override TWidget's width: we can only set width at construction time. + * + * @param width new widget width (ignored) + */ + @Override + public void setWidth(final int width) { + // Do nothing + } + + /** + * Override TWidget's height: we can only set height at construction + * time. + * + * @param height new widget height (ignored) + */ + @Override + public void setHeight(final int height) { + // Do nothing + } + /** * Draw a radio button with label. */ @@ -163,9 +184,9 @@ public class TRadioGroup extends TWidget { int buttonX = 1; int buttonY = getChildren().size() + 1; if (StringUtils.width(label) + 4 > getWidth()) { - setWidth(StringUtils.width(label) + 7); + super.setWidth(StringUtils.width(label) + 7); } - setHeight(getChildren().size() + 3); + super.setHeight(getChildren().size() + 3); TRadioButton button = new TRadioButton(this, buttonX, buttonY, label, getChildren().size() + 1); diff --git a/src/jexer/TWidget.java b/src/jexer/TWidget.java index b17b73f6..9dd21c1a 100644 --- a/src/jexer/TWidget.java +++ b/src/jexer/TWidget.java @@ -43,6 +43,7 @@ import jexer.event.TKeypressEvent; import jexer.event.TMenuEvent; import jexer.event.TMouseEvent; import jexer.event.TResizeEvent; +import jexer.layout.LayoutManager; import jexer.menu.TMenu; import jexer.ttree.TTreeItem; import jexer.ttree.TTreeView; @@ -136,6 +137,11 @@ public abstract class TWidget implements Comparable { */ private int cursorY = 0; + /** + * Layout manager. + */ + private LayoutManager layout = null; + // ------------------------------------------------------------------------ // Constructors ----------------------------------------------------------- // ------------------------------------------------------------------------ @@ -212,15 +218,15 @@ public abstract class TWidget implements Comparable { this.parent = parent; children = new ArrayList(); - if (parent != null) { - this.window = parent.window; - parent.addChild(this); - } - this.x = x; this.y = y; this.width = width; this.height = height; + + if (parent != null) { + this.window = parent.window; + parent.addChild(this); + } } /** @@ -570,6 +576,9 @@ public abstract class TWidget implements Comparable { if (resize.getType() == TResizeEvent.Type.WIDGET) { width = resize.getWidth(); height = resize.getHeight(); + if (layout != null) { + layout.onResize(resize); + } } else { // Let children see the screen resize for (TWidget widget: children) { @@ -732,6 +741,9 @@ public abstract class TWidget implements Comparable { } children.remove(child); child.parent = null; + if (layout != null) { + layout.remove(this); + } } /** @@ -854,7 +866,7 @@ public abstract class TWidget implements Comparable { * * @return widget width */ - public final int getWidth() { + public int getWidth() { return this.width; } @@ -863,8 +875,12 @@ public abstract class TWidget implements Comparable { * * @param width new widget width */ - public final void setWidth(final int width) { + public void setWidth(final int width) { this.width = width; + if (layout != null) { + layout.onResize(new TResizeEvent(TResizeEvent.Type.WIDGET, + width, height)); + } } /** @@ -872,7 +888,7 @@ public abstract class TWidget implements Comparable { * * @return widget height */ - public final int getHeight() { + public int getHeight() { return this.height; } @@ -881,8 +897,12 @@ public abstract class TWidget implements Comparable { * * @param height new widget height */ - public final void setHeight(final int height) { + public void setHeight(final int height) { this.height = height; + if (layout != null) { + layout.onResize(new TResizeEvent(TResizeEvent.Type.WIDGET, + width, height)); + } } /** @@ -900,6 +920,39 @@ public abstract class TWidget implements Comparable { setY(y); setWidth(width); setHeight(height); + if (layout != null) { + layout.onResize(new TResizeEvent(TResizeEvent.Type.WIDGET, + width, height)); + } + } + + /** + * Get the layout manager. + * + * @return the layout manager, or null if not set + */ + public LayoutManager getLayoutManager() { + return layout; + } + + /** + * Set the layout manager. + * + * @param layout the new layout manager + */ + public void setLayoutManager(LayoutManager layout) { + if (this.layout != null) { + for (TWidget w: children) { + this.layout.remove(w); + } + this.layout = null; + } + this.layout = layout; + if (this.layout != null) { + for (TWidget w: children) { + this.layout.add(w); + } + } } /** @@ -1262,6 +1315,9 @@ public abstract class TWidget implements Comparable { for (int i = 0; i < children.size(); i++) { children.get(i).tabOrder = i; } + if (layout != null) { + layout.add(child); + } } /** diff --git a/src/jexer/demos/DemoCheckBoxWindow.java b/src/jexer/demos/DemoCheckBoxWindow.java index c982244f..aa29506b 100644 --- a/src/jexer/demos/DemoCheckBoxWindow.java +++ b/src/jexer/demos/DemoCheckBoxWindow.java @@ -39,6 +39,7 @@ import jexer.TComboBox; import jexer.TMessageBox; import jexer.TRadioGroup; import jexer.TWindow; +import jexer.layout.StretchLayoutManager; import static jexer.TCommand.*; import static jexer.TKeypress.*; @@ -87,6 +88,8 @@ public class DemoCheckBoxWindow extends TWindow { // centered on screen. super(parent, i18n.getString("windowTitle"), 0, 0, 60, 17, flags); + setLayoutManager(new StretchLayoutManager(getWidth(), getHeight())); + int row = 1; // Add some widgets diff --git a/src/jexer/demos/DemoMainWindow.java b/src/jexer/demos/DemoMainWindow.java index 54234ba3..1c8b4fbc 100644 --- a/src/jexer/demos/DemoMainWindow.java +++ b/src/jexer/demos/DemoMainWindow.java @@ -44,6 +44,7 @@ import jexer.TTimer; import jexer.TWidget; import jexer.TWindow; import jexer.event.TCommandEvent; +import jexer.layout.StretchLayoutManager; import static jexer.TCommand.*; import static jexer.TKeypress.*; @@ -108,6 +109,8 @@ public class DemoMainWindow extends TWindow { // centered on screen. super(parent, i18n.getString("windowTitle"), 0, 0, 64, 23, flags); + setLayoutManager(new StretchLayoutManager(getWidth(), getHeight())); + int row = 1; // Add some widgets diff --git a/src/jexer/demos/DemoMsgBoxWindow.java b/src/jexer/demos/DemoMsgBoxWindow.java index c2d4ff61..7d106c7b 100644 --- a/src/jexer/demos/DemoMsgBoxWindow.java +++ b/src/jexer/demos/DemoMsgBoxWindow.java @@ -36,6 +36,7 @@ import jexer.TApplication; import jexer.TInputBox; import jexer.TMessageBox; import jexer.TWindow; +import jexer.layout.StretchLayoutManager; import static jexer.TCommand.*; import static jexer.TKeypress.*; @@ -73,6 +74,8 @@ public class DemoMsgBoxWindow extends TWindow { // will be centered on screen. super(parent, i18n.getString("windowTitle"), 0, 0, 64, 18, flags); + setLayoutManager(new StretchLayoutManager(getWidth(), getHeight())); + int row = 1; // Add some widgets diff --git a/src/jexer/demos/DemoTextFieldWindow.java b/src/jexer/demos/DemoTextFieldWindow.java index 7eb68d6a..6e6b3309 100644 --- a/src/jexer/demos/DemoTextFieldWindow.java +++ b/src/jexer/demos/DemoTextFieldWindow.java @@ -42,6 +42,7 @@ import jexer.TField; import jexer.TLabel; import jexer.TMessageBox; import jexer.TWindow; +import jexer.layout.StretchLayoutManager; import static jexer.TCommand.*; import static jexer.TKeypress.*; @@ -100,6 +101,8 @@ public class DemoTextFieldWindow extends TWindow { // will be centered on screen. super(parent, i18n.getString("windowTitle"), 0, 0, 60, 20, flags); + setLayoutManager(new StretchLayoutManager(getWidth(), getHeight())); + int row = 1; addLabel(i18n.getString("textField1"), 1, row); diff --git a/src/jexer/layout/StretchLayoutManager.java b/src/jexer/layout/StretchLayoutManager.java index 548c04a7..3dd74521 100644 --- a/src/jexer/layout/StretchLayoutManager.java +++ b/src/jexer/layout/StretchLayoutManager.java @@ -28,6 +28,9 @@ */ package jexer.layout; +import java.awt.Rectangle; +import java.util.HashMap; + import jexer.TWidget; import jexer.event.TResizeEvent; @@ -41,10 +44,45 @@ public class StretchLayoutManager implements LayoutManager { // Variables -------------------------------------------------------------- // ------------------------------------------------------------------------ + /** + * Current width. + */ + private int width = 0; + + /** + * Current height. + */ + private int height = 0; + + /** + * Original width. + */ + private int originalWidth = 0; + + /** + * Original height. + */ + private int originalHeight = 0; + + /** + * Map of widget to original dimensions. + */ + private HashMap children = new HashMap(); + // ------------------------------------------------------------------------ // Constructors ----------------------------------------------------------- // ------------------------------------------------------------------------ + /** + * Public constructor. + * + * @param width the width of the parent widget + * @param height the height of the parent widget + */ + public StretchLayoutManager(final int width, final int height) { + originalWidth = width; + originalHeight = height; + } // ------------------------------------------------------------------------ // LayoutManager ---------------------------------------------------------- @@ -57,7 +95,11 @@ public class StretchLayoutManager implements LayoutManager { * @param resize resize event */ public void onResize(final TResizeEvent resize) { - // TODO + if (resize.getType() == TResizeEvent.Type.WIDGET) { + width = resize.getWidth(); + height = resize.getHeight(); + layoutChildren(); + } } /** @@ -66,7 +108,9 @@ public class StretchLayoutManager implements LayoutManager { * @param child the widget to manage */ public void add(final TWidget child) { - // TODO + Rectangle rect = new Rectangle(child.getX(), child.getY(), + child.getWidth(), child.getHeight()); + children.put(child, rect); } /** @@ -75,7 +119,33 @@ public class StretchLayoutManager implements LayoutManager { * @param child the widget to remove */ public void remove(final TWidget child) { - // TODO + children.remove(child); + } + + // ------------------------------------------------------------------------ + // StretchLayoutManager --------------------------------------------------- + // ------------------------------------------------------------------------ + + /** + * Resize/reposition child widgets based on difference between current + * dimensions and the original dimensions. + */ + public void layoutChildren() { + double widthRatio = (double) width / originalWidth; + if (!Double.isFinite(widthRatio)) { + widthRatio = 1; + } + double heightRatio = (double) height / originalHeight; + if (!Double.isFinite(heightRatio)) { + heightRatio = 1; + } + for (TWidget child: children.keySet()) { + Rectangle rect = children.get(child); + child.setDimensions((int) (rect.getX() * widthRatio), + (int) (rect.getY() * heightRatio), + (int) (rect.getWidth() * widthRatio), + (int) (rect.getHeight() * heightRatio)); + } } } -- 2.27.0