From d2103944293d33f6371cf44ebd2d61580de601d9 Mon Sep 17 00:00:00 2001 From: BenTalagan Date: Fri, 12 Dec 2025 14:40:41 +0100 Subject: [PATCH] Update Reannotate v0.4.4 > v0.4.5 --- Various/talagan_Reannotate.lua | 9 +- .../talagan_Reannotate Quick Preview.lua | 2 +- .../talagan_Reannotate/modules/defines.lua | 27 +++- .../modules/project_settings.lua | 124 ++++++++++-------- .../talagan_Reannotate/modules/settings.lua | 6 +- .../widgets/overlay_canvas.lua | 29 ++-- .../widgets/settings_editor.lua | 41 +++++- 7 files changed, 156 insertions(+), 82 deletions(-) diff --git a/Various/talagan_Reannotate.lua b/Various/talagan_Reannotate.lua index 3ffd58c5c..2ebafccd3 100644 --- a/Various/talagan_Reannotate.lua +++ b/Various/talagan_Reannotate.lua @@ -1,6 +1,6 @@ --[[ @description Reannotate - Annotation tool for REAPER -@version 0.4.4 +@version 0.4.6 @author Ben 'Talagan' Babut @donation https://www.paypal.com/donate/?business=3YEZMY9D6U8NC&no_recurring=1¤cy_code=EUR @license MIT @@ -10,10 +10,9 @@ Forum Thread https://forum.cockos.com/showthread.php?t=304147 @metapackage @changelog - - [Feature] Posters - - [Feature] Can now add annotations to regions - - [Feature] Progress bar sticker - - [Bug fixes] Various bug fixes + - [Feature] Stickers can be positioned top or bottom + - [Bug Fix] Markdown is now wrapped in posters + - [Bug Fix] Plain text is now wrapped in posters @provides [nomain] talagan_Reannotate/ext/**/* [nomain] talagan_Reannotate/classes/**/* diff --git a/Various/talagan_Reannotate/actions/talagan_Reannotate Quick Preview.lua b/Various/talagan_Reannotate/actions/talagan_Reannotate Quick Preview.lua index 3f1e6551e..0b35e5ef8 100644 --- a/Various/talagan_Reannotate/actions/talagan_Reannotate Quick Preview.lua +++ b/Various/talagan_Reannotate/actions/talagan_Reannotate Quick Preview.lua @@ -27,7 +27,7 @@ local QuickPreviewOverlay = require "widgets/quick_preview_overlay" local S = require "modules/settings" local D = require "modules/debug" -S.setSetting("UseDebugger", false) +S.setSetting("UseDebugger", true) S.setSetting("UseProfiler", false) D.LaunchDebugStubIfNeeded() D.LaunchProfilerIfNeeded() diff --git a/Various/talagan_Reannotate/modules/defines.lua b/Various/talagan_Reannotate/modules/defines.lua index 9d39d1f4b..ae8b0ca28 100644 --- a/Various/talagan_Reannotate/modules/defines.lua +++ b/Various/talagan_Reannotate/modules/defines.lua @@ -41,6 +41,13 @@ Defines.POSTER_TYPES = { POSTER_TYPE_COUNT = 6 } +Defines.STICKER_POSITIONINGS = { + TOP_RIGHT = 0, + BOTTOM_RIGHT = 1, + + POSITIONING_COUNT = 2 +} + function Defines.deepCopy(orig) local orig_type = type(orig) local copy @@ -125,7 +132,7 @@ function Defines.PosterTypeToName(type, default_type) if type == Defines.POSTER_TYPES.NOTE_RENDERERED_AS_PLAIN_POSTER then return "Note as plain" end if type == Defines.POSTER_TYPES.NOTE_RENDERERED_AS_MARKDOWN_POSTER then return "Note as markdown" end - error("DEVELOPER ERROR : Unknown post type" .. type) + error("DEVELOPER ERROR : Unknown poster type " .. type) end function Defines.PosterTypeComboInfo(default_type) @@ -141,4 +148,22 @@ function Defines.PosterTypeComboInfo(default_type) end + +function Defines.StickerPositioningToName(val) + if val == Defines.STICKER_POSITIONINGS.TOP_RIGHT then return "Top Right" end + if val == Defines.STICKER_POSITIONINGS.BOTTOM_RIGHT then return "Bottom Right" end + error("DEVELOPER ERROR : Unknown positioning type" .. val) +end +function Defines.StickerPositiongComboInfo() + local start = 0 + local ret = { list = {} , reverse_lookup = {} } + for i=start, Defines.STICKER_POSITIONINGS.POSITIONING_COUNT-1 do + local s = Defines.StickerPositioningToName(i) + ret.list[#ret.list+1] = s + ret.reverse_lookup[s] = i + end + return ret +end + + return Defines diff --git a/Various/talagan_Reannotate/modules/project_settings.lua b/Various/talagan_Reannotate/modules/project_settings.lua index fab33e525..3905b2a3e 100644 --- a/Various/talagan_Reannotate/modules/project_settings.lua +++ b/Various/talagan_Reannotate/modules/project_settings.lua @@ -16,6 +16,8 @@ PS.slot_labels_dirty = nil PS.poster_default_type = nil +-- ====== STYLES ====== + -- Not edited directly because we want preview / save features. function PS.RetrieveProjectMarkdownStyle() local _, str = reaper.GetSetMediaTrackInfo_String(D.ActiveProjectMasterTrack(), "P_EXT:Reannotate_ProjectMarkdownStyle", "", false) @@ -55,104 +57,110 @@ function PS.CommitProjectMarkdownStyle(markdown_style) reaper.GetSetMediaTrackInfo_String(D.ActiveProjectMasterTrack(),"P_EXT:Reannotate_ProjectMarkdownStyle", str, true) end +-- ====== LABELS ====== - -function PS.RetrieveProjectStickerSize() - local _, str = reaper.GetSetMediaTrackInfo_String(D.ActiveProjectMasterTrack(), "P_EXT:Reannotate_ProjectStickerSize", "", false) - local fallback = false - local size = nil +function PS.RetrieveProjectSlotLabels() + local _, str = reaper.GetSetMediaTrackInfo_String(D.ActiveProjectMasterTrack(), "P_EXT:Reannotate_ProjectSlotLabels", "", false) + local slot_labels = {} if str == "" or str == nil then - fallback = true else - size = tonumber(str) + slot_labels = JSON.decode(str) end - if fallback then - size = S.getSetting("NewProjectStickerSize") - PS.CommitProjectStickerSize(size) + -- Ensure labels have names by defaulting to global setting + for i = 0, D.MAX_SLOTS -1 do + slot_labels[i+1] = slot_labels[i+1] or S.getSetting("SlotLabel_" .. i) end - return size + PS.slot_labels = slot_labels end -function PS.CommitProjectStickerSize(size) - reaper.GetSetMediaTrackInfo_String(D.ActiveProjectMasterTrack(),"P_EXT:Reannotate_ProjectStickerSize", "" .. size, true) +function PS.CommitProjectSlotLabels() + if not PS.slot_labels_dirty then return end + if not PS.slot_labels then PS.RetrieveProjectSlotLabels() end + + local str = JSON.encode(PS.slot_labels) + reaper.GetSetMediaTrackInfo_String(D.ActiveProjectMasterTrack(), "P_EXT:Reannotate_ProjectSlotLabels", str, true) + PS.slot_labels_dirty = false +end +function PS.SlotLabel(slot) + if not PS.slot_labels then PS.RetrieveProjectSlotLabels() end + return PS.slot_labels[slot+1] +end +function PS.SetSlotLabel(slot, label) + if not PS.slot_labels then PS.RetrieveProjectSlotLabels() end + PS.slot_labels[slot+1] = label + PS.slot_labels_dirty = true + PS.CommitProjectSlotLabels() end -function PS.RetrieveProjectPosterDefaultType() - local _, str = reaper.GetSetMediaTrackInfo_String(D.ActiveProjectMasterTrack(), "P_EXT:Reannotate_PosterDefaultType", "", false) - local fallback = false - local type = nil + +function PS.CommitProjectSetting(project_key, value) + reaper.GetSetMediaTrackInfo_String(D.ActiveProjectMasterTrack(),"P_EXT:" .. project_key, "" .. value, true) +end +function PS.RetrieveProjectSettingWithFallback(project_key, global_setting_key) + local _, str = reaper.GetSetMediaTrackInfo_String(D.ActiveProjectMasterTrack(), "P_EXT:" .. project_key, "", false) + local fallback = false + local value = nil if str == "" or str == nil then fallback = true else - type = tonumber(str) + value = tonumber(str) end if fallback then - type = S.getSetting("NewProjectPosterDefaultType") - PS.CommitProjectPosterDefaultType(type) + value = S.getSetting(global_setting_key) + PS.CommitProjectSetting(project_key, value) end - return type + return value end -function PS.CommitProjectPosterDefaultType(type) - reaper.GetSetMediaTrackInfo_String(D.ActiveProjectMasterTrack(),"P_EXT:Reannotate_PosterDefaultType", "" .. type, true) + +function PS.RetrieveProjectStickerSize() + return PS.RetrieveProjectSettingWithFallback("Reannotate_ProjectStickerSize","NewProjectStickerSize") +end +function PS.CommitProjectStickerSize(size) + PS.CommitProjectSetting("Reannotate_ProjectStickerSize", size) end + +function PS.RetrieveProjectPosterDefaultType() + return PS.RetrieveProjectSettingWithFallback("Reannotate_PosterDefaultType", "NewProjectPosterDefaultType") +end +function PS.CommitProjectPosterDefaultType(type) + PS.CommitProjectSetting("Reannotate_PosterDefaultType", type) +end function PS.ProjectPosterDefaultType() if not PS.poster_default_type then PS.poster_default_type = PS.RetrieveProjectPosterDefaultType() end return PS.poster_default_type end - function PS.SetProjectPosterDefaultType(type) PS.poster_default_type = type PS.CommitProjectPosterDefaultType(type) end - -function PS.RetrieveProjectSlotLabels() - local _, str = reaper.GetSetMediaTrackInfo_String(D.ActiveProjectMasterTrack(), "P_EXT:Reannotate_ProjectSlotLabels", "", false) - local slot_labels = {} - if str == "" or str == nil then - else - slot_labels = JSON.decode(str) - end - - -- Ensure labels have names by defaulting to global setting - for i = 0, D.MAX_SLOTS -1 do - slot_labels[i+1] = slot_labels[i+1] or S.getSetting("SlotLabel_" .. i) +function PS.RetrieveProjectStickerPositioning() + return PS.RetrieveProjectSettingWithFallback("Reannotate_StickerPositioning", "NewProjectStickerPositioning") +end +function PS.CommitProjectStickerPositioning(val) + PS.CommitProjectSetting("Reannotate_StickerPositioning", val) +end +function PS.ProjectStickerPositioning() + if not PS.sticker_positioning then + PS.sticker_positioning = PS.RetrieveProjectStickerPositioning() end - - PS.slot_labels = slot_labels + return PS.sticker_positioning end - -function PS.CommitProjectSlotLabels() - if not PS.slot_labels_dirty then return end - if not PS.slot_labels then PS.RetrieveProjectSlotLabels() end - - local str = JSON.encode(PS.slot_labels) - reaper.GetSetMediaTrackInfo_String(D.ActiveProjectMasterTrack(), "P_EXT:Reannotate_ProjectSlotLabels", str, true) - PS.slot_labels_dirty = false +function PS.SetProjectStickerPositioning(val) + PS.sticker_positioning = val + PS.CommitProjectStickerPositioning(val) end -function PS.SlotLabel(slot) - if not PS.slot_labels then PS.RetrieveProjectSlotLabels() end - return PS.slot_labels[slot+1] -end - -function PS.SetSlotLabel(slot, label) - if not PS.slot_labels then PS.RetrieveProjectSlotLabels() end - PS.slot_labels[slot+1] = label - PS.slot_labels_dirty = true - PS.CommitProjectSlotLabels() -end - return PS diff --git a/Various/talagan_Reannotate/modules/settings.lua b/Various/talagan_Reannotate/modules/settings.lua index a16217f3f..ebcd881a2 100644 --- a/Various/talagan_Reannotate/modules/settings.lua +++ b/Various/talagan_Reannotate/modules/settings.lua @@ -28,7 +28,8 @@ local DefaultMarkdownStyle = { separator = { padding_top = 3, padding_bottom = 7 } } -local DefaultPosterType = D.POSTER_TYPES.NOTE_RENDERERED_AS_PLAIN_POSTER +local DefaultPosterType = D.POSTER_TYPES.NOTE_RENDERERED_AS_PLAIN_POSTER +local DefaultStickerPositioning = D.STICKER_POSITIONINGS.BOTTOM_RIGHT local SettingDefs = { UseDebugger = { type = "bool", default = false }, @@ -47,7 +48,8 @@ local SettingDefs = { UIFontSize = { type = "int", default = 12 }, NewProjectMarkdown = { type = "json", default = DefaultMarkdownStyle }, NewProjectStickerSize = { type = "int", default = 12 }, - NewProjectPosterDefaultType = { type = "int", default = DefaultPosterType } + NewProjectPosterDefaultType = { type = "int", default = DefaultPosterType }, + NewProjectStickerPositioning = { type = "int", default = DefaultStickerPositioning } }; local function unsafestr(str) diff --git a/Various/talagan_Reannotate/widgets/overlay_canvas.lua b/Various/talagan_Reannotate/widgets/overlay_canvas.lua index af659a11a..eddb6b408 100644 --- a/Various/talagan_Reannotate/widgets/overlay_canvas.lua +++ b/Various/talagan_Reannotate/widgets/overlay_canvas.lua @@ -294,11 +294,12 @@ function OverlayCanvas:renderThingSlotPoster(thing, slot, ctx, draw_list, x1, x2 local tttext = (use_note_text and thing.notes:slotText(slot) or thing.notes:slotCustomPoster(slot)) or '' cache.plain = ImGuiMdText.ASTToPlainText( ImGuiMdAst(tttext), {newlines=true}) end - ImGui.Text(ctx, cache.plain) + ImGui.TextWrapped(ctx, cache.plain) + --ImGui.Text(ctx, cache.plain) else if not cache.mdwidget then local tttext = (use_note_text and thing.notes:slotText(slot) or thing.notes:slotCustomPoster(slot)) or '' - cache.mdwidget = ImGuiMd:new(ctx, "thing_md_widget_" .. thing.rand .. "_" .. slot, {wrap = false, skip_last_whitespace = true, autopad = true, additional_window_flags = ImGui.WindowFlags_NoSavedSettings | ImGui.WindowFlags_NoFocusOnAppearing | ImGui.WindowFlags_NoInputs | ImGui.WindowFlags_NoScrollbar }, PS.RetrieveProjectMarkdownStyle() ) + cache.mdwidget = ImGuiMd:new(ctx, "thing_md_widget_" .. thing.rand .. "_" .. slot, {wrap = true, skip_last_whitespace = true, autopad = true, additional_window_flags = ImGui.WindowFlags_NoSavedSettings | ImGui.WindowFlags_NoFocusOnAppearing | ImGui.WindowFlags_NoInputs | ImGui.WindowFlags_NoScrollbar }, PS.RetrieveProjectMarkdownStyle() ) cache.mdwidget:setText(tttext) end cache.mdwidget:render(ctx) @@ -328,10 +329,6 @@ function OverlayCanvas:renderThingSlotStickers(thing, slot, ctx, x1, x2, y1, y2) end end - local num_on_line = 0 - local cursor_x, cursor_y = x2 - hmargin, y1 + vmargin -- Align top right - - ImGui.SetCursorScreenPos(ctx, x1, y1) local window_flags = ImGui.WindowFlags_NoBackground | ImGui.WindowFlags_NoScrollbar | ImGui.WindowFlags_NoDecoration | @@ -342,28 +339,37 @@ function OverlayCanvas:renderThingSlotStickers(thing, slot, ctx, x1, x2, y1, y2) ImGui.WindowFlags_NoMove -- Use a child for receiving all stickers, this will allow clipping and using standard ImGui directives + -- Make the child overlap the thing + ImGui.SetCursorScreenPos(ctx, x1, y1) if ImGui.BeginChild(ctx, "stickers_for_thing_" .. thing.rand .. "_" .. slot, x2-x1, y2-y1, ImGui.ChildFlags_None, window_flags) then + -- Initialize the cursor ImGui.SetCursorPos(ctx, 0, 0) + -- Clip the subzone local draw_list = ImGui.GetWindowDrawList(ctx) ImGui.DrawList_PushClipRect(draw_list, x1 + 3, y1 + 3, x2 + 3, y2 - 3) + + local bottom_to_top_mode = PS.ProjectStickerPositioning() == D.STICKER_POSITIONINGS.BOTTOM_RIGHT + local num_on_line = 0 + local cursor_x, cursor_y = x2 - hmargin, (bottom_to_top_mode) and (y2 - vmargin) or (y1 + vmargin) -- Align bottom right + for _, sticker in ipairs(slot_stickers) do local metrics = sticker:PreRender(ctx, font_size) local available_width = cursor_x - (x1 + hmargin) if num_on_line ~= 0 and (available_width < metrics.width) then cursor_x = x2 - hmargin - cursor_y = cursor_y + metrics.height + vpad + cursor_y = (bottom_to_top_mode) and (cursor_y - metrics.height - vpad) or (cursor_y + metrics.height + vpad) num_on_line = 0 end - sticker:Render(ctx, metrics, cursor_x - metrics.width, cursor_y) + sticker:Render(ctx, metrics, cursor_x - metrics.width, (bottom_to_top_mode) and (cursor_y - metrics.height) or (cursor_y)) cursor_x = cursor_x - metrics.width - hpad num_on_line = num_on_line + 1 end - -- Force ImGui to extend bounds + ImGui.DrawList_PopClipRect(draw_list) + -- Force ImGui to extend bounds ImGui.Dummy(ctx,0,0) - ImGui.EndChild(ctx) end end @@ -582,8 +588,6 @@ function OverlayCanvas:draw() if succ then - local draw_list = ImGui.GetWindowDrawList(ctx) - if self.grab_focus then ImGui.SetWindowFocus(ctx) self.grab_focus = false @@ -605,6 +609,7 @@ function OverlayCanvas:draw() self:drawQuickSettings() end + -- Check for hovered thing for _, thing in ipairs(visible_things) do if self:thingBelongsToThisCanvas(thing) then local x1 = thing.pos_x + thing.parent.x diff --git a/Various/talagan_Reannotate/widgets/settings_editor.lua b/Various/talagan_Reannotate/widgets/settings_editor.lua index 7da202a6e..615e2bc5c 100644 --- a/Various/talagan_Reannotate/widgets/settings_editor.lua +++ b/Various/talagan_Reannotate/widgets/settings_editor.lua @@ -374,17 +374,33 @@ function SettingsEditor:stickersTable() ImGui.BeginGroup(ctx) ImGui.Selectable(ctx, "New Project", true, 0, WIDGET_WIDTH + (self.preview_new_proj_markdown and PREVIEW_WIDTH + 4 or 0)) + ImGui.BeginGroup(ctx) ImGui.AlignTextToFramePadding(ctx) ImGui.Text(ctx,"Size") ImGui.SameLine(ctx) local sticker_size = S.getSetting("NewProjectStickerSize") - - local b, v = ImGui.SliderInt(ctx, "##font_size", sticker_size, 8, 20) + local b, v = ImGui.SliderInt(ctx, "##sticker_size", sticker_size, 8, 20) if b then S.setSetting("NewProjectStickerSize", v) end + ImGui.AlignTextToFramePadding(ctx) + ImGui.Text(ctx,"Positioning") + ImGui.SameLine(ctx) + local cur_val = S.getSetting("NewProjectStickerPositioning") + local combo_info = D.StickerPositiongComboInfo() + if ImGui.BeginCombo(ctx, "##sticker_positioning_combo", D.StickerPositioningToName(cur_val) , ImGui.ComboFlags_None | ImGui.ComboFlags_WidthFitPreview) then + for _, v in ipairs(combo_info.list) do + local real_val = combo_info.reverse_lookup[v] + if ImGui.Selectable(ctx, v, cur_val == real_val) then + S.setSetting("NewProjectStickerPositioning", real_val) + end + end + ImGui.EndCombo(ctx) + end + ImGui.EndGroup(ctx) + if self.preview_new_proj_markdown then ImGui.SameLine(ctx) ImGui.BeginGroup(ctx) @@ -429,13 +445,32 @@ function SettingsEditor:stickersTable() end ImGui.SetCursorPosX(ctx, xalign + (self.preview_cur_proj_markdown and PREVIEW_WIDTH + 4 or 0)) + + ImGui.BeginGroup(ctx) ImGui.Text(ctx,"Size") ImGui.SameLine(ctx) - local b, v = ImGui.SliderInt(ctx, "##font_size", sticker_size, 8, 20) + local b, v = ImGui.SliderInt(ctx, "##sticker_size", sticker_size, 8, 20) if b then PS.CommitProjectStickerSize(v) end + ImGui.AlignTextToFramePadding(ctx) + ImGui.Text(ctx,"Positioning") + ImGui.SameLine(ctx) + local cur_val = PS.RetrieveProjectStickerPositioning() + local combo_info = D.StickerPositiongComboInfo() + if ImGui.BeginCombo(ctx, "##sticker_positioning_combo", D.StickerPositioningToName(cur_val) , ImGui.ComboFlags_None | ImGui.ComboFlags_WidthFitPreview) then + for _, v in ipairs(combo_info.list) do + local real_val = combo_info.reverse_lookup[v] + if ImGui.Selectable(ctx, v, cur_val == real_val) then + PS.SetProjectStickerPositioning(real_val) + end + end + ImGui.EndCombo(ctx) + end + + ImGui.EndGroup(ctx) + ImGui.EndGroup(ctx) ImGui.PopID(ctx) end