changeset 1939:60e1df60503c

swing
author Franklin Schmidt <fschmidt@gmail.com>
date Sat, 17 May 2025 22:20:10 -0600
parents bd00b36380d9
children 5a79d8b92f74
files src/luan/modules/swing/Abstract_button.luan src/luan/modules/swing/Awt_window.luan src/luan/modules/swing/Button_group.luan src/luan/modules/swing/Component.luan src/luan/modules/swing/Dialog.luan src/luan/modules/swing/Frame.luan src/luan/modules/swing/Radio_button.luan src/luan/modules/swing/Scroll_pane.luan src/luan/modules/swing/TextAreaLineNumbersLuan.java src/luan/modules/swing/TextAreaLuan.java src/luan/modules/swing/Text_area_line_numbers.luan src/luan/modules/swing/WeakDocumentListener.java
diffstat 12 files changed, 156 insertions(+), 39 deletions(-) [+]
line wrap: on
line diff
--- a/src/luan/modules/swing/Abstract_button.luan	Fri May 16 17:20:29 2025 -0600
+++ b/src/luan/modules/swing/Abstract_button.luan	Sat May 17 22:20:10 2025 -0600
@@ -14,12 +14,19 @@
 local KeyEvent = require "java:java.awt.event.KeyEvent"
 local SwingLuan = require "java:luan.modules.swing.SwingLuan"
 local newActionListener = SwingLuan.newActionListener
+local SwingConstants = require "java:javax.swing.SwingConstants"
 local Logging = require "luan:logging/Logging.luan"
 local logger = Logging.logger "swing/Abstract_button"
 
 
 local Abstract_button = {}
 
+local alignments = {
+	left = SwingConstants.LEFT
+	center = SwingConstants.CENTER
+	right = SwingConstants.RIGHT
+}
+
 function Abstract_button.__index(abstract_button,key)
 	local rtn = super__index(abstract_button,key)
 	if rtn ~= fail then return rtn end
@@ -64,6 +71,16 @@
 	if mnemonic~=nil then jbutton.setMnemonic(KeyEvent.getExtendedKeyCodeForChar(char_to_int(mnemonic))) end
 	local action_listener = delete(props,"action_listener")
 	if action_listener~=nil then jbutton.addActionListener(newActionListener(action_listener)) end
+	local horizontal_alignment = delete(props,"horizontal_alignment")
+	if horizontal_alignment~=nil then
+		local align = alignments[horizontal_alignment] or error "invalid horizontal_alignment"
+		jbutton.setHorizontalAlignment(align)
+	end
+	local horizontal_text_position = delete(props,"horizontal_text_position")
+	if horizontal_text_position~=nil then
+		local align = alignments[horizontal_text_position] or error "invalid horizontal_text_position"
+		jbutton.setHorizontalTextPosition(align)
+	end
 	function button.add_action_listener(action_listener)
 		jbutton.addActionListener(newActionListener(action_listener))
 	end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/modules/swing/Awt_window.luan	Sat May 17 22:20:10 2025 -0600
@@ -0,0 +1,51 @@
+local Luan = require "luan:Luan.luan"
+local error = Luan.error
+local Utils = require "luan:swing/Utils.luan"
+local fail = Utils.fail or error()
+local to_dimension = Utils.to_dimension or error()
+local Awt_container = require "luan:swing/Awt_container.luan"
+local super__index = Awt_container.__index or error()
+local super__new_index = Awt_container.__new_index or error()
+local super_construct = Awt_container.construct or error()
+require "java"
+local SwingLuan = require "java:luan.modules.swing.SwingLuan"
+local newCloseListener = SwingLuan.newCloseListener
+local newWindowFocusListener = SwingLuan.newWindowFocusListener
+
+
+local Awt_window = {}
+
+function Awt_window.__index(window,key)
+	local rtn = super__index(window,key)
+	if rtn ~= fail then return rtn end
+	local jwindow = window.java
+	return fail
+end
+
+function Awt_window.__new_index(window,key,value)
+	local rtn = super__new_index(window,key,value)
+	if rtn ~= fail then return end
+	local jwindow = window.java
+	if key == "visible" then
+		jwindow.setVisible(value)
+		return
+	end
+	if key == "size" then
+		jwindow.setSize(to_dimension(value))
+		return
+	end
+	return fail
+end
+
+function Awt_window.construct(window,props)
+	super_construct(window,props)
+	local jwindow = window.java
+	function window.add_close_listener(close_listener)
+		jwindow.addWindowListener(newCloseListener(close_listener))
+	end
+	function window.add_window_focus_listener(window_focus_listener)
+		jwindow.addWindowFocusListener(newWindowFocusListener(window_focus_listener))
+	end
+end
+
+return Awt_window
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/modules/swing/Button_group.luan	Sat May 17 22:20:10 2025 -0600
@@ -0,0 +1,18 @@
+local Luan = require "luan:Luan.luan"
+local error = Luan.error
+require "java"
+local ButtonGroup = require "java:javax.swing.ButtonGroup"
+
+
+local Button_group = {}
+
+function Button_group.new()
+	local jgroup = ButtonGroup.new()
+	local group = { java = jgroup }
+	function group.add(button)
+		jgroup.add(button.java)
+	end
+	return group
+end
+
+return Button_group
--- a/src/luan/modules/swing/Component.luan	Fri May 16 17:20:29 2025 -0600
+++ b/src/luan/modules/swing/Component.luan	Sat May 17 22:20:10 2025 -0600
@@ -106,8 +106,10 @@
 	function component.dont_gc(obj)
 		component._dont_gc[obj] = true
 	end
+	function component.add(child)
+		jcomponent.add(child.java,child.constraints)
+	end
 	component.set_layout = jcomponent.setLayout
-	return component
 end
 Component.construct = construct
 
--- a/src/luan/modules/swing/Dialog.luan	Fri May 16 17:20:29 2025 -0600
+++ b/src/luan/modules/swing/Dialog.luan	Sat May 17 22:20:10 2025 -0600
@@ -8,6 +8,10 @@
 local check_empty = Utils.check_empty or error()
 local check_not_nil = Utils.check_not_nil or error()
 local new_component = require("luan:swing/Component.luan").new_component or error()
+local Awt_window = require "luan:swing/Awt_window.luan"
+local super__index = Awt_window.__index or error()
+local super__new_index = Awt_window.__new_index or error()
+local super_construct = Awt_window.construct or error()
 require "java"
 local JDialog = require "java:javax.swing.JDialog"
 local Logging = require "luan:logging/Logging.luan"
@@ -17,10 +21,10 @@
 local Dialog = {}
 
 function Dialog.__index(dialog,key)
+	local rtn = super__index(dialog,key)
+	if rtn ~= fail then return rtn end
 	local jdialog = dialog.java
-	if key == "visible" then
-		return jdialog.isVisible()
-	end
+--[[
 	if key == "component" then
 		local jcomponent = jdialog.getContentPane()
 		local component = jcomponent.getClientProperty("luan")
@@ -29,15 +33,14 @@
 		end
 		return component
 	end
+]]
 	return fail
 end
 
 function Dialog.__new_index(dialog,key,value)
+	local rtn = super__new_index(dialog,key,value)
+	if rtn ~= fail then return end
 	local jdialog = dialog.java
-	if key == "visible" then
-		jdialog.setVisible(value)
-		return
-	end
 	return fail
 end
 
@@ -46,8 +49,9 @@
 function Dialog.new(props)
 	check_not_nil(props)
 	local owner_frame = delete(props,"owner_frame")
-	local jdialog = owner_frame and JDialog.new(owner_frame.java)
+	local jdialog = JDialog.new( owner_frame and owner_frame.java )
 	local dialog = { java = jdialog }
+	super_construct(dialog,props)
 	local content_pane = delete(props,"content_pane")
 	if content_pane~=nil then jdialog.setContentPane(content_pane.java) end
 	check_empty(props)
--- a/src/luan/modules/swing/Frame.luan	Fri May 16 17:20:29 2025 -0600
+++ b/src/luan/modules/swing/Frame.luan	Sat May 17 22:20:10 2025 -0600
@@ -7,16 +7,12 @@
 local make_metatable = Utils.make_metatable or error()
 local delete = Utils.delete or error()
 local check_empty = Utils.check_empty or error()
-local to_dimension = Utils.to_dimension or error()
-local Awt_container = require "luan:swing/Awt_container.luan"
-local super__index = Awt_container.__index or error()
-local super__new_index = Awt_container.__new_index or error()
-local super_construct = Awt_container.construct or error()
+local Awt_window = require "luan:swing/Awt_window.luan"
+local super__index = Awt_window.__index or error()
+local super__new_index = Awt_window.__new_index or error()
+local super_construct = Awt_window.construct or error()
 require "java"
 local JFrame = require "java:javax.swing.JFrame"
-local SwingLuan = require "java:luan.modules.swing.SwingLuan"
-local newCloseListener = SwingLuan.newCloseListener
-local newWindowFocusListener = SwingLuan.newWindowFocusListener
 local Logging = require "luan:logging/Logging.luan"
 local logger = Logging.logger "swing/Frame"
 
@@ -38,18 +34,10 @@
 	local rtn = super__new_index(frame,key,value)
 	if rtn ~= fail then return end
 	local jframe = frame.java
-	if key == "visible" then
-		jframe.setVisible(value)
-		return
-	end
 	if key == "title" then
 		jframe.setTitle(value)
 		return
 	end
-	if key == "size" then
-		jframe.setSize(to_dimension(value))
-		return
-	end
 	return fail
 end
 
@@ -61,12 +49,6 @@
 	local content_pane = delete(props,"content_pane")
 	if content_pane~=nil then jframe.setContentPane(content_pane.java) end
 	check_empty(props)
-	function frame.add_close_listener(close_listener)
-		jframe.addWindowListener(newCloseListener(close_listener))
-	end
-	function frame.add_window_focus_listener(window_focus_listener)
-		jframe.addWindowFocusListener(newWindowFocusListener(window_focus_listener))
-	end
 	function frame.set_menu_bar(menu_bar)
 		jframe.setJMenuBar(menu_bar.java)
 	end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/modules/swing/Radio_button.luan	Sat May 17 22:20:10 2025 -0600
@@ -0,0 +1,28 @@
+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 check_empty = Utils.check_empty or error()
+local Abstract_button = require "luan:swing/Abstract_button.luan"
+local super__index = Abstract_button.__index or error()
+local super__new_index = Abstract_button.__new_index or error()
+local super_construct = Abstract_button.construct or error()
+local super_mt = Abstract_button.mt or error()
+require "java"
+local JRadioButton = require "java:javax.swing.JRadioButton"
+local Logging = require "luan:logging/Logging.luan"
+local logger = Logging.logger "swing/Radio_button"
+
+
+local Radio_button = {}
+
+function Radio_button.new(props)
+	local jbutton = JRadioButton.new()
+	local button = { java = jbutton }
+	super_construct(button,props)
+	check_empty(props)
+	set_metatable(button,super_mt)
+	return button
+end
+
+return Radio_button
--- a/src/luan/modules/swing/Scroll_pane.luan	Fri May 16 17:20:29 2025 -0600
+++ b/src/luan/modules/swing/Scroll_pane.luan	Sat May 17 22:20:10 2025 -0600
@@ -8,6 +8,8 @@
 local Component = require "luan:swing/Component.luan"
 local super_construct = Component.construct or error()
 local super_mt = Component.mt or error()
+local Swing = require "luan:swing/Swing.luan"
+local run_later = Swing.run_later or error()
 require "java"
 local JScrollPane = require "java:javax.swing.JScrollPane"
 
@@ -25,6 +27,12 @@
 	function scroll_pane.set_row_header_view(view)
 		jscroll_pane.setRowHeaderView(view.java)
 	end
+	function scroll_pane.scroll_to_right()
+		run_later( function()
+			local bar = jscroll_pane.getHorizontalScrollBar()
+			bar.setValue( bar.getMaximum() )
+		end )
+	end
 	set_metatable(scroll_pane,super_mt)
 	return scroll_pane
 end
--- a/src/luan/modules/swing/TextAreaLineNumbersLuan.java	Fri May 16 17:20:29 2025 -0600
+++ b/src/luan/modules/swing/TextAreaLineNumbersLuan.java	Sat May 17 22:20:10 2025 -0600
@@ -30,6 +30,7 @@
 	private int width;
 	private int lines;
 	private int lineStartSelection = -1;
+	private final LuanDocumentListener ldl = new LuanDocumentListener(this);
 
 	public TextAreaLineNumbersLuan(TextAreaLuan textArea) {
 		this.textArea = textArea;
@@ -43,7 +44,7 @@
 		}
 		fixWidth();
 		fixHeights();
-		textArea.getDocument().addDocumentListener(new WeakDocumentListener(new LuanDocumentListener(this)));
+		textArea.getDocument().addDocumentListener(new WeakDocumentListener(ldl));
 		textArea.addPropertyChangeListener("lineWrap",lineWrapListener);
 		textArea.addComponentListener(resizeListener);
 	}
--- a/src/luan/modules/swing/TextAreaLuan.java	Fri May 16 17:20:29 2025 -0600
+++ b/src/luan/modules/swing/TextAreaLuan.java	Sat May 17 22:20:10 2025 -0600
@@ -54,6 +54,7 @@
 	private boolean showWhitespace = false;
 	private List<Range> highlights = Collections.emptyList();
 	private static final Color highlightColor = new Color(0x2dada3);
+	private final LuanDocumentListener ldl = new LuanDocumentListener(this);
 
 	public TextAreaLuan() {
 		super();
@@ -61,7 +62,7 @@
 		if( UIManager.getLookAndFeel().getName().startsWith("FlatLaf") ) {
 			setCaret(flatLafCaret);
 		}
-		getDocument().addDocumentListener(new WeakDocumentListener(new LuanDocumentListener(this)));
+		getDocument().addDocumentListener(new WeakDocumentListener(ldl));
 	}
 
 	public int getLineHeight(int line) throws BadLocationException {
--- a/src/luan/modules/swing/Text_area_line_numbers.luan	Fri May 16 17:20:29 2025 -0600
+++ b/src/luan/modules/swing/Text_area_line_numbers.luan	Sat May 17 22:20:10 2025 -0600
@@ -11,11 +11,11 @@
 local TextAreaLineNumbersLuan = require "java:luan.modules.swing.TextAreaLineNumbersLuan"
 
 
-local TextAreaLineNumbers = {}
+local Text_area_line_numbers = {}
 
 local mt = make_metatable(Component)
 
-function TextAreaLineNumbers.new(props)
+function Text_area_line_numbers.new(props)
 	local text_area = delete(props,"text_area") or error "text_area property requied"
 	local jtaln = TextAreaLineNumbersLuan.new(text_area.java)
 	local taln = { java = jtaln }
@@ -25,4 +25,4 @@
 	return taln
 end
 
-return TextAreaLineNumbers
+return Text_area_line_numbers
--- a/src/luan/modules/swing/WeakDocumentListener.java	Fri May 16 17:20:29 2025 -0600
+++ b/src/luan/modules/swing/WeakDocumentListener.java	Sat May 17 22:20:10 2025 -0600
@@ -3,19 +3,24 @@
 import java.lang.ref.WeakReference;
 import javax.swing.event.DocumentListener;
 import javax.swing.event.DocumentEvent;
+import goodjava.logging.Logger;
+import goodjava.logging.LoggerFactory;
 
 
 public class WeakDocumentListener implements DocumentListener {
+	private static final Logger logger = LoggerFactory.getLogger(WeakDocumentListener.class);
 	private final WeakReference<DocumentListener> ref;
 
 	public WeakDocumentListener(DocumentListener dl) {
 		ref = new WeakReference<DocumentListener>(dl);
 	}
 
-	private DocumentListener get(DocumentEvent e) {
+	private DocumentListener get(DocumentEvent event) {
 		DocumentListener dl = ref.get();
-		if( dl==null )
-			e.getDocument().removeDocumentListener(this);
+		if( dl==null ) {
+			//logger.info("remove");
+			event.getDocument().removeDocumentListener(this);
+		}
 		return dl;
 	}