From 3f3514a211f928791d38a05949d2926915cf813c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Obr=C4=99bski?= Date: Wed, 4 Sep 2024 23:30:53 +0200 Subject: [PATCH 01/18] Add basic gui/notes tool print notes list and centering on them --- gui/notes.lua | 125 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 gui/notes.lua diff --git a/gui/notes.lua b/gui/notes.lua new file mode 100644 index 000000000..03794b5bb --- /dev/null +++ b/gui/notes.lua @@ -0,0 +1,125 @@ +-- Map notes +--@ module = true + +local gui = require 'gui' +local widgets = require 'gui.widgets' +local script = require 'gui.script' +local text_editor = reqscript('internal/journal/text_editor') + +local map_points = df.global.plotinfo.waypoints.points + +local NOTE_LIST_RESIZE_MIN = {w=26} +local RESIZE_MIN = {w=65, h=30} +local NOTE_SEARCH_BATCH_SIZE = 10 + +NotesWindow = defclass(NotesWindow, widgets.Window) +NotesWindow.ATTRS { + frame_title='DF Notes', + resizable=true, + resize_min=RESIZE_MIN, + frame_inset={l=0,r=0,t=0,b=0}, +} + +function NotesWindow:init() + self:addviews{ + widgets.Panel{ + view_id='note_list_panel', + frame={l=0, w=NOTE_LIST_RESIZE_MIN.w, t=0, b=1}, + visible=true, + frame_inset={l=1, t=1, b=1, r=1}, + autoarrange_subviews=true, + + subviews={ + widgets.HotkeyLabel { + key='CUSTOM_ALT_S', + label='Search', + frame={l=0}, + auto_width=true, + on_activate=function() self.subviews.search:setFocus(true) end, + }, + text_editor.TextEditor{ + view_id='search', + frame={l=0,h=3}, + frame_style=gui.FRAME_INTERIOR, + one_line_mode=true, + on_text_change=self:callback('loadFilteredNotes') + }, + widgets.List{ + view_id='note_list', + frame={l=0}, + frame_inset={t=1}, + row_height=1, + on_submit=self:callback('loadNote') + }, + } + }, + widgets.Divider{ + view_id='note_list_divider', + + frame={l=NOTE_LIST_RESIZE_MIN.w,t=0,b=0,w=1}, + + interior_b=false, + frame_style_t=false, + frame_style_b=false, + }, + } + + self:loadFilteredNotes('') +end + +function NotesWindow:loadNote(ind, note) + dfhack.gui.pauseRecenter(note.point.pos) +end + +function NotesWindow:loadFilteredNotes(search_phrase) + script.start(function () + local choices = {} + + for ind, map_point in ipairs(map_points) do + if ind > 0 and ind % NOTE_SEARCH_BATCH_SIZE == 0 then + script.sleep(1, 'frames') + end + + if #search_phrase < 3 or map_point.name:find(search_phrase) then + table.insert(choices, { + text=map_point.name, + point=map_point + }) + end + end + + self.subviews.note_list:setChoices(choices) + end) +end + + +NotesScreen = defclass(NotesScreen, gui.ZScreen) +NotesScreen.ATTRS { + focus_path='gui/notes', +} + +function NotesScreen:init() + self:addviews{ + NotesWindow{ + view_id='notes_window', + frame={w=RESIZE_MIN.w, h=35}, + }, + } +end + +function NotesScreen:onDismiss() + view = nil +end + +function main(options) + if not dfhack.isMapLoaded() or not dfhack.world.isFortressMode() then + qerror('notes requires a fortress map to be loaded') + end + + view = view and view:raise() or NotesScreen{ + }:show() +end + +if not dfhack_flags.module then + main() +end From 9f10c5de88c41c3ababd8fd796e83638aa72a254 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Obr=C4=99bski?= Date: Thu, 5 Sep 2024 07:53:41 +0200 Subject: [PATCH 02/18] Improve gui notes searching engine logic --- gui/notes.lua | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/gui/notes.lua b/gui/notes.lua index 03794b5bb..2a14613a5 100644 --- a/gui/notes.lua +++ b/gui/notes.lua @@ -10,7 +10,7 @@ local map_points = df.global.plotinfo.waypoints.points local NOTE_LIST_RESIZE_MIN = {w=26} local RESIZE_MIN = {w=65, h=30} -local NOTE_SEARCH_BATCH_SIZE = 10 +local NOTE_SEARCH_BATCH_SIZE = 25 NotesWindow = defclass(NotesWindow, widgets.Window) NotesWindow.ATTRS { @@ -72,15 +72,36 @@ function NotesWindow:loadNote(ind, note) end function NotesWindow:loadFilteredNotes(search_phrase) + local full_list_loaded = self.curr_search_phrase == '' + + search_phrase = search_phrase:lower() + if #search_phrase < 3 then + search_phrase = '' + end + + self.curr_search_phrase = search_phrase + script.start(function () + if #search_phrase == 0 and full_list_loaded then + return + end + local choices = {} for ind, map_point in ipairs(map_points) do if ind > 0 and ind % NOTE_SEARCH_BATCH_SIZE == 0 then script.sleep(1, 'frames') end + if self.curr_search_phrase ~= search_phrase then + -- stop the work if user provided new search phrase + return + end - if #search_phrase < 3 or map_point.name:find(search_phrase) then + local point_name_lowercase = map_point.name:lower() + if ( + point_name_lowercase ~= nil and #point_name_lowercase > 0 and + point_name_lowercase:find(search_phrase) + ) then table.insert(choices, { text=map_point.name, point=map_point From df9c87b3c046e084c4cc6c5d9dc1349a0c2f6609 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Obr=C4=99bski?= Date: Sun, 8 Sep 2024 19:44:39 +0200 Subject: [PATCH 03/18] Prepare size-adjustable note details view for gui/notes --- gui/notes.lua | 82 +++++++++++++++++++++++++++++++++++++++++++++++++-- notes.lua | 2 +- 2 files changed, 81 insertions(+), 3 deletions(-) diff --git a/gui/notes.lua b/gui/notes.lua index 2a14613a5..6d06efc0e 100644 --- a/gui/notes.lua +++ b/gui/notes.lua @@ -21,6 +21,8 @@ NotesWindow.ATTRS { } function NotesWindow:init() + self.selected_note = nil + self:addviews{ widgets.Panel{ view_id='note_list_panel', @@ -49,7 +51,7 @@ function NotesWindow:init() frame={l=0}, frame_inset={t=1}, row_height=1, - on_submit=self:callback('loadNote') + on_submit=function (ind, note) self:loadNote(note) end }, } }, @@ -62,12 +64,80 @@ function NotesWindow:init() frame_style_t=false, frame_style_b=false, }, + widgets.Panel{ + view_id='note_details', + frame={l=NOTE_LIST_RESIZE_MIN.w + 1,t=0,b=0}, + frame_inset=1, + autoarrange_gap=1, + subviews={ + widgets.Panel{ + view_id="name_panel", + frame_title='Name', + frame_style=gui.FRAME_INTERIOR, + frame={l=0,r=0,t=0,h=4}, + frame_inset={l=1,r=1}, + auto_height=true, + subviews={ + widgets.Label{ + view_id='name', + frame={t=0,l=0,r=0} + }, + }, + }, + widgets.Panel{ + view_id="comment_panel", + frame_title='Comment', + frame_style=gui.FRAME_INTERIOR, + frame={l=0,r=0,t=4,b=2}, + frame_inset={l=1,r=1,t=1}, + subviews={ + widgets.Label{ + view_id='comment', + frame={t=0,l=0,r=0} + }, + } + }, + widgets.Panel{ + frame={l=0,r=0,b=0,h=2}, + frame_inset={l=1,r=1,t=1}, + subviews={ + widgets.HotkeyLabel{ + view_id='edit', + frame={l=0,t=0,h=1}, + auto_width=true, + label='Edit', + key='CUSTOM_ALT_U', + -- on_activate=function() self:createNote() end, + -- enabled=function() return #self.subviews.name:getText() > 0 end, + }, + widgets.HotkeyLabel{ + view_id='delete', + frame={r=0,t=0,h=1}, + auto_width=true, + label='Delete', + key='CUSTOM_ALT_D', + -- on_activate=function() self:deleteNote() end, + }, + } + } + } + } } self:loadFilteredNotes('') end -function NotesWindow:loadNote(ind, note) +function NotesWindow:loadNote(note) + self.selected_note = note + + local note_width = self.subviews.name_panel.frame_body.width + local wrapped_name = note.point.name:wrap(note_width) + local wrapped_comment = note.point.comment:wrap(note_width) + + self.subviews.name:setText(wrapped_name) + self.subviews.comment:setText(wrapped_comment) + self.subviews.note_details:updateLayout() + dfhack.gui.pauseRecenter(note.point.pos) end @@ -113,6 +183,14 @@ function NotesWindow:loadFilteredNotes(search_phrase) end) end +function NotesWindow:postUpdateLayout() + if self.selected_note == nil then + self.subviews.note_list:submit() + else + self:loadNote(self.selected_note) + end +end + NotesScreen = defclass(NotesScreen, gui.ZScreen) NotesScreen.ATTRS { diff --git a/notes.lua b/notes.lua index 99aab4a74..8b71a0764 100644 --- a/notes.lua +++ b/notes.lua @@ -227,7 +227,7 @@ function NoteManager:init() key='CUSTOM_ALT_D', visible=edit_mode, on_activate=function() self:deleteNote() end, - } or nil, + }, } } }, From f480dde05ad854293df01a0d3d195bc7830fe03b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Obr=C4=99bski?= Date: Sun, 8 Sep 2024 20:28:30 +0200 Subject: [PATCH 04/18] Add a way to update/delete note from the `gui/notes` tool --- gui/notes.lua | 51 ++++++--- internal/notes/note_manager.lua | 180 ++++++++++++++++++++++++++++++++ notes.lua | 173 +----------------------------- 3 files changed, 219 insertions(+), 185 deletions(-) create mode 100644 internal/notes/note_manager.lua diff --git a/gui/notes.lua b/gui/notes.lua index 6d06efc0e..c6e8e290f 100644 --- a/gui/notes.lua +++ b/gui/notes.lua @@ -5,6 +5,7 @@ local gui = require 'gui' local widgets = require 'gui.widgets' local script = require 'gui.script' local text_editor = reqscript('internal/journal/text_editor') +local note_manager = reqscript('internal/notes/note_manager') local map_points = df.global.plotinfo.waypoints.points @@ -22,6 +23,7 @@ NotesWindow.ATTRS { function NotesWindow:init() self.selected_note = nil + self.note_manager = nil self:addviews{ widgets.Panel{ @@ -107,8 +109,7 @@ function NotesWindow:init() auto_width=true, label='Edit', key='CUSTOM_ALT_U', - -- on_activate=function() self:createNote() end, - -- enabled=function() return #self.subviews.name:getText() > 0 end, + on_activate=function() self:showNoteManager(self.selected_note) end, }, widgets.HotkeyLabel{ view_id='delete', @@ -116,7 +117,7 @@ function NotesWindow:init() auto_width=true, label='Delete', key='CUSTOM_ALT_D', - -- on_activate=function() self:deleteNote() end, + on_activate=function() self:deleteNote(self.selected_note) end, }, } } @@ -124,12 +125,41 @@ function NotesWindow:init() } } - self:loadFilteredNotes('') + self:loadFilteredNotes('', true) +end + +function NotesWindow:showNoteManager(note) + if self.note_manager ~= nil then + self.note_manager:dismiss() + end + + self.note_manager = note_manager.NoteManager{ + note=note, + on_dismiss=function() self.visible = true end + } + + self.visible = false + return self.note_manager:show():raise() +end + +function NotesWindow:deleteNote(note) + for ind, map_point in pairs(map_points) do + if map_point.id == note.point.id then + map_points:erase(ind) + break + end + end + + self:loadFilteredNotes(self.curr_search_phrase, true) end function NotesWindow:loadNote(note) self.selected_note = note + if note == nil then + return + end + local note_width = self.subviews.name_panel.frame_body.width local wrapped_name = note.point.name:wrap(note_width) local wrapped_comment = note.point.comment:wrap(note_width) @@ -141,7 +171,7 @@ function NotesWindow:loadNote(note) dfhack.gui.pauseRecenter(note.point.pos) end -function NotesWindow:loadFilteredNotes(search_phrase) +function NotesWindow:loadFilteredNotes(search_phrase, force) local full_list_loaded = self.curr_search_phrase == '' search_phrase = search_phrase:lower() @@ -152,7 +182,7 @@ function NotesWindow:loadFilteredNotes(search_phrase) self.curr_search_phrase = search_phrase script.start(function () - if #search_phrase == 0 and full_list_loaded then + if #search_phrase == 0 and full_list_loaded and not force then return end @@ -180,15 +210,8 @@ function NotesWindow:loadFilteredNotes(search_phrase) end self.subviews.note_list:setChoices(choices) - end) -end - -function NotesWindow:postUpdateLayout() - if self.selected_note == nil then self.subviews.note_list:submit() - else - self:loadNote(self.selected_note) - end + end) end diff --git a/internal/notes/note_manager.lua b/internal/notes/note_manager.lua new file mode 100644 index 000000000..79c76b4e7 --- /dev/null +++ b/internal/notes/note_manager.lua @@ -0,0 +1,180 @@ +--@ module = true + +local gui = require('gui') +local widgets = require('gui.widgets') +local text_editor = reqscript('internal/journal/text_editor') + +local waypoints = df.global.plotinfo.waypoints +local map_points = df.global.plotinfo.waypoints.points + +NoteManager = defclass(NoteManager, gui.ZScreen) +NoteManager.ATTRS{ + focus_path='notes/note-manager', + note=DEFAULT_NIL, + on_update=DEFAULT_NIL, + on_dismiss=DEFAULT_NIL, +} + +function NoteManager:init() + local edit_mode = self.note ~= nil + + self:addviews{ + widgets.Window{ + frame={w=35,h=20}, + frame_inset={t=1}, + resizable=true, + frame_title='Note', + subviews={ + widgets.HotkeyLabel { + key='CUSTOM_ALT_N', + label='Name', + frame={l=0,t=0}, + auto_width=true, + on_activate=function() self.subviews.name:setFocus(true) end, + }, + text_editor.TextEditor{ + view_id='name', + frame={t=1,h=3}, + frame_style=gui.FRAME_INTERIOR, + init_text=self.note and self.note.point.name or '', + -- init_cursor=self.note and #self.note.point.name + 1 or 1, + one_line_mode=true + }, + widgets.HotkeyLabel { + key='CUSTOM_ALT_C', + label='Comment', + frame={l=0,t=5}, + auto_width=true, + on_activate=function() self.subviews.comment:setFocus(true) end, + }, + text_editor.TextEditor{ + view_id='comment', + frame={t=6,b=3}, + frame_style=gui.FRAME_INTERIOR, + init_text=self.note and self.note.point.comment or '', + -- init_cursor=1 + }, + widgets.Panel{ + view_id='buttons', + frame={b=0,h=1}, + frame_inset={l=1,r=1}, + subviews={ + widgets.HotkeyLabel{ + view_id='Save', + frame={l=0,t=0,h=1}, + auto_width=true, + label='Save', + key='CUSTOM_ALT_S', + visible=edit_mode, + on_activate=function() self:saveNote() end, + enabled=function() return #self.subviews.name:getText() > 0 end, + }, + widgets.HotkeyLabel{ + view_id='Create', + frame={l=0,t=0,h=1}, + auto_width=true, + label='Create', + key='CUSTOM_ALT_S', + visible=not edit_mode, + on_activate=function() self:createNote() end, + enabled=function() return #self.subviews.name:getText() > 0 end, + }, + widgets.HotkeyLabel{ + view_id='delete', + frame={r=0,t=0,h=1}, + auto_width=true, + label='Delete', + key='CUSTOM_ALT_D', + visible=edit_mode, + on_activate=function() self:deleteNote() end, + }, + } + } + }, + }, + } +end + +function NoteManager:createNote() + local cursor_pos = guidm.getCursorPos() + if cursor_pos == nil then + dfhack.printerr('Enable keyboard cursor to add a note.') + return + end + + local name = self.subviews.name:getText() + local comment = self.subviews.comment:getText() + + if #name == 0 then + dfhack.printerr('Note need at least a name') + return + end + + map_points:insert("#", { + new=true, + + id = waypoints.next_point_id, + tile=88, + fg_color=7, + bg_color=0, + name=name, + comment=comment, + pos=cursor_pos + }) + waypoints.next_point_id = waypoints.next_point_id + 1 + + if self.on_update then + self.on_update() + end + + self:dismiss() +end + +function NoteManager:saveNote() + if self.note == nil then + return + end + + local name = self.subviews.name:getText() + local comment = self.subviews.comment:getText() + + if #name == 0 then + dfhack.printerr('Note need at least a name') + return + end + + self.note.point.name = name + self.note.point.comment = comment + + if self.on_update then + self.on_update() + end + + self:dismiss() +end + +function NoteManager:deleteNote() + if self.note == nil then + return + end + + for ind, map_point in pairs(map_points) do + if map_point.id == self.note.point.id then + map_points:erase(ind) + break + end + end + + if self.on_update then + self.on_update() + end + + self:dismiss() +end + +function NoteManager:onDismiss() + self.note = nil + if self.on_dismiss then + self:on_dismiss() + end +end diff --git a/notes.lua b/notes.lua index 8b71a0764..deef9bfad 100644 --- a/notes.lua +++ b/notes.lua @@ -5,7 +5,7 @@ local widgets = require('gui.widgets') local textures = require('gui.textures') local overlay = require('plugins.overlay') local guidm = require('gui.dwarfmode') -local text_editor = reqscript('internal/journal/text_editor') +local note_manager = reqscript('internal/notes/note_manager') local green_pin = dfhack.textures.loadTileset( 'hack/data/art/note_green_pin_map.png', @@ -22,7 +22,6 @@ NotesOverlay.ATTRS{ overlay_onupdate_max_freq_seconds=30, } -local waypoints = df.global.plotinfo.waypoints local map_points = df.global.plotinfo.waypoints.points function NotesOverlay:init() @@ -88,7 +87,7 @@ function NotesOverlay:showNoteManager(note) self.note_manager:dismiss() end - self.note_manager = NoteManager{ + self.note_manager = note_manager.NoteManager{ note=note, on_update=function() self:reloadVisibleNotes() end } @@ -148,174 +147,6 @@ function NotesOverlay:reloadVisibleNotes() end end -NoteManager = defclass(NoteManager, gui.ZScreen) -NoteManager.ATTRS{ - focus_path='notes/note-manager', - note=DEFAULT_NIL, - on_update=DEFAULT_NIL, -} - -function NoteManager:init() - local edit_mode = self.note ~= nil - - self:addviews{ - widgets.Window{ - frame={w=35,h=20}, - frame_inset={t=1}, - frame_title='Notes', - resizable=true, - subviews={ - widgets.HotkeyLabel { - key='CUSTOM_ALT_N', - label='Name', - frame={l=0,t=0}, - auto_width=true, - on_activate=function() self.subviews.name:setFocus(true) end, - }, - text_editor.TextEditor{ - view_id='name', - frame={t=1,h=3}, - frame_style=gui.FRAME_INTERIOR, - init_text=self.note and self.note.point.name or '', - init_cursor=self.note and #self.note.point.name+1 or 1, - one_line_mode=true - }, - widgets.HotkeyLabel { - key='CUSTOM_ALT_C', - label='Comment', - frame={l=0,t=5}, - auto_width=true, - on_activate=function() self.subviews.comment:setFocus(true) end, - }, - text_editor.TextEditor{ - view_id='comment', - frame={t=6,b=3}, - frame_style=gui.FRAME_INTERIOR, - init_text=self.note and self.note.point.comment or '', - init_cursor=1 - }, - widgets.Panel{ - view_id='buttons', - frame={b=0,h=1}, - frame_inset={l=1,r=1}, - subviews={ - widgets.HotkeyLabel{ - view_id='Save', - frame={l=0,t=0,h=1}, - auto_width=true, - label='Save', - key='CUSTOM_ALT_S', - visible=edit_mode, - on_activate=function() self:saveNote() end, - enabled=function() return #self.subviews.name:getText() > 0 end, - }, - widgets.HotkeyLabel{ - view_id='Create', - frame={l=0,t=0,h=1}, - auto_width=true, - label='Create', - key='CUSTOM_ALT_S', - visible=not edit_mode, - on_activate=function() self:createNote() end, - enabled=function() return #self.subviews.name:getText() > 0 end, - }, - widgets.HotkeyLabel{ - view_id='delete', - frame={r=0,t=0,h=1}, - auto_width=true, - label='Delete', - key='CUSTOM_ALT_D', - visible=edit_mode, - on_activate=function() self:deleteNote() end, - }, - } - } - }, - }, - } -end - -function NoteManager:createNote() - local cursor_pos = guidm.getCursorPos() - if cursor_pos == nil then - dfhack.printerr('Enable keyboard cursor to add a note.') - return - end - - local name = self.subviews.name:getText() - local comment = self.subviews.comment:getText() - - if #name == 0 then - dfhack.printerr('Note need at least a name') - return - end - - map_points:insert("#", { - new=true, - - id = waypoints.next_point_id, - tile=88, - fg_color=7, - bg_color=0, - name=name, - comment=comment, - pos=cursor_pos - }) - waypoints.next_point_id = waypoints.next_point_id + 1 - - if self.on_update then - self.on_update() - end - - self:dismiss() -end - -function NoteManager:saveNote() - if self.note == nil then - return - end - - local name = self.subviews.name:getText() - local comment = self.subviews.comment:getText() - - if #name == 0 then - dfhack.printerr('Note need at least a name') - return - end - - self.note.point.name = name - self.note.point.comment = comment - - if self.on_update then - self.on_update() - end - - self:dismiss() -end - -function NoteManager:deleteNote() - if self.note == nil then - return - end - - for ind, map_point in pairs(map_points) do - if map_point.id == self.note.point.id then - map_points:erase(ind) - break - end - end - - if self.on_update then - self.on_update() - end - - self:dismiss() -end - -function NoteManager:onDismiss() - self.note = nil -end - -- register widgets OVERLAY_WIDGETS = { map_notes=NotesOverlay From 47a22707a0a8c440aa10860e1e43e6baf1bddf20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Obr=C4=99bski?= Date: Sun, 8 Sep 2024 20:50:39 +0200 Subject: [PATCH 05/18] Make gui/notes center on note on submit --- gui/notes.lua | 49 +++++++++++++++++++++++--------- internal/journal/text_editor.lua | 10 ++++++- 2 files changed, 45 insertions(+), 14 deletions(-) diff --git a/gui/notes.lua b/gui/notes.lua index c6e8e290f..da52966ee 100644 --- a/gui/notes.lua +++ b/gui/notes.lua @@ -32,7 +32,6 @@ function NotesWindow:init() visible=true, frame_inset={l=1, t=1, b=1, r=1}, autoarrange_subviews=true, - subviews={ widgets.HotkeyLabel { key='CUSTOM_ALT_S', @@ -46,14 +45,35 @@ function NotesWindow:init() frame={l=0,h=3}, frame_style=gui.FRAME_INTERIOR, one_line_mode=true, - on_text_change=self:callback('loadFilteredNotes') + on_text_change=self:callback('loadFilteredNotes'), + on_submit=function() + self.subviews.note_list:submit() + end + }, + widgets.Panel{ + frame={h=2}, + frame_inset={t=1}, + subviews={ + widgets.HotkeyLabel { + key='CUSTOM_ALT_L', + label='Notes', + frame={l=0,t=0}, + auto_width=true, + on_activate=function() + self.subviews.note_list:setFocus(true) + end, + }, + } }, widgets.List{ view_id='note_list', frame={l=0}, - frame_inset={t=1}, + frame_inset={t=0}, row_height=1, - on_submit=function (ind, note) self:loadNote(note) end + on_submit=function (ind, note) + self:loadNote(note) + dfhack.gui.pauseRecenter(note.point.pos) + end }, } }, @@ -160,15 +180,16 @@ function NotesWindow:loadNote(note) return end - local note_width = self.subviews.name_panel.frame_body.width - local wrapped_name = note.point.name:wrap(note_width) - local wrapped_comment = note.point.comment:wrap(note_width) + local note_details_frame = self.subviews.name_panel.frame_body + if note_details_frame ~= nil then + local note_width = self.subviews.name_panel.frame_body.width + local wrapped_name = note.point.name:wrap(note_width) + local wrapped_comment = note.point.comment:wrap(note_width) - self.subviews.name:setText(wrapped_name) - self.subviews.comment:setText(wrapped_comment) - self.subviews.note_details:updateLayout() - - dfhack.gui.pauseRecenter(note.point.pos) + self.subviews.name:setText(wrapped_name) + self.subviews.comment:setText(wrapped_comment) + self.subviews.note_details:updateLayout() + end end function NotesWindow:loadFilteredNotes(search_phrase, force) @@ -210,7 +231,9 @@ function NotesWindow:loadFilteredNotes(search_phrase, force) end self.subviews.note_list:setChoices(choices) - self.subviews.note_list:submit() + + local sel_ind, sel_note = self.subviews.note_list:getSelected() + self:loadNote(sel_note) end) end diff --git a/internal/journal/text_editor.lua b/internal/journal/text_editor.lua index cf15776d4..0b7349411 100644 --- a/internal/journal/text_editor.lua +++ b/internal/journal/text_editor.lua @@ -94,6 +94,8 @@ TextEditor.ATTRS{ select_pen = COLOR_CYAN, on_text_change = DEFAULT_NIL, on_cursor_change = DEFAULT_NIL, + -- called on submit, only in one line mode + on_submit = DEFAULT_NIL, one_line_mode = false, debug = false } @@ -112,6 +114,7 @@ function TextEditor:init() select_pen=self.select_pen, debug=self.debug, one_line_mode=self.one_line_mode, + on_submit=self.on_submit, on_text_change=function (val) self:updateLayout() @@ -255,6 +258,7 @@ TextEditorView.ATTRS{ enable_cursor_blink = true, debug = false, one_line_mode = false, + on_submit = DEFAULT_NIL, history_size = 10, } @@ -796,7 +800,11 @@ end function TextEditorView:onTextManipulationInput(keys) if keys.SELECT then -- handle enter - if not self.one_line_mode then + if self.one_line_mode then + if self.on_submit then + self:on_submit() + end + else self.history:store( HISTORY_ENTRY.WHITESPACE_BLOCK, self.text, From adebc95df51b88047f49d80bddf362eab7112da1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Obr=C4=99bski?= Date: Sun, 8 Sep 2024 22:31:38 +0200 Subject: [PATCH 06/18] Add note add feature to `gui/notes` tool --- gui/notes.lua | 142 +++++++++++++++++++++++++++---- internal/journal/text_editor.lua | 12 ++- internal/notes/note_manager.lua | 10 ++- notes.lua | 2 +- 4 files changed, 144 insertions(+), 22 deletions(-) diff --git a/gui/notes.lua b/gui/notes.lua index da52966ee..7022b7106 100644 --- a/gui/notes.lua +++ b/gui/notes.lua @@ -3,6 +3,7 @@ local gui = require 'gui' local widgets = require 'gui.widgets' +local guidm = require('gui.dwarfmode') local script = require 'gui.script' local text_editor = reqscript('internal/journal/text_editor') local note_manager = reqscript('internal/notes/note_manager') @@ -13,12 +14,20 @@ local NOTE_LIST_RESIZE_MIN = {w=26} local RESIZE_MIN = {w=65, h=30} local NOTE_SEARCH_BATCH_SIZE = 25 +local green_pin = dfhack.textures.loadTileset( + 'hack/data/art/note_green_pin_map.png', + 32, + 32, + true +) + NotesWindow = defclass(NotesWindow, widgets.Window) NotesWindow.ATTRS { frame_title='DF Notes', resizable=true, resize_min=RESIZE_MIN, frame_inset={l=0,r=0,t=0,b=0}, + on_note_add=DEFAULT_NIL } function NotesWindow:init() @@ -30,7 +39,7 @@ function NotesWindow:init() view_id='note_list_panel', frame={l=0, w=NOTE_LIST_RESIZE_MIN.w, t=0, b=1}, visible=true, - frame_inset={l=1, t=1, b=1, r=1}, + frame_inset={l=1,t=1,b=1,r=1}, autoarrange_subviews=true, subviews={ widgets.HotkeyLabel { @@ -67,7 +76,7 @@ function NotesWindow:init() }, widgets.List{ view_id='note_list', - frame={l=0}, + frame={l=0,b=2}, frame_inset={t=0}, row_height=1, on_submit=function (ind, note) @@ -75,11 +84,22 @@ function NotesWindow:init() dfhack.gui.pauseRecenter(note.point.pos) end }, - } + }, + }, + widgets.HotkeyLabel{ + view_id='create', + frame={l=1,b=1,h=1}, + auto_width=true, + label='New note', + key='CUSTOM_ALT_N', + visible=edit_mode, + on_activate=function() + if self.on_note_add then + self:on_note_add() + end + end, }, widgets.Divider{ - view_id='note_list_divider', - frame={l=NOTE_LIST_RESIZE_MIN.w,t=0,b=0,w=1}, interior_b=false, @@ -155,6 +175,10 @@ function NotesWindow:showNoteManager(note) self.note_manager = note_manager.NoteManager{ note=note, + on_update=function() + self:reloadFilteredNotes() + dfhack.internal.runCommand('overlay trigger notes.map_notes') + end, on_dismiss=function() self.visible = true end } @@ -170,7 +194,7 @@ function NotesWindow:deleteNote(note) end end - self:loadFilteredNotes(self.curr_search_phrase, true) + self:reloadFilteredNotes() end function NotesWindow:loadNote(note) @@ -180,16 +204,26 @@ function NotesWindow:loadNote(note) return end - local note_details_frame = self.subviews.name_panel.frame_body - if note_details_frame ~= nil then - local note_width = self.subviews.name_panel.frame_body.width - local wrapped_name = note.point.name:wrap(note_width) - local wrapped_comment = note.point.comment:wrap(note_width) - - self.subviews.name:setText(wrapped_name) - self.subviews.comment:setText(wrapped_comment) - self.subviews.note_details:updateLayout() + -- self.note_width_calculated = false +end + +function NotesWindow:postUpdateLayout() + if self.selected_note == nil then + return end + local note_details_frame = self.subviews.name_panel.frame_body + + local note_width = self.subviews.name_panel.frame_body.width + local wrapped_name = self.selected_note.point.name:wrap(note_width) + local wrapped_comment = self.selected_note.point.comment:wrap(note_width) + + self.subviews.name:setText(wrapped_name) + self.subviews.comment:setText(wrapped_comment) + self.subviews.note_details:updateLayout() +end + +function NotesWindow:reloadFilteredNotes() + self:loadFilteredNotes(self.curr_search_phrase, true) end function NotesWindow:loadFilteredNotes(search_phrase, force) @@ -234,24 +268,100 @@ function NotesWindow:loadFilteredNotes(search_phrase, force) local sel_ind, sel_note = self.subviews.note_list:getSelected() self:loadNote(sel_note) + self:updateLayout() end) end - NotesScreen = defclass(NotesScreen, gui.ZScreen) NotesScreen.ATTRS { focus_path='gui/notes', + pass_movement_keys=true, } function NotesScreen:init() + self.is_adding_note = false + self.adding_note_pos = nil self:addviews{ NotesWindow{ view_id='notes_window', frame={w=RESIZE_MIN.w, h=35}, + on_note_add=self:callback('startNoteAdd') }, } end +function NotesScreen:startNoteAdd() + self.adding_note_pos = nil + self.subviews.notes_window.visible = false + self.is_adding_note = true +end + +function NotesScreen:stopNoteAdd() + self.subviews.notes_window.visible = true + self.is_adding_note = false +end + +function NotesScreen:onInput(keys) + if self.is_adding_note then + if (keys.SELECT or keys._MOUSE_L) then + self.adding_note_pos = dfhack.gui.getMousePos() + + local manager = note_manager.NoteManager{ + note=nil, + on_update=function() + self.subviews.notes_window:reloadFilteredNotes() + dfhack.internal.runCommand('overlay trigger notes.map_notes') + self:dismiss() + end, + on_dismiss=function() + self:stopNoteAdd() + end + }:show() + manager:setNotePos(self.adding_note_pos) + + return true + elseif (keys.LEAVESCREEN or keys._MOUSE_R)then + self:stopNoteAdd() + return true + end + end + + return NotesScreen.super.onInput(self, keys) +end + +function NotesScreen:onRenderFrame(dc, rect) + NotesScreen.super.onRenderFrame(self, dc, rect) + + if not dfhack.screen.inGraphicsMode() and not gui.blink_visible(500) then + return + end + + if self.is_adding_note then + local curr_pos = self.adding_note_pos or dfhack.gui.getMousePos() + if not curr_pos then + return + end + + local function get_overlay_pen(pos) + if same_xy(curr_pos, pos) then + local texpos = dfhack.textures.getTexposByHandle(green_pin[1]) + return dfhack.pen.parse{ + ch='X', + fg=COLOR_BLUE, + tile=texpos + } + end + end + + guidm.renderMapOverlay(get_overlay_pen, { + x1=curr_pos.x, + y1=curr_pos.y, + x2=curr_pos.x, + y2=curr_pos.y, + }) + end +end + function NotesScreen:onDismiss() view = nil end diff --git a/internal/journal/text_editor.lua b/internal/journal/text_editor.lua index 0b7349411..b5da3950b 100644 --- a/internal/journal/text_editor.lua +++ b/internal/journal/text_editor.lua @@ -235,14 +235,18 @@ function TextEditor:renderSubviews(dc) end function TextEditor:onInput(keys) - if (self.subviews.scrollbar.is_dragging) then - return self.subviews.scrollbar:onInput(keys) - end - if keys._MOUSE_L and self:getMousePos() then self:setFocus(true) end + if not self.focus then + return false + end + + if (self.subviews.scrollbar.is_dragging) then + return self.subviews.scrollbar:onInput(keys) + end + return TextEditor.super.onInput(self, keys) end diff --git a/internal/notes/note_manager.lua b/internal/notes/note_manager.lua index 79c76b4e7..fa0d35807 100644 --- a/internal/notes/note_manager.lua +++ b/internal/notes/note_manager.lua @@ -16,6 +16,7 @@ NoteManager.ATTRS{ } function NoteManager:init() + self.note_pos = nil local edit_mode = self.note ~= nil self:addviews{ @@ -95,8 +96,12 @@ function NoteManager:init() } end +function NoteManager:setNotePos(note_pos) + self.notes_pos = note_pos +end + function NoteManager:createNote() - local cursor_pos = guidm.getCursorPos() + local cursor_pos = self.notes_pos or guidm.getCursorPos() if cursor_pos == nil then dfhack.printerr('Enable keyboard cursor to add a note.') return @@ -145,6 +150,9 @@ function NoteManager:saveNote() self.note.point.name = name self.note.point.comment = comment + if self.notes_pos then + self.note.pos=self.notes_pos + end if self.on_update then self.on_update() diff --git a/notes.lua b/notes.lua index deef9bfad..f5a17788d 100644 --- a/notes.lua +++ b/notes.lua @@ -36,7 +36,7 @@ function NotesOverlay:overlay_onupdate() end function NotesOverlay:overlay_trigger(args) - return self:showNoteManager() + self:reloadVisibleNotes() end function NotesOverlay:onInput(keys) From 936eed6d657a2f775c4189a612b319a272d66418 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Obr=C4=99bski?= Date: Mon, 9 Sep 2024 22:18:44 +0200 Subject: [PATCH 07/18] Improve gui/notes note list navigation --- gui/notes.lua | 38 +++++++++++++++++--------------------- notes.lua | 4 ++-- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/gui/notes.lua b/gui/notes.lua index 7022b7106..3df059dd2 100644 --- a/gui/notes.lua +++ b/gui/notes.lua @@ -21,6 +21,18 @@ local green_pin = dfhack.textures.loadTileset( true ) +NotesSearchField = defclass(NotesSearchField, text_editor.TextEditor) +NotesSearchField.ATTRS {} + +function NotesSearchField:onInput(keys) + -- allow cursor up/down to be used to navigate the notes list + if keys.KEYBOARD_CURSOR_UP or keys.KEYBOARD_CURSOR_DOWN then + return false + end + + return NotesSearchField.super.onInput(self, keys) +end + NotesWindow = defclass(NotesWindow, widgets.Window) NotesWindow.ATTRS { frame_title='DF Notes', @@ -49,7 +61,7 @@ function NotesWindow:init() auto_width=true, on_activate=function() self.subviews.search:setFocus(true) end, }, - text_editor.TextEditor{ + NotesSearchField{ view_id='search', frame={l=0,h=3}, frame_style=gui.FRAME_INTERIOR, @@ -59,25 +71,10 @@ function NotesWindow:init() self.subviews.note_list:submit() end }, - widgets.Panel{ - frame={h=2}, - frame_inset={t=1}, - subviews={ - widgets.HotkeyLabel { - key='CUSTOM_ALT_L', - label='Notes', - frame={l=0,t=0}, - auto_width=true, - on_activate=function() - self.subviews.note_list:setFocus(true) - end, - }, - } - }, widgets.List{ view_id='note_list', frame={l=0,b=2}, - frame_inset={t=0}, + frame_inset={t=1}, row_height=1, on_submit=function (ind, note) self:loadNote(note) @@ -177,7 +174,7 @@ function NotesWindow:showNoteManager(note) note=note, on_update=function() self:reloadFilteredNotes() - dfhack.internal.runCommand('overlay trigger notes.map_notes') + dfhack.run_command_silent('overlay trigger notes.map_notes') end, on_dismiss=function() self.visible = true end } @@ -204,7 +201,7 @@ function NotesWindow:loadNote(note) return end - -- self.note_width_calculated = false + self:updateLayout() end function NotesWindow:postUpdateLayout() @@ -268,7 +265,6 @@ function NotesWindow:loadFilteredNotes(search_phrase, force) local sel_ind, sel_note = self.subviews.note_list:getSelected() self:loadNote(sel_note) - self:updateLayout() end) end @@ -310,7 +306,7 @@ function NotesScreen:onInput(keys) note=nil, on_update=function() self.subviews.notes_window:reloadFilteredNotes() - dfhack.internal.runCommand('overlay trigger notes.map_notes') + dfhack.run_command_silent('overlay trigger notes.map_notes') self:dismiss() end, on_dismiss=function() diff --git a/notes.lua b/notes.lua index f5a17788d..1d192f34f 100644 --- a/notes.lua +++ b/notes.lua @@ -35,7 +35,7 @@ function NotesOverlay:overlay_onupdate() self:reloadVisibleNotes() end -function NotesOverlay:overlay_trigger(args) +function NotesOverlay:overlay_trigger(cmd, title) self:reloadVisibleNotes() end @@ -164,7 +164,7 @@ local function main(args) return end - return dfhack.internal.runCommand('overlay trigger notes.map_notes') + return dfhack.run_command('overlay trigger notes.map_notes add') end end From 3100192e3f82f5c6492cb96c8690ca770b1119af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Obr=C4=99bski?= Date: Tue, 10 Sep 2024 19:38:30 +0200 Subject: [PATCH 08/18] Simplify gui/notes note text preview wrapping feature --- gui/notes.lua | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/gui/notes.lua b/gui/notes.lua index 3df059dd2..5824e7052 100644 --- a/gui/notes.lua +++ b/gui/notes.lua @@ -107,7 +107,6 @@ function NotesWindow:init() view_id='note_details', frame={l=NOTE_LIST_RESIZE_MIN.w + 1,t=0,b=0}, frame_inset=1, - autoarrange_gap=1, subviews={ widgets.Panel{ view_id="name_panel", @@ -115,11 +114,11 @@ function NotesWindow:init() frame_style=gui.FRAME_INTERIOR, frame={l=0,r=0,t=0,h=4}, frame_inset={l=1,r=1}, - auto_height=true, subviews={ - widgets.Label{ + widgets.WrappedLabel{ view_id='name', - frame={t=0,l=0,r=0} + auto_height=false, + frame={l=0,r=0,t=0,b=0}, }, }, }, @@ -130,9 +129,10 @@ function NotesWindow:init() frame={l=0,r=0,t=4,b=2}, frame_inset={l=1,r=1,t=1}, subviews={ - widgets.Label{ + widgets.WrappedLabel{ view_id='comment', - frame={t=0,l=0,r=0} + auto_height=false, + frame={l=0,r=0,t=0,b=0}, }, } }, @@ -201,21 +201,9 @@ function NotesWindow:loadNote(note) return end - self:updateLayout() -end - -function NotesWindow:postUpdateLayout() - if self.selected_note == nil then - return - end - local note_details_frame = self.subviews.name_panel.frame_body - - local note_width = self.subviews.name_panel.frame_body.width - local wrapped_name = self.selected_note.point.name:wrap(note_width) - local wrapped_comment = self.selected_note.point.comment:wrap(note_width) + self.subviews.name.text_to_wrap = self.selected_note.point.name + self.subviews.comment.text_to_wrap = self.selected_note.point.comment - self.subviews.name:setText(wrapped_name) - self.subviews.comment:setText(wrapped_comment) self.subviews.note_details:updateLayout() end From f3b128d1d5ae5ad55c3d8fc13a51181d5468445c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Obr=C4=99bski?= Date: Tue, 10 Sep 2024 19:44:25 +0200 Subject: [PATCH 09/18] Fix gui/notes issue with initial loading of selected note --- gui/notes.lua | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/gui/notes.lua b/gui/notes.lua index 5824e7052..f04cf5cbe 100644 --- a/gui/notes.lua +++ b/gui/notes.lua @@ -45,6 +45,7 @@ NotesWindow.ATTRS { function NotesWindow:init() self.selected_note = nil self.note_manager = nil + self.curr_search_phrase = nil self:addviews{ widgets.Panel{ @@ -161,8 +162,12 @@ function NotesWindow:init() } } } +end - self:loadFilteredNotes('', true) +function NotesWindow:postUpdateLayout() + if self.curr_search_phrase == nil then + self:loadFilteredNotes('', true) + end end function NotesWindow:showNoteManager(note) From 98220c06ffec1ae23d9f930f7a306e40a8a69cd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Obr=C4=99bski?= Date: Tue, 10 Sep 2024 19:51:28 +0200 Subject: [PATCH 10/18] Restore way to add notes by `notes add` command --- internal/notes/note_manager.lua | 1 + notes.lua | 10 +++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/internal/notes/note_manager.lua b/internal/notes/note_manager.lua index fa0d35807..8d33bcc16 100644 --- a/internal/notes/note_manager.lua +++ b/internal/notes/note_manager.lua @@ -2,6 +2,7 @@ local gui = require('gui') local widgets = require('gui.widgets') +local guidm = require('gui.dwarfmode') local text_editor = reqscript('internal/journal/text_editor') local waypoints = df.global.plotinfo.waypoints diff --git a/notes.lua b/notes.lua index 1d192f34f..c4c9e78b3 100644 --- a/notes.lua +++ b/notes.lua @@ -35,8 +35,12 @@ function NotesOverlay:overlay_onupdate() self:reloadVisibleNotes() end -function NotesOverlay:overlay_trigger(cmd, title) - self:reloadVisibleNotes() +function NotesOverlay:overlay_trigger(cmd) + if cmd == 'add' then + self:showNoteManager() + else + self:reloadVisibleNotes() + end end function NotesOverlay:onInput(keys) @@ -164,7 +168,7 @@ local function main(args) return end - return dfhack.run_command('overlay trigger notes.map_notes add') + return dfhack.run_command_silent('overlay trigger notes.map_notes add') end end From 01fe42c1cac175cddd642522ba464b59b7420913 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Obr=C4=99bski?= Date: Tue, 10 Sep 2024 20:03:39 +0200 Subject: [PATCH 11/18] Add basic documentation for `gui/notes` tool --- docs/gui/notes.rst | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 docs/gui/notes.rst diff --git a/docs/gui/notes.rst b/docs/gui/notes.rst new file mode 100644 index 000000000..d10b5b6d5 --- /dev/null +++ b/docs/gui/notes.rst @@ -0,0 +1,33 @@ +gui/notes +========= + +.. dfhack-tool:: + :summary: Interactive panel for managing map-specific notes. + :tags: fort interface map + +The `gui/notes` tool provides a comprehensive interface for interacting +with map-specific notes. It is designed to streamline the process +of note management in Dwarf Fortress, making it simpler +and more intuitive to keep track of important map-specific information. + +This tool builds upon the functionality of the `notes` tool, +enhancing it by providing a user-friendly panel for easier management +and visibility of notes across the Dwarf Fortress game map. + +Usage +----- + +:: + + gui/notes + +Launch the notes management panel. + +Supported Features +------------------ + +- Interactive Panel: Manage all aspects of notes through a centralized graphical interface. +- Search (:kbd:`Alt` + :kbd:`S`): Quickly find notes +- Direct Map Interaction (:kbd:`Alt` + :kbd:`N`): Add new notes by clicking on the map. +- Edit (:kbd:`Alt` + :kbd:`U`): Easily modify existing notes. +- Delete (:kbd:`Alt` + :kbd:`D`): Easily remove existing notes. From 5ff4e50b70f189f79aac2fab214a2dd06e6d72e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Obr=C4=99bski?= Date: Tue, 10 Sep 2024 20:40:23 +0200 Subject: [PATCH 12/18] Auto enable notes overlay when `gui/notes` is visible --- gui/notes.lua | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/gui/notes.lua b/gui/notes.lua index f04cf5cbe..d6354ac1e 100644 --- a/gui/notes.lua +++ b/gui/notes.lua @@ -5,6 +5,7 @@ local gui = require 'gui' local widgets = require 'gui.widgets' local guidm = require('gui.dwarfmode') local script = require 'gui.script' +local overlay = require 'plugins.overlay' local text_editor = reqscript('internal/journal/text_editor') local note_manager = reqscript('internal/notes/note_manager') @@ -13,6 +14,7 @@ local map_points = df.global.plotinfo.waypoints.points local NOTE_LIST_RESIZE_MIN = {w=26} local RESIZE_MIN = {w=65, h=30} local NOTE_SEARCH_BATCH_SIZE = 25 +local OVERLAY_NAME = 'notes.map_notes' local green_pin = dfhack.textures.loadTileset( 'hack/data/art/note_green_pin_map.png', @@ -351,7 +353,17 @@ function NotesScreen:onRenderFrame(dc, rect) end end +function NotesScreen:onAboutToShow() + if not overlay.get_state().config[OVERLAY_NAME].enabled then + self.should_disable_overlay = true + overlay.overlay_command({'enable', 'notes.map_notes'}) + end +end + function NotesScreen:onDismiss() + if self.should_disable_overlay then + overlay.overlay_command({'disable', 'notes.map_notes'}) + end view = nil end From 8ad4fa10b8f0b129dde67a97ef58201025411450 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Obr=C4=99bski?= Date: Thu, 19 Sep 2024 07:34:26 +0200 Subject: [PATCH 13/18] Polishing gui notes --- gui/notes.lua | 7 +++++-- internal/notes/note_manager.lua | 1 - 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/gui/notes.lua b/gui/notes.lua index d6354ac1e..b0c263e12 100644 --- a/gui/notes.lua +++ b/gui/notes.lua @@ -79,6 +79,9 @@ function NotesWindow:init() frame={l=0,b=2}, frame_inset={t=1}, row_height=1, + on_select=function (ind, note) + self:loadNote(note) + end, on_submit=function (ind, note) self:loadNote(note) dfhack.gui.pauseRecenter(note.point.pos) @@ -300,9 +303,9 @@ function NotesScreen:onInput(keys) local manager = note_manager.NoteManager{ note=nil, on_update=function() - self.subviews.notes_window:reloadFilteredNotes() dfhack.run_command_silent('overlay trigger notes.map_notes') - self:dismiss() + self.subviews.notes_window:reloadFilteredNotes() + self:stopNoteAdd() end, on_dismiss=function() self:stopNoteAdd() diff --git a/internal/notes/note_manager.lua b/internal/notes/note_manager.lua index 8d33bcc16..5affb69b6 100644 --- a/internal/notes/note_manager.lua +++ b/internal/notes/note_manager.lua @@ -54,7 +54,6 @@ function NoteManager:init() frame={t=6,b=3}, frame_style=gui.FRAME_INTERIOR, init_text=self.note and self.note.point.comment or '', - -- init_cursor=1 }, widgets.Panel{ view_id='buttons', From 5742e4e4d3209a174061d6b4aea653887efe2a99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Obr=C4=99bski?= Date: Thu, 19 Sep 2024 19:01:57 +0200 Subject: [PATCH 14/18] Improve gui/notes and gui/journal keyboard control --- docs/gui/journal.rst | 4 ++-- docs/notes.rst | 2 +- gui/notes.lua | 16 +++++---------- internal/journal/text_editor.lua | 6 +++--- internal/notes/note_manager.lua | 6 +++--- test/gui/journal.lua | 34 ++++++++++++++++---------------- 6 files changed, 31 insertions(+), 37 deletions(-) diff --git a/docs/gui/journal.rst b/docs/gui/journal.rst index d6004ec95..0063ff63a 100644 --- a/docs/gui/journal.rst +++ b/docs/gui/journal.rst @@ -26,8 +26,8 @@ Supported Features - New Lines: Easily insert new lines using the :kbd:`Enter` key, supporting multiline text input. - Text Wrapping: Text automatically wraps within the editor, ensuring lines fit within the display without manual adjustments. - Backspace Support: Use the backspace key to delete characters to the left of the cursor. -- Delete Character: :kbd:`Ctrl` + :kbd:`D` deletes the character under the cursor. -- Line Navigation: :kbd:`Ctrl` + :kbd:`H` (like "Home") moves the cursor to the beginning of the current line, and :kbd:`Ctrl` + :kbd:`E` (like "End") moves it to the end. +- Delete Character: :kbd:`Delete` deletes the character under the cursor. +- Line Navigation: :kbd:`Home` moves the cursor to the beginning of the current line, and :kbd:`End` moves it to the end. - Delete Current Line: :kbd:`Ctrl` + :kbd:`U` deletes the entire current line where the cursor is located. - Delete Rest of Line: :kbd:`Ctrl` + :kbd:`K` deletes text from the cursor to the end of the line. - Delete Last Word: :kbd:`Ctrl` + :kbd:`W` removes the word immediately before the cursor. diff --git a/docs/notes.rst b/docs/notes.rst index faed2c8fb..19e169428 100644 --- a/docs/notes.rst +++ b/docs/notes.rst @@ -29,7 +29,7 @@ Creating a Note 1. Use the keyboard cursor to select the desired map tile where you want to place a note. 2. Execute ``notes add`` via the DFHack console. 3. In the pop-up dialog, fill in the note's title and detailed comment. -4. Press :kbd:`Alt` + :kbd:`S` to create the note. +4. Press :kbd:`Ctrl` + :kbd:`S` to create the note. Editing or Deleting a Note -------------------------- diff --git a/gui/notes.lua b/gui/notes.lua index b0c263e12..b649356f0 100644 --- a/gui/notes.lua +++ b/gui/notes.lua @@ -57,13 +57,6 @@ function NotesWindow:init() frame_inset={l=1,t=1,b=1,r=1}, autoarrange_subviews=true, subviews={ - widgets.HotkeyLabel { - key='CUSTOM_ALT_S', - label='Search', - frame={l=0}, - auto_width=true, - on_activate=function() self.subviews.search:setFocus(true) end, - }, NotesSearchField{ view_id='search', frame={l=0,h=3}, @@ -94,7 +87,7 @@ function NotesWindow:init() frame={l=1,b=1,h=1}, auto_width=true, label='New note', - key='CUSTOM_ALT_N', + key='CUSTOM_CTRL_N', visible=edit_mode, on_activate=function() if self.on_note_add then @@ -151,7 +144,7 @@ function NotesWindow:init() frame={l=0,t=0,h=1}, auto_width=true, label='Edit', - key='CUSTOM_ALT_U', + key='CUSTOM_CTRL_E', on_activate=function() self:showNoteManager(self.selected_note) end, }, widgets.HotkeyLabel{ @@ -159,7 +152,7 @@ function NotesWindow:init() frame={r=0,t=0,h=1}, auto_width=true, label='Delete', - key='CUSTOM_ALT_D', + key='CUSTOM_CTRL_D', on_activate=function() self:deleteNote(self.selected_note) end, }, } @@ -357,7 +350,8 @@ function NotesScreen:onRenderFrame(dc, rect) end function NotesScreen:onAboutToShow() - if not overlay.get_state().config[OVERLAY_NAME].enabled then + local notes_overlay = overlay.get_state().config[OVERLAY_NAME] + if notes_overlay and not notes_overlay.enabled then self.should_disable_overlay = true overlay.overlay_command({'enable', 'notes.map_notes'}) end diff --git a/internal/journal/text_editor.lua b/internal/journal/text_editor.lua index b5da3950b..abbca900e 100644 --- a/internal/journal/text_editor.lua +++ b/internal/journal/text_editor.lua @@ -786,13 +786,13 @@ function TextEditorView:onCursorInput(keys) local word_end = self:wordEndOffset() self:setCursor(word_end) return true - elseif keys.CUSTOM_CTRL_H then + elseif keys.CUSTOM_HOME then -- line start self:setCursor( self:lineStartOffset() ) return true - elseif keys.CUSTOM_CTRL_E then + elseif keys.CUSTOM_END then -- line end self:setCursor( self:lineEndOffset() @@ -890,7 +890,7 @@ function TextEditorView:onTextManipulationInput(keys) self:eraseSelection() return true - elseif keys.CUSTOM_CTRL_D then + elseif keys.CUSTOM_DELETE then -- delete char, there is no support for `Delete` key self.history:store(HISTORY_ENTRY.DELETE, self.text, self.cursor) diff --git a/internal/notes/note_manager.lua b/internal/notes/note_manager.lua index 5affb69b6..b7a8d8059 100644 --- a/internal/notes/note_manager.lua +++ b/internal/notes/note_manager.lua @@ -65,7 +65,7 @@ function NoteManager:init() frame={l=0,t=0,h=1}, auto_width=true, label='Save', - key='CUSTOM_ALT_S', + key='CUSTOM_CTRL_S', visible=edit_mode, on_activate=function() self:saveNote() end, enabled=function() return #self.subviews.name:getText() > 0 end, @@ -75,7 +75,7 @@ function NoteManager:init() frame={l=0,t=0,h=1}, auto_width=true, label='Create', - key='CUSTOM_ALT_S', + key='CUSTOM_CTRL_S', visible=not edit_mode, on_activate=function() self:createNote() end, enabled=function() return #self.subviews.name:getText() > 0 end, @@ -85,7 +85,7 @@ function NoteManager:init() frame={r=0,t=0,h=1}, auto_width=true, label='Delete', - key='CUSTOM_ALT_D', + key='CUSTOM_CTRL_D', visible=edit_mode, on_activate=function() self:deleteNote() end, }, diff --git a/test/gui/journal.lua b/test/gui/journal.lua index d845aef20..d86e415d1 100644 --- a/test/gui/journal.lua +++ b/test/gui/journal.lua @@ -772,7 +772,7 @@ function test.handle_delete() text_area:setCursor(1) journal:onRender() - simulate_input_keys('CUSTOM_CTRL_D') + simulate_input_keys('CUSTOM_DELETE') expect.eq(read_rendered_text(text_area), table.concat({ '_: Lorem ipsum dolor sit amet, consectetur adipiscing elit.', @@ -783,7 +783,7 @@ function test.handle_delete() text_area:setCursor(124) journal:onRender() - simulate_input_keys('CUSTOM_CTRL_D') + simulate_input_keys('CUSTOM_DELETE') expect.eq(read_rendered_text(text_area), table.concat({ '0: Lorem ipsum dolor sit amet, consectetur adipiscing elit.', @@ -794,7 +794,7 @@ function test.handle_delete() text_area:setCursor(123) journal:onRender() - simulate_input_keys('CUSTOM_CTRL_D') + simulate_input_keys('CUSTOM_DELETE') expect.eq(read_rendered_text(text_area), table.concat({ '0: Lorem ipsum dolor sit amet, consectetur adipiscing elit.', @@ -805,7 +805,7 @@ function test.handle_delete() text_area:setCursor(171) journal:onRender() - simulate_input_keys('CUSTOM_CTRL_D') + simulate_input_keys('CUSTOM_DELETE') expect.eq(read_rendered_text(text_area), table.concat({ '0: Lorem ipsum dolor sit amet, consectetur adipiscing elit.', @@ -815,7 +815,7 @@ function test.handle_delete() }, '\n')); for i=1,59 do - simulate_input_keys('CUSTOM_CTRL_D') + simulate_input_keys('CUSTOM_DELETE') end expect.eq(read_rendered_text(text_area), table.concat({ @@ -824,7 +824,7 @@ function test.handle_delete() 'nibhorttitor mi, vitae rutrum eros metus nec libero._', }, '\n')); - simulate_input_keys('CUSTOM_CTRL_D') + simulate_input_keys('CUSTOM_DELETE') expect.eq(read_rendered_text(text_area), table.concat({ '0: Lorem ipsum dolor sit amet, consectetur adipiscing elit.', @@ -849,7 +849,7 @@ function test.line_end() text_area:setCursor(1) journal:onRender() - simulate_input_keys('CUSTOM_CTRL_E') + simulate_input_keys('CUSTOM_END') expect.eq(read_rendered_text(text_area), table.concat({ '60: Lorem ipsum dolor sit amet, consectetur adipiscing elit._', @@ -861,7 +861,7 @@ function test.line_end() text_area:setCursor(70) journal:onRender() - simulate_input_keys('CUSTOM_CTRL_E') + simulate_input_keys('CUSTOM_END') expect.eq(read_rendered_text(text_area), table.concat({ '60: Lorem ipsum dolor sit amet, consectetur adipiscing elit.', @@ -873,7 +873,7 @@ function test.line_end() text_area:setCursor(200) journal:onRender() - simulate_input_keys('CUSTOM_CTRL_E') + simulate_input_keys('CUSTOM_END') expect.eq(read_rendered_text(text_area), table.concat({ '60: Lorem ipsum dolor sit amet, consectetur adipiscing elit.', @@ -882,7 +882,7 @@ function test.line_end() '60: Lorem ipsum dolor sit amet, consectetur adipiscing elit._', }, '\n')); - simulate_input_keys('CUSTOM_CTRL_E') + simulate_input_keys('CUSTOM_END') expect.eq(read_rendered_text(text_area), table.concat({ '60: Lorem ipsum dolor sit amet, consectetur adipiscing elit.', @@ -905,7 +905,7 @@ function test.line_beging() simulate_input_text(text) - simulate_input_keys('CUSTOM_CTRL_H') + simulate_input_keys('CUSTOM_HOME') expect.eq(read_rendered_text(text_area), table.concat({ '60: Lorem ipsum dolor sit amet, consectetur adipiscing elit.', @@ -917,7 +917,7 @@ function test.line_beging() text_area:setCursor(173) journal:onRender() - simulate_input_keys('CUSTOM_CTRL_H') + simulate_input_keys('CUSTOM_HOME') expect.eq(read_rendered_text(text_area), table.concat({ '60: Lorem ipsum dolor sit amet, consectetur adipiscing elit.', @@ -929,7 +929,7 @@ function test.line_beging() text_area:setCursor(1) journal:onRender() - simulate_input_keys('CUSTOM_CTRL_H') + simulate_input_keys('CUSTOM_HOME') expect.eq(read_rendered_text(text_area), table.concat({ '_0: Lorem ipsum dolor sit amet, consectetur adipiscing elit.', @@ -1355,10 +1355,10 @@ function test.line_navigation_reset_selection() 'porttitor mi, vitae rutrum eros metus nec libero.', }, '\n')); - simulate_input_keys('CUSTOM_CTRL_H') + simulate_input_keys('CUSTOM_HOME') expect.eq(read_selected_text(text_area), '') - simulate_input_keys('CUSTOM_CTRL_E') + simulate_input_keys('CUSTOM_END') expect.eq(read_selected_text(text_area), '') journal:dismiss() @@ -1496,7 +1496,7 @@ function test.delete_char_delete_selection() 'porttitor mi, vitae rutrum ero', }, '\n')); - simulate_input_keys('CUSTOM_CTRL_D') + simulate_input_keys('CUSTOM_DELETE') expect.eq(read_rendered_text(text_area), table.concat({ '60: _ metus nec libero.', @@ -2236,7 +2236,7 @@ function test.restore_text_between_sessions() local journal, text_area = arrange_empty_journal({w=80,save_on_change=true}) simulate_input_keys('CUSTOM_CTRL_A') - simulate_input_keys('CUSTOM_CTRL_D') + simulate_input_keys('CUSTOM_DELETE') local text = table.concat({ '60: Lorem ipsum dolor sit amet, consectetur adipiscing elit.', From 9f33bebf3a8f9943df86d6b933d3c6c2eef40d6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Obr=C4=99bski?= Date: Thu, 19 Sep 2024 19:11:44 +0200 Subject: [PATCH 15/18] Disable up/down control in text field in one-line-mode --- gui/notes.lua | 14 +------------- internal/journal/text_editor.lua | 7 +++++++ 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/gui/notes.lua b/gui/notes.lua index b649356f0..9ec7234fe 100644 --- a/gui/notes.lua +++ b/gui/notes.lua @@ -23,18 +23,6 @@ local green_pin = dfhack.textures.loadTileset( true ) -NotesSearchField = defclass(NotesSearchField, text_editor.TextEditor) -NotesSearchField.ATTRS {} - -function NotesSearchField:onInput(keys) - -- allow cursor up/down to be used to navigate the notes list - if keys.KEYBOARD_CURSOR_UP or keys.KEYBOARD_CURSOR_DOWN then - return false - end - - return NotesSearchField.super.onInput(self, keys) -end - NotesWindow = defclass(NotesWindow, widgets.Window) NotesWindow.ATTRS { frame_title='DF Notes', @@ -57,7 +45,7 @@ function NotesWindow:init() frame_inset={l=1,t=1,b=1,r=1}, autoarrange_subviews=true, subviews={ - NotesSearchField{ + text_editor.TextEditor{ view_id='search', frame={l=0,h=3}, frame_style=gui.FRAME_INTERIOR, diff --git a/internal/journal/text_editor.lua b/internal/journal/text_editor.lua index abbca900e..e7164c463 100644 --- a/internal/journal/text_editor.lua +++ b/internal/journal/text_editor.lua @@ -752,6 +752,9 @@ function TextEditorView:onCursorInput(keys) self:setCursor(self.cursor + 1) return true elseif keys.KEYBOARD_CURSOR_UP then + if self.one_line_mode then + return false + end local x, y = self.wrapped_text:indexToCoords(self.cursor) local last_cursor_x = self.last_cursor_x or x local offset = y > 1 and @@ -761,6 +764,10 @@ function TextEditorView:onCursorInput(keys) self.last_cursor_x = last_cursor_x return true elseif keys.KEYBOARD_CURSOR_DOWN then + if self.one_line_mode then + return false + end + local x, y = self.wrapped_text:indexToCoords(self.cursor) local last_cursor_x = self.last_cursor_x or x local offset = y < #self.wrapped_text.lines and From 1998f766b13b122295b454fb7aa9a89dca7c57bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Obr=C4=99bski?= Date: Thu, 19 Sep 2024 20:53:23 +0200 Subject: [PATCH 16/18] Migrate note manager confirmation to ctrl+enter --- docs/notes.rst | 2 +- internal/notes/note_manager.lua | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/notes.rst b/docs/notes.rst index 19e169428..a67e05b37 100644 --- a/docs/notes.rst +++ b/docs/notes.rst @@ -29,7 +29,7 @@ Creating a Note 1. Use the keyboard cursor to select the desired map tile where you want to place a note. 2. Execute ``notes add`` via the DFHack console. 3. In the pop-up dialog, fill in the note's title and detailed comment. -4. Press :kbd:`Ctrl` + :kbd:`S` to create the note. +4. Press :kbd:`Ctrl` + :kbd:`Enter` to create the note. Editing or Deleting a Note -------------------------- diff --git a/internal/notes/note_manager.lua b/internal/notes/note_manager.lua index b7a8d8059..9df64d969 100644 --- a/internal/notes/note_manager.lua +++ b/internal/notes/note_manager.lua @@ -65,7 +65,7 @@ function NoteManager:init() frame={l=0,t=0,h=1}, auto_width=true, label='Save', - key='CUSTOM_CTRL_S', + key='CUSTOM_CTRL_ENTER', visible=edit_mode, on_activate=function() self:saveNote() end, enabled=function() return #self.subviews.name:getText() > 0 end, @@ -75,7 +75,7 @@ function NoteManager:init() frame={l=0,t=0,h=1}, auto_width=true, label='Create', - key='CUSTOM_CTRL_S', + key='CUSTOM_CTRL_ENTER', visible=not edit_mode, on_activate=function() self:createNote() end, enabled=function() return #self.subviews.name:getText() > 0 end, From aff2ab8a87300c1d1e0f1375b26e7e0f345632a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Obr=C4=99bski?= Date: Thu, 19 Sep 2024 20:53:58 +0200 Subject: [PATCH 17/18] Make `gui/notes` respect the global search settings --- gui/notes.lua | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/gui/notes.lua b/gui/notes.lua index 9ec7234fe..09e731924 100644 --- a/gui/notes.lua +++ b/gui/notes.lua @@ -3,9 +3,11 @@ local gui = require 'gui' local widgets = require 'gui.widgets' -local guidm = require('gui.dwarfmode') +local guidm = require 'gui.dwarfmode' local script = require 'gui.script' local overlay = require 'plugins.overlay' +local utils = require 'utils' + local text_editor = reqscript('internal/journal/text_editor') local note_manager = reqscript('internal/notes/note_manager') @@ -228,10 +230,9 @@ function NotesWindow:loadFilteredNotes(search_phrase, force) return end - local point_name_lowercase = map_point.name:lower() if ( - point_name_lowercase ~= nil and #point_name_lowercase > 0 and - point_name_lowercase:find(search_phrase) + #map_point.name > 0 and + utils.search_text(map_point.name, search_phrase) ) then table.insert(choices, { text=map_point.name, From 76c70e780e1d29608c1b2ee9a5f27c8abe2f792a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Obr=C4=99bski?= Date: Fri, 20 Sep 2024 19:28:43 +0200 Subject: [PATCH 18/18] Make gui/notes search for any length of search text --- gui/notes.lua | 3 --- 1 file changed, 3 deletions(-) diff --git a/gui/notes.lua b/gui/notes.lua index 09e731924..309130f97 100644 --- a/gui/notes.lua +++ b/gui/notes.lua @@ -208,9 +208,6 @@ function NotesWindow:loadFilteredNotes(search_phrase, force) local full_list_loaded = self.curr_search_phrase == '' search_phrase = search_phrase:lower() - if #search_phrase < 3 then - search_phrase = '' - end self.curr_search_phrase = search_phrase