|
|
@ -0,0 +1,311 @@ |
|
|
|
-- 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 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 |
|
|
|
|
|
|
|
timeDisplay = math.floor(timeRaw/60) .. ":" .. math.floor((timeRaw%60)*1000)/1000 |
|
|
|
|
|
|
|
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() |