|
| 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.08" |
| 7 | + finaleplugin.Date = "2024/07/28" |
| 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 special_layer = { |
| 34 | + [0] = "(\"Current\" Layer)", |
| 35 | + [5] = "(Chord Layer)", |
| 36 | + [6] = "(Expression Layer)", |
| 37 | +} |
| 38 | +local c = { -- user config values |
| 39 | + layer = 0, |
| 40 | + start_at = 0, -- {start_options} chosen index (0-based) |
| 41 | + window_pos_x = false, |
| 42 | + window_pos_y = false, |
| 43 | +} |
| 44 | +local hotkey = { -- customise hotkeys (lowercase only) |
| 45 | + start_at = "z", |
| 46 | + show_info = "q", |
| 47 | +} |
| 48 | +local configuration = require("library.configuration") |
| 49 | +local mixin = require("library.mixin") |
| 50 | +local utils = require("library.utils") |
| 51 | +local library = require("library.general_library") |
| 52 | +local script_name = library.calc_script_name() |
| 53 | +local name = plugindef():gsub("%.%.%.", "") |
| 54 | +local refocus_document = false -- set to true if utils.show_notes_dialog is used |
| 55 | + |
| 56 | +local function dialog_set_position(dialog) |
| 57 | + if c.window_pos_x and c.window_pos_y then |
| 58 | + dialog:StorePosition() |
| 59 | + dialog:SetRestorePositionOnlyData(c.window_pos_x, c.window_pos_y) |
| 60 | + dialog:RestorePosition() |
| 61 | + end |
| 62 | +end |
| 63 | + |
| 64 | +local function dialog_save_position(dialog) |
| 65 | + dialog:StorePosition() |
| 66 | + c.window_pos_x = dialog.StoredX |
| 67 | + c.window_pos_y = dialog.StoredY |
| 68 | + configuration.save_user_settings(script_name, c) |
| 69 | +end |
| 70 | + |
| 71 | +local function user_dialog() |
| 72 | + local y = 0 |
| 73 | + local y_off = finenv.UI():IsOnMac() and 3 or 0 |
| 74 | + local x_off = 54 -- horiz offset for Layer Number and Radio Group |
| 75 | + local save = c.layer |
| 76 | + local dialog = mixin.FCXCustomLuaWindow():SetTitle(name) |
| 77 | + |
| 78 | + local function flip_radio() |
| 79 | + local radio = dialog:GetControl("start_at") |
| 80 | + radio:SetSelectedItem((radio:GetSelectedItem() + 1) % 3) |
| 81 | + end |
| 82 | + local function show_info() |
| 83 | + utils.show_notes_dialog(dialog, "About " .. name, 300, 155) |
| 84 | + refocus_document = true |
| 85 | + end |
| 86 | + local function cstat(x, wide, str, id) |
| 87 | + dialog:CreateStatic(x, y, id):SetWidth(wide):SetText(str) |
| 88 | + end |
| 89 | + cstat(0, 190, "Assign Playback of All Expressions") |
| 90 | + y = y + 22 |
| 91 | + cstat(0, x_off, "to Layer:") |
| 92 | + dialog:CreateEdit(x_off, y - y_off, "layer"):SetInteger(save):SetWidth(20) |
| 93 | + :AddHandleCommand(function(self) |
| 94 | + local s = self:GetText():lower() |
| 95 | + if s:find("[^0-6]") then |
| 96 | + if s:find(hotkey.start_at) then flip_radio() |
| 97 | + elseif s:find(hotkey.show_info) then show_info() |
| 98 | + end |
| 99 | + else |
| 100 | + save = tonumber(s:sub(-1)) or 0 |
| 101 | + dialog:GetControl("data"):SetText(special_layer[save] or "") |
| 102 | + end |
| 103 | + self:SetInteger(save):SetKeyboardFocus() |
| 104 | + end) |
| 105 | + cstat(x_off + 28, 110, (special_layer[save] or ""), "data") |
| 106 | + y = y + 22 |
| 107 | + cstat(0, 160, "Begin Playback At:") |
| 108 | + dialog:CreateButton(165, y, "q"):SetText("?"):SetWidth(20) |
| 109 | + :AddHandleCommand(function() show_info() end) |
| 110 | + y = y + 16 |
| 111 | + local labels = finale.FCStrings() |
| 112 | + labels:CopyFromStringTable(start_options[1]) |
| 113 | + dialog:CreateRadioButtonGroup(x_off, y, 3, "start_at") |
| 114 | + :SetText(labels):SetWidth(130) |
| 115 | + :SetSelectedItem(c.start_at) |
| 116 | + y = y + 14 |
| 117 | + cstat(x_off / 2, 50, "[" .. hotkey.start_at .. "]") |
| 118 | + dialog:CreateOkButton() |
| 119 | + dialog:CreateCancelButton() |
| 120 | + dialog_set_position(dialog) |
| 121 | + dialog:RegisterInitWindow(function() |
| 122 | + local q = dialog:GetControl("q") |
| 123 | + q:SetFont(q:CreateFontInfo():SetBold(true)) end) |
| 124 | + dialog:RegisterHandleOkButtonPressed(function() |
| 125 | + c.layer = dialog:GetControl("layer"):GetInteger() |
| 126 | + c.start_at = dialog:GetControl("start_at"):GetSelectedItem() -- 0-based |
| 127 | + end) |
| 128 | + dialog:RegisterCloseWindow(function(self) dialog_save_position(self) end) |
| 129 | + return (dialog:ExecuteModal() == finale.EXECMODAL_OK) |
| 130 | +end |
| 131 | + |
| 132 | +local function playback_layer() |
| 133 | + if finenv.Region():IsEmpty() then |
| 134 | + finenv.UI():AlertError( |
| 135 | + "Please select some music\nbefore running this script", |
| 136 | + name .. " Error") |
| 137 | + return |
| 138 | + end |
| 139 | + configuration.get_user_settings(script_name, c, true) |
| 140 | + local qim = finenv.QueryInvokedModifierKeys |
| 141 | + local mod_key = qim and (qim(finale.CMDMODKEY_ALT) or qim(finale.CMDMODKEY_SHIFT)) |
| 142 | + |
| 143 | + if mod_key or user_dialog() then |
| 144 | + local start_option = start_options[2][c.start_at + 1] -- user choice -> actual index |
| 145 | + local expressions = finale.FCExpressions() |
| 146 | + expressions:LoadAllForRegion(finenv.Region()) |
| 147 | + for exp in each(expressions) do |
| 148 | + if exp.StaffGroupID == 0 then -- exclude "Staff List" expressions |
| 149 | + exp.PlaybackLayerAssignment = c.layer |
| 150 | + exp.PlaybackStart = start_option |
| 151 | + exp:Save() |
| 152 | + end |
| 153 | + end |
| 154 | + end |
| 155 | + if refocus_document then finenv.UI():ActivateDocumentWindow() end |
| 156 | +end |
| 157 | + |
| 158 | +playback_layer() |
0 commit comments