|
| 1 | +function plugindef() |
| 2 | + finaleplugin.RequireSelection = false |
| 3 | + finaleplugin.Author = "Carl Vine" |
| 4 | + finaleplugin.AuthorURL = "http://carlvine.com/lua/" |
| 5 | + finaleplugin.Copyright = "https://creativecommons.org/licenses/by/4.0/" |
| 6 | + finaleplugin.Version = "0.07" |
| 7 | + finaleplugin.Date = "2024/07/27" |
| 8 | + finaleplugin.Notes = [[ |
| 9 | + Change the assigned playback layer and position for all expressions |
| 10 | + in the current selection. |
| 11 | + Layers __1-4__ are the _standard_ playback layers. |
| 12 | + Layer numbers __0__, __5__ and __6__ are interpreted respectively |
| 13 | + as __Current__, __Chord__ and __Expression__ Layers for playback. |
| 14 | +
|
| 15 | + Hold down _Shift_ when starting the script to repeat the same action |
| 16 | + as last time without a confirmation dialog. |
| 17 | + ]] |
| 18 | + return "Expression Playback...", |
| 19 | + "Expression Playback", |
| 20 | + "Change the assigned playback layer for all expressions in the current selection" |
| 21 | +end |
| 22 | + |
| 23 | +local start_options = { -- "Begin Playback At:" (ordered) |
| 24 | + { "Alignment Point", |
| 25 | + "Beginning of Measure", |
| 26 | + "Position in Measure" |
| 27 | + }, -- + corresponding index of EXPRESSION_PLAYBACK_STARTPOINTS: |
| 28 | + { finale.EXPRPLAYSTART_ALIGNMENTPOINT, |
| 29 | + finale.EXPRPLAYSTART_BEGINNINGOFMEASURE, |
| 30 | + finale.EXPRPLAYSTART_POSINMEASURE |
| 31 | + } |
| 32 | +} |
| 33 | +local c = { -- user config values |
| 34 | + layer = 0, |
| 35 | + start_at = 1, -- {start_options} chosen index (1-based) |
| 36 | + window_pos_x = false, |
| 37 | + window_pos_y = false, |
| 38 | +} |
| 39 | +local hotkey = { -- customise hotkeys (lowercase only) |
| 40 | + start_at = "z", |
| 41 | + show_info = "q", |
| 42 | +} |
| 43 | +local configuration = require("library.configuration") |
| 44 | +local mixin = require("library.mixin") |
| 45 | +local utils = require("library.utils") |
| 46 | +local library = require("library.general_library") |
| 47 | +local script_name = library.calc_script_name() |
| 48 | +local name = plugindef():gsub("%.%.%.", "") |
| 49 | +local refocus_document = false -- set to true if utils.show_notes_dialog is used |
| 50 | + |
| 51 | +local function dialog_set_position(dialog) |
| 52 | + if c.window_pos_x and c.window_pos_y then |
| 53 | + dialog:StorePosition() |
| 54 | + dialog:SetRestorePositionOnlyData(c.window_pos_x, c.window_pos_y) |
| 55 | + dialog:RestorePosition() |
| 56 | + end |
| 57 | +end |
| 58 | + |
| 59 | +local function dialog_save_position(dialog) |
| 60 | + dialog:StorePosition() |
| 61 | + c.window_pos_x = dialog.StoredX |
| 62 | + c.window_pos_y = dialog.StoredY |
| 63 | + configuration.save_user_settings(script_name, c) |
| 64 | +end |
| 65 | + |
| 66 | +local function user_dialog() |
| 67 | + local y = 0 |
| 68 | + local y_off = finenv.UI():IsOnMac() and 3 or 0 |
| 69 | + local x_off = 54 -- horiz offset for Layer Number and Radio Group |
| 70 | + local save = c.layer |
| 71 | + local dialog = mixin.FCXCustomLuaWindow():SetTitle(name) |
| 72 | + |
| 73 | + local function flip_radio() |
| 74 | + local radio = dialog:GetControl("start_at") |
| 75 | + radio:SetSelectedItem((radio:GetSelectedItem() + 1) % 3) |
| 76 | + end |
| 77 | + local function show_info() |
| 78 | + utils.show_notes_dialog(dialog, "About " .. name, 300, 155) |
| 79 | + refocus_document = true |
| 80 | + end |
| 81 | + local function cstat(x, wide, str) |
| 82 | + dialog:CreateStatic(x, y):SetWidth(wide):SetText(str) |
| 83 | + end |
| 84 | + cstat(0, 190, "Assign Playback of All Expressions") |
| 85 | + y = y + 22 |
| 86 | + cstat(0, x_off, "to Layer:") |
| 87 | + dialog:CreateEdit(x_off, y - y_off, "layer"):SetInteger(save):SetWidth(20) |
| 88 | + :AddHandleCommand(function(self) |
| 89 | + local s = self:GetText():lower() |
| 90 | + if s:find("[^0-6]") then |
| 91 | + if s:find(hotkey.start_at) then flip_radio() |
| 92 | + elseif s:find(hotkey.show_info) then show_info() |
| 93 | + end |
| 94 | + else |
| 95 | + save = tonumber(s:sub(-1)) or 0 |
| 96 | + end |
| 97 | + self:SetInteger(save):SetKeyboardFocus() |
| 98 | + end) |
| 99 | + y = y + 22 |
| 100 | + cstat(0, 160, "Begin Playback At:") |
| 101 | + dialog:CreateButton(165, y, "q"):SetText("?"):SetWidth(20) |
| 102 | + :AddHandleCommand(function() show_info() end) |
| 103 | + y = y + 16 |
| 104 | + local labels = finale.FCStrings() |
| 105 | + labels:CopyFromStringTable(start_options[1]) |
| 106 | + dialog:CreateRadioButtonGroup(x_off, y, 3, "start_at") |
| 107 | + :SetText(labels):SetWidth(130) |
| 108 | + :SetSelectedItem(c.start_at - 1) |
| 109 | + y = y + 14 |
| 110 | + cstat(x_off / 2, 50, "[" .. hotkey.start_at .. "]") |
| 111 | + dialog:CreateOkButton() |
| 112 | + dialog:CreateCancelButton() |
| 113 | + dialog_set_position(dialog) |
| 114 | + dialog:RegisterInitWindow(function() |
| 115 | + local q = dialog:GetControl("q") |
| 116 | + q:SetFont(q:CreateFontInfo():SetBold(true)) end) |
| 117 | + dialog:RegisterHandleOkButtonPressed(function() |
| 118 | + c.layer = dialog:GetControl("layer"):GetInteger() |
| 119 | + c.start_at = dialog:GetControl("start_at"):GetSelectedItem() + 1 |
| 120 | + end) |
| 121 | + dialog:RegisterCloseWindow(function(self) dialog_save_position(self) end) |
| 122 | + return (dialog:ExecuteModal() == finale.EXECMODAL_OK) |
| 123 | +end |
| 124 | + |
| 125 | +local function playback_layer() |
| 126 | + if finenv.Region():IsEmpty() then |
| 127 | + finenv.UI():AlertError( |
| 128 | + "Please select some music\nbefore running this script", |
| 129 | + name .. " Error") |
| 130 | + return |
| 131 | + end |
| 132 | + configuration.get_user_settings(script_name, c, true) |
| 133 | + local qim = finenv.QueryInvokedModifierKeys |
| 134 | + local mod_key = qim and (qim(finale.CMDMODKEY_ALT) or qim(finale.CMDMODKEY_SHIFT)) |
| 135 | + |
| 136 | + if mod_key or user_dialog() then |
| 137 | + local start_option = start_options[2][c.start_at] -- user choice -> actual index |
| 138 | + local expressions = finale.FCExpressions() |
| 139 | + expressions:LoadAllForRegion(finenv.Region()) |
| 140 | + for exp in each(expressions) do |
| 141 | + if exp.StaffGroupID == 0 then -- exclude "Staff List" expressions |
| 142 | + exp.PlaybackLayerAssignment = c.layer |
| 143 | + exp.PlaybackStart = start_option |
| 144 | + exp:Save() |
| 145 | + end |
| 146 | + end |
| 147 | + end |
| 148 | + if refocus_document then finenv.UI():ActivateDocumentWindow() end |
| 149 | +end |
| 150 | + |
| 151 | +playback_layer() |
0 commit comments