Skip to content

Commit ea60f70

Browse files
authored
Merge pull request #755 from cv-on-hub/cv-slur-changer
Update slur_changer.lua
2 parents fd60e91 + 609fa1e commit ea60f70

File tree

1 file changed

+70
-92
lines changed

1 file changed

+70
-92
lines changed

src/slur_changer.lua

Lines changed: 70 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ function plugindef()
44
finaleplugin.Author = "Carl Vine"
55
finaleplugin.AuthorURL = "https://carlvine.com/lua"
66
finaleplugin.Copyright = "https://creativecommons.org/licenses/by/4.0/"
7-
finaleplugin.Version = "0.05"
8-
finaleplugin.Date = "2024/07/09"
7+
finaleplugin.Version = "0.09"
8+
finaleplugin.Date = "2024/07/26"
99
finaleplugin.MinJWLuaVersion = 0.70
1010
finaleplugin.Notes = [[
1111
Change the characteristics of every slur in the current selection.
@@ -17,7 +17,8 @@ function plugindef()
1717
To repeat the last action without a confirmation dialog
1818
hold down _Shift_ when opening the script.
1919
]]
20-
return "Slur Changer...", "Slur Changer",
20+
return "Slur Changer...",
21+
"Slur Changer",
2122
"Change the characteristics of slurs in the current selection"
2223
end
2324

@@ -28,8 +29,6 @@ local layer_lib = require("library.layer")
2829
local library = require("library.general_library")
2930
local script_name = library.calc_script_name()
3031
local name = plugindef():gsub("%.%.%.", "")
31-
local selection
32-
local saved_bounds = {}
3332

3433
local config = {
3534
dummy = "dummy", -- stop warning about table string mismatch
@@ -41,27 +40,28 @@ local config = {
4140
window_pos_y = nil,
4241
-- other default values copied from dialog_options{} below
4342
}
44-
local dialog_options = { -- NAME key; HOTKEY; text description (ordered)
43+
local dialog_options = { -- NAME key; HOTKEY; menu listing (ordered)
4544
{ "visible_yes", "V", "Visible" },
4645
{ "visible_no", "I", "Invisible" },
47-
{ "flip", "X", "Flip" },
48-
{ "SMARTSHAPE_SLURUP", "O", "Slur: Over" },
49-
{ "SMARTSHAPE_SLURDOWN", "U", "Slur: Under" },
50-
{ "SMARTSHAPE_SLURAUTO", "A", "Slur: Auto" },
51-
{ "SMARTSHAPE_DASHEDSLURUP", "D", "Dashed: Over" },
52-
{ "SMARTSHAPE_DASHEDSLURDOWN", "F", "Dashed: Under" },
53-
{ "SMARTSHAPE_DASHEDSLURAUTO", "G", "Dashed: Auto" },
54-
{ "ENG_SS_OFFSTATE", "B", "Engraver: ON" },
55-
{ "ENG_SS_ONSTATE", "N", "Engraver: OFF" },
56-
{ "ENG_SS_AUTOSTATE", "M", "Engraver: AUTO" },
57-
{ "ACC_SS_OFFSTATE", "J", "Accidental Avoid: ON" },
58-
{ "ACC_SS_ONSTATE", "K", "Accidental Avoid: OFF" },
59-
{ "ACC_SS_AUTOSTATE", "L", "Accidental Avoid: AUTO" },
46+
{ "flip", "X", "Flip Direction" },
47+
{ "SMARTSHAPE_SLURAUTO", "A", "Slur Direction Auto" },
48+
{ "SMARTSHAPE_SLURUP", "O", "Slur Direction Over" },
49+
{ "SMARTSHAPE_SLURDOWN", "U", "Slur Direction Under" },
50+
{ "SMARTSHAPE_DASHEDSLURAUTO", "D", "Dashed Auto" },
51+
{ "SMARTSHAPE_DASHEDSLURUP", "F", "Dashed Over" },
52+
{ "SMARTSHAPE_DASHEDSLURDOWN", "G", "Dashed Under" },
53+
{ "ENGRAV_AUTO", "B", "Engraver Slur Auto" },
54+
{ "ENGRAV_ON", "N", "Engraver Slur On" },
55+
{ "ENGRAV_OFF" , "M", "Engraver Slur Off" },
56+
{ "AVACCI_AUTO", "J", "Avoid Accidentals Auto" },
57+
{ "AVACCI_ON", "K", "Avoid Accidentals On" },
58+
{ "AVACCI_OFF", "L", "Avoid Accidentals Off" },
6059
{ "remove", "R", "Remove Manual Adj." },
6160
{ "erase", "E", "Erase All" },
6261
{ "default", "Z", "Default Values" }
6362
}
6463
for _, v in ipairs(dialog_options) do config[v[1]] = v[2] end -- (map hotkeys)
64+
local ss_3state = { ON = 0, OFF = 1, AUTO = 2 }
6565

6666
local function dialog_set_position(dialog)
6767
if config.window_pos_x and config.window_pos_y then
@@ -88,27 +88,19 @@ local function get_staff_name(staff_num)
8888
return str
8989
end
9090

91-
local function track_selection()
92-
local bounds = { -- primary region selection boundaries
93-
"StartStaff", "StartMeasure", "StartMeasurePos",
94-
"EndStaff", "EndMeasure", "EndMeasurePos",
95-
}
96-
-- update selection
91+
local function update_selection()
9792
local rgn = finenv.Region()
98-
if rgn:IsEmpty() then
99-
selection = "no staff, no selection" -- default
93+
if rgn:IsEmpty() then return nil
10094
else
101-
for _, property in ipairs(bounds) do
102-
saved_bounds[property] = rgn[property]
103-
end
104-
selection = get_staff_name(rgn.StartStaff)
95+
local s = get_staff_name(rgn.StartStaff)
10596
if rgn.EndStaff ~= rgn.StartStaff then
106-
selection = selection .. "-" .. get_staff_name(rgn.EndStaff)
97+
s = s .. "-" .. get_staff_name(rgn.EndStaff)
10798
end
108-
selection = selection .. " m." .. rgn.StartMeasure
99+
s = s .. " m." .. rgn.StartMeasure
109100
if rgn.StartMeasure ~= rgn.EndMeasure then
110-
selection = selection .. "-" .. rgn.EndMeasure
101+
s = s .. "-" .. rgn.EndMeasure
111102
end
103+
return s
112104
end
113105
end
114106

@@ -179,11 +171,16 @@ local function slur_match_layer(slur)
179171
return (entry.LayerNumber == config.layer) -- layer number matched
180172
end
181173

174+
local function slur_defaults(slur)
175+
slur.EngraverSlur = ss_3state.AUTO
176+
slur.PresetShape = true
177+
slur.ShapeType = finale.SMARTSHAPE_SLURAUTO
178+
slur.Visible = true
179+
slur:GetCtrlPointAdjust():SetDefaultSlurShape()
180+
end
181+
182182
local function slur_manual_clear(slur)
183-
slur.PresetShape = true
184-
slur:IsAutoSlur(true)
185-
slur:SetSlurFlags(true)
186-
slur:SetEngraverSlur(finale.SS_AUTOSTATE)
183+
slur_defaults(slur)
187184
local ctrl_points = {
188185
"ControlPoint1OffsetX", "ControlPoint1OffsetY",
189186
"ControlPoint2OffsetX", "ControlPoint2OffsetY"
@@ -204,45 +201,36 @@ local function slur_manual_clear(slur)
204201
end
205202
end
206203

207-
local function change_the_slurs(dialog)
208-
if finenv.Region():IsEmpty() then
209-
local ui = dialog and dialog:CreateChildUI() or finenv.UI()
210-
ui:AlertError("Please select some music\nbefore running this script", name)
211-
return
212-
end
204+
local function change_the_slurs()
213205
local selected = dialog_options[config.last_selected + 1]
214206
local state = selected[1]
215-
local checked = {}
216-
local undo = string.format("Slur %s %s", selected[3]:gsub(" ", ""), selection)
207+
local s = update_selection()
208+
if not s then return end
209+
local undo = string.format("Slur %s %s", selected[3]:gsub(" ", ""), s)
217210
if config.layer > 0 then undo = undo .. " L" .. config.layer end
218211
finenv.StartNewUndoBlock(undo)
219212
--
220-
local ss_state = state:sub(5) -- one of "SS_ONSTATE", "SS_OFFSTATE", "SS_AUTOSTATE"
221-
for mark in loadallforregion(finale.FCSmartShapeMeasureMarks(), finenv.Region()) do
213+
local ss_state = state:sub(8) -- one of AUTO/ON/OFF for "ENGRAV_" & "AVACCI_" states
214+
local marks = finale.FCSmartShapeMeasureMarks()
215+
marks:LoadAllForRegion(finenv.Region(), true)
216+
for mark in each(marks) do
222217
local slur = mark:CreateSmartShape()
223-
if not checked[slur.ItemNo] then -- only examine shapes once
224-
checked[slur.ItemNo] = true
225-
if slur and slur:IsSlur() and
226-
(not slur:IsEntryBased() or slur_match_layer(slur))
227-
then
228-
if state == "default" then
229-
slur.EngraverSlur = finale.SS_AUTOSTATE
230-
slur.ShapeType = finale.SMARTSHAPE_SLURAUTO
231-
slur.Visible = true
232-
slur:GetCtrlPointAdjust():SetDefaultSlurShape()
233-
elseif state:find("visible") then slur.Visible = state:find("yes")
234-
elseif state == "erase" then slur:DeleteData()
235-
elseif state == "remove" then slur_manual_clear(slur)
236-
elseif state == "flip" then
237-
local a = slur:IsDashedSlur() and "DASHEDSLUR" or "SLUR"
238-
local b = (slur:IsOverSlur() or slur:IsAutoSlur()) and "DOWN" or "UP"
239-
slur.ShapeType = finale["SMARTSHAPE_" .. a .. b]
240-
elseif state:find("ENG_") then slur.EngraverSlur = finale[ss_state]
241-
elseif state:find("ACC_") then slur.AvoidAccidentals = finale[ss_state]
242-
else slur.ShapeType = finale[state]
243-
end
244-
slur:Save()
218+
if slur and slur:IsSlur() and
219+
(not slur:IsEntryBased() or slur_match_layer(slur))
220+
then
221+
if state == "default" then slur_defaults(slur)
222+
elseif state:find("visible") then slur.Visible = state:find("yes")
223+
elseif state == "erase" then slur:DeleteData()
224+
elseif state == "remove" then slur_manual_clear(slur)
225+
elseif state == "flip" then
226+
local a = slur:IsDashedSlur() and "DASHEDSLUR" or "SLUR"
227+
local b = (slur:IsOverSlur() or slur:IsAutoSlur()) and "DOWN" or "UP"
228+
slur.ShapeType = finale["SMARTSHAPE_" .. a .. b]
229+
elseif state:find("ENGRAV") then slur.EngraverSlur = ss_3state[ss_state]
230+
elseif state:find("AVACCI") then slur.AvoidAccidentals = ss_3state[ss_state]
231+
else slur.ShapeType = finale[state]
245232
end
233+
slur:Save()
246234
end
247235
end
248236
finenv.EndUndoBlock(true)
@@ -260,7 +248,7 @@ local function run_the_dialog()
260248
local key_list = dialog:CreateListBox(0, 22):SetWidth(box_wide):SetHeight(box_high)
261249
-- local functions
262250
local function show_info()
263-
utils.show_notes_dialog(dialog, "About " .. name, 400, 140)
251+
utils.show_notes_dialog(dialog, "About " .. name, 400, 125)
264252
end
265253
local function fill_key_list()
266254
local join = finenv.UI():IsOnMac() and "\t" or ": "
@@ -276,18 +264,10 @@ local function run_the_dialog()
276264
ok, is_duplicate = reassign_keystrokes(dialog, key_list:GetSelectedItem() + 1)
277265
end
278266
if ok then fill_key_list()
279-
else configuration.get_user_settings(script_name, config) -- reinstall hotkeys
267+
else configuration.get_user_settings(script_name, config) -- reinstall saved hotkeys
280268
end
281269
key_list:SetKeyboardFocus()
282270
end
283-
local function on_timer() -- track changes in selected region
284-
for k, v in pairs(saved_bounds) do
285-
if finenv.Region()[k] ~= v then -- selection changed
286-
track_selection() -- update selection tracker
287-
break -- all done
288-
end
289-
end
290-
end
291271

292272
fill_key_list()
293273
dialog:CreateButton(box_wide - 20, 0, "q"):SetText("?"):SetWidth(20)
@@ -305,11 +285,11 @@ local function run_the_dialog()
305285
:AddHandleCommand(function(self)
306286
local s = self:GetText():lower()
307287
if s:find("[^0-" .. max .. "]") then
308-
if s:find("[?q]") then show_info()
288+
if s:find("[?q]") then show_info()
309289
elseif s:find("r") then change_keys()
310290
end
311291
else
312-
save_layer = (s == "") and 0 or tonumber(s)
292+
save_layer = (s ~= "") and tonumber(s) or 0
313293
end
314294
self:SetInteger(save_layer):SetKeyboardFocus()
315295
end)
@@ -318,32 +298,30 @@ local function run_the_dialog()
318298
dialog:CreateOkButton():SetText("Apply")
319299
dialog:CreateCancelButton():SetText("Close")
320300
dialog_set_position(dialog)
321-
dialog:RegisterHandleTimer(on_timer)
322-
dialog:RegisterInitWindow(function(self)
323-
self:SetTimer(config.timer_id, 125)
301+
dialog:RegisterInitWindow(function()
324302
key_list:SetKeyboardFocus()
325303
local q = dialog:GetControl("q")
326304
q:SetFont(q:CreateFontInfo():SetBold(true))
327305
end)
328306
dialog:RegisterHandleOkButtonPressed(function()
329307
config.last_selected = key_list:GetSelectedItem() -- save list choice (0-based)
330308
config.layer = layer:GetInteger()
331-
change_the_slurs(dialog)
332-
end)
333-
dialog:RegisterCloseWindow(function(self)
334-
self:StopTimer(config.timer_id)
335-
dialog_save_position(self)
309+
change_the_slurs()
336310
end)
311+
dialog:RegisterCloseWindow(function(self) dialog_save_position(self) end)
337312
dialog:RunModeless()
338313
end
339314

340315
local function change_slurs()
316+
if finenv.Region():IsEmpty() then
317+
finenv.UI():AlertError("Please select some music\nbefore running this script", name)
318+
return
319+
end
341320
configuration.get_user_settings(script_name, config, true)
342321
local qim = finenv.QueryInvokedModifierKeys
343322
local mod_key = qim and (qim(finale.CMDMODKEY_ALT) or qim(finale.CMDMODKEY_SHIFT))
344323

345-
track_selection() -- track current selected region
346-
if mod_key then change_the_slurs(nil)
324+
if mod_key then change_the_slurs()
347325
else run_the_dialog()
348326
end
349327
end

0 commit comments

Comments
 (0)