319 lines
11 KiB
Lua
319 lines
11 KiB
Lua
-- Reaper scripted "Big Clock" window with extra functions
|
|
-- - Normal time display as in the usual "Big Clock"
|
|
-- - Time since last project marker
|
|
-- - Time since last region start
|
|
-- Author: Ludwig Frühschütz
|
|
-- Source: https://www.eleton-audio.de
|
|
-- Git: https://files.eleton-audio.de/gitea/Ludwig/Reaper-Scripts.git
|
|
-- License: GPL v3.0
|
|
-- Requires: Reaper 5 or 6
|
|
-- Basic gui stuff by forum user "spk77": https://forum.cockos.com/showthread.php?t=161557
|
|
|
|
|
|
-- Some adjustable settings:
|
|
local timeSinceProject = true -- EITHER this one is true OR one of the next two
|
|
local timeSinceMarker = false
|
|
local timeSinceRegion = false
|
|
|
|
-- Nothing to adjust here anymore...
|
|
local script_path
|
|
local mouse
|
|
local Menu
|
|
local gui = {} -- contains some settings for the GUI
|
|
local quit = false
|
|
local sws_present = false
|
|
|
|
-- Send a message to the console
|
|
function msg(m)
|
|
reaper.ShowConsoleMsg(tostring(m) .. "\n")
|
|
end
|
|
|
|
-- Store state to project variables
|
|
function storeExtState()
|
|
if timeSinceProject then
|
|
reaper.SetProjExtState(0, 'bigclock_extra', 'timeSinceProject', '1')
|
|
else
|
|
reaper.SetProjExtState(0, 'bigclock_extra', 'timeSinceProject', '0')
|
|
end
|
|
|
|
if timeSinceMarker then
|
|
reaper.SetProjExtState(0, 'bigclock_extra', 'timeSinceMarker', '1')
|
|
else
|
|
reaper.SetProjExtState(0, 'bigclock_extra', 'timeSinceMarker', '0')
|
|
end
|
|
|
|
if timeSinceRegion then
|
|
reaper.SetProjExtState(0, 'bigclock_extra', 'timeSinceRegion', '1')
|
|
else
|
|
reaper.SetProjExtState(0, 'bigclock_extra', 'timeSinceRegion', '0')
|
|
end
|
|
|
|
reaper.SetProjExtState(0, 'bigclock_extra', 'dockState', gfx.dock(-1))
|
|
end
|
|
|
|
---------------------------
|
|
-- functions for graphics...
|
|
---------------------------
|
|
|
|
-- Returns current script's path
|
|
function get_script_path()
|
|
local info = debug.getinfo(1,'S');
|
|
local script_path = info.source:match[[^@?(.*[\/])[^\/]-$]]
|
|
return script_path
|
|
end
|
|
|
|
-- gui init stuff, including rightclick-menu
|
|
function gui_init()
|
|
-- Get "script path"
|
|
script_path = get_script_path()
|
|
--msg(script_path)
|
|
|
|
-- Modify "package.path"
|
|
package.path = package.path .. ";" .. script_path .. "?.lua"
|
|
--msg(package.path)
|
|
|
|
-- Import files ("classes", functions etc.)--
|
|
require "class" -- import "base class"
|
|
mouse = require "mouse"
|
|
Menu = require "menu class"
|
|
|
|
-- Create "right click" menu --
|
|
-- Create a "Menu" instance
|
|
rc_menu = Menu("rc_menu")
|
|
|
|
-- Add menu items to "rc_menu"
|
|
-- ">" at the start spawns a submenu, | at the end creates a spacer
|
|
rc_menu:add_item({label = "Time since project start",
|
|
toggleable = true,
|
|
selected = timeSinceProject})
|
|
rc_menu:add_item({label = "Time since previous marker",
|
|
toggleable = true,
|
|
selected = timeSinceMarker})
|
|
rc_menu:add_item({label = "Time since previous region",
|
|
toggleable = true,
|
|
selected = timeSinceRegion})
|
|
rc_menu:add_item({label = "Quit"})
|
|
|
|
-- Let's add a command to all created items:
|
|
rc_menu.items[1].command = function()
|
|
if rc_menu.items[1].selected then
|
|
timeSinceProject = true
|
|
timeSinceMarker = false
|
|
timeSinceRegion = false
|
|
rc_menu.items[2].selected = false
|
|
rc_menu.items[3].selected = false
|
|
else
|
|
--dont let user disable option but force selection of other option
|
|
rc_menu.items[1].selected = true;
|
|
end
|
|
storeExtState()
|
|
end
|
|
rc_menu.items[2].command = function()
|
|
if rc_menu.items[2].selected then
|
|
timeSinceProject = false
|
|
timeSinceMarker = true
|
|
timeSinceRegion = false
|
|
rc_menu.items[1].selected = false
|
|
rc_menu.items[3].selected = false
|
|
else
|
|
--dont let user disable option but force selection of other option
|
|
rc_menu.items[2].selected = true;
|
|
end
|
|
storeExtState()
|
|
end
|
|
rc_menu.items[3].command = function()
|
|
if rc_menu.items[3].selected then
|
|
timeSinceProject = false
|
|
timeSinceMarker = false
|
|
timeSinceRegion = true
|
|
rc_menu.items[1].selected = false
|
|
rc_menu.items[2].selected = false
|
|
else
|
|
--dont let user disable option but force selection of other option
|
|
rc_menu.items[3].selected = true;
|
|
end
|
|
storeExtState()
|
|
end
|
|
rc_menu.items[4].command = function() quit = true end
|
|
end
|
|
|
|
-- Draw GUI --
|
|
function drawGui()
|
|
local retval = 0
|
|
local val
|
|
local timeRaw
|
|
local timeDisplay
|
|
local timeDisplaySeconds
|
|
local markerId
|
|
local regionId
|
|
local isRegion
|
|
local markerRegionPos
|
|
local regionEnd
|
|
local markerRegionName
|
|
local markerRegionNumber
|
|
|
|
-- get time depending on play state
|
|
if reaper.GetAllProjectPlayStates(0) == 0 then -- 0: stopped
|
|
timeRaw = reaper.GetCursorPosition()
|
|
else -- 1: play; 2: pause; 4: record (and their bitwise |)
|
|
timeRaw = reaper.GetPlayPosition()
|
|
end
|
|
|
|
-- calculate time since previous marker or region
|
|
markerId, regionId = reaper.GetLastMarkerAndCurRegion(0, timeRaw)
|
|
if timeSinceMarker then
|
|
retval, isRegion, markerRegionPos, regionEnd, markerRegionName, markerRegionNumber = reaper.EnumProjectMarkers(markerId)
|
|
elseif timeSinceRegion then
|
|
retval, isRegion, markerRegionPos, regionEnd, markerRegionName, markerRegionNumber = reaper.EnumProjectMarkers(regionId)
|
|
end
|
|
if retval > 0 then timeRaw = timeRaw - markerRegionPos end
|
|
|
|
-- construct display string, with leading zeros if neccessary (e.g. 27:08.321)
|
|
timeDisplaySeconds = math.floor((timeRaw%60)*1000)/1000
|
|
timeDisplay = math.floor(timeRaw/60) .. ":"
|
|
if timeDisplaySeconds < 10 then
|
|
timeDisplay = timeDisplay .. "0"
|
|
end
|
|
timeDisplay = timeDisplay .. timeDisplaySeconds
|
|
|
|
gfx.clear = 3355443 -- background is dark grey
|
|
|
|
-- If window is docked, use different scaling
|
|
if gfx.dock(-1) > 0 then
|
|
-- landscape format
|
|
if gfx.w > gfx.h then
|
|
gfx.x = 20
|
|
gfx.y = ( gfx.h-select(2, gfx.measurestr(timeDisplay)) ) / 2
|
|
gui.settings.font_size = gfx.h / 2
|
|
gfx.setfont(1,"Arial", gui.settings.font_size)
|
|
-- check if string fits into window, if not decrease fontsize a little, check again and loop
|
|
while gfx.measurestr(timeDisplay) > (gfx.w - 2*gfx.x) do
|
|
gui.settings.font_size = gui.settings.font_size / 1.1
|
|
gfx.setfont(1,"Arial", gui.settings.font_size)
|
|
end
|
|
gfx.printf(timeDisplay)
|
|
-- portrait format
|
|
else
|
|
gfx.x = gfx.w/15
|
|
gfx.y = ( gfx.h-select(2, gfx.measurestr(timeDisplay)) ) / 2
|
|
gui.settings.font_size = gfx.w / 3
|
|
gfx.setfont(1,"Arial", gui.settings.font_size)
|
|
gfx.printf(timeDisplay)
|
|
end
|
|
else -- window is not docked
|
|
-- landscape format
|
|
if gfx.w > gfx.h then
|
|
gfx.x = gfx.w/20
|
|
gfx.y = ( gfx.h-select(2, gfx.measurestr(timeDisplay)) ) / 2
|
|
gui.settings.font_size = gfx.w / 6
|
|
gfx.setfont(1,"Arial", gui.settings.font_size)
|
|
-- check if string fits into window, if not decrease fontsize a little, check again and loop
|
|
while gfx.measurestr(timeDisplay) > (gfx.w - 2*gfx.x) do
|
|
gui.settings.font_size = gui.settings.font_size / 1.1
|
|
gfx.setfont(1,"Arial", gui.settings.font_size)
|
|
end
|
|
gfx.printf(timeDisplay)
|
|
-- portrait format
|
|
else
|
|
gfx.x = gfx.w/20
|
|
gfx.y = ( gfx.h-select(2, gfx.measurestr(timeDisplay)) ) / 2
|
|
gui.settings.font_size = gfx.w / 3
|
|
gfx.setfont(1,"Arial", gui.settings.font_size)
|
|
gfx.printf(timeDisplay)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Called on script termination. Store stuff...
|
|
function onExit()
|
|
storeExtState()
|
|
end
|
|
|
|
-- Main init function
|
|
function init()
|
|
-- check for SWS extensions
|
|
if reaper.NamedCommandLookup('_SWS_ABOUT') > 0 then sws_present = true end
|
|
-- load settings from rpp
|
|
local retval
|
|
local val
|
|
retval, val = reaper.GetProjExtState(0, 'bigclock_extra', 'timeSinceProject')
|
|
if retval > 0 then
|
|
if tonumber(val) > 0 then
|
|
timeSinceProject = true
|
|
else
|
|
timeSinceProject = false
|
|
end
|
|
end
|
|
retval, val = reaper.GetProjExtState(0, 'bigclock_extra', 'timeSinceMarker')
|
|
if retval > 0 then
|
|
if tonumber(val) > 0 then
|
|
timeSinceMarker = true
|
|
else
|
|
timeSinceMarker = false
|
|
end
|
|
end
|
|
retval, val = reaper.GetProjExtState(0, 'bigclock_extra', 'timeSinceRegion')
|
|
if retval > 0 then
|
|
if tonumber(val) > 0 then
|
|
timeSinceRegion = true
|
|
else
|
|
timeSinceRegion = false
|
|
end
|
|
end
|
|
|
|
-- init stuff...
|
|
gui_init()
|
|
|
|
-- Add stuff to "gui" table
|
|
gui.settings = {} -- Add "settings" table to "gui" table
|
|
gui.settings.font_size = 50 -- font size
|
|
gui.settings.docker_id = 0 -- try 0, 1, 257, 513, 1027 etc.
|
|
|
|
-- Initialize gfx window --
|
|
gfx.init("Big Clock Extra", 350, 100, gui.settings.docker_id)
|
|
gfx.setfont(1,"Arial", gui.settings.font_size)
|
|
gfx.clear = 3355443 -- background is dark grey
|
|
|
|
-- Restore docked state
|
|
retval, val = reaper.GetProjExtState(0, 'bigclock_extra', 'dockState')
|
|
if retval > 0 then
|
|
gfx.dock(val)
|
|
end
|
|
end
|
|
|
|
-- Main loop --
|
|
function mainloop()
|
|
-- mouseclicks?
|
|
local RMB_state = mouse.cap(mouse.RB)
|
|
local LMB_state = mouse.cap(mouse.LB)
|
|
local mx = gfx.mouse_x
|
|
local my = gfx.mouse_y
|
|
|
|
if not mouse.last_RMB_state and gfx.mouse_cap&2 == 2 then
|
|
-- right click pressed down -> show "right click menu" at mouse cursor
|
|
rc_menu:show(mx, my)
|
|
if sws_present then
|
|
reaper.Main_OnCommand( reaper.NamedCommandLookup('_BR_FOCUS_ARRANGE_WND'), 0 ) -- focus arranger
|
|
end
|
|
end
|
|
|
|
if not mouse.last_LMB_state and gfx.mouse_cap&1 == 1 then
|
|
-- left click pressed down
|
|
if sws_present then
|
|
reaper.Main_OnCommand( reaper.NamedCommandLookup('_BR_FOCUS_ARRANGE_WND'), 0 ) -- focus arranger
|
|
end
|
|
end
|
|
|
|
mouse.last_RMB_state = RMB_state -- store current right mouse button state
|
|
mouse.last_LMB_state = LMB_state -- store current left mouse button state
|
|
|
|
drawGui()
|
|
gfx.update()
|
|
if gfx.getchar() >= 0 and not quit then reaper.defer(mainloop) end
|
|
end
|
|
|
|
-- START HERE...
|
|
reaper.atexit(onExit)
|
|
init()
|
|
mainloop()
|