changeset 1914:d5776185f9d7

config
author Franklin Schmidt <fschmidt@gmail.com>
date Thu, 17 Apr 2025 18:36:27 -0600
parents 4f0c14fad13b
children 15dda75a887f
files src/luan/modules/editor/find.luan src/luan/modules/editor/menu.luan src/luan/modules/editor/window.luan src/luan/modules/swing/Awt_container.luan src/luan/modules/swing/Component.luan src/luan/modules/swing/Frame.luan src/luan/modules/swing/SwingLuan.java src/luan/modules/swing/TextAreaLuan.java src/luan/modules/swing/TextFieldLuan.java src/luan/modules/swing/Text_area.luan src/luan/modules/swing/Text_field.luan src/luan/modules/swing/Utils.luan
diffstat 12 files changed, 272 insertions(+), 58 deletions(-) [+]
line wrap: on
line diff
--- a/src/luan/modules/editor/find.luan	Wed Apr 16 22:16:42 2025 -0600
+++ b/src/luan/modules/editor/find.luan	Thu Apr 17 18:36:27 2025 -0600
@@ -135,13 +135,13 @@
 	end
 	find_field = new_text_field{
 		constraints = "growx"
-		show_whitespace = true
+		whitespace_visible = true
 		action = "next"
 		action_listener = find_match
 	}
 	replace_field = new_text_field{
 		constraints = "growx"
-		show_whitespace = true
+		whitespace_visible = true
 		action = "replace"
 		action_listener = replace_match
 	}
--- a/src/luan/modules/editor/menu.luan	Wed Apr 16 22:16:42 2025 -0600
+++ b/src/luan/modules/editor/menu.luan	Thu Apr 17 18:36:27 2025 -0600
@@ -84,6 +84,16 @@
 						action_listener = action_listener(text_area.print)
 					}
 					revert
+--[[
+					new_menu_item{
+						text = "Test"
+						action_listener = function(_)
+							local location = window.frame.location
+							location.y = location.y - 20
+							window.frame.location = location
+						end
+					}
+]]
 				}
 			}
 			new_menu{
@@ -151,13 +161,14 @@
 						text = "Word Wrap"
 						state = text_area.line_wrap
 						action_listener = function(event)
-							text_area.line_wrap = event.source.state
+							window.set_line_wrap(event.source.state)
 						end
 					}
 					new_check_box_menu_item{
 						text = "Show Whitespace"
+						state = text_area.whitespace_visible
 						action_listener = function(event)
-							text_area.show_whitespace(event.source.state)
+							window.set_whitespace_visible(event.source.state)
 						end
 					}
 					new_menu_item{
@@ -193,7 +204,7 @@
 							end
 							local size = to_number(input)
 							try
-								text_area.tab_size = size
+								window.set_tab_size(size)
 								status_bar.text = "Set tab size to "..size
 							catch e
 								status_bar.text = "Invalid tab size: "..input
--- a/src/luan/modules/editor/window.luan	Wed Apr 16 22:16:42 2025 -0600
+++ b/src/luan/modules/editor/window.luan	Thu Apr 17 18:36:27 2025 -0600
@@ -1,5 +1,6 @@
 local Luan = require "luan:Luan.luan"
 local error = Luan.error
+local stringify = Luan.stringify or error()
 local Math = require "luan:Math.luan"
 local min = Math.min or error()
 local String = require "luan:String.luan"
@@ -19,18 +20,28 @@
 local new_label = require("luan:swing/Label.luan").new or error()
 local make_find_panel = require "luan:editor/find.luan"
 local add_menu_bar = require "luan:editor/menu.luan"
+local Logging = require "luan:logging/Logging.luan"
+local logger = Logging.logger "editor/window"
 
 
 local n_windows = 0
 local documents = {}
 
+local config = {
+	size = { width=700, height=700 }
+	line_wrap = true
+	whitespace_visible = false
+	tab_size = 4
+}
+
 local function new_window(file)
 	local window = {}
 	window.has_file = file~=nil and file.is_file()
 	local text_area = new_text_area{
 		wrap_style_word = true
-		line_wrap = true
-		tab_size = 4
+		line_wrap = config.line_wrap
+		whitespace_visible = config.whitespace_visible
+		tab_size = config.tab_size
 		font = { family="Monospaced", size=13 }
 	}
 	window.text_area = text_area
@@ -56,7 +67,7 @@
 	window.status_bar = status_bar
 	local find_panel = make_find_panel(window)
 	local frame = new_frame{
-		preferred_size = { width=700, height=700 }
+		preferred_size = config.size
 		content_pane = new_panel{
 			layout = new_mig_layout("insets 0,wrap,fill,hidemode 3","","[][grow 0]")
 			children = {
@@ -81,6 +92,14 @@
 			Luan.exit()
 		end
 	end)
+	frame.add_resize_stopped_listener( 200, function()
+		--logger.info(stringify(frame.size))
+		config.size = frame.size
+	end)
+	frame.add_move_stopped_listener( 200, function()
+		--logger.info(stringify(frame.location))
+		config.location = frame.location
+	end)
 	local function set_title()
 		local s = title
 		if not text_area.document.is_unedited() then
@@ -180,8 +199,23 @@
 		local pos = text_area.get_line_start_position(line)
 		text_area.set_selection(pos)
 	end
+	function window.set_line_wrap(line_wrap)
+		text_area.line_wrap = line_wrap
+		config.line_wrap = line_wrap
+	end
+	function window.set_whitespace_visible(whitespace_visible)
+		text_area.whitespace_visible = whitespace_visible
+		config.whitespace_visible = whitespace_visible
+	end
+	function window.set_tab_size(tab_size)
+		text_area.tab_size = tab_size
+		config.tab_size = tab_size
+	end
 	add_menu_bar(window)
 	frame.pack()
+	if config.location ~= nil then
+		frame.location = config.location
+	end
 	frame.visible = true
 	text_area.request_focus_in_window()
 	n_windows = n_windows + 1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/modules/swing/Awt_container.luan	Thu Apr 17 18:36:27 2025 -0600
@@ -0,0 +1,82 @@
+local Luan = require "luan:Luan.luan"
+local error = Luan.error
+local ipairs = Luan.ipairs or error()
+local Utils = require "luan:swing/Utils.luan"
+local fail = Utils.fail or error()
+local delete = Utils.delete or error()
+local check_not_nil = Utils.check_not_nil or error()
+local to_dimension = Utils.to_dimension or error()
+local from_dimension = Utils.from_dimension or error()
+local to_point = Utils.to_point or error()
+local from_point = Utils.from_point or error()
+require "java"
+local SwingLuan = require "java:luan.modules.swing.SwingLuan"
+local newResizeListener = SwingLuan.newResizeListener
+local notifyAfterResizeStops = SwingLuan.notifyAfterResizeStops
+local newMoveListener = SwingLuan.newMoveListener
+local notifyAfterMoveStops = SwingLuan.notifyAfterMoveStops
+
+
+local Awt_container = {}
+
+function Awt_container.__index(component,key)
+	local jcomponent = component.java
+	if key == "foreground_color" then
+		return jcomponent.getForeground()
+	end
+	if key == "visible" then
+		return jcomponent.isVisible()
+	end
+	if key == "size" then
+		return from_dimension(jcomponent.getSize())
+	end
+	if key == "location" then
+		return from_point(jcomponent.getLocation())
+	end
+	return fail
+end
+
+function Awt_container.__new_index(component,key,value)
+	local jcomponent = component.java
+	if key == "location" then
+		jcomponent.setLocation(to_point(value))
+		return
+	end
+	return fail
+end
+
+--Awt_container.mt = make_metatable(Awt_container)
+
+function Awt_container.construct(component,props)
+	check_not_nil(props)
+	local jcomponent = component.java
+	local size = delete(props,"size")
+	if size~=nil then jcomponent.setSize(size.width,size.height) end
+	local location = delete(props,"location")
+	if location~=nil then jcomponent.setLocation(location.x,location.y) end
+	local preferred_size = delete(props,"preferred_size")
+	if preferred_size~=nil then jcomponent.setPreferredSize(to_dimension(preferred_size)) end
+	function component.add(el)
+		jcomponent.add(el.java)
+	end
+	function component.remove(el)
+		jcomponent.remove(el.java)
+	end
+	function component.add_all(list)
+		for _, child in ipairs(list) do
+			jcomponent.add(child.java)
+		end
+	end
+	function component.add_resize_listener(fn)
+		jcomponent.addComponentListener(newResizeListener(fn))
+	end
+	function component.add_resize_stopped_listener( time_after_stopped, fn )
+		notifyAfterResizeStops( jcomponent, newResizeListener(fn), time_after_stopped )
+	end
+	function component.add_move_stopped_listener( time_after_stopped, fn )
+		notifyAfterMoveStops( jcomponent, newMoveListener(fn), time_after_stopped )
+	end
+	return component
+end
+
+return Awt_container
--- a/src/luan/modules/swing/Component.luan	Wed Apr 16 22:16:42 2025 -0600
+++ b/src/luan/modules/swing/Component.luan	Thu Apr 17 18:36:27 2025 -0600
@@ -8,8 +8,11 @@
 local make_metatable = Utils.make_metatable or error()
 local delete = Utils.delete or error()
 local check_empty = Utils.check_empty or error()
-local check_not_nil = Utils.check_not_nil or error()
 local get_font = require("luan:swing/Font.luan").get 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 JComponent = require "java:javax.swing.JComponent"
 local JPanel = require "java:javax.swing.JPanel"
@@ -24,22 +27,20 @@
 }
 
 function Component.__index(component,key)
-	if key == "foreground_color" then
-		return component.java.getForeground()
-	end
+	local rtn = super__index(component,key)
+	if rtn ~= fail then return rtn end
 	if key == "border" then
 		return component.java.getBorder()
 	end
 	if key == "constraints" then
 		return nil
 	end
-	if key == "visible" then
-		return component.java.isVisible()
-	end
 	return fail
 end
 
 function Component.__new_index(component,key,value)
+	local rtn = super__new_index(component,key,value)
+	if rtn ~= fail then return end
 	if key == "foreground_color" then
 		component.java.setForeground(value)
 		return
@@ -59,7 +60,7 @@
 Component.mt = mt
 
 local function construct(component,props)
-	check_not_nil(props)
+	super_construct(component,props)
 	local jcomponent = component.java
 	jcomponent.putClientProperty("luan",component)
 	local layout = delete(props,"layout")
@@ -106,17 +107,6 @@
 		component._dont_gc[obj] = true
 	end
 	component.set_layout = jcomponent.setLayout
-	function component.add(el)
-		jcomponent.add(el.java)
-	end
-	function component.remove(el)
-		jcomponent.remove(el.java)
-	end
-	function component.add_all(list)
-		for _, child in ipairs(list) do
-			jcomponent.add(child.java)
-		end
-	end
 	return component
 end
 Component.construct = construct
--- a/src/luan/modules/swing/Frame.luan	Wed Apr 16 22:16:42 2025 -0600
+++ b/src/luan/modules/swing/Frame.luan	Thu Apr 17 18:36:27 2025 -0600
@@ -8,8 +8,10 @@
 local make_metatable = Utils.make_metatable or error()
 local delete = Utils.delete or error()
 local check_empty = Utils.check_empty or error()
-local check_not_nil = Utils.check_not_nil 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 JFrame = require "java:javax.swing.JFrame"
 local FileDialog = require "java:java.awt.FileDialog"
@@ -23,9 +25,8 @@
 local Frame = {}
 
 function Frame.__index(frame,key)
-	if key == "visible" then
-		return frame.java.isVisible()
-	end
+	local rtn = super__index(frame,key)
+	if rtn ~= fail then return rtn end
 	if key == "title" then
 		return frame.java.getTitle()
 	end
@@ -33,6 +34,8 @@
 end
 
 function Frame.__new_index(frame,key,value)
+	local rtn = super__new_index(frame,key,value)
+	if rtn ~= fail then return end
 	if key == "visible" then
 		frame.java.setVisible(value)
 		return
@@ -94,21 +97,16 @@
 end
 
 function Frame.new(props)
-	check_not_nil(props)
 	local jframe = JFrame.new()
 	jframe.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
 	local frame = { java = jframe }
+	super_construct(frame,props)
 	local content_pane = delete(props,"content_pane")
 	if content_pane~=nil then jframe.setContentPane(content_pane.java) end
-	local preferred_size = delete(props,"preferred_size")
-	if preferred_size~=nil then jframe.setPreferredSize(to_dimension(preferred_size)) end
 	check_empty(props)
 	function frame.add_close_listener(close_listener)
 		jframe.addWindowListener(newCloseListener(close_listener))
 	end
-	function frame.add(component)
-		jframe.add(component.java)
-	end
 	function frame.set_menu_bar(menu_bar)
 		jframe.setJMenuBar(menu_bar.java)
 	end
--- a/src/luan/modules/swing/SwingLuan.java	Wed Apr 16 22:16:42 2025 -0600
+++ b/src/luan/modules/swing/SwingLuan.java	Thu Apr 17 18:36:27 2025 -0600
@@ -6,14 +6,19 @@
 import javax.swing.Action;
 import javax.swing.AbstractAction;
 import javax.swing.JComponent;
+import javax.swing.Timer;
 import javax.swing.text.JTextComponent;
 import javax.swing.text.Document;
 import javax.swing.undo.UndoManager;
+import java.awt.Component;
 import java.awt.event.ActionListener;
 import java.awt.event.ActionEvent;
 import java.awt.event.WindowListener;
 import java.awt.event.WindowEvent;
 import java.awt.event.WindowAdapter;
+import java.awt.event.ComponentListener;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
 import goodjava.logging.Logger;
 import goodjava.logging.LoggerFactory;
 import luan.Luan;
@@ -81,19 +86,80 @@
 
 	public static WindowListener newCloseListener(final Luan luan,LuanFunction fn) {
 		return new WindowAdapter() {
-			private void call() {
+			@Override public void windowClosed(WindowEvent event) {
+				try {
+					fn.call(luan);
+				} catch(LuanException e) {
+					exception(e);
+				}
+			}
+		};
+	}
+
+	public static ComponentListener newResizeListener(final Luan luan,LuanFunction fn) {
+		return new ComponentAdapter() {
+			@Override public void componentResized(ComponentEvent event) {
 				try {
 					fn.call(luan);
 				} catch(LuanException e) {
-					throw new LuanRuntimeException(e);
+					exception(e);
 				}
 			}
-			@Override public void windowClosed(WindowEvent e) {
-				call();
+		};
+	}
+
+	public static void notifyAfterResizeStops(Component comp,final ComponentListener cl,int timeAfterStopped) {
+		comp.addComponentListener( new ComponentAdapter() {
+			ComponentEvent event;
+			final Timer timer = new Timer( timeAfterStopped, new ActionListener() {
+				@Override public void actionPerformed(ActionEvent _e) {
+					cl.componentResized(event);
+				}
+			} );
+
+			{
+				timer.setRepeats(false);
+			}
+
+			@Override public void componentResized(ComponentEvent event) {
+				this.event = event;
+				timer.restart();
+			}
+		} );
+	}
+
+	public static ComponentListener newMoveListener(final Luan luan,LuanFunction fn) {
+		return new ComponentAdapter() {
+			@Override public void componentMoved(ComponentEvent event) {
+				try {
+					fn.call(luan);
+				} catch(LuanException e) {
+					exception(e);
+				}
 			}
 		};
 	}
 
+	public static void notifyAfterMoveStops(Component comp,final ComponentListener cl,int timeAfterStopped) {
+		comp.addComponentListener( new ComponentAdapter() {
+			ComponentEvent event;
+			final Timer timer = new Timer( timeAfterStopped, new ActionListener() {
+				@Override public void actionPerformed(ActionEvent _e) {
+					cl.componentMoved(event);
+				}
+			} );
+
+			{
+				timer.setRepeats(false);
+			}
+
+			@Override public void componentMoved(ComponentEvent event) {
+				this.event = event;
+				timer.restart();
+			}
+		} );
+	}
+
 	public static void fixTextComponent(final JTextComponent tc) {
 		tc.getInputMap().put(KeyStroke.getKeyStroke("meta Z"),"undo");
 		Action undoAction = new AbstractAction() {
--- a/src/luan/modules/swing/TextAreaLuan.java	Wed Apr 16 22:16:42 2025 -0600
+++ b/src/luan/modules/swing/TextAreaLuan.java	Thu Apr 17 18:36:27 2025 -0600
@@ -79,7 +79,11 @@
 		return getLineHeight(line) / getRowHeight();
 	}
 
-	public void showWhitespace(boolean showWhitespace) {
+	public boolean isWhitespaceVisible() {
+		return showWhitespace;
+	}
+
+	public void setWhitespaceVisible(boolean showWhitespace) {
 		this.showWhitespace = showWhitespace;
 		repaint();
 	}
--- a/src/luan/modules/swing/TextFieldLuan.java	Wed Apr 16 22:16:42 2025 -0600
+++ b/src/luan/modules/swing/TextFieldLuan.java	Thu Apr 17 18:36:27 2025 -0600
@@ -14,7 +14,11 @@
 
 	private boolean showWhitespace = false;
 
-	public void showWhitespace(boolean showWhitespace) {
+	public boolean isWhitespaceVisible() {
+		return showWhitespace;
+	}
+
+	public void setWhitespaceVisible(boolean showWhitespace) {
 		this.showWhitespace = showWhitespace;
 		repaint();
 	}
--- a/src/luan/modules/swing/Text_area.luan	Wed Apr 16 22:16:42 2025 -0600
+++ b/src/luan/modules/swing/Text_area.luan	Thu Apr 17 18:36:27 2025 -0600
@@ -22,23 +22,27 @@
 function Text_area.__index(text_area,key)
 	local rtn = super__index(text_area,key)
 	if rtn ~= fail then return rtn end
+	local jtext_area = text_area.java
 	if key == "line_wrap" then
-		return text_area.java.getLineWrap()
+		return jtext_area.getLineWrap()
 	end
 	if key == "wrap_style_word" then
-		return text_area.java.getWrapStyleWord()
+		return jtext_area.getWrapStyleWord()
 	end
 	if key == "tab_size" then
-		return text_area.java.getTabSize()
+		return jtext_area.getTabSize()
 	end
 	if key == "rows" then
-		return text_area.java.getRows()
+		return jtext_area.getRows()
 	end
 	if key == "columns" then
-		return text_area.java.getColumns()
+		return jtext_area.getColumns()
 	end
 	if key == "line_count" then
-		return text_area.java.getLineCount()
+		return jtext_area.getLineCount()
+	end
+	if key == "whitespace_visible" then
+		return jtext_area.isWhitespaceVisible()
 	end
 	return fail
 end
@@ -46,24 +50,29 @@
 function Text_area.__new_index(text_area,key,value)
 	local rtn = super__new_index(text_area,key,value)
 	if rtn ~= fail then return end
+	local jtext_area = text_area.java
 	if key == "line_wrap" then
-		text_area.java.setLineWrap(value)
+		jtext_area.setLineWrap(value)
 		return
 	end
 	if key == "wrap_style_word" then
-		text_area.java.setWrapStyleWord(value)
+		jtext_area.setWrapStyleWord(value)
 		return
 	end
 	if key == "tab_size" then
-		text_area.java.setTabSize(value)
+		jtext_area.setTabSize(value)
 		return
 	end
 	if key == "rows" then
-		text_area.java.setRows(value)
+		jtext_area.setRows(value)
 		return
 	end
 	if key == "columns" then
-		text_area.java.setColumns(value)
+		jtext_area.setColumns(value)
+		return
+	end
+	if key == "whitespace_visible" then
+		jtext_area.setWhitespaceVisible(value)
 		return
 	end
 	return fail
@@ -85,8 +94,9 @@
 	if line_wrap~=nil then jtext_area.setLineWrap(line_wrap) end
 	local tab_size = delete(props,"tab_size")
 	if tab_size~=nil then jtext_area.setTabSize(tab_size) end
+	local whitespace_visible = delete(props,"whitespace_visible")
+	if whitespace_visible~=nil then jtext_area.setWhitespaceVisible(whitespace_visible) end
 	check_empty(props)
-	text_area.show_whitespace = jtext_area.showWhitespace
 	function text_area.get_line_from_position(pos)
 		return jtext_area.getLineOfOffset(pos-1) + 1
 	end
--- a/src/luan/modules/swing/Text_field.luan	Wed Apr 16 22:16:42 2025 -0600
+++ b/src/luan/modules/swing/Text_field.luan	Thu Apr 17 18:36:27 2025 -0600
@@ -27,8 +27,8 @@
 	if action~=nil then jtext_field.setActionCommand(action) end
 	local action_listener = delete(props,"action_listener")
 	if action_listener~=nil then jtext_field.addActionListener(newActionListener(action_listener)) end
-	local show_whitespace = delete(props,"show_whitespace")
-	if show_whitespace~=nil then jtext_field.showWhitespace(show_whitespace) end
+	local whitespace_visible = delete(props,"whitespace_visible")
+	if whitespace_visible~=nil then jtext_field.setWhitespaceVisible(whitespace_visible) end
 	check_empty(props)
 	set_metatable(text_field,super_mt)
 	return text_field
--- a/src/luan/modules/swing/Utils.luan	Wed Apr 16 22:16:42 2025 -0600
+++ b/src/luan/modules/swing/Utils.luan	Thu Apr 17 18:36:27 2025 -0600
@@ -7,6 +7,7 @@
 local is_empty = Table.is_empty or error()
 require "java"
 local Dimension = require "java:java.awt.Dimension"
+local Point = require "java:java.awt.Point"
 
 
 local Utils = {}
@@ -58,4 +59,18 @@
 	return Dimension.new(width,height)
 end
 
+function Utils.from_dimension(dim)
+	return { width=dim.width, height=dim.height }
+end
+
+function Utils.to_point(tbl)
+	local x = tbl.x or error "missing x"
+	local y = tbl.y or error "missing y"
+	return Point.new(x,y)
+end
+
+function Utils.from_point(point)
+	return { x=point.x, y=point.y }
+end
+
 return Utils