diff --git a/docs/gui/journal.rst b/docs/gui/journal.rst index a13bda3e67..0063ff63ad 100644 --- a/docs/gui/journal.rst +++ b/docs/gui/journal.rst @@ -8,68 +8,47 @@ gui/journal The `gui/journal` interface makes it easy to take notes and document important details for the fortresses. -With this multi-line text editor, you can keep track of your fortress's -background story, goals, notable events, and both short- and long-term plans. +With this multi-line text editor, +you can keep track of your fortress's background story, goals, notable events, +and both short-term and long-term plans. This is particularly useful when you need to take a longer break from the game. -Having detailed notes makes it much easier to resume your game after a few -weeks or months without losing track of your progress and objectives. +Having detailed notes makes it much easier to resume your game after +a few weeks or months, without losing track of your progress and objectives. Supported Features ------------------ -- Cursor Control: Navigate through text using arrow keys (Left, Right, Up, - and Down) for precise cursor placement. -- Fast Rewind: Use :kbd:`Ctrl` + :kbd:`Left` and :kbd:`Ctrl` + :kbd:`Right` to - move the cursor one word back or forward. -- Longest X Position Memory: The cursor remembers the longest x position when - moving up or down, making vertical navigation more intuitive. -- Mouse Control: Use the mouse to position the cursor within the text, - providing an alternative to keyboard navigation. -- 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. +- Cursor Control: Navigate through text using arrow keys (left, right, up, down) for precise cursor placement. +- Fast Rewind: Use :kbd:`Ctrl` + :kbd:`Left` / :kbd:`Ctrl` + :kbd:`B` and :kbd:`Ctrl` + :kbd:`Right` / :kbd:`Ctrl` + :kbd:`F` to move the cursor one word back or forward. +- Longest X Position Memory: The cursor remembers the longest x position when moving up or down, making vertical navigation more intuitive. +- Mouse Control: Use the mouse to position the cursor within the text, providing an alternative to keyboard navigation. +- 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:`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. -- Text Selection: Select text with the mouse, with support for replacing or - removing selected text. -- Jump to Beginning/End: Quickly move the cursor to the beginning or end of the - text using :kbd:`Ctrl` + :kbd:`Home` and :kbd:`Ctrl` + :kbd:`End`. -- Select Word/Line: Use double click to select current word, or triple click to - select current line +- 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. +- Text Selection: Select text with the mouse, with support for replacing or removing selected text. +- Jump to Beginning/End: Quickly move the cursor to the beginning or end of the text using :kbd:`Shift` + :kbd:`Up` and :kbd:`Shift` + :kbd:`Down`. +- Select Word/Line: Use double click to select current word, or triple click to select current line - Select All: Select entire text by :kbd:`Ctrl` + :kbd:`A` -- Undo/Redo: Undo/Redo changes by :kbd:`Ctrl` + :kbd:`Z` / :kbd:`Ctrl` + - :kbd:`Y` -- Clipboard Operations: Perform OS clipboard cut, copy, and paste operations on - selected text, allowing you to paste the copied content into other - applications. +- Undo/Redo: Undo/Redo changes by :kbd:`Ctrl` + :kbd:`Z` / :kbd:`Ctrl` + :kbd:`Y` +- Clipboard Operations: Perform OS clipboard cut, copy, and paste operations on selected text, allowing you to paste the copied content into other applications. - Copy Text: Use :kbd:`Ctrl` + :kbd:`C` to copy selected text. - - copy selected text, if available - - If no text is selected it copy the entire current line, including the - terminating newline if present. + - copy selected text, if available + - If no text is selected it copy the entire current line, including the terminating newline if present. - Cut Text: Use :kbd:`Ctrl` + :kbd:`X` to cut selected text. - - cut selected text, if available - - If no text is selected it will cut the entire current line, including the - terminating newline if present -- Paste Text: Use :kbd:`Ctrl` + :kbd:`V` to paste text from the clipboard into - the editor. - - replace selected text, if available - - If no text is selected, paste text in the cursor position + - cut selected text, if available + - If no text is selected it will cut the entire current line, including the terminating newline if present +- Paste Text: Use :kbd:`Ctrl` + :kbd:`V` to paste text from the clipboard into the editor. + - replace selected text, if available + - If no text is selected, paste text in the cursor position - Scrolling behaviour for long text build-in -- Table of contents (:kbd:`Ctrl` + :kbd:`O`), with headers line prefixed by - ``#``, e.g. ``# Fort history``, ``## Year 1`` -- Table of contents navigation: jump to previous/next section by :kbd:`Ctrl` + - :kbd:`Up` / :kbd:`Ctrl` + :kbd:`Down` +- Table of contents (:kbd:`Ctrl` + :kbd:`O`), with headers line prefixed by '#', e.g. '# Fort history', '## Year 1' +- Table of contents navigation: jump to previous/next section by :kbd:`Ctrl` + :kbd:`Up` / :kbd:`Ctrl` + :kbd:`Down` Usage ----- diff --git a/docs/gui/notes.rst b/docs/gui/notes.rst new file mode 100644 index 0000000000..d10b5b6d57 --- /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. diff --git a/docs/notes.rst b/docs/notes.rst index faed2c8fbf..a67e05b37c 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:`Enter` to create the note. Editing or Deleting a Note -------------------------- diff --git a/gui/notes.lua b/gui/notes.lua new file mode 100644 index 0000000000..358af1de6c --- /dev/null +++ b/gui/notes.lua @@ -0,0 +1,363 @@ +-- Map notes +--@ module = true + +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 utils = require 'utils' + +local note_manager = reqscript('internal/notes/note_manager') + +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', + 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() + self.selected_note = nil + self.note_manager = nil + self.curr_search_phrase = nil + + 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.TextArea{ + view_id='search', + frame={l=0,h=3}, + frame_style=gui.FRAME_INTERIOR, + one_line_mode=true, + on_text_change=self:callback('loadFilteredNotes'), + on_submit=function() + self.subviews.note_list:submit() + end + }, + widgets.List{ + view_id='note_list', + 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) + end + }, + }, + }, + widgets.HotkeyLabel{ + view_id='create', + frame={l=1,b=1,h=1}, + auto_width=true, + label='New note', + key='CUSTOM_CTRL_N', + visible=edit_mode, + on_activate=function() + if self.on_note_add then + self:on_note_add() + end + end, + }, + widgets.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, + }, + widgets.Panel{ + view_id='note_details', + frame={l=NOTE_LIST_RESIZE_MIN.w + 1,t=0,b=0}, + frame_inset=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}, + subviews={ + widgets.WrappedLabel{ + view_id='name', + auto_height=false, + frame={l=0,r=0,t=0,b=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.WrappedLabel{ + view_id='comment', + auto_height=false, + frame={l=0,r=0,t=0,b=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_CTRL_E', + on_activate=function() self:showNoteManager(self.selected_note) end, + }, + widgets.HotkeyLabel{ + view_id='delete', + frame={r=0,t=0,h=1}, + auto_width=true, + label='Delete', + key='CUSTOM_CTRL_D', + on_activate=function() self:deleteNote(self.selected_note) end, + }, + } + } + } + } + } +end + +function NotesWindow:postUpdateLayout() + if self.curr_search_phrase == nil then + self:loadFilteredNotes('', true) + end +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_update=function() + self:reloadFilteredNotes() + dfhack.run_command_silent('overlay trigger notes.map_notes') + end, + 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:reloadFilteredNotes() +end + +function NotesWindow:loadNote(note) + self.selected_note = note + + if note == nil then + return + end + + self.subviews.name.text_to_wrap = self.selected_note.point.name + self.subviews.comment.text_to_wrap = self.selected_note.point.comment + + self.subviews.note_details:updateLayout() +end + +function NotesWindow:reloadFilteredNotes() + self:loadFilteredNotes(self.curr_search_phrase, true) +end + +function NotesWindow:loadFilteredNotes(search_phrase, force) + local full_list_loaded = self.curr_search_phrase == '' + + search_phrase = search_phrase:lower() + + self.curr_search_phrase = search_phrase + + script.start(function () + if #search_phrase == 0 and full_list_loaded and not force 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 ( + #map_point.name > 0 and + utils.search_text(map_point.name, search_phrase) + ) then + table.insert(choices, { + text=map_point.name, + point=map_point + }) + end + end + + self.subviews.note_list:setChoices(choices) + + local sel_ind, sel_note = self.subviews.note_list:getSelected() + self:loadNote(sel_note) + 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() + dfhack.run_command_silent('overlay trigger notes.map_notes') + self.subviews.notes_window:reloadFilteredNotes() + self:stopNoteAdd() + 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:onAboutToShow() + 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 +end + +function NotesScreen:onDismiss() + if self.should_disable_overlay then + overlay.overlay_command({'disable', 'notes.map_notes'}) + end + 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 diff --git a/internal/notes/note_manager.lua b/internal/notes/note_manager.lua new file mode 100644 index 0000000000..6ba76555be --- /dev/null +++ b/internal/notes/note_manager.lua @@ -0,0 +1,188 @@ +--@ module = true + +local gui = require('gui') +local widgets = require('gui.widgets') +local guidm = require('gui.dwarfmode') + +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() + self.note_pos = nil + 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, + }, + widgets.TextArea{ + 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, + }, + widgets.TextArea{ + view_id='comment', + frame={t=6,b=3}, + frame_style=gui.FRAME_INTERIOR, + init_text=self.note and self.note.point.comment or '', + }, + 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_CTRL_ENTER', + 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_CTRL_ENTER', + 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_CTRL_D', + visible=edit_mode, + on_activate=function() self:deleteNote() end, + }, + } + } + }, + }, + } +end + +function NoteManager:setNotePos(note_pos) + self.notes_pos = note_pos +end + +function NoteManager:createNote() + local cursor_pos = self.notes_pos or 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.notes_pos then + self.note.pos=self.notes_pos + end + + 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 9bb4bc7bce..f9cd2a854c 100644 --- a/notes.lua +++ b/notes.lua @@ -1,10 +1,8 @@ --@ module = true -local gui = require('gui') -local widgets = require('gui.widgets') -local textures = require('gui.textures') local overlay = require('plugins.overlay') local guidm = require('gui.dwarfmode') +local note_manager = reqscript('internal/notes/note_manager') local green_pin = dfhack.textures.loadTileset( 'hack/data/art/note_green_pin_map.png', @@ -21,7 +19,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() @@ -35,8 +32,12 @@ function NotesOverlay:overlay_onupdate() self:reloadVisibleNotes() end -function NotesOverlay:overlay_trigger(args) - return self:showNoteManager() +function NotesOverlay:overlay_trigger(cmd) + if cmd == 'add' then + self:showNoteManager() + else + self:reloadVisibleNotes() + end end function NotesOverlay:onInput(keys) @@ -87,7 +88,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 } @@ -147,174 +148,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, - }, - widgets.TextArea{ - 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, - }, - widgets.TextArea{ - 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, - } or nil, - } - } - }, - }, - } -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 @@ -332,7 +165,7 @@ local function main(args) return end - return dfhack.internal.runCommand('overlay trigger notes.map_notes') + return dfhack.run_command_silent('overlay trigger notes.map_notes add') end end diff --git a/test/gui/journal.lua b/test/gui/journal.lua index d7f0ad4daf..19975a7379 100644 --- a/test/gui/journal.lua +++ b/test/gui/journal.lua @@ -530,11 +530,6 @@ function test.table_of_contents_selection_follows_cursor() journal:dismiss() end -if df_major_version < 51 then - -- temporary ignore test features that base on newest API of the DF game - return -end - function test.table_of_contents_keyboard_navigation() local journal, text_area = arrange_empty_journal({ w=100, @@ -623,6 +618,3 @@ function test.show_tutorials_on_first_use() expect.str_find('Section 1\n', read_rendered_text(toc_panel)); journal:dismiss() end - --- TODO: separate journal tests from TextEditor tests --- add "one_line_mode" tests