From 1527e00b169cbbcc99d013a7e20979aed6921a31 Mon Sep 17 00:00:00 2001 From: unboundlopez <47876628+unboundlopez@users.noreply.github.com> Date: Sat, 30 Sep 2023 14:53:32 -0500 Subject: [PATCH 01/17] search-filter.lua Searches dwarf citizens through a widget/window. Things to do is add ctrl + f to launch search-filter or alt + f. Well, any shortcut works as long as it's convenient. --- search-filter.lua | 115 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 search-filter.lua diff --git a/search-filter.lua b/search-filter.lua new file mode 100644 index 0000000000..70ab56d056 --- /dev/null +++ b/search-filter.lua @@ -0,0 +1,115 @@ +-- Required libraries +local gui = require('gui') -- Importing the 'gui' library +local widgets = require('gui.widgets') -- Importing the 'widgets' library + +-- Define SearchEngine class +SearchEngine = defclass(SearchEngine, widgets.Window) -- Defining a new class 'SearchEngine' that inherits from 'widgets.Window' +SearchEngine.ATTRS = { + frame_title='Search Engine for Citizens', -- Title of the frame + frame={w=50, h=45}, -- Dimensions of the frame + resizable=true, -- Frame can be resized + resize_min={w=43, h=20}, -- Minimum dimensions when resizing +} + +function SearchEngine:init() -- Initialization function for the SearchEngine class + self:addviews{ + widgets.EditField{ + view_id='edit', + frame={t=1, l=1}, -- Position of the EditField view + text='', -- Initial text in the EditField view + on_change=self:callback('updateList'), -- Callback function when text in EditField changes + }, + widgets.List{ + view_id='list', + frame={t=3, b=0}, + choices=self:getCitizens(), -- Choices in the List view are obtained from getCitizens function + on_select=self:callback('onSelect'), -- Callback function when a citizen is selected from the list + } + } +end + +function SearchEngine:getCitizens() -- Function to get all citizens + local citizens = {} + for _, unit in ipairs(df.global.world.units.active) do + if dfhack.units.isCitizen(unit) then -- Check if a unit is a citizen + table.insert(citizens, {text=dfhack.TranslateName(dfhack.units.getVisibleName(unit)), search_normalized=dfhack.toSearchNormalized(dfhack.TranslateName(dfhack.units.getVisibleName(unit))), id=unit.id}) + -- If unit is a citizen, insert it into the citizens table with its name, normalized search name and id. + end + end + table.sort(citizens, function(a, b) return a.text < b.text end) -- Sort the citizens table alphabetically by name + return citizens -- Return the table of citizens +end + +function SearchEngine:updateList() + local input = dfhack.toSearchNormalized(self.subviews.edit.text) + local citizens = self:getCitizens() + local filtered_citizens = {} + + for _, citizen in ipairs(citizens) do + if string.find(citizen.search_normalized, input) then + table.insert(filtered_citizens, citizen) + end + end + + self.subviews.list:setChoices(filtered_citizens) +end + +function SearchEngine:onSelect(index, citizen) + local gui = require 'gui' + local scr = dfhack.gui.getDFViewscreen() + local sw, sh = dfhack.screen.getWindowSize() + + df.global.plotinfo.follow_unit = citizen.id + -- Simulate input when a dwarf is selected. This input is to click on the character sheet or an item that was accidently selected. it also helps refresh the view + df.global.gps.mouse_x = 130 + df.global.gps.precise_mouse_x = df.global.gps.mouse_x * df.global.gps.tile_pixel_x + df.global.gps.mouse_y = 20 + df.global.gps.precise_mouse_y = df.global.gps.mouse_y * df.global.gps.tile_pixel_y + df.global.enabler.mouse_lbut = 0 + df.global.enabler.mouse_lbut_down = 0 + + --left click simulation + df.global.enabler.tracking_on = 1 + df.global.enabler.mouse_lbut = 1 + df.global.enabler.mouse_lbut_down = 1 + gui.simulateInput(scr, '_MOUSE_L') + --Right click simulation + df.global.enabler.tracking_on = 1 + df.global.enabler.mouse_rbut = 1 + df.global.enabler.mouse_rbut_down = 1 + gui.simulateInput(scr, '_MOUSE_R') + df.global.enabler.mouse_rbut = 0 + df.global.enabler.mouse_rbut_down = 0 + + -- Simulate input when a dwarf is selected #2 + df.global.gps.mouse_x = 55 + df.global.gps.precise_mouse_x = df.global.gps.mouse_x * df.global.gps.tile_pixel_x + df.global.gps.mouse_y = 35 + df.global.gps.precise_mouse_y = df.global.gps.mouse_y * df.global.gps.tile_pixel_y + + --left click simulation + df.global.enabler.tracking_on = 1 + df.global.enabler.mouse_lbut = 1 + df.global.enabler.mouse_lbut_down = 1 + gui.simulateInput(scr, '_MOUSE_L') + df.global.enabler.mouse_lbut = 0 + df.global.enabler.mouse_lbut_down = 0 + + +end + +-- Screen creation +SearchEngineScreen = defclass(SearchEngineScreen, gui.ZScreen) +SearchEngineScreen.ATTRS = { + focus_path='SearchEngine', +} + +function SearchEngineScreen:init() + self:addviews{SearchEngine{}} +end + +function SearchEngineScreen:onDismiss() + view = nil +end + +view = view and view:raise() or SearchEngineScreen{}:show() \ No newline at end of file From 96439374401ecccc4504beede562328729241dd0 Mon Sep 17 00:00:00 2001 From: unboundlopez <47876628+unboundlopez@users.noreply.github.com> Date: Sat, 30 Sep 2023 15:32:28 -0500 Subject: [PATCH 02/17] Update search-filter.lua hopefully fixed trailing white spaces --- search-filter.lua | 74 +++++++++++++++++++++++------------------------ 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/search-filter.lua b/search-filter.lua index 70ab56d056..df961cd647 100644 --- a/search-filter.lua +++ b/search-filter.lua @@ -4,7 +4,7 @@ local widgets = require('gui.widgets') -- Importing the 'widgets' library -- Define SearchEngine class SearchEngine = defclass(SearchEngine, widgets.Window) -- Defining a new class 'SearchEngine' that inherits from 'widgets.Window' -SearchEngine.ATTRS = { +SearchEngine.ATTRS = { frame_title='Search Engine for Citizens', -- Title of the frame frame={w=50, h=45}, -- Dimensions of the frame resizable=true, -- Frame can be resized @@ -12,16 +12,16 @@ SearchEngine.ATTRS = { } function SearchEngine:init() -- Initialization function for the SearchEngine class - self:addviews{ - widgets.EditField{ - view_id='edit', + self:addviews{ + widgets.EditField{ + view_id='edit', frame={t=1, l=1}, -- Position of the EditField view text='', -- Initial text in the EditField view on_change=self:callback('updateList'), -- Callback function when text in EditField changes }, - widgets.List{ - view_id='list', - frame={t=3, b=0}, + widgets.List{ + view_id='list', + frame={t=3, b=0}, choices=self:getCitizens(), -- Choices in the List view are obtained from getCitizens function on_select=self:callback('onSelect'), -- Callback function when a citizen is selected from the list } @@ -29,8 +29,8 @@ function SearchEngine:init() -- Initialization function for the SearchEngine cla end function SearchEngine:getCitizens() -- Function to get all citizens - local citizens = {} - for _, unit in ipairs(df.global.world.units.active) do + local citizens = {} + for _, unit in ipairs(df.global.world.units.active) do if dfhack.units.isCitizen(unit) then -- Check if a unit is a citizen table.insert(citizens, {text=dfhack.TranslateName(dfhack.units.getVisibleName(unit)), search_normalized=dfhack.toSearchNormalized(dfhack.TranslateName(dfhack.units.getVisibleName(unit))), id=unit.id}) -- If unit is a citizen, insert it into the citizens table with its name, normalized search name and id. @@ -40,26 +40,26 @@ function SearchEngine:getCitizens() -- Function to get all citizens return citizens -- Return the table of citizens end -function SearchEngine:updateList() - local input = dfhack.toSearchNormalized(self.subviews.edit.text) - local citizens = self:getCitizens() - local filtered_citizens = {} +function SearchEngine:updateList() + local input = dfhack.toSearchNormalized(self.subviews.edit.text) + local citizens = self:getCitizens() + local filtered_citizens = {} - for _, citizen in ipairs(citizens) do - if string.find(citizen.search_normalized, input) then - table.insert(filtered_citizens, citizen) - end - end + for _, citizen in ipairs(citizens) do + if string.find(citizen.search_normalized, input) then + table.insert(filtered_citizens, citizen) + end + end - self.subviews.list:setChoices(filtered_citizens) -end + self.subviews.list:setChoices(filtered_citizens) +end -function SearchEngine:onSelect(index, citizen) +function SearchEngine:onSelect(index, citizen) local gui = require 'gui' local scr = dfhack.gui.getDFViewscreen() local sw, sh = dfhack.screen.getWindowSize() - df.global.plotinfo.follow_unit = citizen.id + df.global.plotinfo.follow_unit = citizen.id -- Simulate input when a dwarf is selected. This input is to click on the character sheet or an item that was accidently selected. it also helps refresh the view df.global.gps.mouse_x = 130 df.global.gps.precise_mouse_x = df.global.gps.mouse_x * df.global.gps.tile_pixel_x @@ -72,14 +72,14 @@ function SearchEngine:onSelect(index, citizen) df.global.enabler.tracking_on = 1 df.global.enabler.mouse_lbut = 1 df.global.enabler.mouse_lbut_down = 1 - gui.simulateInput(scr, '_MOUSE_L') + gui.simulateInput(scr, '_MOUSE_L') --Right click simulation df.global.enabler.tracking_on = 1 df.global.enabler.mouse_rbut = 1 df.global.enabler.mouse_rbut_down = 1 gui.simulateInput(scr, '_MOUSE_R') df.global.enabler.mouse_rbut = 0 - df.global.enabler.mouse_rbut_down = 0 + df.global.enabler.mouse_rbut_down = 0 -- Simulate input when a dwarf is selected #2 df.global.gps.mouse_x = 55 @@ -95,21 +95,21 @@ function SearchEngine:onSelect(index, citizen) df.global.enabler.mouse_lbut = 0 df.global.enabler.mouse_lbut_down = 0 - + end --- Screen creation -SearchEngineScreen = defclass(SearchEngineScreen, gui.ZScreen) -SearchEngineScreen.ATTRS = { - focus_path='SearchEngine', -} +-- Screen creation +SearchEngineScreen = defclass(SearchEngineScreen, gui.ZScreen) +SearchEngineScreen.ATTRS = { + focus_path='SearchEngine', +} -function SearchEngineScreen:init() - self:addviews{SearchEngine{}} -end +function SearchEngineScreen:init() + self:addviews{SearchEngine{}} +end -function SearchEngineScreen:onDismiss() - view = nil -end +function SearchEngineScreen:onDismiss() + view = nil +end -view = view and view:raise() or SearchEngineScreen{}:show() \ No newline at end of file +view = view and view:raise() or SearchEngineScreen{}:show() From 01f5700dfe6af4246331cd04d67b04b911eeccf2 Mon Sep 17 00:00:00 2001 From: unboundlopez <47876628+unboundlopez@users.noreply.github.com> Date: Sat, 30 Sep 2023 15:38:58 -0500 Subject: [PATCH 03/17] Update search-filter.lua Cleared the whitespace Search for EOL in VScode settings and click on '\n' to make LF default From 0838f4a33801507278b5f728dfcaf0b6f7cc9789 Mon Sep 17 00:00:00 2001 From: unboundlopez <47876628+unboundlopez@users.noreply.github.com> Date: Sat, 30 Sep 2023 15:51:09 -0500 Subject: [PATCH 04/17] Update search-filter.lua From 644e19a94ba0b7b83033ba3db0e664c9f0b1eb6f Mon Sep 17 00:00:00 2001 From: unboundlopez <47876628+unboundlopez@users.noreply.github.com> Date: Sat, 30 Sep 2023 15:52:54 -0500 Subject: [PATCH 05/17] Update search-filter.lua From a30352576c7dbebdcafb5520cddeb27e70c6ca33 Mon Sep 17 00:00:00 2001 From: unboundlopez Date: Sat, 30 Sep 2023 16:16:02 -0500 Subject: [PATCH 06/17] Signed-off-by: unboundlopez --- search-filter.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/search-filter.lua b/search-filter.lua index df961cd647..25f52378e6 100644 --- a/search-filter.lua +++ b/search-filter.lua @@ -95,7 +95,6 @@ function SearchEngine:onSelect(index, citizen) df.global.enabler.mouse_lbut = 0 df.global.enabler.mouse_lbut_down = 0 - end -- Screen creation From df0662b0d75ad3387a5d3f28b4a8ed85a5168d26 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 30 Sep 2023 21:23:46 +0000 Subject: [PATCH 07/17] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- search-filter.lua | 228 +++++++++++++++++++++++----------------------- 1 file changed, 114 insertions(+), 114 deletions(-) diff --git a/search-filter.lua b/search-filter.lua index 25f52378e6..65966a144e 100644 --- a/search-filter.lua +++ b/search-filter.lua @@ -1,114 +1,114 @@ --- Required libraries -local gui = require('gui') -- Importing the 'gui' library -local widgets = require('gui.widgets') -- Importing the 'widgets' library - --- Define SearchEngine class -SearchEngine = defclass(SearchEngine, widgets.Window) -- Defining a new class 'SearchEngine' that inherits from 'widgets.Window' -SearchEngine.ATTRS = { - frame_title='Search Engine for Citizens', -- Title of the frame - frame={w=50, h=45}, -- Dimensions of the frame - resizable=true, -- Frame can be resized - resize_min={w=43, h=20}, -- Minimum dimensions when resizing -} - -function SearchEngine:init() -- Initialization function for the SearchEngine class - self:addviews{ - widgets.EditField{ - view_id='edit', - frame={t=1, l=1}, -- Position of the EditField view - text='', -- Initial text in the EditField view - on_change=self:callback('updateList'), -- Callback function when text in EditField changes - }, - widgets.List{ - view_id='list', - frame={t=3, b=0}, - choices=self:getCitizens(), -- Choices in the List view are obtained from getCitizens function - on_select=self:callback('onSelect'), -- Callback function when a citizen is selected from the list - } - } -end - -function SearchEngine:getCitizens() -- Function to get all citizens - local citizens = {} - for _, unit in ipairs(df.global.world.units.active) do - if dfhack.units.isCitizen(unit) then -- Check if a unit is a citizen - table.insert(citizens, {text=dfhack.TranslateName(dfhack.units.getVisibleName(unit)), search_normalized=dfhack.toSearchNormalized(dfhack.TranslateName(dfhack.units.getVisibleName(unit))), id=unit.id}) - -- If unit is a citizen, insert it into the citizens table with its name, normalized search name and id. - end - end - table.sort(citizens, function(a, b) return a.text < b.text end) -- Sort the citizens table alphabetically by name - return citizens -- Return the table of citizens -end - -function SearchEngine:updateList() - local input = dfhack.toSearchNormalized(self.subviews.edit.text) - local citizens = self:getCitizens() - local filtered_citizens = {} - - for _, citizen in ipairs(citizens) do - if string.find(citizen.search_normalized, input) then - table.insert(filtered_citizens, citizen) - end - end - - self.subviews.list:setChoices(filtered_citizens) -end - -function SearchEngine:onSelect(index, citizen) - local gui = require 'gui' - local scr = dfhack.gui.getDFViewscreen() - local sw, sh = dfhack.screen.getWindowSize() - - df.global.plotinfo.follow_unit = citizen.id - -- Simulate input when a dwarf is selected. This input is to click on the character sheet or an item that was accidently selected. it also helps refresh the view - df.global.gps.mouse_x = 130 - df.global.gps.precise_mouse_x = df.global.gps.mouse_x * df.global.gps.tile_pixel_x - df.global.gps.mouse_y = 20 - df.global.gps.precise_mouse_y = df.global.gps.mouse_y * df.global.gps.tile_pixel_y - df.global.enabler.mouse_lbut = 0 - df.global.enabler.mouse_lbut_down = 0 - - --left click simulation - df.global.enabler.tracking_on = 1 - df.global.enabler.mouse_lbut = 1 - df.global.enabler.mouse_lbut_down = 1 - gui.simulateInput(scr, '_MOUSE_L') - --Right click simulation - df.global.enabler.tracking_on = 1 - df.global.enabler.mouse_rbut = 1 - df.global.enabler.mouse_rbut_down = 1 - gui.simulateInput(scr, '_MOUSE_R') - df.global.enabler.mouse_rbut = 0 - df.global.enabler.mouse_rbut_down = 0 - - -- Simulate input when a dwarf is selected #2 - df.global.gps.mouse_x = 55 - df.global.gps.precise_mouse_x = df.global.gps.mouse_x * df.global.gps.tile_pixel_x - df.global.gps.mouse_y = 35 - df.global.gps.precise_mouse_y = df.global.gps.mouse_y * df.global.gps.tile_pixel_y - - --left click simulation - df.global.enabler.tracking_on = 1 - df.global.enabler.mouse_lbut = 1 - df.global.enabler.mouse_lbut_down = 1 - gui.simulateInput(scr, '_MOUSE_L') - df.global.enabler.mouse_lbut = 0 - df.global.enabler.mouse_lbut_down = 0 - -end - --- Screen creation -SearchEngineScreen = defclass(SearchEngineScreen, gui.ZScreen) -SearchEngineScreen.ATTRS = { - focus_path='SearchEngine', -} - -function SearchEngineScreen:init() - self:addviews{SearchEngine{}} -end - -function SearchEngineScreen:onDismiss() - view = nil -end - -view = view and view:raise() or SearchEngineScreen{}:show() +-- Required libraries +local gui = require('gui') -- Importing the 'gui' library +local widgets = require('gui.widgets') -- Importing the 'widgets' library + +-- Define SearchEngine class +SearchEngine = defclass(SearchEngine, widgets.Window) -- Defining a new class 'SearchEngine' that inherits from 'widgets.Window' +SearchEngine.ATTRS = { + frame_title='Search Engine for Citizens', -- Title of the frame + frame={w=50, h=45}, -- Dimensions of the frame + resizable=true, -- Frame can be resized + resize_min={w=43, h=20}, -- Minimum dimensions when resizing +} + +function SearchEngine:init() -- Initialization function for the SearchEngine class + self:addviews{ + widgets.EditField{ + view_id='edit', + frame={t=1, l=1}, -- Position of the EditField view + text='', -- Initial text in the EditField view + on_change=self:callback('updateList'), -- Callback function when text in EditField changes + }, + widgets.List{ + view_id='list', + frame={t=3, b=0}, + choices=self:getCitizens(), -- Choices in the List view are obtained from getCitizens function + on_select=self:callback('onSelect'), -- Callback function when a citizen is selected from the list + } + } +end + +function SearchEngine:getCitizens() -- Function to get all citizens + local citizens = {} + for _, unit in ipairs(df.global.world.units.active) do + if dfhack.units.isCitizen(unit) then -- Check if a unit is a citizen + table.insert(citizens, {text=dfhack.TranslateName(dfhack.units.getVisibleName(unit)), search_normalized=dfhack.toSearchNormalized(dfhack.TranslateName(dfhack.units.getVisibleName(unit))), id=unit.id}) + -- If unit is a citizen, insert it into the citizens table with its name, normalized search name and id. + end + end + table.sort(citizens, function(a, b) return a.text < b.text end) -- Sort the citizens table alphabetically by name + return citizens -- Return the table of citizens +end + +function SearchEngine:updateList() + local input = dfhack.toSearchNormalized(self.subviews.edit.text) + local citizens = self:getCitizens() + local filtered_citizens = {} + + for _, citizen in ipairs(citizens) do + if string.find(citizen.search_normalized, input) then + table.insert(filtered_citizens, citizen) + end + end + + self.subviews.list:setChoices(filtered_citizens) +end + +function SearchEngine:onSelect(index, citizen) + local gui = require 'gui' + local scr = dfhack.gui.getDFViewscreen() + local sw, sh = dfhack.screen.getWindowSize() + + df.global.plotinfo.follow_unit = citizen.id + -- Simulate input when a dwarf is selected. This input is to click on the character sheet or an item that was accidently selected. it also helps refresh the view + df.global.gps.mouse_x = 130 + df.global.gps.precise_mouse_x = df.global.gps.mouse_x * df.global.gps.tile_pixel_x + df.global.gps.mouse_y = 20 + df.global.gps.precise_mouse_y = df.global.gps.mouse_y * df.global.gps.tile_pixel_y + df.global.enabler.mouse_lbut = 0 + df.global.enabler.mouse_lbut_down = 0 + + --left click simulation + df.global.enabler.tracking_on = 1 + df.global.enabler.mouse_lbut = 1 + df.global.enabler.mouse_lbut_down = 1 + gui.simulateInput(scr, '_MOUSE_L') + --Right click simulation + df.global.enabler.tracking_on = 1 + df.global.enabler.mouse_rbut = 1 + df.global.enabler.mouse_rbut_down = 1 + gui.simulateInput(scr, '_MOUSE_R') + df.global.enabler.mouse_rbut = 0 + df.global.enabler.mouse_rbut_down = 0 + + -- Simulate input when a dwarf is selected #2 + df.global.gps.mouse_x = 55 + df.global.gps.precise_mouse_x = df.global.gps.mouse_x * df.global.gps.tile_pixel_x + df.global.gps.mouse_y = 35 + df.global.gps.precise_mouse_y = df.global.gps.mouse_y * df.global.gps.tile_pixel_y + + --left click simulation + df.global.enabler.tracking_on = 1 + df.global.enabler.mouse_lbut = 1 + df.global.enabler.mouse_lbut_down = 1 + gui.simulateInput(scr, '_MOUSE_L') + df.global.enabler.mouse_lbut = 0 + df.global.enabler.mouse_lbut_down = 0 + +end + +-- Screen creation +SearchEngineScreen = defclass(SearchEngineScreen, gui.ZScreen) +SearchEngineScreen.ATTRS = { + focus_path='SearchEngine', +} + +function SearchEngineScreen:init() + self:addviews{SearchEngine{}} +end + +function SearchEngineScreen:onDismiss() + view = nil +end + +view = view and view:raise() or SearchEngineScreen{}:show() From 5d86f4f0631b934a972276e65a43ee802cb7b07c Mon Sep 17 00:00:00 2001 From: unboundlopez <47876628+unboundlopez@users.noreply.github.com> Date: Mon, 2 Oct 2023 20:02:56 -0500 Subject: [PATCH 08/17] Update search-filter.lua --- search-filter.lua | 81 +++++++++++++++++++++++------------------------ 1 file changed, 40 insertions(+), 41 deletions(-) diff --git a/search-filter.lua b/search-filter.lua index 65966a144e..3260bbf745 100644 --- a/search-filter.lua +++ b/search-filter.lua @@ -5,7 +5,7 @@ local widgets = require('gui.widgets') -- Importing the 'widgets' library -- Define SearchEngine class SearchEngine = defclass(SearchEngine, widgets.Window) -- Defining a new class 'SearchEngine' that inherits from 'widgets.Window' SearchEngine.ATTRS = { - frame_title='Search Engine for Citizens', -- Title of the frame + frame_title='Search Engine for Fort-Controlled Units', -- Title of the frame frame={w=50, h=45}, -- Dimensions of the frame resizable=true, -- Frame can be resized resize_min={w=43, h=20}, -- Minimum dimensions when resizing @@ -22,79 +22,78 @@ function SearchEngine:init() -- Initialization function for the SearchEngine cla widgets.List{ view_id='list', frame={t=3, b=0}, - choices=self:getCitizens(), -- Choices in the List view are obtained from getCitizens function - on_select=self:callback('onSelect'), -- Callback function when a citizen is selected from the list + choices=self:getFortControlledUnits(), -- Choices in the List view are obtained from getFortControlledUnits function + on_select=self:callback('onSelect'), -- Callback function when a unit is selected from the list } } end -function SearchEngine:getCitizens() -- Function to get all citizens - local citizens = {} +function SearchEngine:getFortControlledUnits() + local fortControlledUnits = {} for _, unit in ipairs(df.global.world.units.active) do - if dfhack.units.isCitizen(unit) then -- Check if a unit is a citizen - table.insert(citizens, {text=dfhack.TranslateName(dfhack.units.getVisibleName(unit)), search_normalized=dfhack.toSearchNormalized(dfhack.TranslateName(dfhack.units.getVisibleName(unit))), id=unit.id}) - -- If unit is a citizen, insert it into the citizens table with its name, normalized search name and id. + local unitName = dfhack.TranslateName(dfhack.units.getVisibleName(unit)) + if unitName == "" then + -- Use the race name if the unit's name field is empty + unitName = dfhack.units.getRaceName(unit) + end + if dfhack.units.isFortControlled(unit) then + table.insert(fortControlledUnits, {text=unitName, search_normalized=dfhack.toSearchNormalized(unitName), id=unit.id}) end end - table.sort(citizens, function(a, b) return a.text < b.text end) -- Sort the citizens table alphabetically by name - return citizens -- Return the table of citizens + table.sort(fortControlledUnits, function(a, b) return a.text < b.text end) + return fortControlledUnits end function SearchEngine:updateList() local input = dfhack.toSearchNormalized(self.subviews.edit.text) - local citizens = self:getCitizens() - local filtered_citizens = {} + local fortControlledUnits = self:getFortControlledUnits() + local filtered_fortControlledUnits = {} - for _, citizen in ipairs(citizens) do - if string.find(citizen.search_normalized, input) then - table.insert(filtered_citizens, citizen) + for _, unit in ipairs(fortControlledUnits) do + if string.find(unit.search_normalized, input) then + table.insert(filtered_fortControlledUnits, unit) end end - self.subviews.list:setChoices(filtered_citizens) + self.subviews.list:setChoices(filtered_fortControlledUnits) end -function SearchEngine:onSelect(index, citizen) +function SearchEngine:onSelect(index, unit) local gui = require 'gui' local scr = dfhack.gui.getDFViewscreen() - local sw, sh = dfhack.screen.getWindowSize() - df.global.plotinfo.follow_unit = citizen.id - -- Simulate input when a dwarf is selected. This input is to click on the character sheet or an item that was accidently selected. it also helps refresh the view + df.global.plotinfo.follow_unit = unit.id + df.global.game.main_interface.view_sheets.open = true -- Changes the character sheet to true + df.global.game.main_interface.view_sheets.active_id = unit.id -- changes the id of the character + df.global.game.main_interface.view_sheets.active_sheet = 0 -- changes the active sheet to be a unit + df.global.gps.mouse_x = 130 df.global.gps.precise_mouse_x = df.global.gps.mouse_x * df.global.gps.tile_pixel_x + df.global.gps.mouse_y = 20 df.global.gps.precise_mouse_y = df.global.gps.mouse_y * df.global.gps.tile_pixel_y + df.global.enabler.mouse_lbut = 0 df.global.enabler.mouse_lbut_down = 0 - --left click simulation - df.global.enabler.tracking_on = 1 - df.global.enabler.mouse_lbut = 1 - df.global.enabler.mouse_lbut_down = 1 - gui.simulateInput(scr, '_MOUSE_L') - --Right click simulation - df.global.enabler.tracking_on = 1 - df.global.enabler.mouse_rbut = 1 - df.global.enabler.mouse_rbut_down = 1 - gui.simulateInput(scr, '_MOUSE_R') - df.global.enabler.mouse_rbut = 0 - df.global.enabler.mouse_rbut_down = 0 - - -- Simulate input when a dwarf is selected #2 - df.global.gps.mouse_x = 55 - df.global.gps.precise_mouse_x = df.global.gps.mouse_x * df.global.gps.tile_pixel_x - df.global.gps.mouse_y = 35 - df.global.gps.precise_mouse_y = df.global.gps.mouse_y * df.global.gps.tile_pixel_y + -- Left click simulation + simulateClick(scr, '_MOUSE_L') + + -- Right click simulation + simulateClick(scr, '_MOUSE_R') +end + +function simulateClick(scr, button) + local gui = require 'gui' - --left click simulation df.global.enabler.tracking_on = 1 df.global.enabler.mouse_lbut = 1 df.global.enabler.mouse_lbut_down = 1 - gui.simulateInput(scr, '_MOUSE_L') + + gui.simulateInput(scr, button) + df.global.enabler.mouse_lbut = 0 df.global.enabler.mouse_lbut_down = 0 - end -- Screen creation From c96d99100f356b48bfcfa5e385044a01dd43e205 Mon Sep 17 00:00:00 2001 From: unboundlopez <47876628+unboundlopez@users.noreply.github.com> Date: Wed, 4 Oct 2023 12:32:44 -0500 Subject: [PATCH 09/17] Update search-filter.lua I think I'm done. May be compatible with others. --- search-filter.lua | 62 +++++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 34 deletions(-) diff --git a/search-filter.lua b/search-filter.lua index 3260bbf745..5570b4d2f7 100644 --- a/search-filter.lua +++ b/search-filter.lua @@ -59,41 +59,35 @@ function SearchEngine:updateList() end function SearchEngine:onSelect(index, unit) - local gui = require 'gui' - local scr = dfhack.gui.getDFViewscreen() +-- Assign the unit to a specific id +local unit = df.unit.find(unit.id) + + print(unit.id) +-- Get the position of the unit and center the camera on the unit +local x, y, z = dfhack.units.getPosition(unit) +dfhack.gui.revealInDwarfmodeMap(xyz2pos(x, y, z), true) + +-- Get the dimensions of the Dwarf Fortress map +local dims = dfhack.gui.getDwarfmodeViewDims() +-- Calculate zoom factor based on current viewport zoom level +local gpsZoom = df.global.gps.viewport_zoom_factor +-- Set the mouse x and y positions to click on the unit +df.global.gps.precise_mouse_x = (x - df.global.window_x) * gpsZoom // 4 + gpsZoom // 8 +df.global.gps.precise_mouse_y = (y - df.global.window_y) * gpsZoom // 4 + gpsZoom // 8 + +-- Enable mouse tracking and set the left mouse button as pressed +df.global.enabler.tracking_on = 1 +df.global.enabler.mouse_lbut = 1 +df.global.enabler.mouse_lbut_down = 1 + +-- Simulate a left mouse click at the current mouse position +gui.simulateInput(dfhack.gui.getDFViewscreen(), '_MOUSE_L') + +-- Disable mouse tracking and set the left mouse button as not pressed +df.global.enabler.tracking_on = 0 +df.global.enabler.mouse_lbut = 0 +df.global.enabler.mouse_lbut_down = 0 - df.global.plotinfo.follow_unit = unit.id - df.global.game.main_interface.view_sheets.open = true -- Changes the character sheet to true - df.global.game.main_interface.view_sheets.active_id = unit.id -- changes the id of the character - df.global.game.main_interface.view_sheets.active_sheet = 0 -- changes the active sheet to be a unit - - df.global.gps.mouse_x = 130 - df.global.gps.precise_mouse_x = df.global.gps.mouse_x * df.global.gps.tile_pixel_x - - df.global.gps.mouse_y = 20 - df.global.gps.precise_mouse_y = df.global.gps.mouse_y * df.global.gps.tile_pixel_y - - df.global.enabler.mouse_lbut = 0 - df.global.enabler.mouse_lbut_down = 0 - - -- Left click simulation - simulateClick(scr, '_MOUSE_L') - - -- Right click simulation - simulateClick(scr, '_MOUSE_R') -end - -function simulateClick(scr, button) - local gui = require 'gui' - - df.global.enabler.tracking_on = 1 - df.global.enabler.mouse_lbut = 1 - df.global.enabler.mouse_lbut_down = 1 - - gui.simulateInput(scr, button) - - df.global.enabler.mouse_lbut = 0 - df.global.enabler.mouse_lbut_down = 0 end -- Screen creation From 1d2f3c39fc9854fb216fb2527194f821d9653e99 Mon Sep 17 00:00:00 2001 From: unboundlopez <47876628+unboundlopez@users.noreply.github.com> Date: Thu, 5 Oct 2023 00:20:58 -0500 Subject: [PATCH 10/17] Update search-filter.lua I believe I'm done. I couldn't figure out how to add panels/tabs/buttons to the widget, but that's ok. I changed the conditions so visitors and hostile can be searched alongside citizens using the program. --- search-filter.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/search-filter.lua b/search-filter.lua index 5570b4d2f7..bbfa6d7733 100644 --- a/search-filter.lua +++ b/search-filter.lua @@ -36,7 +36,7 @@ function SearchEngine:getFortControlledUnits() -- Use the race name if the unit's name field is empty unitName = dfhack.units.getRaceName(unit) end - if dfhack.units.isFortControlled(unit) then + if dfhack.units.isVisible(unit) and dfhack.units.isActive(unit) then table.insert(fortControlledUnits, {text=unitName, search_normalized=dfhack.toSearchNormalized(unitName), id=unit.id}) end end @@ -62,7 +62,6 @@ function SearchEngine:onSelect(index, unit) -- Assign the unit to a specific id local unit = df.unit.find(unit.id) - print(unit.id) -- Get the position of the unit and center the camera on the unit local x, y, z = dfhack.units.getPosition(unit) dfhack.gui.revealInDwarfmodeMap(xyz2pos(x, y, z), true) @@ -81,6 +80,8 @@ df.global.enabler.mouse_lbut = 1 df.global.enabler.mouse_lbut_down = 1 -- Simulate a left mouse click at the current mouse position +gui.simulateInput(dfhack.gui.getDFViewscreen(), '_MOUSE_R') + gui.simulateInput(dfhack.gui.getDFViewscreen(), '_MOUSE_L') -- Disable mouse tracking and set the left mouse button as not pressed From fa8f6765eeed6f14210b855444c0d0fc94ff9ace Mon Sep 17 00:00:00 2001 From: unboundlopez <47876628+unboundlopez@users.noreply.github.com> Date: Thu, 29 May 2025 10:12:47 -0500 Subject: [PATCH 11/17] Add files via upload --- docs/zUniform.rst | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 docs/zUniform.rst diff --git a/docs/zUniform.rst b/docs/zUniform.rst new file mode 100644 index 0000000000..c9cf734c86 --- /dev/null +++ b/docs/zUniform.rst @@ -0,0 +1,23 @@ +squad-uniform +============= + +An overlay UI that allows importing and exporting squad uniforms. + +Usage +----- + +To use this overlay: + +1. Press `q` to open the squad sidebar. +2. Select a squad by clicking its checkbox. +3. Click the `Equip` button. +4. Either: + - Press `Add uniform` to create a new one, **or** + - Click a unit’s `Details` button to customize their equipment. +5. The `[Import]` and `[Export]` buttons will now appear in the **bottom-right** corner of the screen. + - You can also use the hotkeys: + - `Ctrl+I` to import a uniform + - `Ctrl+E` to export the current uniform + +Uniforms are saved to and loaded from the following folder: +Dwarf Fortress\dfhack-config\squad_uniform From 54b7742b8a3e06830daa8f7c77fe420a686e94c2 Mon Sep 17 00:00:00 2001 From: unboundlopez <47876628+unboundlopez@users.noreply.github.com> Date: Thu, 29 May 2025 10:14:32 -0500 Subject: [PATCH 12/17] Delete docs/zUniform.rst --- docs/zUniform.rst | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100644 docs/zUniform.rst diff --git a/docs/zUniform.rst b/docs/zUniform.rst deleted file mode 100644 index c9cf734c86..0000000000 --- a/docs/zUniform.rst +++ /dev/null @@ -1,23 +0,0 @@ -squad-uniform -============= - -An overlay UI that allows importing and exporting squad uniforms. - -Usage ------ - -To use this overlay: - -1. Press `q` to open the squad sidebar. -2. Select a squad by clicking its checkbox. -3. Click the `Equip` button. -4. Either: - - Press `Add uniform` to create a new one, **or** - - Click a unit’s `Details` button to customize their equipment. -5. The `[Import]` and `[Export]` buttons will now appear in the **bottom-right** corner of the screen. - - You can also use the hotkeys: - - `Ctrl+I` to import a uniform - - `Ctrl+E` to export the current uniform - -Uniforms are saved to and loaded from the following folder: -Dwarf Fortress\dfhack-config\squad_uniform From d32b51a9037b7ad540330cfcd27d9275af4a8dd7 Mon Sep 17 00:00:00 2001 From: unboundlopez <47876628+unboundlopez@users.noreply.github.com> Date: Thu, 29 May 2025 10:16:02 -0500 Subject: [PATCH 13/17] Add files via upload --- docs/zUniform.rst | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 docs/zUniform.rst diff --git a/docs/zUniform.rst b/docs/zUniform.rst new file mode 100644 index 0000000000..c9cf734c86 --- /dev/null +++ b/docs/zUniform.rst @@ -0,0 +1,23 @@ +squad-uniform +============= + +An overlay UI that allows importing and exporting squad uniforms. + +Usage +----- + +To use this overlay: + +1. Press `q` to open the squad sidebar. +2. Select a squad by clicking its checkbox. +3. Click the `Equip` button. +4. Either: + - Press `Add uniform` to create a new one, **or** + - Click a unit’s `Details` button to customize their equipment. +5. The `[Import]` and `[Export]` buttons will now appear in the **bottom-right** corner of the screen. + - You can also use the hotkeys: + - `Ctrl+I` to import a uniform + - `Ctrl+E` to export the current uniform + +Uniforms are saved to and loaded from the following folder: +Dwarf Fortress\dfhack-config\squad_uniform From 205d59d215f3160ab9f89d6900705423d0eb2687 Mon Sep 17 00:00:00 2001 From: unboundlopez <47876628+unboundlopez@users.noreply.github.com> Date: Thu, 29 May 2025 10:17:25 -0500 Subject: [PATCH 14/17] Update zUniform.rst --- docs/zUniform.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/zUniform.rst b/docs/zUniform.rst index c9cf734c86..e82a6297ef 100644 --- a/docs/zUniform.rst +++ b/docs/zUniform.rst @@ -20,4 +20,5 @@ To use this overlay: - `Ctrl+E` to export the current uniform Uniforms are saved to and loaded from the following folder: + Dwarf Fortress\dfhack-config\squad_uniform From 90472f3af534892d5cadb80e761ba539793a5481 Mon Sep 17 00:00:00 2001 From: unboundlopez <47876628+unboundlopez@users.noreply.github.com> Date: Thu, 29 May 2025 22:54:13 -0500 Subject: [PATCH 15/17] Update and rename search-filter.lua to zUniform.lua --- search-filter.lua | 108 -------------------- zUniform.lua | 249 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 249 insertions(+), 108 deletions(-) delete mode 100644 search-filter.lua create mode 100644 zUniform.lua diff --git a/search-filter.lua b/search-filter.lua deleted file mode 100644 index bbfa6d7733..0000000000 --- a/search-filter.lua +++ /dev/null @@ -1,108 +0,0 @@ --- Required libraries -local gui = require('gui') -- Importing the 'gui' library -local widgets = require('gui.widgets') -- Importing the 'widgets' library - --- Define SearchEngine class -SearchEngine = defclass(SearchEngine, widgets.Window) -- Defining a new class 'SearchEngine' that inherits from 'widgets.Window' -SearchEngine.ATTRS = { - frame_title='Search Engine for Fort-Controlled Units', -- Title of the frame - frame={w=50, h=45}, -- Dimensions of the frame - resizable=true, -- Frame can be resized - resize_min={w=43, h=20}, -- Minimum dimensions when resizing -} - -function SearchEngine:init() -- Initialization function for the SearchEngine class - self:addviews{ - widgets.EditField{ - view_id='edit', - frame={t=1, l=1}, -- Position of the EditField view - text='', -- Initial text in the EditField view - on_change=self:callback('updateList'), -- Callback function when text in EditField changes - }, - widgets.List{ - view_id='list', - frame={t=3, b=0}, - choices=self:getFortControlledUnits(), -- Choices in the List view are obtained from getFortControlledUnits function - on_select=self:callback('onSelect'), -- Callback function when a unit is selected from the list - } - } -end - -function SearchEngine:getFortControlledUnits() - local fortControlledUnits = {} - for _, unit in ipairs(df.global.world.units.active) do - local unitName = dfhack.TranslateName(dfhack.units.getVisibleName(unit)) - if unitName == "" then - -- Use the race name if the unit's name field is empty - unitName = dfhack.units.getRaceName(unit) - end - if dfhack.units.isVisible(unit) and dfhack.units.isActive(unit) then - table.insert(fortControlledUnits, {text=unitName, search_normalized=dfhack.toSearchNormalized(unitName), id=unit.id}) - end - end - table.sort(fortControlledUnits, function(a, b) return a.text < b.text end) - return fortControlledUnits -end - -function SearchEngine:updateList() - local input = dfhack.toSearchNormalized(self.subviews.edit.text) - local fortControlledUnits = self:getFortControlledUnits() - local filtered_fortControlledUnits = {} - - for _, unit in ipairs(fortControlledUnits) do - if string.find(unit.search_normalized, input) then - table.insert(filtered_fortControlledUnits, unit) - end - end - - self.subviews.list:setChoices(filtered_fortControlledUnits) -end - -function SearchEngine:onSelect(index, unit) --- Assign the unit to a specific id -local unit = df.unit.find(unit.id) - --- Get the position of the unit and center the camera on the unit -local x, y, z = dfhack.units.getPosition(unit) -dfhack.gui.revealInDwarfmodeMap(xyz2pos(x, y, z), true) - --- Get the dimensions of the Dwarf Fortress map -local dims = dfhack.gui.getDwarfmodeViewDims() --- Calculate zoom factor based on current viewport zoom level -local gpsZoom = df.global.gps.viewport_zoom_factor --- Set the mouse x and y positions to click on the unit -df.global.gps.precise_mouse_x = (x - df.global.window_x) * gpsZoom // 4 + gpsZoom // 8 -df.global.gps.precise_mouse_y = (y - df.global.window_y) * gpsZoom // 4 + gpsZoom // 8 - --- Enable mouse tracking and set the left mouse button as pressed -df.global.enabler.tracking_on = 1 -df.global.enabler.mouse_lbut = 1 -df.global.enabler.mouse_lbut_down = 1 - --- Simulate a left mouse click at the current mouse position -gui.simulateInput(dfhack.gui.getDFViewscreen(), '_MOUSE_R') - -gui.simulateInput(dfhack.gui.getDFViewscreen(), '_MOUSE_L') - --- Disable mouse tracking and set the left mouse button as not pressed -df.global.enabler.tracking_on = 0 -df.global.enabler.mouse_lbut = 0 -df.global.enabler.mouse_lbut_down = 0 - -end - --- Screen creation -SearchEngineScreen = defclass(SearchEngineScreen, gui.ZScreen) -SearchEngineScreen.ATTRS = { - focus_path='SearchEngine', -} - -function SearchEngineScreen:init() - self:addviews{SearchEngine{}} -end - -function SearchEngineScreen:onDismiss() - view = nil -end - -view = view and view:raise() or SearchEngineScreen{}:show() diff --git a/zUniform.lua b/zUniform.lua new file mode 100644 index 0000000000..148b389bed --- /dev/null +++ b/zUniform.lua @@ -0,0 +1,249 @@ +--@ module=true + +local gui = require('gui') +local widgets = require('gui.widgets') +local overlay = require('plugins.overlay') +local dialogs = require('gui.dialogs') +local json = require('json') + +local UNIFORM_DIR = dfhack.getDFPath() .. '/dfhack-config/squad_uniform/' + +local function ensure_uniform_dir() + if not dfhack.filesystem.isdir(UNIFORM_DIR) then + dfhack.filesystem.mkdir(UNIFORM_DIR) + end +end + +local function is_valid_name(name) + return name and #name > 0 and not name:find('[^%w%._%s]') +end + +local function get_uniform_files() + ensure_uniform_dir() + local files = {} + local list = dfhack.filesystem.listdir(UNIFORM_DIR) + if list then + for _, file in ipairs(list) do + if file:match('%.dfuniform$') then + table.insert(files, file) + end + end + table.sort(files) + end + return files +end + +local function import_uniform_file(filepath) + ensure_uniform_dir() + local file, err = io.open(filepath, 'r') + if not file then + return false, 'Failed to open file for reading: ' .. tostring(err) + end + + local text = file:read('*a') + file:close() + + local ok, data = pcall(json.decode, text) + if not ok or type(data) ~= 'table' then + return false, 'Failed to decode uniform file or invalid format.' + end + + local uniform_data = data.uniform + if type(uniform_data) ~= 'table' then + return false, 'Uniform data is missing or invalid.' + end + + local nickname = data.nickname + if not nickname or nickname == '' then + nickname = filepath:match('([^/\\]+)%.dfuniform$') or 'ImportedUniform' + end + + local panel = df.global.game.main_interface and df.global.game.main_interface.squad_equipment + if not panel then + return false, 'Squad equipment panel is not available. Please open the Military > Equipment screen.' + end + + local n = #uniform_data + panel.cs_cat:resize(n) + panel.cs_it_spec_item_id:resize(n) + panel.cs_it_type:resize(n) + panel.cs_it_subtype:resize(n) + panel.cs_civ_mat:resize(n) + panel.cs_spec_mat:resize(n) + panel.cs_spec_matg:resize(n) + panel.cs_color_pattern_index:resize(n) + panel.cs_icp_flag:resize(n) + panel.cs_assigned_item_number:resize(n) + panel.cs_assigned_item_id:resize(n) + + panel.open = true + panel.customizing_equipment = true + panel.customizing_squad_entering_uniform_nickname = true + panel.customizing_squad_uniform_nickname = nickname + + for i, slot in ipairs(uniform_data) do + local idx = i - 1 + panel.cs_cat[idx] = slot.cat or -1 + panel.cs_it_spec_item_id[idx] = slot.spec_item_id or -1 + panel.cs_it_type[idx] = slot.it_type or -1 + panel.cs_it_subtype[idx] = slot.it_subtype or -1 + panel.cs_civ_mat[idx] = slot.civ_mat or -1 + panel.cs_spec_mat[idx] = slot.spec_mat or -1 + panel.cs_spec_matg[idx] = slot.spec_matg or -1 + panel.cs_color_pattern_index[idx] = slot.color_pattern_index or -1 + panel.cs_icp_flag[idx] = slot.icp_flag or 0 + panel.cs_assigned_item_number[idx] = slot.assigned_item_number or -1 + panel.cs_assigned_item_id[idx] = slot.assigned_item_id or -1 + end + + panel.cs_uniform_flag = data.uniform_flag or 2 + + return true, 'Uniform successfully imported!' +end + +local function export_uniform_file(filepath) + ensure_uniform_dir() + local panel = df.global.game.main_interface and df.global.game.main_interface.squad_equipment + if not panel then + return false, 'Squad equipment panel is not available. Please open the Military > Equipment screen.' + end + + local n = #panel.cs_cat + local uniform_data = {} + for i = 0, n - 1 do + table.insert(uniform_data, { + cat = panel.cs_cat[i], + spec_item_id = panel.cs_it_spec_item_id[i], + it_type = panel.cs_it_type[i], + it_subtype = panel.cs_it_subtype[i], + civ_mat = panel.cs_civ_mat[i], + spec_mat = panel.cs_spec_mat[i], + spec_matg = panel.cs_spec_matg[i], + color_pattern_index = panel.cs_color_pattern_index[i], + icp_flag = panel.cs_icp_flag[i], + assigned_item_number = panel.cs_assigned_item_number[i], + assigned_item_id = panel.cs_assigned_item_id[i], + }) + end + + local nickname = panel.customizing_squad_uniform_nickname or '' + local uniform_flag = panel.cs_uniform_flag or 2 + + local file, err = io.open(filepath, 'w') + if not file then return false, 'Failed to open file for writing: ' .. tostring(err) end + file:write(json.encode({ + nickname = nickname, + uniform = uniform_data, + uniform_flag = uniform_flag + })) + file:close() + return true, 'Uniform saved to ' .. filepath +end + +local function ExportUniformDialog() + dialogs.InputBox{ + frame_title = 'Export Squad Uniform', + text = 'Enter file name (no extension):', + on_input = function(name) + if not is_valid_name(name) then + dialogs.showMessage("Invalid Name", "Name can only contain letters, numbers, underscores, periods, and spaces.") + return + end + local fname = UNIFORM_DIR .. name .. '.dfuniform' + local ok, msg = export_uniform_file(fname) + if ok then + dfhack.println('Exported to: ' .. fname) + else + dfhack.printerr(msg) + end + end + }:show() +end + +local function get_uniform_choices() + local files = get_uniform_files() + local choices = {} + for _, f in ipairs(files) do + table.insert(choices, {text = f}) + end + return choices +end + +local function ImportUniformDialog() + ensure_uniform_dir() + local dlg + local function get_dlg() return dlg end + + dlg = dialogs.ListBox{ + frame_title = 'Import/Delete Squad Uniform', + with_filter = true, + choices = get_uniform_choices(), + on_select = function(_, choice) + dfhack.timeout(2, 'frames', function() + local fname = UNIFORM_DIR .. choice.text + local ok, msg = import_uniform_file(fname) + if ok then + dfhack.println('Imported from: ' .. fname) + else + dfhack.printerr(msg) + end + end) + end, + dismiss_on_select2 = false, + on_select2 = function(_, choice) + local fname = UNIFORM_DIR .. choice.text + if not dfhack.filesystem.isfile(fname) then return end + + dialogs.showYesNoPrompt('Delete uniform file?', + 'Are you sure you want to delete "' .. fname .. '"?', nil, + function() + os.remove(fname) + dfhack.println('Deleted: ' .. fname) + local list = get_dlg().subviews.list + local filter = list:getFilter() + list:setChoices(get_uniform_choices(), list:getSelected()) + list:setFilter(filter) + end) + end, + select2_hint = 'Delete file', + }:show() +end + +local UniformOverlay = defclass(UniformOverlay, overlay.OverlayWidget) +UniformOverlay.ATTRS{ + desc = 'Manage squad uniforms.', + viewscreens = 'dwarfmode/Squads/Equipment/Customizing/Default', + default_enabled = true, + default_pos = {x = -33, y = -5}, + frame = {w = 40, h = 3}, +} + +function UniformOverlay:init() + self:addviews{ + widgets.Panel{ + frame = {t = 0, l = 0, w = 40, h = 3}, + frame_style = gui.MEDIUM_FRAME, + frame_background = gui.CLEAR_PEN, + subviews = { + widgets.HotkeyLabel{ + frame = {l = 0, t = 0}, + label = '[Import]', + key = 'CUSTOM_CTRL_I', + auto_width = true, + on_activate = ImportUniformDialog, + }, + widgets.HotkeyLabel{ + frame = {l = 20, t = 0}, + label = '[Export]', + key = 'CUSTOM_CTRL_E', + auto_width = true, + on_activate = ExportUniformDialog, + }, + }, + }, + } +end + +OVERLAY_WIDGETS = { + uniform_overlay = UniformOverlay, +} From 06d8c62f5b637218dcdfdcf0448bb53d0d3b2dfc Mon Sep 17 00:00:00 2001 From: unboundlopez <47876628+unboundlopez@users.noreply.github.com> Date: Thu, 29 May 2025 23:07:52 -0500 Subject: [PATCH 16/17] Update zUniform.rst --- docs/zUniform.rst | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/docs/zUniform.rst b/docs/zUniform.rst index e82a6297ef..4d1e279e78 100644 --- a/docs/zUniform.rst +++ b/docs/zUniform.rst @@ -1,24 +1,29 @@ -squad-uniform +zUniform.rst ============= -An overlay UI that allows importing and exporting squad uniforms. +An overlay UI for importing and exporting squad uniforms in Dwarf Fortress. + +Overview +-------- + +This tool adds an interface overlay to the squad equipment screen, allowing you to easily save and load uniform setups. Usage ----- -To use this overlay: +To use the overlay: -1. Press `q` to open the squad sidebar. -2. Select a squad by clicking its checkbox. -3. Click the `Equip` button. +1. Press ``q`` to open the squad sidebar. +2. Select a squad by checking its checkbox. +3. Click the ``Equip`` button. 4. Either: - - Press `Add uniform` to create a new one, **or** - - Click a unit’s `Details` button to customize their equipment. -5. The `[Import]` and `[Export]` buttons will now appear in the **bottom-right** corner of the screen. - - You can also use the hotkeys: - - `Ctrl+I` to import a uniform - - `Ctrl+E` to export the current uniform + - Click ``Add uniform`` to create a new one, **or** + - Click a unit’s ``Details`` button to customize their equipment. +5. The ``[Import]`` and ``[Export]`` buttons will now appear in the **bottom-right** corner of the screen. + - You can also use hotkeys: + - ``Ctrl+I`` to import a uniform + - ``Ctrl+E`` to export the current uniform Uniforms are saved to and loaded from the following folder: -Dwarf Fortress\dfhack-config\squad_uniform +``Dwarf Fortress\dfhack-config\squad_uniform`` From a66cce90fa320b7270af31af9d96182ad360bc91 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 30 May 2025 04:11:14 +0000 Subject: [PATCH 17/17] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- docs/zUniform.rst | 58 +++++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/docs/zUniform.rst b/docs/zUniform.rst index 4d1e279e78..417168b5eb 100644 --- a/docs/zUniform.rst +++ b/docs/zUniform.rst @@ -1,29 +1,29 @@ -zUniform.rst -============= - -An overlay UI for importing and exporting squad uniforms in Dwarf Fortress. - -Overview --------- - -This tool adds an interface overlay to the squad equipment screen, allowing you to easily save and load uniform setups. - -Usage ------ - -To use the overlay: - -1. Press ``q`` to open the squad sidebar. -2. Select a squad by checking its checkbox. -3. Click the ``Equip`` button. -4. Either: - - Click ``Add uniform`` to create a new one, **or** - - Click a unit’s ``Details`` button to customize their equipment. -5. The ``[Import]`` and ``[Export]`` buttons will now appear in the **bottom-right** corner of the screen. - - You can also use hotkeys: - - ``Ctrl+I`` to import a uniform - - ``Ctrl+E`` to export the current uniform - -Uniforms are saved to and loaded from the following folder: - -``Dwarf Fortress\dfhack-config\squad_uniform`` +zUniform.rst +============= + +An overlay UI for importing and exporting squad uniforms in Dwarf Fortress. + +Overview +-------- + +This tool adds an interface overlay to the squad equipment screen, allowing you to easily save and load uniform setups. + +Usage +----- + +To use the overlay: + +1. Press ``q`` to open the squad sidebar. +2. Select a squad by checking its checkbox. +3. Click the ``Equip`` button. +4. Either: + - Click ``Add uniform`` to create a new one, **or** + - Click a unit’s ``Details`` button to customize their equipment. +5. The ``[Import]`` and ``[Export]`` buttons will now appear in the **bottom-right** corner of the screen. + - You can also use hotkeys: + - ``Ctrl+I`` to import a uniform + - ``Ctrl+E`` to export the current uniform + +Uniforms are saved to and loaded from the following folder: + +``Dwarf Fortress\dfhack-config\squad_uniform``