|
|
- -- 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 (startup settings that can be changed in GUI):
- local timeSinceProject = true -- EITHER this one is true OR one of the next two
- local timeSinceMarker = false
- local timeSinceRegion = false
- local timeUnitHMS = true -- EITHER this one is true OR one of the next one
- local timeUnitMeasures = 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
-
- -- Round number
- function round(num, numDecimalPlaces)
- local mult = 10^(numDecimalPlaces or 0)
- return math.floor(num * mult + 0.5) / mult
- 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
-
- if timeUnitMeasures then
- reaper.SetProjExtState(0, 'bigclock_extra', 'timeUnit', 'measures')
- else
- reaper.SetProjExtState(0, 'bigclock_extra', 'timeUnit', 'hms')
- 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 = "HH:MM:SS.xxx",
- toggleable = true,
- selected = timeUnitHMS})
- rc_menu:add_item({label = "Measures.Beats.xx|",
- toggleable = true,
- selected = timeUnitMeasures})
- 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()
- if rc_menu.items[4].selected then
- timeUnitHMS = true
- timeUnitMeasures = false
- rc_menu.items[5].selected = false
- else
- --dont let user disable option but force selection of other option
- rc_menu.items[5].selected = true;
- end
- storeExtState()
- end
- rc_menu.items[5].command = function()
- if rc_menu.items[5].selected then
- timeUnitHMS = false
- timeUnitMeasures = true
- rc_menu.items[4].selected = false
- else
- --dont let user disable option but force selection of other option
- rc_menu.items[4].selected = true;
- end
- storeExtState()
- end
- rc_menu.items[6].command = function() quit = true end
- end
-
- -- Draw GUI --
- function drawGui()
- local retval = 0
- local val
- local timeRaw
- local timeDisplay
- local timeDisplayHours
- local timeDisplayMinutes
- local timeDisplaySeconds
- local timeMeasures
- local timeBeats
- 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
- if timeUnitMeasures then
- -- measures and beats: e.g. 07.3.99
- timeBeats, timeMeasures, _, _, _ = reaper.TimeMap2_timeToBeats(0, timeRaw)
- timeDisplay = timeMeasures+1 .. '.' .. round(timeBeats+1, 2)
- else
- -- minutes and seconds: MM:SS.xxx (e.g. 27:08.321)
- timeDisplayHours = math.floor(timeRaw/3600)
- timeRaw = timeRaw%3600
- timeDisplayMinutes = math.floor(timeRaw/60)
- timeDisplaySeconds = round(timeRaw%60, 3)
- if timeDisplayHours > 0 then
- timeDisplay = timeDisplayHours .. ":"
- if timeDisplayMinutes < 10 then
- timeDisplay = timeDisplay .. "0"
- end
- else
- timeDisplay = ""
- end
- timeDisplay = timeDisplay .. timeDisplayMinutes .. ":"
- if timeDisplaySeconds < 10 then
- timeDisplay = timeDisplay .. "0"
- end
- timeDisplay = timeDisplay .. timeDisplaySeconds
- end
-
- 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
- retval, val = reaper.GetProjExtState(0, 'bigclock_extra', 'timeUnit')
- if retval > 0 then
- if val == 'measures' then
- timeUnitMeasures = true
- timeUnitHMS = false
- else
- timeUnitMeasures = false
- timeUnitHMS = true
- 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()
|