changeset 1874:54e65b36947b default tip

swing
author Franklin Schmidt <fschmidt@gmail.com>
date Sat, 05 Apr 2025 08:20:43 -0600
parents cf38353d77bd
children
files src/luan/modules/swing/Border.luan src/luan/modules/swing/Component.luan src/luan/modules/swing/List.luan src/luan/modules/swing/Scroll_pane.luan src/luan/modules/swing/SwingLuan.java src/luan/modules/swing/TextAreaLineNumbers.java src/luan/modules/swing/TextAreaLineNumbers.luan src/luan/modules/swing/TextAreaLineNumbersLuan.java src/luan/modules/swing/TextAreaLuan.java src/luan/modules/swing/Text_area.luan src/luan/modules/swing/UndoManagerLuan.java src/luan/modules/swing/WeakDocumentListener.java
diffstat 12 files changed, 222 insertions(+), 67 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/modules/swing/Border.luan	Sat Apr 05 08:20:43 2025 -0600
@@ -0,0 +1,15 @@
+local Luan = require "luan:Luan.luan"
+local error = Luan.error
+local Number = require "luan:Number.luan"
+local integer = Number.integer or error()
+require "java"
+local BorderFactory = require "java:javax.swing.BorderFactory"
+
+
+local Border = {}
+
+function Border.create_empty_border(top,left,bottom,right)
+	return BorderFactory.createEmptyBorder(top,left,bottom,right)
+end
+
+return Border
--- a/src/luan/modules/swing/Component.luan	Thu Apr 03 16:17:56 2025 -0600
+++ b/src/luan/modules/swing/Component.luan	Sat Apr 05 08:20:43 2025 -0600
@@ -13,6 +13,9 @@
 	if key == "foreground_color" then
 		return component.java.getForeground()
 	end
+	if key == "border" then
+		return component.java.getBorder()
+	end
 	return fail
 end
 
@@ -21,6 +24,10 @@
 		component.java.setForeground(value)
 		return
 	end
+	if key == "border" then
+		component.java.setBorder(value)
+		return
+	end
 	return fail
 end
 
--- a/src/luan/modules/swing/List.luan	Thu Apr 03 16:17:56 2025 -0600
+++ b/src/luan/modules/swing/List.luan	Sat Apr 05 08:20:43 2025 -0600
@@ -11,7 +11,8 @@
 require "java"
 local JList = require "java:javax.swing.JList"
 local DefaultListModel = require "java:javax.swing.DefaultListModel"
-local TextAreaLineNumbers = require "java:luan.modules.swing.TextAreaLineNumbers"
+local Logging = require "luan:logging/Logging.luan"
+local logger = Logging.logger "swing/List"
 
 
 local List = {}
@@ -54,8 +55,4 @@
 	return new(DefaultListModel.new())
 end
 
-function List.new_text_area_line_numbers(text_area)
-	return new(TextAreaLineNumbers.new(text_area.java))
-end
-
 return List
--- a/src/luan/modules/swing/Scroll_pane.luan	Thu Apr 03 16:17:56 2025 -0600
+++ b/src/luan/modules/swing/Scroll_pane.luan	Sat Apr 05 08:20:43 2025 -0600
@@ -1,9 +1,9 @@
 local Luan = require "luan:Luan.luan"
 local error = Luan.error
 local set_metatable = Luan.set_metatable or error()
+local Utils = require "luan:swing/Utils.luan"
+local make_metatable = Utils.make_metatable or error()
 local Component = require "luan:swing/Component.luan"
-local super__index = Component.__index or error()
-local super__new_index = Component.__new_index or error()
 local super = Component.new or error()
 require "java"
 local JScrollPane = require "java:javax.swing.JScrollPane"
@@ -11,15 +11,7 @@
 
 local Scroll_pane = {}
 
-local mt = {}
-
-function mt.__index(scroll_pane,key)
-	error("'"..key.."' not defined")
-end
-
-function mt.__new_index(scroll_pane,key,value)
-	error("'"..key.."' not defined")
-end
+local mt = make_metatable(Component)
 
 function Scroll_pane.new(view)
 	local jscroll_pane = JScrollPane.new(view.java)
--- a/src/luan/modules/swing/SwingLuan.java	Thu Apr 03 16:17:56 2025 -0600
+++ b/src/luan/modules/swing/SwingLuan.java	Sat Apr 05 08:20:43 2025 -0600
@@ -21,7 +21,7 @@
 import luan.LuanRuntimeException;
 
 
-public final class SwingLuan {
+public class SwingLuan {
 
 	static {
 		//System.setProperty("apple.awt.application.name", "MyApplication");
--- a/src/luan/modules/swing/TextAreaLineNumbers.java	Thu Apr 03 16:17:56 2025 -0600
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-package luan.modules.swing;
-
-import javax.swing.AbstractListModel;
-import javax.swing.JTextArea;
-import javax.swing.event.DocumentListener;
-import javax.swing.event.DocumentEvent;
-
-
-public final class TextAreaLineNumbers extends AbstractListModel<Integer> implements DocumentListener {
-	private final JTextArea textArea;
-	private int lines;
-
-	public TextAreaLineNumbers(JTextArea textArea) {
-		this.textArea = textArea;
-		this.lines = textArea.getLineCount();
-		textArea.getDocument().addDocumentListener(new WeakDocumentListener(this));
-	}
-
-	@Override public Integer getElementAt(int index) {
-		return index + 1;
-	}
-
-	@Override public int getSize() {
-		return lines;
-	}
-
-	@Override public void changedUpdate(DocumentEvent e) {
-		int n = textArea.getLineCount();
-		if( lines < n ) {
-			fireIntervalAdded(e.getDocument(),lines,n-1);
-			lines = n;
-		} else if( lines > n ) {
-			fireIntervalRemoved(e.getDocument(),n,lines-1);
-			lines = n;
-		}
-	}
-
-	@Override public void removeUpdate(DocumentEvent e) {
-		changedUpdate(e);
-	}
-
-	@Override public void insertUpdate(DocumentEvent e) {
-		changedUpdate(e);
-	}
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/modules/swing/TextAreaLineNumbers.luan	Sat Apr 05 08:20:43 2025 -0600
@@ -0,0 +1,24 @@
+local Luan = require "luan:Luan.luan"
+local error = Luan.error
+local set_metatable = Luan.set_metatable or error()
+local Utils = require "luan:swing/Utils.luan"
+local make_metatable = Utils.make_metatable or error()
+local Component = require "luan:swing/Component.luan"
+local super = Component.new or error()
+require "java"
+local TextAreaLineNumbersLuan = require "java:luan.modules.swing.TextAreaLineNumbersLuan"
+
+
+local TextAreaLineNumbers = {}
+
+local mt = make_metatable(Component)
+
+function TextAreaLineNumbers.new(text_area)
+	local jtaln = TextAreaLineNumbersLuan.new(text_area.java)
+	local taln = { java = jtaln }
+	super(taln)
+	set_metatable(taln,mt)
+	return taln
+end
+
+return TextAreaLineNumbers
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/modules/swing/TextAreaLineNumbersLuan.java	Sat Apr 05 08:20:43 2025 -0600
@@ -0,0 +1,139 @@
+package luan.modules.swing;
+
+import java.awt.Font;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.Color;
+import javax.swing.JPanel;
+import javax.swing.BoxLayout;
+import javax.swing.JLabel;
+import javax.swing.SwingUtilities;
+import javax.swing.event.DocumentListener;
+import javax.swing.event.DocumentEvent;
+import javax.swing.text.BadLocationException;
+import goodjava.logging.Logger;
+import goodjava.logging.LoggerFactory;
+
+
+public class TextAreaLineNumbersLuan extends JPanel implements DocumentListener {
+	private static final Logger logger = LoggerFactory.getLogger(TextAreaLineNumbersLuan.class);
+
+	private final TextAreaLuan textArea;
+	private int width;
+	private int lines;
+
+	public TextAreaLineNumbersLuan(TextAreaLuan textArea) {
+		this.textArea = textArea;
+		this.lines = textArea.getLineCount();
+		//logger.info("lines "+lines);
+		setFont(textArea.getFont());
+		setLayout( new BoxLayout(this, BoxLayout.Y_AXIS) );
+		for( int i=1; i<=lines; i++ ) {
+			JLabel label = newJLabel(i);
+			add(label);
+		}
+		fixWidth();
+		fixHeights();
+		textArea.getDocument().addDocumentListener(new WeakDocumentListener(this));
+	}
+
+	private JLabel newJLabel(int i) {
+		String text = String.valueOf(i);
+		JLabel label = new JLabel(text,JLabel.RIGHT);
+		label.setVerticalAlignment(JLabel.TOP);
+		label.setFont(getFont());
+		label.setForeground(getForeground());
+		return label;
+	}
+
+	private void fixWidth() {
+		Component last = getComponent(getComponentCount()-1);
+		int lastWidth = last.getPreferredSize().width;
+		//logger.info("lastWidth "+lastWidth);
+		if( width != lastWidth ) {
+			width = lastWidth;
+			for( Component label : getComponents() ) {
+				Dimension size = label.getPreferredSize();
+				Dimension newSize = new Dimension( width, size.height );
+				label.setPreferredSize(newSize);
+				label.setMaximumSize(newSize);
+				//label.revalidate();
+				//logger.info("setPreferredSize "+label.getPreferredSize().width);
+			}
+			//revalidate();
+			//repaint();
+			//logger.info("firstWidth0 "+getComponent(0).getSize().width);
+		}
+	}
+
+	private void doFixHeights() {
+		Component[] a = getComponents();
+		for( int i=0; i<a.length; i++ ) {
+			Component label = a[i];
+			Dimension size = label.getPreferredSize();
+			int height;
+			try {
+				height = textArea.getLineHeight(i);
+			} catch(BadLocationException e) {
+				throw new RuntimeException(e);
+			}
+			//logger.info("height "+i+" "+height);
+			if( height != size.height ) {
+				Dimension newSize = new Dimension( size.width, height );
+				label.setPreferredSize(newSize);
+				label.setMaximumSize(newSize);
+			}
+		}
+		revalidate();
+		//repaint();
+	}
+
+	private final Runnable fixHeightsRunnable = new Runnable() {
+		public void run() {
+			doFixHeights();
+		}
+	};
+
+	private void fixHeights() {
+		SwingUtilities.invokeLater(fixHeightsRunnable);
+	}
+
+	@Override public void setForeground(Color fg) {
+		super.setForeground(fg);
+		for( Component label : getComponents() ) {
+			label.setForeground(fg);
+		}
+	}
+
+	@Override public void changedUpdate(DocumentEvent e) {
+		//logger.info(e.getType().toString());
+		int n = textArea.getLineCount();
+		if( lines < n ) {
+			for( int i=lines+1; i<=n; i++ ) {
+				JLabel label = newJLabel(i);
+				add(label);
+			}
+			lines = n;
+		} else if( lines > n ) {
+			for( int i=n; i<lines; i++ ) {
+				//logger.info("getComponentCount "+getComponentCount());
+				//logger.info("remove "+n);
+				remove(n);
+				//logger.info("getComponentCount "+getComponentCount());
+			}
+			lines = n;
+			//revalidate();
+			repaint();
+		}
+		fixHeights();
+	}
+
+	@Override public void removeUpdate(DocumentEvent e) {
+		changedUpdate(e);
+	}
+
+	@Override public void insertUpdate(DocumentEvent e) {
+		changedUpdate(e);
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/modules/swing/TextAreaLuan.java	Sat Apr 05 08:20:43 2025 -0600
@@ -0,0 +1,27 @@
+package luan.modules.swing;
+
+import java.awt.Rectangle;
+import javax.swing.JTextArea;
+import javax.swing.text.BadLocationException;
+import goodjava.logging.Logger;
+import goodjava.logging.LoggerFactory;
+
+
+public class TextAreaLuan extends JTextArea {
+	private static final Logger logger = LoggerFactory.getLogger(TextAreaLuan.class);
+
+	public int getLineHeight(int line) throws BadLocationException {
+		Rectangle r1 = modelToView(getLineStartOffset(line));
+//		if( r1 == null )  return 0;  // hack
+		int startOffset = r1.y;
+		int endOffset = modelToView(getLineEndOffset(line)).y;
+		int height = endOffset - startOffset;
+		if( height == 0 )
+			height = getRowHeight();
+		return height;
+	}
+
+	public int getLineRows(int line) throws BadLocationException {
+		return getLineHeight(line) / getRowHeight();
+	}
+}
--- a/src/luan/modules/swing/Text_area.luan	Thu Apr 03 16:17:56 2025 -0600
+++ b/src/luan/modules/swing/Text_area.luan	Sat Apr 05 08:20:43 2025 -0600
@@ -9,7 +9,7 @@
 local super__new_index = Text_component.__new_index or error()
 local new_text_component = Text_component.new or error()
 require "java"
-local JTextArea = require "java:javax.swing.JTextArea"
+local TextAreaLuan = require "java:luan.modules.swing.TextAreaLuan"
 
 
 local Text_area = {}
@@ -67,7 +67,7 @@
 local mt = make_metatable(Text_area)
 
 function Text_area.new()
-	local text_area = { java = JTextArea.new() }
+	local text_area = { java = TextAreaLuan.new() }
 	new_text_component(text_area)
 	local jtext_area = text_area.java
 	set_metatable(text_area,mt)
--- a/src/luan/modules/swing/UndoManagerLuan.java	Thu Apr 03 16:17:56 2025 -0600
+++ b/src/luan/modules/swing/UndoManagerLuan.java	Sat Apr 05 08:20:43 2025 -0600
@@ -16,7 +16,7 @@
 import goodjava.logging.LoggerFactory;
 
 
-public final class UndoManagerLuan extends UndoManager {
+public class UndoManagerLuan extends UndoManager {
 	private static final Logger logger = LoggerFactory.getLogger(UndoManagerLuan.class);
 
 	private final WeakHashMap<LuanFunction,Boolean> map = new WeakHashMap<LuanFunction,Boolean>();
--- a/src/luan/modules/swing/WeakDocumentListener.java	Thu Apr 03 16:17:56 2025 -0600
+++ b/src/luan/modules/swing/WeakDocumentListener.java	Sat Apr 05 08:20:43 2025 -0600
@@ -5,7 +5,7 @@
 import javax.swing.event.DocumentEvent;
 
 
-public final class WeakDocumentListener implements DocumentListener {
+public class WeakDocumentListener implements DocumentListener {
 	private final WeakReference<DocumentListener> ref;
 
 	public WeakDocumentListener(DocumentListener dl) {