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
34 changes: 34 additions & 0 deletions Various/talagan_Reannotate.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
--[[
@description Reannotate - Annotation tool for REAPER
@version 0.3.0
@author Ben 'Talagan' Babut
@donation https://www.paypal.com/donate/?business=3YEZMY9D6U8NC&no_recurring=1&currency_code=EUR
@license MIT
@screenshot
https://stash.reaper.fm/50870/reannotate_screenshot_reapack.png
@links
Forum Thread https://forum.cockos.com/showthread.php?t= TODO
@metapackage
@changelog
- First release
@provides
[nomain] talagan_Reannotate/ext/**/*
[nomain] talagan_Reannotate/classes/**/*
[nomain] talagan_Reannotate/images/**/*
[nomain] talagan_Reannotate/modules/**/*
[nomain] talagan_Reannotate/widgets/**/*

[main=main] talagan_Reannotate/actions/talagan_Reannotate Quick Preview.lua > talagan_Reannotate Quick Preview.lua
@about
Reannotate is a visual annotation tool for Reaper.

It comes as a modal overlay over Reaper, allowing to quickly consult and add some kind of colored "Post-It" notes over objects (tracks, envelopes, items, and project). These notes can be previewed as tooltips by hovering the mouse over objects and can use markdown syntax.

Basic filtering by category and search is available (pretty basic for now but may evolve).

SWS and Reaper notes may be edited with Reannotate. They will appear in a dedicated category, allowing retro-compatibility for older projects or projects written by users not using Reannotate.

You can consult the forum thread for more info.

Please note that this tool is very young and may contain bugs.
--]]
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
-- @noindex
-- @author Ben 'Talagan' Babut
-- @license MIT
-- @description This file is part of Reannotate

local ACTION = debug.getinfo(1,"S").source
local ACTION_DIR = (ACTION:match[[^@?(.*[\/])[^\/]-$]]):gsub("talagan_Reannotate/actions/$","/") -- Works both in dev and prod

package.path = package.path .. ";" .. ACTION_DIR .. "talagan_Reannotate/?.lua"
package.path = package.path .. ";" .. reaper.ImGui_GetBuiltinPath() .. '/?.lua'
package.path = package.path .. ";" .. (reaper.GetResourcePath() .. "/Scripts/ReaTeam Scripts/Development/talagan_ReaImGui Markdown") .. '/?.lua'

local Dependencies = require "ext/dependencies"
if not Dependencies.checkDependencies() then
return
end

local AppContext = require "classes/app_context"
local QuickPreviewOverlay = require "widgets/quick_preview_overlay"

local S = require "modules/settings"
local D = require "modules/debug"

S.setSetting("UseDebugger", false)
S.setSetting("UseProfiler", false)
D.LaunchDebugStubIfNeeded()
D.LaunchProfilerIfNeeded()

local app_ctx = AppContext:new()
local overlay = QuickPreviewOverlay:new()

-- Force focus on the main window to avoid glitches
reaper.JS_Window_SetFocus(app_ctx.mv.hwnd)

if app_ctx.launch_context:isLaunchedByKeyboardShortcut() then
-- The action is launched by shortcut
-- Prevent the action to be re-launched (flag == 2).
-- We'll track the holding of the shortcut and quit when released
reaper.set_action_options(4|2)
else
-- The action is launched from a button... or something else
-- We want it to keep running until it's toggled off
reaper.set_action_options(1|4)
end

--log("Launched")

function MainLoop()
app_ctx:tick()

if not app_ctx.launch_context:isShortcutStillPressed() then
app_ctx.shortcut_was_released_once = true
end

--log("Running...")
app_ctx:updateWindowLayouts()

if app_ctx.arrange_view_watcher:tick() then
overlay:updateVisibleThings()
end

overlay:draw()

if app_ctx.want_quit then
return
end

-- Defer the loop
reaper.defer(MainLoop)
end

-- Set focus to the arrange view. This prevent bugs
-- For example if the MIDI Editor has focus, the held shortcut
-- Will glitch
reaper.defer(MainLoop)

-- Register cleanup function on script exit
reaper.atexit(function()
-- Restore focus.
reaper.JS_Window_SetFocus(app_ctx.launch_context.focused_hwnd)
reaper.set_action_options(8)
--log("Exiting.")
end)
132 changes: 132 additions & 0 deletions Various/talagan_Reannotate/classes/app_context.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
-- @noindex
-- @author Ben 'Talagan' Babut
-- @license MIT
-- @description This file is part of Reannotate

local LaunchContext = require "classes/launch_context"
local ArrangeViewWatcher = require "classes/arrange_view_watcher"
local ImGui = require "ext/imgui"

local Notes = require "classes/notes"

local AppContext = {}
AppContext.__index = AppContext

function AppContext:new()
local instance = {}
setmetatable(instance, self)
instance:_initialize()
return instance
end

function AppContext:findMCPHwnds()

local mixerHwnd = reaper.JS_Window_Find("Mixer",true)
local next_child = mixerHwnd

local master_mcp_hwnd = nil
local other_mcp_hwnd = nil
while next_child do
next_child = reaper.JS_Window_FindEx(mixerHwnd, next_child, "REAPERMCPDisplay", "")
if next_child then
local title = reaper.JS_Window_GetTitle(next_child)
if title == "master" then
master_mcp_hwnd = next_child
else
other_mcp_hwnd = next_child
end
end
end

return master_mcp_hwnd, other_mcp_hwnd
end

function AppContext:getImage(image_name)
self.images = self.images or {}
local images = self.images

if (not images[image_name]) or (not ImGui.ValidatePtr(images[image_name], 'ImGui_Image*')) then
local bin = require("images/" .. image_name)
images[image_name] = ImGui.CreateImageFromMem(bin)
-- Prevent the GC from freeing this image
ImGui.Attach(self.imgui_ctx, images[image_name])
end

return images[image_name]
end

function AppContext:_initialize()
self.launch_context = LaunchContext:new()
self.arrange_view_watcher = ArrangeViewWatcher:new()
self.mv = { hwnd=reaper.GetMainHwnd() }
self.av = { hwnd=reaper.JS_Window_FindChildByID(self.mv.hwnd, 1000) }
self.tcp = { hwnd=reaper.JS_Window_FindEx(reaper.GetMainHwnd(), reaper.GetMainHwnd(), "REAPERTCPDisplay", "") }
self.main_toolbar = { hwnd=reaper.JS_Window_Find('Main toolbar', true)}
self.time_ruler = { hwnd=reaper.JS_Window_FindChildByID(self.mv.hwnd, 1005) }

local master_mcp_hwnd, other_mcp_hwnd = self:findMCPHwnds()

self.mcp_master = { hwnd=master_mcp_hwnd }
self.mcp_other = { hwnd=other_mcp_hwnd }

self.imgui_ctx = ImGui.CreateContext("Reannotate")

self.cursor_func = ImGui.CreateFunctionFromEEL([[
(WANTED_CURSOR >= 0)?(
CursorPos = WANTED_CURSOR;
WANTED_CURSOR = -1;
);
]])

self.arial_font = ImGui.CreateFont("Arial", ImGui.FontFlags_None)
self.arial_font_italic = ImGui.CreateFont("Arial", ImGui.FontFlags_Italic | ImGui.FontFlags_Bold)

self.enabled_category_filters = {}
for i=1, Notes.MAX_SLOTS do
self.enabled_category_filters[i] = true
end

ImGui.Attach(self.imgui_ctx, self.cursor_func)
ImGui.Attach(self.imgui_ctx, self.arial_font)

AppContext.__singleton = self
end

function AppContext:retrieveCoordinates(sub, scrollbar_w, scrollbar_h)
if not sub.hwnd then return end
local _, x, y, r, b = reaper.JS_Window_GetRect(sub.hwnd)

sub.x, sub.w, sub.h = x, r - x, math.abs(b - y)
sub.x, sub.y = ImGui.PointConvertNative(self.imgui_ctx, x, y, true )

if scrollbar_w then sub.w = sub.w - scrollbar_w end
if scrollbar_h then sub.h = sub.h - scrollbar_h end

end

function AppContext:updateWindowLayouts()

self:retrieveCoordinates(self.av, 16, 16)
self:retrieveCoordinates(self.mv)
self:retrieveCoordinates(self.tcp)
self:retrieveCoordinates(self.mcp_master)
self:retrieveCoordinates(self.mcp_other)
self:retrieveCoordinates(self.main_toolbar)
self:retrieveCoordinates(self.time_ruler)

self.av.start_time, self.av.end_time = reaper.GetSet_ArrangeView2(0, false, 0, 0)
end

function AppContext:tick()
self.frame_time = reaper.time_precise()
end

function AppContext:flog(txt)
--reaper.ShowConsoleMsg("[" .. string.format("%.3f",self.frame_time) .. "] " .. txt .. "\n")
end

function AppContext.instance()
return AppContext.__singleton
end

return AppContext
66 changes: 66 additions & 0 deletions Various/talagan_Reannotate/classes/arrange_view_watcher.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
-- @noindex
-- @author Ben 'Talagan' Babut
-- @license MIT
-- @description This file is part of Reannotate

-- This class watches for changes in the arrange view.
local ArrangeViewWatcher = {}
ArrangeViewWatcher.__index = ArrangeViewWatcher

function ArrangeViewWatcher:new(cb)
local instance = {}
setmetatable(instance, self)
instance:_initialize(cb)
return instance
end

function ArrangeViewWatcher:_initialize(cb)
self.pcount = nil
self.astart = nil
self.aend = nil
self.last_track_y = nil
self.last_track_h = nil
self.cb = cb
end

function ArrangeViewWatcher:tick()
local npcount = reaper.GetProjectStateChangeCount()
local nastart, naend = reaper.GetSet_ArrangeView2(0, false, 0, 0)

local lt = reaper.GetTrack(0,reaper.CountTracks()-1)
local ly = nil
local lh = nil
local lx = nil
local lw = nil

if lt then ly = reaper.GetMediaTrackInfo_Value(lt, "I_TCPY") end
if lt then lh = reaper.GetMediaTrackInfo_Value(lt, "I_TCPH") end

-- Also detect MCP changes.
if lt then lx = reaper.GetMediaTrackInfo_Value(lt, "I_MCPX") end
if lt then lw = reaper.GetMediaTrackInfo_Value(lt, "I_MCPW") end

if not (npcount == self.pcount) or
not (nastart == self.astart) or
not (naend == self.aend) or
not (lh == self.last_track_h) or
not (ly == self.last_track_y) or
not (lx == self.last_track_x) or
not (lw == self.last_track_w) then
if self.cb then self.cb() end
self.pcount = npcount
self.astart = nastart
self.aend = naend
self.last_track_y = ly
self.last_track_h = lh
self.last_track_x = lx
self.last_track_w = lw
return true
end

return false
end

return ArrangeViewWatcher


Loading