Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

notes script #1287

Merged
merged 15 commits into from
Sep 6, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions internal/journal/table_of_contents.lua
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@ function TableOfContents:init()

local function can_prev()
local toc = self.subviews.table_of_contents
return #toc:getChoices() > 0 and toc:getSelected() > 1
return #toc:getChoices() > 0
end
local function can_next()
local toc = self.subviews.table_of_contents
local num_choices = #toc:getChoices()
return num_choices > 0 and toc:getSelected() < num_choices
return num_choices > 0
end

self:addviews{
Expand Down
10 changes: 8 additions & 2 deletions internal/journal/text_editor.lua
Original file line number Diff line number Diff line change
Expand Up @@ -169,14 +169,14 @@ function TextEditor:setCursor(cursor_offset)
end

function TextEditor:getPreferredFocusState()
return true
return self.parent_view.focus
end

function TextEditor:postUpdateLayout()
self:updateScrollbar(self.render_start_line_y)

if self.subviews.text_area.cursor == nil then
local cursor = self.init_cursor or #self.text + 1
local cursor = self.init_cursor or #self.init_text + 1
self.subviews.text_area:setCursor(cursor)
self:scrollToCursor(cursor)
end
Expand Down Expand Up @@ -234,6 +234,10 @@ function TextEditor:onInput(keys)
return self.subviews.scrollbar:onInput(keys)
end

if keys._MOUSE_L and self:getMousePos() then
self:setFocus(true)
end

return TextEditor.super.onInput(self, keys)
end

Expand Down Expand Up @@ -629,6 +633,8 @@ function TextEditorView:onInput(keys)
self:paste()
self.history:store(HISTORY_ENTRY.OTHER, self.text, self.cursor)
return true
else
return TextEditor.super.onInput(self, keys)
end
end

Expand Down
335 changes: 335 additions & 0 deletions notes.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,335 @@
--@ 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 text_editor = reqscript('internal/journal/text_editor')

local green_pin = dfhack.textures.loadTileset('hack/data/art/note-green-pin.png', 32, 32, true)

NotesOverlay = defclass(NotesOverlay, overlay.OverlayWidget)
NotesOverlay.ATTRS{
desc='Render map notes.',
viewscreens='dwarfmode',
default_enabled=true,
overlay_onupdate_max_freq_seconds=30,
}

local waypoints = df.global.plotinfo.waypoints
local map_points = df.global.plotinfo.waypoints.points

function NotesOverlay:init()
self.visible_notes = {}
self.note_manager = nil
self.last_click_pos = {}
self:reloadVisibleNotes()
end

function NotesOverlay:overlay_onupdate()
self:reloadVisibleNotes()
end

function NotesOverlay:overlay_trigger(args)
return self:showNoteManager()
end

function NotesOverlay:onInput(keys)
if keys._MOUSE_L then
local top_most_screen = dfhack.gui.getDFViewscreen(true)
if dfhack.gui.matchFocusString('dwarfmode/Default', top_most_screen) then
local pos = dfhack.gui.getMousePos()
if pos == nil then
return false
end

local note = self:clickedNote(pos)
if note ~= nil then
self:showNoteManager(note)
end
end
end
end

function NotesOverlay:clickedNote(click_pos)
local pos_curr_note = same_xyz(self.last_click_pos, click_pos)
myk002 marked this conversation as resolved.
Show resolved Hide resolved
and self.note_manager
and self.note_manager.note
or nil

self.last_click_pos = click_pos

local last_note_on_pos = nil
local first_note_on_pos = nil
for _, note in ipairs(self.visible_notes) do
if same_xyz(note.point.pos, click_pos) then
if (last_note_on_pos and pos_curr_note
and last_note_on_pos.point.id == pos_curr_note.point.id
) then
return note
end

first_note_on_pos = first_note_on_pos or note
last_note_on_pos = note
end
end

return first_note_on_pos
end

function NotesOverlay:showNoteManager(note)
if self.note_manager ~= nil then
self.note_manager:dismiss()
end

self.note_manager = NoteManager{
note=note,
on_update=function() self:reloadVisibleNotes() end
}

return self.note_manager:show()
end

function NotesOverlay:viewportChanged()
return self.viewport_pos.x ~= df.global.window_x or
self.viewport_pos.y ~= df.global.window_y or
self.viewport_pos.z ~= df.global.window_z
end

function NotesOverlay:onRenderFrame(dc)
if not df.global.pause_state and not dfhack.screen.inGraphicsMode() then
return
end

if self:viewportChanged() then
self:reloadVisibleNotes()
end

dc:map(true)

local texpos = dfhack.textures.getTexposByHandle(green_pin[1])
dc:pen({fg=COLOR_BLACK, bg=COLOR_LIGHTCYAN, tile=texpos})

for _, note in pairs(self.visible_notes) do
dc
:seek(note.screen_pos.x, note.screen_pos.y)
:char('N')
end

dc:map(false)
end

function NotesOverlay:reloadVisibleNotes()
self.visible_notes = {}

local viewport = guidm.Viewport.get()
self.viewport_pos = {
x=df.global.window_x,
y=df.global.window_y,
z=df.global.window_z
}

for _, map_point in ipairs(map_points) do
if (viewport:isVisible(map_point.pos)
and map_point.name ~= nil and #map_point.name > 0)
then
local screen_pos = viewport:tileToScreen(map_point.pos)
table.insert(self.visible_notes, {
point=map_point,
screen_pos=screen_pos
})
end
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},
resizable=true,
subviews={
widgets.HotkeyLabel {
myk002 marked this conversation as resolved.
Show resolved Hide resolved
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=1
},
widgets.HotkeyLabel {
myk002 marked this conversation as resolved.
Show resolved Hide resolved
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{
myk002 marked this conversation as resolved.
Show resolved Hide resolved
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
}

local function main(args)
if #args == 0 then
return
end

if args[1] == 'add' then
local cursor_pos = guidm.getCursorPos()
if cursor_pos == nil then
dfhack.printerr('Enable keyboard cursor to add a note.')
return
end

return dfhack.internal.runCommand('overlay trigger notes.map_notes')
end
end

if not dfhack_flags.module then
main({...})
end
Loading