@@ -4,8 +4,8 @@ function plugindef()
44 finaleplugin .Author = " Carl Vine"
55 finaleplugin .AuthorURL = " https://carlvine.com/lua/"
66 finaleplugin .Copyright = " CC0 https://creativecommons.org/publicdomain/zero/1.0/"
7- finaleplugin .Version = " 0.16 "
8- finaleplugin .Date = " 2024/05/03 "
7+ finaleplugin .Version = " 0.18 "
8+ finaleplugin .Date = " 2024/07/29 "
99 finaleplugin .MinJWLuaVersion = 0.72
1010 finaleplugin .CategoryTags = " Pitch, Transposition"
1111 finaleplugin .ScriptGroupName = " Transpose Diatonic"
@@ -16,15 +16,13 @@ function plugindef()
1616 To repeat the last action without a confirmation dialog
1717 hold down [Shift] when starting the script.
1818
19- Select __Modeless__ if you prefer the dialog window to
20- "float" above your score and you can change the score selection
21- while the script remains active. In this mode click __Apply__
22- [Return] to transpose and __Cancel__ [Escape] to close the window.
19+ Select __Modeless Dialog__ if you want the dialog window to persist
20+ on-screen for repeated use until you click __Close__ [_Escape_].
2321 Cancelling __Modeless__ will apply the _next_
2422 time you use the script.
2523
2624 > These key commands are available
27- > if a "numeric" field is highlighted:
25+ > if a _numeric_ field is highlighted:
2826
2927 > - __1-8__: interval (unison, 2nd, 3rd, .. 8ve)
3028 > - __0-8__: extra octave
@@ -33,7 +31,7 @@ function plugindef()
3331 > - __q__: show this script information
3432 > - __z__: toggle _Up/Down_
3533 > - __x__: toggle _Preserve Existing Notes_
36- > - __c__ : toggle _Modeless_
34+ > - __m__ : toggle _Modeless_
3735 ]]
3836 return " Transpose Diatonic..." , " Transpose Diatonic" ,
3937 " Transpose notes and chords up or down by the chosen diatonic interval"
@@ -49,10 +47,7 @@ local refocus_document = false
4947local selection
5048local interval_names = { " unis." , " 2nd" , " 3rd" , " 4th" , " 5th" , " 6th" , " 7th" , " 8ve" }
5149local saved_bounds = {}
52- local bounds = { -- selection boundaries
53- " StartStaff" , " StartMeasure" , " StartMeasurePos" ,
54- " EndStaff" , " EndMeasure" , " EndMeasurePos" ,
55- }
50+
5651local config = { -- over-written by saved user data
5752 interval = 1 , -- 1 = unison; 2 = second etc.
5853 octave = 0 ,
@@ -71,13 +66,13 @@ local numerics = { -- edit boxes: key / text
7166}
7267local checks = { -- checkboxes: key / text
7368 { " do_preserve" , " Preserve Existing Notes" },
74- { " modeless" , " \" Modeless\" Dialog" }
69+ { " modeless" , " Modeless Dialog" }
7570}
7671local hotkey = { -- customise hotkeys
7772 show_info = " q" ,
7873 direction = " z" ,
7974 do_preserve = " x" ,
80- modeless = " c " ,
75+ modeless = " m " ,
8176}
8277
8378local function dialog_set_position (dialog )
@@ -107,10 +102,12 @@ end
107102
108103local function update_selection ()
109104 local rgn = finenv .Region ()
110- if rgn :IsEmpty () then
111- saved_bounds = {0 , 0 , 0 , 0 , 0 , 0 }
112- selection = " no staff, no selection" -- default
113- else
105+ selection = " no staff, no selection" -- empty default
106+ if not rgn :IsEmpty () then
107+ local bounds = { -- selection boundaries
108+ " StartStaff" , " StartMeasure" , " StartMeasurePos" ,
109+ " EndStaff" , " EndMeasure" , " EndMeasurePos" ,
110+ }
114111 for _ , prop in ipairs (bounds ) do
115112 saved_bounds [prop ] = rgn [prop ]
116113 end
@@ -125,14 +122,26 @@ local function update_selection()
125122 end
126123end
127124
128- local function transpose_diatonic ()
125+ local function nil_region_error (dialog )
126+ if finenv .Region ():IsEmpty () then
127+ local ui = dialog and dialog :CreateChildUI () or finenv .UI ()
128+ ui :AlertError (
129+ " Please select some music\n before running this script." ,
130+ finaleplugin .ScriptGroupName
131+ )
132+ return true
133+ end
134+ return false
135+ end
136+
137+ local function transpose_diatonic (dialog )
138+ if nil_region_error (dialog ) then return end -- empty -> do nothing
129139 local direction = (config .direction * - 2 ) + 1
130140 local shift = ((config .octave * 7 ) + config .interval - 1 ) * direction
131141 if shift ~= 0 then
132142 finenv .StartNewUndoBlock (
133- string.format (" Transp. Diat. %s %s %s oct%d" ,
134- selection , (config .direction == 1 and " Dn" or " Up" ),
135- interval_names [config .interval ], config .octave ),
143+ string.format (" Transp. Diat. %s %s" ,
144+ (config .direction == 0 and " Up" or " Dn" ), selection ),
136145 false
137146 )
138147 for entry in eachentrysaved (finenv .Region (), config .layer ) do
@@ -153,10 +162,10 @@ local function run_the_dialog()
153162 local dialog = mixin .FCXCustomLuaWindow ():SetTitle (" Transpose" )
154163 -- local functions
155164 local function show_info ()
156- utils .show_notes_dialog (dialog , " About " .. finaleplugin .ScriptGroupName , 400 , 345 )
165+ utils .show_notes_dialog (dialog , " About " .. finaleplugin .ScriptGroupName , 400 , 320 )
157166 refocus_document = true
158167 end
159- local function dy (diff ) y = diff and ( y + diff ) or ( y + y_inc ) end
168+ local function dy (diff ) y = y + ( diff or y_inc ) end
160169 local function cs (cx , cy , ctext , cwide )
161170 local stat = dialog :CreateStatic (cx , cy ):SetText (ctext )
162171 local _ = cwide and stat :SetWidth (cwide ) or stat :DoAutoResizeWidth ()
@@ -166,27 +175,27 @@ local function run_the_dialog()
166175 answer [id ]:SetCheck ((answer [id ]:GetCheck () + 1 ) % 2 )
167176 end
168177 local function key_command (id ) -- key command replacements
169- local ctl = answer [id ]
170- local val = ctl :GetText ():lower ()
171- if val :find (" [^0-8]" )
172- or (id == " layer" and val :find (" [^0-" .. max .. " ]" ))
173- or (id == " interval" and val :find (" 0" ))
178+ local s = answer [id ]:GetText ():lower ()
179+ if s :find (" [^0-8]" )
180+ or (id == " layer" and s :find (" [^0-" .. max .. " ]" ))
181+ or (id == " interval" and s :find (" 0" ))
174182 then
175- if val :find (hotkey .direction ) then -- flip direction
183+ if s :find (hotkey .direction ) then -- flip direction
176184 local n = answer .direction :GetSelectedItem ()
177185 answer .direction :SetSelectedItem ((n + 1 ) % 2 )
178- elseif val :find (hotkey .modeless ) then toggle_check (" modeless" )
179- elseif val :find (hotkey .do_preserve ) then toggle_check (" do_preserve" )
180- elseif val :find (hotkey .show_info ) then show_info ()
186+ elseif s :find (hotkey .modeless ) then toggle_check (" modeless" )
187+ elseif s :find (hotkey .do_preserve ) then toggle_check (" do_preserve" )
188+ elseif s :find (hotkey .show_info ) then show_info ()
181189 end
182- elseif val ~= " " then
183- save [id ] = val :sub (- 1 )
190+ else
191+ save [id ] = s :sub (- 1 )
192+ if save [id ] == " " then save [id ] = " 0" end
184193 if id == " interval" then
185- local n = tonumber ( save [id ]) or 1
186- answer .msg :SetText (interval_names [n ])
194+ if save [ id ] == " 0 " then save [id ] = " 1 " end
195+ answer .msg :SetText (interval_names [tonumber ( save [ id ]) ])
187196 end
188197 end
189- ctl :SetText (save [id ]):SetKeyboardFocus ()
198+ answer [ id ] :SetText (save [id ]):SetKeyboardFocus ()
190199 end
191200 local function on_timer () -- look for changes in selected region
192201 for k , v in pairs (saved_bounds ) do
@@ -220,13 +229,11 @@ local function run_the_dialog()
220229 answer .q = dialog :CreateButton (x_step + 43 , y - y_inc - 1 ):SetText (" ?" ):SetWidth (20 )
221230 :AddHandleCommand (function () show_info () end )
222231 answer .info = cs (0 , y , selection , x_step + 40 )
223-
224- dialog :CreateOkButton ():SetText (config .modeless and " Apply" or " OK" )
225- dialog :CreateCancelButton ()
232+ dialog :CreateOkButton () :SetText (config .modeless and " Apply" or " OK" )
233+ dialog :CreateCancelButton ():SetText (config .modeless and " Close" or " Cancel" )
226234 dialog_set_position (dialog )
227235 if config .modeless then dialog :RegisterHandleTimer (on_timer ) end
228236 dialog :RegisterInitWindow (function (self )
229- dialog :SetOkButtonCanClose (not config .modeless )
230237 if config .modeless then self :SetTimer (config .timer_id , 125 ) end
231238 local bold = answer .a :CreateFontInfo ():SetBold (true )
232239 for _ , v in ipairs {" a" , " q" , " msg" } do
@@ -241,7 +248,7 @@ local function run_the_dialog()
241248 end
242249 config .direction = answer .direction :GetSelectedItem ()
243250 config .do_preserve = (answer .do_preserve :GetCheck () == 1 )
244- transpose_diatonic ()
251+ transpose_diatonic (dialog )
245252 end )
246253 dialog :RegisterCloseWindow (function (self )
247254 if config .modeless then self :StopTimer (config .timer_id ) end
261268
262269function do_diatonic ()
263270 configuration .get_user_settings (script_name , config , true )
264- if not config .modeless and finenv .Region ():IsEmpty () then
265- finenv .UI ():AlertError (
266- " Please select some music\n before running this script." ,
267- finaleplugin .ScriptGroupName
268- )
269- return
270- end
271+ if not config .modeless and nil_region_error () then return end
272+
271273 local qim = finenv .QueryInvokedModifierKeys
272274 local mod_key = qim and (qim (finale .CMDMODKEY_ALT ) or qim (finale .CMDMODKEY_SHIFT ))
273275
0 commit comments