Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 5 additions & 7 deletions Various/talagan_Reannotate.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
--[[
@description Reannotate - Annotation tool for REAPER
@version 0.4.3
@version 0.4.4
@author Ben 'Talagan' Babut
@donation https://www.paypal.com/donate/?business=3YEZMY9D6U8NC&no_recurring=1&currency_code=EUR
@license MIT
Expand All @@ -10,12 +10,10 @@
Forum Thread https://forum.cockos.com/showthread.php?t=304147
@metapackage
@changelog
- [Feature] The markdown stylesheet is now customizable
- [Feature] UI Font size is now customizable
- [Feature] Note editor's width is now remembered
- [Bug Fix] Tooltips with vertical scrollbars could affect the layout of other tooltips shown immediately after
- [Rework] Moved project notes to the transport zone instead of the time ruler (will be used for regions / markers ?)
- [Rework] Optimizations
- [Feature] Posters
- [Feature] Can now add annotations to regions
- [Feature] Progress bar sticker
- [Bug fixes] Various bug fixes
@provides
[nomain] talagan_Reannotate/ext/**/*
[nomain] talagan_Reannotate/classes/**/*
Expand Down
4 changes: 4 additions & 0 deletions Various/talagan_Reannotate/classes/app_context.lua
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,10 @@ function AppContext:_initialize()
AppContext.__singleton = self
end

-- Return absolute coordinates, normalized by ImGui PointConvertNative.
-- These coordinates are meant to be used with drawlists essentially.
-- Scrollbar corrections may be passed.
-- DPI is applied if there's scaling under windows
function AppContext:retrieveCoordinates(sub, scrollbar_w, scrollbar_h)
if not sub.hwnd then return end
local _, x, y, x2, y2 = reaper.JS_Window_GetRect(sub.hwnd)
Expand Down
29 changes: 21 additions & 8 deletions Various/talagan_Reannotate/classes/mem_cache.lua
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,13 @@ end

function MemCache.GetObjectGUID(object)
local guid = ''
if reaper.ValidatePtr(object, "MediaTrack*") then
if type(object) == "table" then
if object.t == 'region' then
return object.guid
else
error("Unhandled custom type " .. object.t .. " for object")
end
elseif reaper.ValidatePtr(object, "MediaTrack*") then
local tguid = reaper.GetTrackGUID(object)
guid = tguid
elseif reaper.ValidatePtr(object,"MediaItem*") then
Expand All @@ -49,24 +55,31 @@ function MemCache:getObjectCache(object)
-- Build object cache

local name = ''
local type = ''
if reaper.ValidatePtr(object, "MediaTrack*") then
local kind = ''
if type(object) == "table" then
if object.t == 'region' then
name = object.n or ''
kind = object.t
else
error("Unhandled custom type " .. object.t .. " for object")
end
elseif reaper.ValidatePtr(object, "MediaTrack*") then
local _, tname = reaper.GetTrackName(object)
name = tname
type = 'track'
kind = 'track'
elseif reaper.ValidatePtr(object,"MediaItem*") then
local take = reaper.GetActiveTake(object)
if take then
name = reaper.GetTakeName(take)
end
type = 'item'
kind = 'item'
elseif reaper.ValidatePtr(object, "TrackEnvelope*") then
local _, ename = reaper.GetEnvelopeName(object)
name = ename
type = 'env'
kind = 'env'
elseif reaper.ValidatePtr(object, "ReaProject*") then
name = "Project"
type = 'project'
kind = 'project'
else
error("Unhandled type for object")
end
Expand All @@ -76,7 +89,7 @@ function MemCache:getObjectCache(object)
guid = guid,
object = object,
name = name,
type = type,
type = kind,
-- Notes cache
notes = Notes:new(object)
}
Expand Down
153 changes: 144 additions & 9 deletions Various/talagan_Reannotate/classes/notes.lua
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ local JSON = require "ext/json"
local CheckboxHelper = require "modules/checkbox_helper"
local Sticker = require "classes/sticker"
local D = require "modules/defines"
local PS = require "modules/project_settings"

local function normalizeNotes(str)
return str:gsub("\r","")
Expand All @@ -23,6 +24,7 @@ local function normalizeReannotateData(data)
if not data.slots then data.slots = {} end
if not data.stickers then data.stickers = {} end
if not data.cb then data.cb = {} end
if not data.posters then data.posters = {} end

for i=1, D.MAX_SLOTS-1 do
data.slots[i] = data.slots[i] or "" -- Stored text
Expand All @@ -31,6 +33,9 @@ local function normalizeReannotateData(data)
data.tt_sizes[i].h = normalizeCoordinate(data.tt_sizes[i].h, D.TT_DEFAULT_H)
data.stickers[i] = data.stickers[i] or {} -- List or empty list of packed stickers
data.cb[i] = data.cb[i] or {} -- Checkbox cache
data.posters[i] = data.posters[i] or {}
data.posters[i].t = data.posters[i].t or D.POSTER_TYPES.PROJECT_DEFAULT
data.posters[i].s = data.posters[i].s or ""
end

-- Special treatment for slot 0
Expand All @@ -39,14 +44,23 @@ local function normalizeReannotateData(data)
data.sws_reaper_tt_size.h = normalizeCoordinate(data.sws_reaper_tt_size.h, D.TT_DEFAULT_H)
data.sws_reaper_stickers = data.sws_reaper_stickers or {}
data.sr_cb = data.sr_cb or {}
data.sws_reaper_poster = data.sws_reaper_poster or {}
data.sws_reaper_poster.t = data.sws_reaper_poster.t or D.POSTER_TYPES.PROJECT_DEFAULT
data.sws_reaper_poster.s = data.sws_reaper_poster.s or ""
-- data.sws_reaper_text <-- stored in reaper / SWS

return data
end

local function AttributeGetterSetter(object)
local getter = nil
if reaper.ValidatePtr(object, "MediaTrack*") then
if type(object) == 'table' then
if object.t == 'region' then
-- We'll store on the master track with a different ke
getter = reaper.GetSetMediaTrackInfo_String
else
error("Unhandled custom type " .. object.t .. " for object ")
end
elseif reaper.ValidatePtr(object, "MediaTrack*") then
getter = reaper.GetSetMediaTrackInfo_String
elseif reaper.ValidatePtr(object, "TrackEnvelope*") then
getter = reaper.GetSetEnvelopeInfo_String
Expand All @@ -62,15 +76,27 @@ local function AttributeGetterSetter(object)
end

local function StoreKey(object)
if reaper.ValidatePtr(object, "ReaProject*") then
if type(object) == 'table' then
if object.t == 'region' then
return "P_EXT:Reannotate_RegionNotes:" .. object.guid
else
error("Unhandled custom type " .. object.t .. " for object ")
end
elseif reaper.ValidatePtr(object, "ReaProject*") then
return "P_EXT:Reannotate_ProjectNotes"
else
return "P_EXT:Reannotate_Notes"
end
end

local function StoreObject(object)
if reaper.ValidatePtr(object, "ReaProject*") then
if type(object) == 'table' then
if object.t == 'region' then
return reaper.GetMasterTrack(D.ActiveProject())
else
error("Unhandled custom type " .. object.t .. " for object ")
end
elseif reaper.ValidatePtr(object, "ReaProject*") then
return reaper.GetMasterTrack(D.ActiveProject())
else
return object
Expand Down Expand Up @@ -109,12 +135,14 @@ local function SetObjectNotes_Reannotate(object, data)
-- SWS/Reaper additional
sws_reaper_tt_size = data.sws_reaper_tt_size,
sr_cb = data.sr_cb,
sws_reaper_stickers = {},
sws_reaper_poster = D.deepCopy(data.sws_reaper_poster),
-- Reannotate structures
tt_sizes = data.tt_sizes,
slots = data.slots,
cb = data.cb,
stickers = {},
sws_reaper_stickers = {}
posters = D.deepCopy(data.posters)
}

-- Serialize stickers
Expand All @@ -123,6 +151,7 @@ local function SetObjectNotes_Reannotate(object, data)
end
new_data.sws_reaper_stickers = Sticker.PackCollection(data.sws_reaper_stickers)

-- Normalize before packing
new_data = normalizeReannotateData(new_data)

local data_str = JSON.encode(new_data)
Expand Down Expand Up @@ -187,9 +216,28 @@ local function SetActiveProjectNotes_SWS_Reaper(str)
return reaper.GetSetProjectNotes(project, true, notes)
end

-------------
-- REGION --
-------------

local function GetRegionNotes_SWS_Reaper(object)
-- Not handled by SWS
return true, ""
end
local function SetRegionNotes_SWS_Reaper(object, str)
-- Not handled by SWS
return true, ""
end

local function GetObjectNotes_SWS_Reaper(notes)
local object = notes._object
if reaper.ValidatePtr(object, "MediaTrack*") then
if type(object) == 'table' then
if object.t == 'region' then
return GetRegionNotes_SWS_Reaper(object)
else
error("Unhandled custom type " .. object.t .. " for object ")
end
elseif reaper.ValidatePtr(object, "MediaTrack*") then
return GetTrackNotes_SWS_Reaper(object)
elseif reaper.ValidatePtr(object, "TrackEnvelope*") then
return GetEnvelopeNotes_SWS_Reaper(object)
Expand All @@ -203,7 +251,13 @@ local function GetObjectNotes_SWS_Reaper(notes)
end

local function SetObjectNotes_SWS_Reaper(object, str)
if reaper.ValidatePtr(object, "MediaTrack*") then
if type(object) == 'table' then
if object.t == 'region' then
return SetRegionNotes_SWS_Reaper(object, str)
else
error("Unhandled custom type " .. object.t .. " for object ")
end
elseif reaper.ValidatePtr(object, "MediaTrack*") then
return SetTrackNotes_SWS_Reaper(object, str)
elseif reaper.ValidatePtr(object,"TrackEnvelope*") then
return SetEnvelopeNotes_SWS_Reaper(object, str)
Expand Down Expand Up @@ -248,17 +302,50 @@ function Notes:commit()
SetObjectNotes_SWS_Reaper(self._object, self.sws_reaper_notes)
end

function Notes:isSlotBlank(slot)
function Notes:isSlotNoteBlank(slot)
if slot == 0 then
if self.sws_reaper_notes and self.sws_reaper_notes ~= "" then return false end
if #self.reannotate_notes.sws_reaper_stickers > 0 then return false end
else
if self.reannotate_notes.slots[slot] and self.reannotate_notes.slots[slot] ~= '' then return false end
end
return true
end

function Notes:isSlotStickersBlank(slot)
if slot == 0 then
if #self.reannotate_notes.sws_reaper_stickers > 0 then return false end
else
if #self.reannotate_notes.stickers[slot] > 0 then return false end
end
return true
end

function Notes:isSlotPosterBlank(slot)
local type = self:resolvedSlotPosterType(slot)
if type == D.POSTER_TYPES.NO_POSTER then
return true
elseif type == D.POSTER_TYPES.CUSTOM_PLAIN_POSTER or type == D.POSTER_TYPES.CUSTOM_MARKDOWN_POSTER then
-- If in custom mode, check custom poster
if slot == 0 then
if self.reannotate_notes.sws_reaper_poster and self.reannotate_notes.sws_reaper_poster.s ~= "" then return false end
else
if self.reannotate_notes.posters[slot] and self.reannotate_notes.posters[slot].s ~= '' then return false end
end
return true
else
-- If not in custom mode, check note
return self:isSlotNoteBlank(slot)
end
end

function Notes:isSlotBlank(slot)
if not self:isSlotNoteBlank(slot) then return false end
if not self:isSlotStickersBlank(slot) then return false end
if not self:isSlotPosterBlank(slot) then return false end

return true
end

function Notes:isBlank()
for slot=0, D.MAX_SLOTS -1 do
if not self:isSlotBlank(slot) then return false end
Expand Down Expand Up @@ -307,6 +394,54 @@ function Notes:setSlotText(slot, str)
end
end

function Notes:resolvedSlotPosterType(slot)
local type = self:slotPosterType(slot)
if type == D.POSTER_TYPES.PROJECT_DEFAULT then
return PS.ProjectPosterDefaultType()
end
return type
end

function Notes:slotCustomPoster(slot)
if slot == 0 then
self.reannotate_notes.sws_reaper_poster = self.reannotate_notes.sws_reaper_poster or { t = D.POSTER_TYPES.PROJECT_DEFAULT, s = '' }
return self.reannotate_notes.sws_reaper_poster.s
else
self.reannotate_notes.posters[slot] = self.reannotate_notes.posters[slot] or { t = D.POSTER_TYPES.PROJECT_DEFAULT, s = '' }
return self.reannotate_notes.posters[slot].s
end
end
function Notes:setSlotCustomPoster(slot, str)
if slot == 0 then
self.reannotate_notes.sws_reaper_poster = self.reannotate_notes.sws_reaper_poster or { t = D.POSTER_TYPES.PROJECT_DEFAULT, s = '' }
self.reannotate_notes.sws_reaper_poster.s = str
else
self.reannotate_notes.posters[slot] = self.reannotate_notes.posters[slot] or { t = D.POSTER_TYPES.PROJECT_DEFAULT, s = '' }
self.reannotate_notes.posters[slot].s = str
end
end


function Notes:slotPosterType(slot)
if slot == 0 then
self.reannotate_notes.sws_reaper_poster = self.reannotate_notes.sws_reaper_poster or { t = D.POSTER_TYPES.PROJECT_DEFAULT, s = '' }
return self.reannotate_notes.sws_reaper_poster.t
else
self.reannotate_notes.posters[slot] = self.reannotate_notes.posters[slot] or { t = D.POSTER_TYPES.PROJECT_DEFAULT, s = '' }
return self.reannotate_notes.posters[slot].t
end
end
function Notes:setSlotPosterType(slot, type)
if slot == 0 then
self.reannotate_notes.sws_reaper_poster = self.reannotate_notes.sws_reaper_poster or { t = D.POSTER_TYPES.PROJECT_DEFAULT, s = '' }
self.reannotate_notes.sws_reaper_poster.t = type
else
self.reannotate_notes.posters[slot] = self.reannotate_notes.posters[slot] or { t = D.POSTER_TYPES.PROJECT_DEFAULT, s = '' }
self.reannotate_notes.posters[slot].t = type
end
end


function Notes:slotStickers(slot)
if slot == 0 then
return self.reannotate_notes.sws_reaper_stickers or {}
Expand Down
Loading