summaryrefslogtreecommitdiff
path: root/NET/worlds/console/TreePanel.java
diff options
context:
space:
mode:
authorFuwn <[email protected]>2026-02-12 22:33:32 -0800
committerFuwn <[email protected]>2026-02-12 22:33:32 -0800
commitc7a9d4a6bd53ed7d61731770f2f10e8b9fd435f9 (patch)
treedf9f48bf128a6c0186a8e91857d6ff30fe0e9f18 /NET/worlds/console/TreePanel.java
downloadworldsplayer-c7a9d4a6bd53ed7d61731770f2f10e8b9fd435f9.tar.xz
worldsplayer-c7a9d4a6bd53ed7d61731770f2f10e8b9fd435f9.zip
Initial commit
Diffstat (limited to 'NET/worlds/console/TreePanel.java')
-rw-r--r--NET/worlds/console/TreePanel.java315
1 files changed, 315 insertions, 0 deletions
diff --git a/NET/worlds/console/TreePanel.java b/NET/worlds/console/TreePanel.java
new file mode 100644
index 0000000..3737f20
--- /dev/null
+++ b/NET/worlds/console/TreePanel.java
@@ -0,0 +1,315 @@
+package NET.worlds.console;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Event;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Point;
+import java.awt.Scrollbar;
+import java.util.Vector;
+
+public class TreePanel extends ExposedPanel implements DialogDisabled {
+ private static final long serialVersionUID = -5534860983354876334L;
+ private Vector<TreeNode> items = new Vector<TreeNode>();
+ private boolean delayRepaints;
+ private boolean needRepaint;
+ private boolean needRecalc;
+ private boolean needMakeVisible;
+ private Scrollbar scrollbar = new WiderScrollbar();
+ private int scrollPos = 0;
+ private int linesVisible;
+ private int selectedIndex = -1;
+ private boolean hasFocus = true;
+ private Font nFont = new Font(Console.message("TreeFont"), 0, 13);
+ private FontMetrics nFontMetrics = this.getFontMetrics(this.nFont);
+ private Font bFont = new Font(Console.message("TreeFont"), 1, 11);
+ private FontMetrics bFontMetrics = this.getFontMetrics(this.bFont);
+ private int fontHeight = Math.max(this.nFontMetrics.getHeight(), this.bFontMetrics.getHeight());
+ private int itemHeight = this.fontHeight;
+ private boolean isDialogDisabled;
+ private static final int[] cxs = new int[]{0, 0, 6};
+ private static final int[] cys = new int[]{6, -6, 0};
+ private MoveablePolygon closedIcon = new MoveablePolygon(cxs, cys);
+ private static final int[] oxs = new int[]{-5, 6, 0};
+ private static final int[] oys = new int[]{0, 0, 6};
+ private MoveablePolygon openedIcon = new MoveablePolygon(oxs, oys);
+ private static final Color normBGColor = new Color(80, 80, 80);
+ private static final Color normFGColor = new Color(190, 190, 190);
+ private static final Color selFGColor = new Color(255, 255, 175);
+ private static final int indentPixels = 14;
+
+ public TreePanel() {
+ this.setBackground(normBGColor);
+ this.setLayout(new BorderLayout());
+ this.add("East", this.scrollbar);
+ this.scrollbar.hide();
+ }
+
+ public synchronized void delayRepaints(boolean state) {
+ if (!(this.delayRepaints = state)) {
+ if (this.needRecalc) {
+ this.recalc();
+ }
+
+ if (this.needMakeVisible) {
+ this.makeVisible(this.selectedIndex);
+ }
+
+ if (this.needRepaint) {
+ this.repaint();
+ }
+ }
+ }
+
+ private synchronized void needRepaint(boolean needRecalc, boolean needMakeVisible) {
+ this.needRepaint = true;
+ this.needRecalc |= needRecalc;
+ this.needMakeVisible |= needMakeVisible;
+ this.delayRepaints(this.delayRepaints);
+ }
+
+ public synchronized int getSelectedIndex() {
+ return this.selectedIndex;
+ }
+
+ public synchronized void select(int item) {
+ this.selectedIndex = item;
+ this.needRepaint(false, true);
+ }
+
+ public void setFocus(boolean hasFocus) {
+ if (this.hasFocus != hasFocus) {
+ this.hasFocus = hasFocus;
+ this.needRepaint(false, false);
+ }
+ }
+
+ @Override
+ public boolean hasFocus() {
+ return this.hasFocus;
+ }
+
+ @Override
+ public synchronized void reshape(int x, int y, int w, int h) {
+ super.reshape(x, y, w, h);
+ this.needRepaint(true, false);
+ }
+
+ public synchronized TreeNode getSelectedNode() {
+ return this.selectedIndex != -1 ? this.items.elementAt(this.selectedIndex) : null;
+ }
+
+ public synchronized void reset(Vector<TreeNode> items) {
+ this.items = items;
+ this.needRepaint(true, false);
+ }
+
+ public synchronized void removeAllElements() {
+ this.items.removeAllElements();
+ this.needRepaint(true, false);
+ }
+
+ public synchronized void insertElementAt(TreeNode ele, int index) {
+ this.items.insertElementAt(ele, index);
+ this.needRepaint(true, false);
+ }
+
+ public synchronized void removeElementAt(int index) {
+ this.items.removeElementAt(index);
+ this.needRepaint(true, false);
+ }
+
+ public synchronized void addElement(TreeNode ele) {
+ this.items.addElement(ele);
+ this.needRepaint(true, false);
+ }
+
+ public int countElements() {
+ return this.items.size();
+ }
+
+ public TreeNode elementAt(int index) {
+ return this.items.elementAt(index);
+ }
+
+ public TreeNode elementAt(Point p) {
+ int item = this.scrollPos + p.y / this.itemHeight;
+ return item < this.items.size() ? this.items.elementAt(item) : null;
+ }
+
+ private void makeVisible(int item) {
+ int count = this.items.size();
+ if (count > this.linesVisible && (item < this.scrollPos || item >= this.scrollPos + this.linesVisible)) {
+ this.setScrollValue(Math.min(item * this.itemHeight, this.scrollbar.getMaximum()));
+ }
+
+ this.needMakeVisible = false;
+ }
+
+ private void add(GridBagLayout gbag, Component comp, GridBagConstraints c) {
+ gbag.setConstraints(comp, c);
+ this.add(comp);
+ }
+
+ public synchronized void recalc() {
+ int height = this.getSize().height;
+ this.linesVisible = Math.max(1, height / this.itemHeight);
+ int count = this.items.size();
+ if (count > this.linesVisible) {
+ if (!this.scrollbar.isVisible()) {
+ this.scrollbar.setVisible(true);
+ this.validate();
+ }
+
+ this.scrollbar.setValues(this.scrollPos * this.itemHeight, this.linesVisible * this.itemHeight, 0, count * this.itemHeight);
+ this.scrollbar.setPageIncrement(this.linesVisible * this.itemHeight);
+ this.scrollbar.setLineIncrement(this.itemHeight);
+ } else {
+ if (this.scrollbar.isVisible()) {
+ this.scrollbar.hide();
+ this.validate();
+ }
+
+ this.scrollPos = 0;
+ }
+
+ this.needRecalc = false;
+ }
+
+ @Override
+ public synchronized void paint(Graphics g) {
+ super.paint(g);
+ int width = this.getSize().width;
+ int height = this.getSize().height;
+ int count = this.items.size();
+ int y = 0;
+
+ for (int i = this.scrollPos; i < count; i++) {
+ TreeNode node = this.elementAt(i);
+ String name = node.toString();
+ boolean isTitle = node.displayAsTitle();
+ Font font = this.nFont;
+ FontMetrics metrics = this.nFontMetrics;
+ if (isTitle) {
+ font = this.bFont;
+ metrics = this.bFontMetrics;
+ }
+
+ g.setFont(font);
+ int ascent = metrics.getAscent();
+ int x = node.getLevel() * 14;
+ g.setColor(normFGColor);
+ if (node.isOpen()) {
+ this.openedIcon.drawFilled(g, x + 5, y + ascent - 5);
+ } else {
+ this.closedIcon.drawFilled(g, x + 5, y + ascent - 5);
+ }
+
+ if (i == this.selectedIndex) {
+ g.setColor(selFGColor);
+ }
+
+ g.drawString(name, x + 11 + 5, y + ascent);
+ if (i == this.selectedIndex && this.hasFocus) {
+ g.drawRect(x + 11 + 3, y, metrics.stringWidth(name) + 3, this.itemHeight);
+ }
+
+ y += this.itemHeight;
+ if (y >= height) {
+ break;
+ }
+ }
+
+ this.needRepaint = false;
+ }
+
+ @Override
+ public boolean handleEvent(Event e) {
+ if (this.isDialogDisabled) {
+ return false;
+ } else {
+ switch (e.id) {
+ case 601:
+ return this.scrollLineUp();
+ case 602:
+ return this.scrollLineDown();
+ case 603:
+ return this.scrollPageUp();
+ case 604:
+ return this.scrollPageDown();
+ case 605:
+ return this.scrollAbsolute();
+ default:
+ return super.handleEvent(e);
+ }
+ }
+ }
+
+ @Override
+ public void dialogDisable(boolean disable) {
+ this.isDialogDisabled = disable;
+ }
+
+ @Override
+ public synchronized boolean mouseDown(Event e, int x, int y) {
+ this.setFocus(true);
+ int item = this.scrollPos + y / this.itemHeight;
+ if (item >= 0 && item < this.items.size()) {
+ if (e.clickCount == 1) {
+ this.treeSelect(item);
+ int yStart = y / this.itemHeight * this.itemHeight;
+ TreeNode node = this.elementAt(item);
+ MoveablePolygon widget = node.isOpen() ? this.openedIcon : this.closedIcon;
+ FontMetrics metrics = node.displayAsTitle() ? this.nFontMetrics : this.bFontMetrics;
+ widget.moveTo(node.getLevel() * 14 + 5, yStart + metrics.getAscent() - 5);
+ if (widget.getBoundingBox().inside(x, y)) {
+ this.treeOpen(item);
+ }
+ } else {
+ this.treeOpen(item);
+ }
+ }
+
+ return true;
+ }
+
+ public void treeSelect(int item) {
+ }
+
+ public void treeOpen(int item) {
+ }
+
+ private boolean setScrollValue(int value) {
+ value = Math.max(this.scrollbar.getMinimum(), value);
+ value = Math.min(this.scrollbar.getMaximum(), value);
+ this.scrollPos = value / this.itemHeight;
+ this.scrollbar.setValue(this.scrollPos * this.itemHeight);
+ this.needRepaint(false, false);
+ return true;
+ }
+
+ private boolean scrollLineUp() {
+ return this.setScrollValue(this.scrollPos * this.itemHeight - this.scrollbar.getLineIncrement());
+ }
+
+ private boolean scrollLineDown() {
+ return this.setScrollValue(this.scrollPos * this.itemHeight + this.scrollbar.getLineIncrement());
+ }
+
+ private boolean scrollPageUp() {
+ return this.setScrollValue(this.scrollPos * this.itemHeight - this.scrollbar.getPageIncrement());
+ }
+
+ private boolean scrollPageDown() {
+ return this.setScrollValue(this.scrollPos * this.itemHeight + this.scrollbar.getPageIncrement());
+ }
+
+ private boolean scrollAbsolute() {
+ return this.setScrollValue(this.scrollbar.getValue());
+ }
+}