From 60ce4c2249bf47d542de615f381f107fd669a7da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20Fr=C3=BChsch=C3=BCtz?= Date: Sat, 25 Jan 2020 22:47:15 +0100 Subject: [PATCH] Added takenumber window from private repository --- TakenumberWindow/Takenumber_Window.lua | 674 +++++++++++++++++++++++++ TakenumberWindow/class.lua | 48 ++ TakenumberWindow/menu class.lua | 190 +++++++ TakenumberWindow/mouse.lua | 34 ++ 4 files changed, 946 insertions(+) create mode 100644 TakenumberWindow/Takenumber_Window.lua create mode 100644 TakenumberWindow/class.lua create mode 100644 TakenumberWindow/menu class.lua create mode 100644 TakenumberWindow/mouse.lua diff --git a/TakenumberWindow/Takenumber_Window.lua b/TakenumberWindow/Takenumber_Window.lua new file mode 100644 index 0000000..76f3205 --- /dev/null +++ b/TakenumberWindow/Takenumber_Window.lua @@ -0,0 +1,674 @@ +-- Reaper Script to add major take management functions, like: +-- - Take counter with unique number ("how often REC was pressed") +-- - Write takenumber to name of recorded file (by changing tracknames) +-- - Group recorded items after stop (all or just horizontally) +-- - Lock to active take (in lanes) after record +-- - Write clean takenames after record, for easy recognition. E.g. "T042 (Violin 1)" +-- Version from 19.6.2019, written by Ludwig Frühschütz +-- Basic gui stuff by forum user "spk77": https://forum.cockos.com/showthread.php?t=161557 + + +-- Some adjustable settings: + -- Initial values if no settings stored in project + local groupItemsAfterRecord = true + local groupItemsHAfterRecord = false + local fillGapsAfterRecord = true + local lockToActiveTakeAfterRecord = true + local writeTakeNamesAfterRecord = true + +-- Nothing to adjust here anymore... +local script_path +local mouse +local Menu +local gui = {} -- contains some settings for the GUI +local increaseTodo = false -- used to detect transition form "REC" to "STOP" and then inc. takenumber +local quit = false +local sws_present = false + +-- Send a message to the console +function msg(m) + reaper.ShowConsoleMsg(tostring(m) .. "\n") +end + +-- Write Takenumber and Trackname to selected items active takenames +function writeTakeNames() + local k = 0 + local thisItem = reaper.GetSelectedMediaItem(0, k) + local takestring + local name = ' ' + -- try to get takenumber from rpp. If not present, leave at "-1" + retval, val = reaper.GetProjExtState(0, 'takenumber_window', 'nexttake') + if retval > 0 then + takestring = 'T' .. string.format('%03d', tonumber(val)) -- format string to prepend to takename, e.g. "T042" + else + takestring = 'T???' + end + -- run through all selected items + while (thisItem) + do + local theTake = reaper.GetActiveTake(thisItem) + local track = reaper.GetMediaItem_Track(thisItem) + -- get trackname without takenumber + name = select( 2, reaper.GetSetMediaTrackInfo_String(track, 'P_NAME', name, false) ) + if name:sub(-5,-4) == '_T' then + name = name:sub(1,-6) + elseif name:sub(-4,-3) == '_T' then + name = name:sub(1,-5) + elseif name:sub(-3,-2) == '_T' then + name = name:sub(1,-4) + elseif name:sub(-2,-1) == '_T' then + name = name:sub(1,-3) + end + reaper.GetSetMediaItemTakeInfo_String(theTake, 'P_NAME', takestring .. ' (' .. name .. ')', true) + k = k+1 + thisItem = reaper.GetSelectedMediaItem(0, k) + end +end + +-- Lock to active take in lanes (to not accidentally select one by clicking) +function setLockToActiveTake() + reaper.Main_OnCommand(41340, 0) -- cant get momentary state, so simply set it every time... +end + +-- Get the highest group-ID in use +function maxProjectGroupID() + local floor = math.floor + local all_item_count = reaper.CountMediaItems(0) + local MaxGroupID = 0 + for i = 0, all_item_count - 1 do + local item = reaper.GetMediaItem(0, i) + local item_group_id = floor(reaper.GetMediaItemInfo_Value(item, "I_GROUPID")) + if item_group_id > MaxGroupID then + MaxGroupID = item_group_id + end + end + return MaxGroupID +end + +-- Group all selected items +function groupItems() + local groupID = maxProjectGroupID() + 1 + local k = 0 + local thisItem = reaper.GetSelectedMediaItem(0, k) + while (thisItem) + do + reaper.SetMediaItemInfo_Value(thisItem, "I_GROUPID", groupID) + k = k+1 + thisItem = reaper.GetSelectedMediaItem(0, k) + end +end + +-- Group selected items horizontally +function groupItemsH() + local init_sel_tracks = {} + local groupID = maxProjectGroupID() + 1 + local j = 0 + local k = 0 + + -- store selected tracks before work... + for i = 0, reaper.CountSelectedTracks(0)-1 do + init_sel_tracks[i+1] = reaper.GetSelectedTrack(0, i) + end + + local thisTrack = reaper.GetTrack(0, j) + while (thisTrack) do + local thisItem = reaper.GetTrackMediaItem(thisTrack, k) + while (thisItem) + do + if reaper.IsMediaItemSelected(thisItem) then + reaper.SetMediaItemInfo_Value(thisItem, "I_GROUPID", groupID) + end + k = k+1 + thisItem = reaper.GetTrackMediaItem(thisTrack, k) + end + k = 0 + j = j+1 + thisTrack = reaper.GetTrack(0, j) + groupID = maxProjectGroupID() + 1 + end + + -- restore selected tracks after work + reaper.Main_OnCommand(40297, 0) -- Unselect all tracks + for _, track in ipairs(init_sel_tracks) do + reaper.SetTrackSelected(track, true) + end +end + +function fillGapsBetweenItems() + if not sws_present then return end + local init_sel_tracks = {} + local init_sel_items = {} + local timesel_start + local timesel_end + + -- store selected tracks and items before work... + for i = 0, reaper.CountSelectedTracks(0)-1 do + init_sel_tracks[i+1] = reaper.GetSelectedTrack(0, i) + end + for i = 0, reaper.CountSelectedMediaItems(0)-1 do + init_sel_items[i+1] = reaper.GetSelectedMediaItem(0, i) + end + -- store time selection + timesel_start, timesel_end = reaper.GetSet_LoopTimeRange(false, true, 0, 1, false) + + -- select track with selected items + reaper.Main_OnCommand(40297, 0) -- Unselect all tracks + local selected_items_count = reaper.CountSelectedMediaItems(0) + for i = 0, selected_items_count - 1 do + local item = reaper.GetSelectedMediaItem(0, i) + local track = reaper.GetMediaItem_Track(item) + reaper.SetTrackSelected(track, true) + end + -- Set time selection to selected items and extend it a little to the right and left, so it includes adjacent items + reaper.Main_OnCommand( 40290, 0 ) -- set time selection to selected items + reaper.Main_OnCommand( 40320, 0 ) -- nudge left edge of time selection left + reaper.Main_OnCommand( 40323, 0 ) -- nudge right edge of time selection right + -- Select adjacent items and fill gaps (and crossfade) + reaper.Main_OnCommand( 40718, 0 ) -- select items on selected tracks and in time selection + reaper.Main_OnCommand( reaper.NamedCommandLookup('_SWS_AWFILLGAPSQUICKXFADE'), 0 ) -- fill gaps between selected items and crossfade + + -- restore selected tracks and items after work + reaper.Main_OnCommand(40297, 0) -- Unselect all tracks + for _, track in ipairs(init_sel_tracks) do + reaper.SetTrackSelected(track, true) + end + reaper.Main_OnCommand(40289, 0) -- Unselect all items + for _, item in ipairs(init_sel_items) do + reaper.SetMediaItemSelected(item, true) + end + reaper.GetSet_LoopTimeRange(true, true, timesel_start, timesel_end, false) +end + +-- Increase the takenumber and write to tracknames +function increaseTake() + local i_track = 0 + local track = reaper.GetTrack(0, i_track) + local name = 'empty' + local take = 1 + local retval + local val + + -- load takenumber from rpp + retval, val = reaper.GetProjExtState(0, 'takenumber_window', 'nexttake') + if retval > 0 then take = tonumber(val) + 1 end -- variable exists? if not keep take=1 + takestring = '_T' .. string.format('%03d', take) -- format string to append to tracks, e.g. "_T042" + + -- run through all tracks and append takenumber + while(track) + do + name = select( 2, reaper.GetSetMediaTrackInfo_String(track, 'P_NAME', name, false) ) + -- check if a takenumber already exists, even if without leading zeros + if name:sub(-5,-4) == '_T' then + name = name:sub(1,-6) + elseif name:sub(-4,-3) == '_T' then + name = name:sub(1,-5) + elseif name:sub(-3,-2) == '_T' then + name = name:sub(1,-4) + elseif name:sub(-2,-1) == '_T' then + name = name:sub(1,-3) + end + -- set new trackname and get next track + reaper.GetSetMediaTrackInfo_String(track, 'P_NAME', name .. takestring, true) + i_track = i_track + 1 + track = reaper.GetTrack(0, i_track) + end + -- write new takenumber to rpp + reaper.SetProjExtState(0, 'takenumber_window', 'nexttake', take) +end + +-- decreases takenumber and write to tracknames +function decreaseTake() + local i_track = 0 + local track = reaper.GetTrack(0, i_track) + local name = 'empty' + local take = 1 + local retval + local val + + -- load takenumber from rpp + retval, val = reaper.GetProjExtState(0, 'takenumber_window', 'nexttake') + if retval > 0 then take = tonumber(val) - 1 end -- variable exists? if not keep take=1 + takestring = '_T' .. string.format('%03d', take) -- format string to append to tracks, e.g. "_T042" + + -- run through all tracks and append takenumber + while(track) + do + name = select( 2, reaper.GetSetMediaTrackInfo_String(track, 'P_NAME', name, false) ) + -- check if a takenumber already exists, even without leading zeros + if name:sub(-5,-4) == '_T' then + name = name:sub(1,-6) + elseif name:sub(-4,-3) == '_T' then + name = name:sub(1,-5) + elseif name:sub(-3,-2) == '_T' then + name = name:sub(1,-4) + elseif name:sub(-2,-1) == '_T' then + name = name:sub(1,-3) + end + -- set new trackname and get next track + reaper.GetSetMediaTrackInfo_String(track, 'P_NAME', name .. takestring, true) + i_track = i_track + 1 + track = reaper.GetTrack(0, i_track) + end + -- write new takenumber to rpp + reaper.SetProjExtState(0, 'takenumber_window', 'nexttake', take) +end + +-- Initialisation for takenumber and tracknames +function initTracknames() + local i_track = 0 + local track = reaper.GetTrack(0, i_track) + local name = 'empty' + local take = 1 + local retval + local val + + -- try to get takenumber from rpp. If not present, set to "1" + retval, val = reaper.GetProjExtState(0, 'takenumber_window', 'nexttake') + if retval > 0 then + take = tonumber(val) + else + reaper.SetProjExtState(0, 'takenumber_window', 'nexttake', take) + end + takestring = '_T' .. string.format('%03d', take) -- format string to append to tracks, e.g. "_T042" + + -- run through all tracks and append takenumber + while(track) + do + name = select( 2, reaper.GetSetMediaTrackInfo_String(track, 'P_NAME', name, false) ) + -- check if a takenumber already exists, even without leading zeros + if name:sub(-5,-4) == '_T' then + name = name:sub(1,-6) + elseif name:sub(-4,-3) == '_T' then + name = name:sub(1,-5) + elseif name:sub(-3,-2) == '_T' then + name = name:sub(1,-4) + elseif name:sub(-2,-1) == '_T' then + name = name:sub(1,-3) + end + -- set new trackname and get next track + reaper.GetSetMediaTrackInfo_String(track, 'P_NAME', name .. takestring, true) + i_track = i_track + 1 + track = reaper.GetTrack(0, i_track) + end +end + +-- Removes Takenumber from tracknames +function cleanTracknames() + local i_track = 0 + local track = reaper.GetTrack(0, i_track) + local name = 'empty' + + -- run through all tracks and remove takenumber + while(track) + do + name = select( 2, reaper.GetSetMediaTrackInfo_String(track, 'P_NAME', name, false) ) + -- check if a takenumber exists, even without leading zeros or without numbers + if name:sub(-5,-4) == '_T' then + name = name:sub(1,-6) + elseif name:sub(-4,-3) == '_T' then + name = name:sub(1,-5) + elseif name:sub(-3,-2) == '_T' then + name = name:sub(1,-4) + elseif name:sub(-2,-1) == '_T' then + name = name:sub(1,-3) + end + -- set new trackname and get next track + reaper.GetSetMediaTrackInfo_String(track, 'P_NAME', name, true) + i_track = i_track + 1 + track = reaper.GetTrack(0, i_track) + end +end + +-- Read takenumber from name of first track and store it to rpp +function getTakeFromTrackOne() + local track = reaper.GetTrack(0, 0) + local name = 'empty' + + name = select( 2, reaper.GetSetMediaTrackInfo_String(track, 'P_NAME', name, false) ) + -- reads takenumber, even without leading zeros + if name:sub(-5,-4) == '_T' then + reaper.SetProjExtState(0, 'takenumber_window', 'nexttake', tonumber(name:sub(-3,-1))) + elseif name:sub(-4,-3) == '_T' then + reaper.SetProjExtState(0, 'takenumber_window', 'nexttake', tonumber(name:sub(-2,-1))) + elseif name:sub(-3,-2) == '_T' then + reaper.SetProjExtState(0, 'takenumber_window', 'nexttake', tonumber(name:sub(-1,-1))) + end +end + +-- Store state to project variables +function storeExtState() + reaper.SetProjExtState(0, 'takenumber_window', 'dockState', gfx.dock(-1)) + + if groupItemsAfterRecord then + reaper.SetProjExtState(0, 'takenumber_window', 'groupItems', '1') + else + reaper.SetProjExtState(0, 'takenumber_window', 'groupItems', '0') + end + + if groupItemsHAfterRecord then + reaper.SetProjExtState(0, 'takenumber_window', 'groupItemsH', '1') + else + reaper.SetProjExtState(0, 'takenumber_window', 'groupItemsH', '0') + end + + if lockToActiveTakeAfterRecord then + reaper.SetProjExtState(0, 'takenumber_window', 'lockToActiveTake', '1') + else + reaper.SetProjExtState(0, 'takenumber_window', 'lockToActiveTake', '0') + end + + if fillGapsAfterRecord then + reaper.SetProjExtState(0, 'takenumber_window', 'fillGaps', '1') + else + reaper.SetProjExtState(0, 'takenumber_window', 'fillGaps', '0') + end + + if writeTakeNamesAfterRecord then + reaper.SetProjExtState(0, 'takenumber_window', 'writeTakenames', '1') + else + reaper.SetProjExtState(0, 'takenumber_window', 'writeTakenames', '0') + end +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 = "Remove takenumber from tracknames"}) + rc_menu:add_item({label = "Write takenumber to tracknames|"}) + rc_menu:add_item({label = "Reset takenumber to one"}) + rc_menu:add_item({label = "Get takenumber from first track"}) + rc_menu:add_item({label = "Increase takenumber by one"}) + rc_menu:add_item({label = "Decrease takenumber by one|"}) + rc_menu:add_item({label = "Group all items of same take", + toggleable = true, + selected = groupItemsAfterRecord}) + rc_menu:add_item({label = "Group items of same take horizontally|", + toggleable = true, + selected = groupItemsAfterRecordH}) + rc_menu:add_item({label = "Crossfade after record (needs SWS)", + toggleable = true, + active = sws_present, + selected = fillGapsAfterRecord and sws_present}) + rc_menu:add_item({label = "Lock to active take after record", + toggleable = true, + selected = lockToActiveTakeAfterRecord}) + rc_menu:add_item({label = "Write clean Takenames after record|", + toggleable = true, + selected = writeTakeNamesAfterRecord}) + rc_menu:add_item({label = "Quit"}) + + -- Let's add a command to all created items: + rc_menu.items[1].command = function() cleanTracknames() end + rc_menu.items[2].command = function() initTracknames() end + rc_menu.items[3].command = function() + reaper.SetProjExtState(0, 'takenumber_window', 'nexttake', '1') + initTracknames() + end + rc_menu.items[4].command = function() + getTakeFromTrackOne() + initTracknames() + end + rc_menu.items[5].command = function() increaseTake() end + rc_menu.items[6].command = function() decreaseTake() end + rc_menu.items[7].command = function() + if rc_menu.items[7].selected then + groupItemsAfterRecord = true + groupItemsHAfterRecord = false + rc_menu.items[8].selected = false + else + groupItemsAfterRecord = false + end + storeExtState() + end + rc_menu.items[8].command = function() + if rc_menu.items[8].selected then + groupItemsHAfterRecord = true + groupItemsAfterRecord = false + rc_menu.items[7].selected = false + else + groupItemsHAfterRecord = false + end + storeExtState() + end + rc_menu.items[9].command = function() + if rc_menu.items[9].selected then + fillGapsAfterRecord = true + else + fillGapsAfterRecord = false + end + storeExtState() + end + rc_menu.items[10].command = function() + if rc_menu.items[10].selected then + lockToActiveTakeAfterRecord = true + else + lockToActiveTakeAfterRecord = false + end + storeExtState() + end + rc_menu.items[11].command = function() + if rc_menu.items[11].selected then + writeTakeNamesAfterRecord = true + else + writeTakeNamesAfterRecord = false + end + storeExtState() + end + rc_menu.items[12].command = function() quit = true end +end + +-- Draw GUI -- +function drawGui() + local take = 1 + local retval + local val + local thisnext = 'Next' + + -- try to get takenumber from rpp. If not present, set to "1" + retval, val = reaper.GetProjExtState(0, 'takenumber_window', 'nexttake') + if retval > 0 then + take = tonumber(val) + else + reaper.SetProjExtState(0, 'takenumber_window', 'nexttake', take) + end + + -- Are we in "record" mode? + if reaper.GetAllProjectPlayStates(0) == 5 then + increaseTodo = true -- after rec-stop we have to increase the takenumber + thisnext = 'This' -- during record the label says "This Take: 42" + gfx.clear = 255 + 20*256 + 20*65536 -- background is red + else -- no, we're not + if increaseTodo then -- we just stopped from record + if writeTakeNamesAfterRecord then --so we do all the magic, here eventually we write nice takenames + writeTakeNames() + end + increaseTake() -- and have to increase the takenumber + if groupItemsAfterRecord then -- and do post-record-stuff + groupItems() + elseif groupItemsHAfterRecord then + groupItemsH() + end + if lockToActiveTakeAfterRecord then + setLockToActiveTake() + end + if fillGapsAfterRecord then + fillGapsBetweenItems() + end + thisnext = 'Next' -- during "not-record" the label says "Next Take: 43" + increaseTodo = false -- and we're done and reset this flag + end + gfx.clear = 3355443 -- background is dark grey + end + + -- 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("Take")) ) / 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(thisnext .. " Take: " .. take) > (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(thisnext .. " Take: " .. take) + -- portrait format + else + gfx.x = gfx.w/15 + gfx.y = ( gfx.h-select(2, gfx.measurestr("Next\nTake\nT123")) ) / 2 + gui.settings.font_size = gfx.w / 3 + gfx.setfont(1,"Arial", gui.settings.font_size) + gfx.printf(thisnext .. "\nTake:\n" .. take) + 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("Take")) ) / 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(thisnext .. " Take: " .. take) > (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(thisnext .. " Take: " .. take) + -- portrait format + else + gfx.x = gfx.w/20 + gfx.y = ( gfx.h-select(2, gfx.measurestr("Next\nTake\nT123")) ) / 2 + gui.settings.font_size = gfx.w / 3 + gfx.setfont(1,"Arial", gui.settings.font_size) + gfx.printf(thisnext .. "\nTake:\n" .. take) + 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, 'takenumber_window', 'groupItems') + if retval > 0 then + if tonumber(val) > 0 then + groupItemsAfterRecord = true + else + groupItemsAfterRecord = false + end + end + retval, val = reaper.GetProjExtState(0, 'takenumber_window', 'groupItemsH') + if retval > 0 then + if tonumber(val) > 0 then + groupItemsAfterRecordH = true + else + groupItemsAfterRecordH = false + end + end + retval, val = reaper.GetProjExtState(0, 'takenumber_window', 'lockToActiveTake') + if retval > 0 then + if tonumber(val) > 0 then + lockToActiveTakeAfterRecord = true + else + lockToActiveTakeAfterRecord = false + end + end + retval, val = reaper.GetProjExtState(0, 'takenumber_window', 'fillGaps') + if retval > 0 then + if tonumber(val) > 0 then + fillGapsAfterRecord = true + else + fillGapsAfterRecord = false + end + end + retval, val = reaper.GetProjExtState(0, 'takenumber_window', 'writeTakenames') + if retval > 0 then + if tonumber(val) > 0 then + writeTakeNamesAfterRecord = true + else + writeTakeNamesAfterRecord = false + end + end + + -- init stuff... + gui_init() + initTracknames() + + -- 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("Rec Take", 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, 'takenumber_window', 'dockState') + if retval > 0 then + gfx.dock(val) + end +end + +-- Main loop -- +function mainloop() + -- mouseclicks? + local RMB_state = mouse.cap(mouse.RB) + 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) + end + + mouse.last_RMB_state = RMB_state -- store current right 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() diff --git a/TakenumberWindow/class.lua b/TakenumberWindow/class.lua new file mode 100644 index 0000000..1507d71 --- /dev/null +++ b/TakenumberWindow/class.lua @@ -0,0 +1,48 @@ +------------- "class.lua" is copied from http://lua-users.org/wiki/SimpleLuaClasses ----------- + +-- class.lua +-- Compatible with Lua 5.1 (not 5.0). +function class(base, init) + local c = {} -- a new class instance + if not init and type(base) == 'function' then + init = base + base = nil + elseif type(base) == 'table' then + -- our new class is a shallow copy of the base class! + for i,v in pairs(base) do + c[i] = v + end + c._base = base + end + -- the class will be the metatable for all its objects, + -- and they will look up their methods in it. + c.__index = c + + -- expose a constructor which can be called by () + local mt = {} + mt.__call = function(class_tbl, ...) + local obj = {} + setmetatable(obj,c) + if init then + init(obj,...) + else + -- make sure that any stuff from the base class is initialized! + if base and base.init then + base.init(obj, ...) + end + end + return obj + end + c.init = init + c.is_a = function(self, klass) + local m = getmetatable(self) + while m do + if m == klass then return true end + m = m._base + end + return false + end + setmetatable(c, mt) + return c +end +---------------------------------------------------------------------------------------- diff --git a/TakenumberWindow/menu class.lua b/TakenumberWindow/menu class.lua new file mode 100644 index 0000000..009a6f2 --- /dev/null +++ b/TakenumberWindow/menu class.lua @@ -0,0 +1,190 @@ +---------------- +-- Menu class -- +---------------- + +-- To create a new menu instance, call this function like this: +-- menu_name = Menu("menu_name") +local Menu = + class( + function(menu, id) + menu.id = id + menu.items = {} -- Menu items are collected to this table + menu.items_str = "" + menu.curr_item_pos = 1 + end + ) + +------------------ +-- Menu methods -- +------------------ + +--[[ +-- True if menu item label starts with "prefix" +function Menu:label_starts_with(label, prefix) + return string.sub(label, 1, string.len(prefix)) == prefix +end +--]] + + +-- Returns "menu item table" (or false if "id" not found) +function Menu:get_item_from_id(id) + for i=1, #self.items do + if self.items[i].id == id then + return self.items[i] + end + end + return false +end + + +-- Updates "menu item type" variables (_has_submenu, _last_item_in_submenu etc.) +function Menu:update_item(item_table) + local t = item_table + t._has_submenu = false + t._last_item_in_submenu = false + t.id = self.curr_item_pos + + if string.sub(t.label, 1, 1) == ">" or + string.sub(t.label, 1, 2) == "<>" or + string.sub(t.label, 1, 2) == "><" then + t._has_submenu = true + t.id = -1 + self.curr_item_pos = self.curr_item_pos - 1 + --end + elseif string.sub(t.label, 1, 1) == "<" then + t._has_submenu = false + t._last_item_in_submenu = true + end + --t.id = self.curr_item_pos + self.curr_item_pos = self.curr_item_pos + 1 +end + + +-- Returns the created table and table index in "menu_obj.items" +function Menu:add_item(...) + local t = ... or {} + self.items[#self.items+1] = t -- add new menu item at the end of menu + + -- Parse arguments + for i,v in pairs(t) do + --msg(i .. " = " .. tostring(v)) + if i == "label" then + t.label = v + elseif i == "selected" then + t.selected = v + elseif i == "active" then + t.active = v + elseif i == "toggleable" then + t.toggleable = v + elseif i == "command" then + t.command = v + end + end + + -- Default values for menu items + -- (Edit these) + if t.label == nil or t.label == "" then + t.label = tostring(#self.items) -- if label is nil or "" -> label is set to "table index in menu_obj.items" + end + + if t.selected == nil then + t.selected = false -- edit + end + + if t.active == nil then + t.active = true -- edit + end + + if t.toggleable == nil then + t.toggleable = false -- edit + end + + return t, #self.items +end + + +-- Get menu item table at index +function Menu:get_item(index) + if self.items[index] == nil then + return false + end + return self.items[index] +end + + +-- Show menu at mx, my +function Menu:show(mx, my) + gfx.x = mx + gfx.y = my + + -- Check which items has a function to call when a menu is about to be shown + for i=1, #self.items do + if self.items[i].on_menu_show ~= nil then + self.items[i].on_menu_show() + end + -- Update item + self:update_item(self.items[i]) + end + + -- Convert menu item tables to string + self.items_str = self:table_to_string() or "" + self.val = gfx.showmenu(self.items_str) + if self.val > 0 then + self:update(self.val) + end + self.curr_item_pos = 1 -- set "menu item position counter" back to the initial value +end + + +function Menu:update(menu_item_index) + -- check which "menu item id" matches with "menu_item_index" + for i=1, #self.items do + if self.items[i].id == menu_item_index then + menu_item_index = i + break + end + end + local i = menu_item_index + -- if menu item is "toggleable" then toggle "selected" state + if self.items[i].toggleable then + self.items[i].selected = not self.items[i].selected + end + -- if menu item has a "command" (function), then call that function + if self.items[i].command ~= nil then + self.items[i].command() + end +end + + +-- Convert "Menu_obj.items" to string +function Menu:table_to_string() + if self.items == nil then + return + end + self.items_str = "" + + for i=1, #self.items do + local temp_str = "" + local menu_item = self.items[i] + if menu_item.selected then + temp_str = "!" + end + + if not menu_item.active then + temp_str = temp_str .. "#" + end + + if menu_item.label ~= "" then + temp_str = temp_str .. menu_item.label .. "|" + end + + self.items_str = self.items_str .. temp_str + end + + return self.items_str +end + +--END of Menu class---------------------------------------------------- + +return Menu + diff --git a/TakenumberWindow/mouse.lua b/TakenumberWindow/mouse.lua new file mode 100644 index 0000000..6907fcc --- /dev/null +++ b/TakenumberWindow/mouse.lua @@ -0,0 +1,34 @@ +----------------- +-- Mouse table -- +----------------- + +local mouse = { + -- Constants + LB = 1, + RB = 2, + CTRL = 4, + SHIFT = 8, + ALT = 16, + + -- "cap" function + cap = function (mask) + if mask == nil then + return gfx.mouse_cap end + return gfx.mouse_cap&mask == mask + end, + + uptime = 0, + + last_x = -1, last_y = -1, + + dx = 0, + dy = 0, + + ox_l = 0, oy_l = 0, -- left click positions + ox_r = 0, oy_r = 0, -- right click positions + capcnt = 0, + last_LMB_state = false, + last_RMB_state = false + } + +return mouse