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

Add table of contents to Gui/journal #1243

Merged
merged 27 commits into from
Aug 3, 2024
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
26a603d
Add simple Table of Contents to journal
wiktor-obrebski Jul 18, 2024
04dc395
Move journal table of contents to right and add resize control
wiktor-obrebski Jul 20, 2024
1f265fb
Add button to toggle journal table of contest visiblity
wiktor-obrebski Jul 20, 2024
77c0beb
Add journal README for Table of contest
wiktor-obrebski Jul 20, 2024
dc008c8
Improve journal table of contents logic, add tests
wiktor-obrebski Jul 20, 2024
48c4b50
Polishing journal table of contents resize logic
wiktor-obrebski Jul 20, 2024
49b8f37
Add journal feat of saving entire layout (including table of contents)
wiktor-obrebski Jul 20, 2024
1204270
Fix journal issue with numpad keys not interpreted as text
wiktor-obrebski Jul 21, 2024
0f6e056
Add undo/redo feature to journal
wiktor-obrebski Jul 21, 2024
7f9976c
Restore journal last cursor position
wiktor-obrebski Jul 21, 2024
0e23cfe
Move journal scrollbar 1 pixel to the right to save space
wiktor-obrebski Jul 22, 2024
0c36c14
Implement new gui for journal table of contents collapsing mechanism
wiktor-obrebski Jul 28, 2024
f3de017
Adjust journal tests to new collapsing table of contents gui
wiktor-obrebski Jul 28, 2024
c3f6ddd
Merge master
wiktor-obrebski Jul 28, 2024
af181ab
Fix journal docs table of contents shortcut
wiktor-obrebski Jul 28, 2024
961c74b
Restore gui/journal fix for ASCII mode layout
wiktor-obrebski Jul 28, 2024
49053dd
Fix typo in gui/journal docs
wiktor-obrebski Jul 28, 2024
fff7aac
Improve journal resize gui, add bottom buttons bar
wiktor-obrebski Jul 28, 2024
a9c517e
Change journal words jump shortcuts to ctrl+left/ctrl+right
wiktor-obrebski Aug 1, 2024
59c54ff
Make journal selected section follows cursor
wiktor-obrebski Aug 1, 2024
e7001f4
Add keyboard navigation to journal table of contents
wiktor-obrebski Aug 1, 2024
17e3706
Fix journal issue with resize frame
wiktor-obrebski Aug 1, 2024
b42b847
Fix journal save layout defaults
wiktor-obrebski Aug 1, 2024
3cfeb81
Temporary disable journal test basing on 51+ DF version
wiktor-obrebski Aug 1, 2024
184ceb6
Add shortcuts to Journal previous/next feature
wiktor-obrebski Aug 2, 2024
1528d76
Merge branch 'master' into HEAD
myk002 Aug 2, 2024
61ec67d
guard DF51-only features
myk002 Aug 3, 2024
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
5 changes: 4 additions & 1 deletion docs/gui/journal.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Supported Features
------------------

- Cursor Control: Navigate through text using arrow keys (left, right, up, down) for precise cursor placement.
- Fast Rewind: Use :kbd:`Shift` + :kbd:`Left` / :kbd:`Ctrl` + :kbd:`B` and :kbd:`Shift` + :kbd:`Right` / :kbd:`Ctrl` + :kbd:`F` to move the cursor one word back or forward.
- 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.
Expand All @@ -35,6 +35,7 @@ Supported Features
- 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.
- Copy Text: Use :kbd:`Ctrl` + :kbd:`C` to copy selected text.
- copy selected text, if available
Expand All @@ -46,6 +47,8 @@ Supported Features
- 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`

Usage
-----
Expand Down
261 changes: 229 additions & 32 deletions gui/journal.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ local widgets = require 'gui.widgets'
local utils = require 'utils'
local json = require 'json'
local text_editor = reqscript('internal/journal/text_editor')
local shifter = reqscript('internal/journal/shifter')
local table_of_contents = reqscript('internal/journal/table_of_contents')

local RESIZE_MIN = {w=32, h=10}

Expand All @@ -18,12 +20,98 @@ JournalWindow.ATTRS {
frame_title='DF Journal',
resizable=true,
resize_min=RESIZE_MIN,
frame_inset=0
frame_inset={l=0,r=0,t=0,b=0},
init_text=DEFAULT_NIL,
init_cursor=1,
save_layout=true,

on_text_change=DEFAULT_NIL,
on_cursor_change=DEFAULT_NIL,
on_layout_change=DEFAULT_NIL
}

function JournalWindow:init()
local config_frame = copyall(journal_config.data.frame or {})
self.frame = self:sanitizeFrame(config_frame)
local frame, toc_visible, toc_width = self:loadConfig()

self.frame = frame and self:sanitizeFrame(frame) or self.frame

self:addviews({
table_of_contents.TableOfContents{
view_id='table_of_contents_panel',
frame={l=0, w=toc_width, t=0, b=1},
visible=toc_visible,
frame_inset={l=1, t=0, b=1, r=1},

resize_min={w=20},
resizable=true,
resize_anchors={l=false, t=false, b=true, r=true},

on_resize_begin=self:callback('onPanelResizeBegin'),
on_resize_end=self:callback('onPanelResizeEnd'),

on_submit=self:callback('onTableOfContentsSubmit')
},
shifter.Shifter{
view_id='shifter',
frame={l=0, w=1, t=1, b=2},
collapsed=not toc_visible,
on_changed = function (collapsed)
self.subviews.table_of_contents_panel.visible = not collapsed
self.subviews.table_of_contents_divider.visible = not collapsed

if not colllapsed then
self.subviews.table_of_contents_panel:reload(
self.subviews.journal_editor:getText(),
self.subviews.journal_editor:getCursor()
)
end

self:ensurePanelsRelSize()
self:updateLayout()
end,
},
widgets.Divider{
frame={l=0,r=0,b=2,h=1},
frame_style_l=false,
frame_style_r=false,
interior_l=true,
},
widgets.Divider{
view_id='table_of_contents_divider',

frame={l=30,t=0,b=2,w=1},
visible=toc_visible,

interior_b=true,
frame_style_t=false,
},
text_editor.TextEditor{
view_id='journal_editor',
frame={t=1, b=3, l=25, r=0},
resize_min={w=30, h=10},
frame_inset={l=1,r=0},
init_text=self.init_text,
init_cursor=self.init_cursor,
on_text_change=self:callback('onTextChange'),
on_cursor_change=self:callback('onCursorChange'),
},
widgets.Panel{
frame={l=0,r=0,b=1,h=1},
frame_inset={l=1,r=1,t=0, w=100},
subviews={
widgets.HotkeyLabel{
key='CUSTOM_CTRL_O',
label='Table of Contents',
on_activate=function() self.subviews.shifter:toggle() end
}
}
}
})

self.subviews.table_of_contents_panel:reload(
self.init_text,
self.subviews.journal_editor:getCursor() or self.init_cursor
)
end

function JournalWindow:sanitizeFrame(frame)
Expand All @@ -48,69 +136,178 @@ function JournalWindow:sanitizeFrame(frame)
return frame
end

function JournalWindow:postUpdateLayout()
self:saveConfig()
end

function JournalWindow:saveConfig()
if not self.save_layout then
return
end

local toc = self.subviews.table_of_contents_panel

utils.assign(journal_config.data, {
frame = self.frame
frame = self.frame,
toc = {
width = toc.frame.w,
visible = toc.visible
}
})
journal_config:write()
end

function JournalWindow:loadConfig()
if not self.save_layout then
return nil, false, 25
end

local window_frame = copyall(journal_config.data.frame or {})
window_frame.w = window_frame.w or 80
window_frame.h = window_frame.h or 50

local table_of_contents = copyall(journal_config.data.toc or {})
table_of_contents.width = table_of_contents.width or 20
table_of_contents.visible = table_of_contents.visible or false

return window_frame, table_of_contents.visible or false, table_of_contents.width or 25
end

function JournalWindow:onPanelResizeBegin()
self.resizing_panels = true
end

function JournalWindow:onPanelResizeEnd()
self.resizing_panels = false
self:ensurePanelsRelSize()

self:updateLayout()
end

function JournalWindow:onRenderBody(painter)
myk002 marked this conversation as resolved.
Show resolved Hide resolved
if self.resizing_panels then
self:ensurePanelsRelSize()
self:updateLayout()
end

return JournalWindow.super.onRenderBody(self, painter)
end

function JournalWindow:ensurePanelsRelSize()
local toc_panel = self.subviews.table_of_contents_panel
local editor = self.subviews.journal_editor
local divider = self.subviews.table_of_contents_divider

toc_panel.frame.w = math.min(
math.max(toc_panel.frame.w, toc_panel.resize_min.w),
self.frame.w - editor.resize_min.w
myk002 marked this conversation as resolved.
Show resolved Hide resolved
)
editor.frame.l = toc_panel.visible and toc_panel.frame.w or 1
divider.frame.l = editor.frame.l - 1
end

function JournalWindow:preUpdateLayout()
self:ensurePanelsRelSize()
end

function JournalWindow:postUpdateLayout()
self:saveConfig()
end

function JournalWindow:onCursorChange(cursor)
self.subviews.table_of_contents_panel:setCursor(cursor)
local section_index = self.subviews.table_of_contents_panel:currentSection()
self.subviews.table_of_contents_panel:setSelectedSection(section_index)

if self.on_cursor_change ~= nil then
self.on_cursor_change(cursor)
end
end

function JournalWindow:onTextChange(text)
self.subviews.table_of_contents_panel:reload(
text,
self.subviews.journal_editor:getCursor()
)

if self.on_text_change ~= nil then
self.on_text_change(text)
end
end

function JournalWindow:onTableOfContentsSubmit(ind, section)
self.subviews.journal_editor:setCursor(section.line_cursor)
self.subviews.journal_editor:scrollToCursor(section.line_cursor)
end

JournalScreen = defclass(JournalScreen, gui.ZScreen)
JournalScreen.ATTRS {
focus_path='journal',
save_on_change=true
save_on_change=true,
save_layout=true,
save_prefix=''
}

function JournalScreen:init(options)
local content = self:loadContextContent()
function JournalScreen:init()
local context = self:loadContext()

self:addviews{
JournalWindow{
view_id='journal_window',
frame_title='DF Journal',
frame={w=65, h=45},
resize_min={w=50, h=20},
resizable=true,
resize_min={w=32, h=10},
frame_inset=0,
subviews={
text_editor.TextEditor{
view_id='journal_editor',
frame={l=1, t=1, b=1, r=0},
text=content,
on_change=function(text) self:saveContextContent(text) end
}
}
}

save_layout=self.save_layout,

init_text=context.text[1],
init_cursor=context.cursor[1],

on_text_change=self:callback('saveContext'),
on_cursor_change=self:callback('saveContext')
},
}
end

function JournalScreen:loadContextContent()
local site_data = dfhack.persistent.getSiteData(JOURNAL_PERSIST_KEY) or {
text = {''}
}
return site_data.text ~= nil and site_data.text[1] or ''
function JournalScreen:loadContext()
local site_data = dfhack.persistent.getSiteData(
self.save_prefix .. JOURNAL_PERSIST_KEY
) or {}
site_data.text = site_data.text or {''}
site_data.cursor = site_data.cursor or {#site_data.text[1] + 1}

return site_data
end

function JournalScreen:saveContextContent(text)
function JournalScreen:onTextChange(text)
self:saveContext(text)
end

function JournalScreen:saveContext()
if self.save_on_change and dfhack.isWorldLoaded() then
dfhack.persistent.saveSiteData(JOURNAL_PERSIST_KEY, {text={text}})
local text = self.subviews.journal_editor:getText()
local cursor = self.subviews.journal_editor:getCursor()

dfhack.persistent.saveSiteData(
self.save_prefix .. JOURNAL_PERSIST_KEY,
{text={text}, cursor={cursor}}
)
end
end

function JournalScreen:onDismiss()
view = nil
end

function main()
function main(options)
if not dfhack.isMapLoaded() or not dfhack.world.isFortressMode() then
qerror('journal requires a fortress map to be loaded')
end

view = view and view:raise() or JournalScreen{}:show()
local save_layout = options and options.save_layout
local save_on_change = options and options.save_on_change

view = view and view:raise() or JournalScreen{
save_prefix=options and options.save_prefix or '',
save_layout=save_layout == nil and true or save_layout,
save_on_change=save_on_change == nil and true or save_on_change,
}:show()
end

if not dfhack_flags.module then
Expand Down
Loading
Loading