-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Add functionality for multiple notes #9456
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
base: dev
Are you sure you want to change the base?
Changes from all commits
d08e7c8
7f1d92c
e4f6486
a78b9db
a1a4ff6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,101 @@ | ||
| -- Path of Building | ||
| -- | ||
| -- Class: Note List | ||
| -- Note list control. | ||
| -- | ||
| local t_insert = table.insert | ||
| local t_remove = table.remove | ||
| local m_max = math.max | ||
|
|
||
| local NotesListClass = newClass("NotesListControl", "ListControl", function(self, anchor, rect, notesTab) | ||
| self.ListControl(anchor, rect, 16, "VERTICAL", true, notesTab.notesOrderList) | ||
| self.notesTab = notesTab | ||
|
|
||
| self.label = "^7Notes:" | ||
| self.controls.delete = new("ButtonControl", {"BOTTOMRIGHT",self,"TOPRIGHT"}, {0, -2, 60, 18}, "Delete", function() | ||
| self:OnSelDelete(self.selIndex, self.selValue) | ||
| end) | ||
|
|
||
| self.controls.delete.enabled = function() | ||
| return self.selValue ~= nil and #self.list > 1 | ||
| end | ||
|
|
||
| self.controls.rename = new("ButtonControl", {"RIGHT",self.controls.delete,"LEFT"}, {-2, 0, 60, 18}, "Rename", function() | ||
| self:RenameNote(notesTab.notes[self.selValue]) | ||
| end) | ||
| self.controls.rename.enabled = function() | ||
| return self.selValue ~= nil | ||
| end | ||
|
|
||
| self.controls.new = new("ButtonControl", {"RIGHT",self.controls.rename,"LEFT"}, {-2, 0, 60, 18}, "New", function() | ||
| self:RenameNote(notesTab:NewNote(), true) | ||
| end) | ||
| end) | ||
|
|
||
| -- Triggered when the order of the list has changed | ||
| function NotesListClass:OnOrderChange(selIndex, selDragIndex) | ||
| self.notesTab.modFlag = true | ||
| end | ||
|
|
||
| function NotesListClass:OnSelDelete(index, noteId) | ||
| local note = self.notesTab.notes[noteId] | ||
| if #self.list > 1 then | ||
| main:OpenConfirmPopup("Delete Note", "Are you sure you want to delete '"..(note.title or "Default").."'?", "Delete", function() | ||
| t_remove(self.list, index) | ||
| self.notesTab.notes[noteId] = nil | ||
|
|
||
| self.selIndex = nil | ||
| self.selValue = nil | ||
|
|
||
| if noteId == self.notesTab.activeNoteId then | ||
| self.notesTab:SetActiveNote(self.list[m_max(1, index - 1)]) | ||
| end | ||
| end) | ||
| end | ||
| end | ||
|
|
||
| -- Get the value to display in the list row | ||
| function NotesListClass:GetRowValue(column, index, noteId) | ||
| local note = self.notesTab.notes[noteId] | ||
| if column == 1 then | ||
| return (note.title or "Default") .. (noteId == self.notesTab.activeNoteId and " ^9(Current)" or "") | ||
| end | ||
| end | ||
|
|
||
| function NotesListClass:RenameNote(note, addOnName) | ||
| local controls = { } | ||
| controls.label = new("LabelControl", nil, {0, 20, 0, 16}, "^7Enter name for this note:") | ||
| controls.edit = new("EditControl", nil, {0, 40, 350, 20}, note.title, nil, nil, 100, function(buf) | ||
| controls.save.enabled = buf:match("%S") | ||
| end) | ||
| controls.save = new("ButtonControl", nil, {-45, 70, 80, 20}, "Save", function() | ||
| note.title = controls.edit.buf | ||
| self.notesTab.modFlag = true | ||
|
|
||
| if addOnName then | ||
| t_insert(self.list, note.id) | ||
| self.selIndex = #self.list | ||
| self.selValue = note.id | ||
| end | ||
|
|
||
| self.notesTab:SetActiveNote(note.id) | ||
| main:ClosePopup() | ||
| end) | ||
| controls.save.enabled = false | ||
| controls.cancel = new("ButtonControl", nil, {45, 70, 80, 20}, "Cancel", function() | ||
| if addOnName then | ||
| self.notesTab.notes[note.id] = nil | ||
| end | ||
| main:ClosePopup() | ||
| end) | ||
| main:OpenPopup(370, 100, note.title and "Rename" or "Note Name", controls, "save", "edit", "cancel") | ||
| end | ||
|
|
||
| -- Triggered when a note is selected from the list | ||
| function NotesListClass:OnSelClick(index, noteId, doubleClick) | ||
| self.notesTab:SaveContentToNote(self.notesTab.activeNoteId) | ||
|
|
||
| if doubleClick and noteId ~= self.notesTab.activeNoteId then | ||
| self.notesTab:SetActiveNote(noteId) | ||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,13 +11,21 @@ local NotesTabClass = newClass("NotesTab", "ControlHost", "Control", function(se | |
|
|
||
| self.build = build | ||
|
|
||
| self.lastContent = "" | ||
| self.notes = { } | ||
| self.notesOrderList = { } | ||
|
|
||
| self.showColorCodes = false | ||
|
|
||
| local listSize = 250 | ||
|
|
||
| local notesDesc = [[^7You can use Ctrl +/- (or Ctrl+Scroll) to zoom in and out and Ctrl+0 to reset. | ||
| This field also supports different colors. Using the caret symbol (^) followed by a Hex code or a number (0-9) will set the color. | ||
| Below are some common color codes PoB uses: ]] | ||
| self.controls.notesDesc = new("LabelControl", {"TOPLEFT",self,"TOPLEFT"}, {8, 8, 150, 16}, notesDesc) | ||
|
|
||
| -- Notes group list | ||
| self.controls.noteList = new("NotesListControl", { "TOPLEFT", self, "TOPLEFT" }, { 8, 30, listSize - 16, 80 }, self) | ||
|
|
||
| self.controls.notesDesc = new("LabelControl", {"TOPLEFT",self.controls.noteList,"TOPRIGHT"}, {8, -22, 150, 16}, notesDesc) | ||
| self.controls.normal = new("ButtonControl", {"TOPLEFT",self.controls.notesDesc,"TOPLEFT"}, {0, 48, 100, 18}, colorCodes.NORMAL.."NORMAL", function() self:SetColor(colorCodes.NORMAL) end) | ||
| self.controls.magic = new("ButtonControl", {"TOPLEFT",self.controls.normal,"TOPLEFT"}, {120, 0, 100, 18}, colorCodes.MAGIC.."MAGIC", function() self:SetColor(colorCodes.MAGIC) end) | ||
| self.controls.rare = new("ButtonControl", {"TOPLEFT",self.controls.magic,"TOPLEFT"}, {120, 0, 100, 18}, colorCodes.RARE.."RARE", function() self:SetColor(colorCodes.RARE) end) | ||
|
|
@@ -31,7 +39,7 @@ Below are some common color codes PoB uses: ]] | |
| self.controls.intelligence = new("ButtonControl", {"TOPLEFT",self.controls.dexterity,"TOPLEFT"}, {120, 0, 100, 18}, colorCodes.INTELLIGENCE.."INTELLIGENCE", function() self:SetColor(colorCodes.INTELLIGENCE) end) | ||
| self.controls.default = new("ButtonControl", {"TOPLEFT",self.controls.intelligence,"TOPLEFT"}, {120, 0, 100, 18}, "^7DEFAULT", function() self:SetColor("^7") end) | ||
|
|
||
| self.controls.edit = new("EditControl", {"TOPLEFT",self.controls.fire,"TOPLEFT"}, {0, 48, 0, 0}, "", nil, "^%C\t\n", nil, nil, 16, true) | ||
| self.controls.edit = new("EditControl", {"TOPLEFT",self.controls.noteList,"BOTTOMLEFT"}, {0, 8, 0, 0}, "", nil, "^%C\t\n", nil, nil, 16, true) | ||
| self.controls.edit.width = function() | ||
| return self.width - 16 | ||
| end | ||
|
|
@@ -42,6 +50,9 @@ Below are some common color codes PoB uses: ]] | |
| self.showColorCodes = not self.showColorCodes | ||
| self:SetShowColorCodes(self.showColorCodes) | ||
| end) | ||
|
|
||
| self:SetActiveNote(1) | ||
|
|
||
| self:SelectControl(self.controls.edit) | ||
| end) | ||
|
|
||
|
|
@@ -68,18 +79,62 @@ function NotesTabClass:SetColor(color) | |
| end | ||
|
|
||
| function NotesTabClass:Load(xml, fileName) | ||
| for _, node in ipairs(xml) do | ||
| self.activeNoteId = 0 | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Existing builds with an empty AI-assisted review disclosure: This finding was identified during a review using OpenAI Codex and confirmed with a focused reproduction. |
||
| self.notes = { } | ||
| self.noteOrderList = { } | ||
|
|
||
| for index, node in ipairs(xml) do | ||
| -- backwards compatibility | ||
| if type(node) == "string" then | ||
| self.controls.edit:SetText(node) | ||
| self.notesOrderList[1] = 1 | ||
| self.notes[1] = { | ||
| id = 1, | ||
| content = node | ||
| } | ||
|
|
||
| self:SetActiveNote(1) | ||
| else | ||
| local savedNoteId = tonumber(node.attrib.id) | ||
| self.notesOrderList[index] = savedNoteId | ||
|
|
||
| self.notes[savedNoteId] = { | ||
| id = savedNoteId, | ||
| title = node.attrib.title, | ||
| content = node[1] or "" | ||
| } | ||
|
|
||
| if node.attrib.active ~= nil then | ||
| self:SetActiveNote(savedNoteId) | ||
| end | ||
| end | ||
| end | ||
| self.lastContent = self.controls.edit.buf | ||
|
|
||
| self.modFlag = false | ||
| end | ||
|
|
||
| function NotesTabClass:Save(xml) | ||
| self:SetShowColorCodes(false) | ||
| t_insert(xml, self.controls.edit.buf) | ||
| self.lastContent = self.controls.edit.buf | ||
|
|
||
| self.notes[self.activeNoteId].content = self.controls.edit.buf | ||
|
|
||
| for _, noteId in ipairs(self.notesOrderList) do | ||
| local attrib = { | ||
| id = tostring(noteId), | ||
| title = self.notes[noteId].title, | ||
| } | ||
|
|
||
| if self.activeNoteId == noteId then | ||
| attrib.active = "1" | ||
| end | ||
|
|
||
| local note = { | ||
| elem = "Note", | ||
| attrib = attrib, | ||
| [1] = self.notes[noteId].content | ||
| } | ||
|
|
||
| t_insert(xml, note) | ||
| end | ||
| end | ||
|
|
||
| function NotesTabClass:Draw(viewPort, inputEvents) | ||
|
|
@@ -91,17 +146,63 @@ function NotesTabClass:Draw(viewPort, inputEvents) | |
| for id, event in ipairs(inputEvents) do | ||
| if event.type == "KeyDown" then | ||
| if event.key == "z" and IsKeyDown("CTRL") then | ||
| self.controls.edit:Undo() | ||
| if self.controls.edit.hasFocus then | ||
| self.controls.edit:Undo() | ||
| end | ||
| elseif event.key == "y" and IsKeyDown("CTRL") then | ||
| self.controls.edit:Redo() | ||
| if self.controls.edit.hasFocus then | ||
| self.controls.edit:Redo() | ||
| end | ||
| end | ||
| end | ||
| end | ||
|
|
||
| self:ProcessControlsInput(inputEvents, viewPort) | ||
|
|
||
| main:DrawBackground(viewPort) | ||
|
|
||
| self:DrawControls(viewPort) | ||
|
|
||
| self.modFlag = (self.lastContent ~= self.controls.edit.buf) | ||
| self.modFlag = (self.notes[self.activeNoteId].content ~= self.controls.edit.buf) or self.modFlag | ||
| end | ||
|
|
||
| -- Creates a new note | ||
| function NotesTabClass:NewNote(noteId) | ||
| local note = { id = noteId, content = "" } | ||
|
|
||
| if not noteId then | ||
| note.id = 1 | ||
| while self.notes[note.id] do | ||
| note.id = note.id + 1 | ||
| end | ||
| end | ||
|
|
||
| self.notes[note.id] = note | ||
|
|
||
| return note | ||
| end | ||
|
|
||
| -- Changes the active note | ||
| function NotesTabClass:SetActiveNote(noteId) | ||
| -- Initialize note if needed | ||
| if not self.notesOrderList[1] then | ||
| self.notesOrderList[1] = 1 | ||
| self:NewNote(1) | ||
| end | ||
|
|
||
| if not noteId then | ||
| noteId = self.activeNoteId | ||
| end | ||
|
|
||
| if not self.notes[noteId] then | ||
| noteId = self.notesOrderList[1] | ||
| end | ||
|
|
||
| self.activeNoteId = noteId | ||
| self.notes[self.activeNoteId].lastContent = self.controls.edit.buf | ||
| self.controls.edit:SetText(self.notes[noteId].content) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Editing a note and then creating a new note or selecting a loadout silently loses the edit. This call replaces the editor buffer before the previous note's content is copied back; the next save only updates the destination note, and reopening restores the previous text. A focused base/head AI-assisted review disclosure: This finding was identified during a review using OpenAI Codex and confirmed with a focused reproduction. |
||
| end | ||
|
|
||
| function NotesTabClass:SaveContentToNote(noteId) | ||
| self.notes[noteId].content = self.controls.edit.buf | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -338,6 +338,10 @@ function buildMode:Init(dbFileName, buildName, buildXML, convertBuild, importLin | |
| t_insert(self.configTab.configSetOrderList, configSet.id) | ||
| configSet.title = loadout | ||
|
|
||
| local note = self.notesTab:NewNote(#self.notesTab.notes + 1) | ||
| t_insert(self.notesTab.notesOrderList, note.id) | ||
| note.title = loadout | ||
|
|
||
| self:SyncLoadouts() | ||
| self.modFlag = true | ||
| main:ClosePopup() | ||
|
|
@@ -387,14 +391,16 @@ function buildMode:Init(dbFileName, buildName, buildXML, convertBuild, importLin | |
| local oneSkill = self.skillsTab and #self.skillsTab.skillSetOrderList == 1 | ||
| local oneItem = self.itemsTab and #self.itemsTab.itemSetOrderList == 1 | ||
| local oneConfig = self.configTab and #self.configTab.configSetOrderList == 1 | ||
| local oneNote = self.notesTab and #self.notesTab.notesOrderList == 1 | ||
|
|
||
| local newSpecId = findNamedSetId(self.treeTab:GetSpecList(), value, self.treeListSpecialLinks) | ||
| local newItemId = oneItem and 1 or findSetId(self.itemsTab.itemSetOrderList, value, self.itemsTab.itemSets, self.itemListSpecialLinks) | ||
| local newSkillId = oneSkill and 1 or findSetId(self.skillsTab.skillSetOrderList, value, self.skillsTab.skillSets, self.skillListSpecialLinks) | ||
| local newConfigId = oneConfig and 1 or findSetId(self.configTab.configSetOrderList, value, self.configTab.configSets, self.configListSpecialLinks) | ||
| local newNoteId = oneNote and 1 or findSetId(self.notesTab.notesOrderList, value, self.notesTab.notes, self.noteListSpecialLinks) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With multiple notes, loadout selection fails in two existing cases. A plain loadout without an exact note title produces AI-assisted review disclosure: This finding was identified during a review using OpenAI Codex and confirmed with a focused reproduction. |
||
|
|
||
| -- if exact match nor special grouping cannot find setIds, bail | ||
| if newSpecId == nil or newItemId == nil or newSkillId == nil or newConfigId == nil then | ||
| if newSpecId == nil or newItemId == nil or newSkillId == nil or newConfigId == nil or newNoteId == nil then | ||
| return | ||
| end | ||
|
|
||
|
|
@@ -410,6 +416,9 @@ function buildMode:Init(dbFileName, buildName, buildXML, convertBuild, importLin | |
| if newConfigId ~= self.configTab.activeConfigSetId then | ||
| self.configTab:SetActiveConfigSet(newConfigId) | ||
| end | ||
| if newNoteId ~= self.notesTab.activeNoteId then | ||
| self.notesTab:SetActiveNote(newNoteId) | ||
| end | ||
|
|
||
| self.controls.buildLoadouts:SelByValue(value) | ||
| end) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Deleting a note is not retained through the normal save flow. This callback removes the note but never marks
notesTab.modFlag; with no other changes, the subsequent Notes draw keeps it false, Save remains disabled, and leaving the build skips the save prompt. Reopening restores the deleted note.AI-assisted review disclosure: This finding was identified during a review using OpenAI Codex and confirmed with a focused reproduction.