@@ -4843,8 +4843,8 @@ function plugindef()
4843
4843
finaleplugin .Author = " Carl Vine"
4844
4844
finaleplugin .AuthorURL = " https://carlvine.com/lua/"
4845
4845
finaleplugin .Copyright = " CC0 https://creativecommons.org/publicdomain/zero/1.0/"
4846
- finaleplugin .Version = " 0.53 "
4847
- finaleplugin .Date = " 2023/12/11 "
4846
+ finaleplugin .Version = " 0.57 "
4847
+ finaleplugin .Date = " 2024/01/25 "
4848
4848
finaleplugin .CategoryTags = " Measures, Region, Selection"
4849
4849
finaleplugin .MinJWLuaVersion = 0.67
4850
4850
finaleplugin .Notes = [[
@@ -4854,7 +4854,7 @@ function plugindef()
4854
4854
slider controls to change the beat and EDU position in each measure,
4855
4855
continuously updating the score highlighting as the selection changes.
4856
4856
Note that when one slider overlaps the other in the same
4857
- measure, it will be pushed out of the way to create a "null"
4857
+ measure, it will push the other out of the way creating a "null"
4858
4858
selection (start = end). This doesn't break anything
4859
4859
but the selection contains no notes.
4860
4860
== Beat Boundaries ==
@@ -4866,10 +4866,18 @@ function plugindef()
4866
4866
relative to the beat, as happens when entering beat numbers
4867
4867
on the inbuilt "Select Region" option.
4868
4868
== Key Commands ==
4869
- - START point: [w][s][a][d] (up-down-left-right) increments [e][r]
4870
- - END point: [f][v][c][b] (up-down-left-right) increments [g][h]
4871
- - [z] toggle the "follow selection" checkbox.
4872
- - [q] show these script notes
4869
+ - (w)(s) @tStart Staff up/down
4870
+ - (d)(f) @tStart Measure left/right
4871
+ - (g)(h) @tStart increments -/+
4872
+ - (j)(k) / (-)(+) @tStart -/+ one EDU
4873
+ - • •
4874
+ - (a)(z) @tEnd Staff up/down
4875
+ - (x)(c) @tEnd Measure left/right
4876
+ - (v)(b) @tEnd increments -/+
4877
+ - (n)(m) / ([)(]) @tEnd -/+ one EDU
4878
+ - • •
4879
+ - (e) toggle the "follow selection" checkbox
4880
+ - (q) show these script notes
4873
4881
]]
4874
4882
finaleplugin .HashURL = " https://raw.githubusercontent.com/finale-lua/lua-scripts/master/hash/selection_refiner.hash"
4875
4883
return " Selection Refiner..." , " Selection Refiner" , " Refine the selected music area with visual feedback"
@@ -4882,7 +4890,7 @@ slider controls to change the beat and EDU position in each measure,
4882
4890
continuously updating the score highlighting as the selection changes.
4883
4891
**
4884
4892
Note that when one slider overlaps the other in the same
4885
- measure, it will be pushed out of the way to create a "null"
4893
+ measure, it will push the other out of the way creating a "null"
4886
4894
selection (start = end). This doesn't break anything
4887
4895
but the selection contains no notes.
4888
4896
**
@@ -4897,21 +4905,30 @@ relative to the beat, as happens when entering beat numbers
4897
4905
on the inbuilt "Select Region" option.
4898
4906
**
4899
4907
== Key Commands ==
4900
- *• (w)(s)(a)(d) @tSTART (up-down-left-right)
4901
- *• (e/r) @t@tSTART increments
4902
- *• (+/-) (t/y) @tSTART +/- one EDU
4903
- *• (f)(v)(c)(b) @tEND (up-down-left-right)
4904
- *• (g/h) @t@tEND increments
4905
- *• ( [/] ) (j/k) @tEND +/- one EDU
4906
- *• (z) toggle the "follow selection" checkbox
4908
+ *• (w)(s) @tStart Staff up/down
4909
+ *• (d)(f) @tStart Measure left/right
4910
+ *• (g)(h) @tStart increments -/+
4911
+ *• (j)(k) / (-)(+) @tStart -/+ one EDU
4912
+ *• • •
4913
+ *• (a)(z) @tEnd Staff up/down
4914
+ *• (x)(c) @tEnd Measure left/right
4915
+ *• (v)(b) @tEnd increments -/+
4916
+ *• (m)(n) / ([)(]) @tEnd -/+ one EDU
4917
+ *• • •
4918
+ *• (e) toggle the "follow selection" checkbox
4907
4919
*• (q) show these script notes
4908
4920
]]
4909
4921
info_notes = info_notes :gsub (" \n %s*" , " " ):gsub (" *" , " \n " ):gsub (" @t" , " \t " )
4910
- local config = { window_pos_x = false , window_pos_y = false , follow_measure = 1 }
4922
+ .. " \n (v" .. finaleplugin .Version .. " )"
4923
+ local config = {
4924
+ follow_measure = 0 ,
4925
+ window_pos_x = false ,
4926
+ window_pos_y = false
4927
+ }
4911
4928
local mixin = require (" library.mixin" )
4912
4929
local library = require (" library.general_library" )
4913
4930
local configuration = require (" library.configuration" )
4914
- local script_name = " selection_refiner "
4931
+ local script_name = library . calc_script_name ()
4915
4932
local function dialog_set_position (dialog )
4916
4933
if config .window_pos_x and config .window_pos_y then
4917
4934
dialog :StorePosition ()
@@ -4925,21 +4942,27 @@ local function dialog_save_position(dialog)
4925
4942
config .window_pos_y = dialog .StoredY
4926
4943
configuration .save_user_settings (script_name , config )
4927
4944
end
4928
- local function power_of_2 (duration )
4929
- local test_rest = finale .NOTE_128TH / 2
4945
+ local function power_of_two (duration )
4946
+ local smallest = finale .NOTE_128TH / 2
4930
4947
local power = 1
4931
- while test_rest < duration and power < 10 do
4932
- test_rest = test_rest * 2
4948
+ while smallest < duration and power < 10 do
4949
+ smallest = smallest * 2
4933
4950
power = power + 1
4934
4951
end
4935
4952
return power
4936
4953
end
4937
4954
local function score_limits (rgn )
4955
+ local staff = finale .FCStaff ()
4956
+ local staff_list = {}
4938
4957
local stack = mixin .FCMMusicRegion ()
4939
- stack :SetRegion (rgn ):SetFullMeasureStack ()
4958
+ stack :SetRegion (rgn ):SetFullDocument ()
4959
+ for staff_number in eachstaff (stack ) do
4960
+ staff :Load (staff_number )
4961
+
4962
+ table.insert (staff_list , staff :CreateDisplayFullNameString ())
4963
+ end
4940
4964
local max_slot = stack .EndSlot
4941
- stack :SetFullDocument ()
4942
- return stack .EndMeasure , max_slot
4965
+ return stack .EndMeasure , max_slot , staff_list
4943
4966
end
4944
4967
local function compile_rest_strings (power )
4945
4968
power = math.min (math.max (power , 1 ), 10 )
@@ -5000,7 +5023,7 @@ local function get_measure_details(region, is_start_sector)
5000
5023
md .mark = md .beatdur / 2
5001
5024
md .steps = 8
5002
5025
end
5003
- local power = power_of_2 (md .mark * 2 )
5026
+ local power = power_of_two (md .mark * 2 )
5004
5027
md .div_dur = md .beatdur / md .steps
5005
5028
md .divisions = md .beats * md .steps
5006
5029
if md .composite then
@@ -5017,12 +5040,6 @@ local function get_measure_details(region, is_start_sector)
5017
5040
md .rests = compile_rest_strings (power )
5018
5041
return md
5019
5042
end
5020
- local function get_staff_name (region , slot )
5021
- local staff_number = region :CalcStaffNumber (slot )
5022
- local staff = finale .FCStaff ()
5023
- staff :Load (staff_number )
5024
- return staff :CreateDisplayFullNameString ()
5025
- end
5026
5043
local function convert_edu_to_rest_string (index , md , backwards )
5027
5044
if backwards then index = md .divisions - index end
5028
5045
local beat = md .rests .beat
@@ -5054,17 +5071,18 @@ end
5054
5071
local function user_chooses (rgn )
5055
5072
local y , rest_wide , x_wide = 40 , 130 , 236
5056
5073
local x_offset = finenv .UI ():IsOnMac () and 0 or 3
5074
+ local name = plugindef ():gsub (" %.%.%." , " " )
5057
5075
local function yd (diff )
5058
5076
y = diff and y + diff or y + 16
5059
5077
end
5060
5078
local function show_info ()
5061
- finenv .UI ():AlertInfo (info_notes , " About " .. plugindef () )
5079
+ finenv .UI ():AlertInfo (info_notes , " About " .. name )
5062
5080
end
5063
5081
5064
5082
local measure , sliders , offset , save_off = {}, {}, {}, {}
5065
- local rest , buttons , index , staff , actions = {}, {}, {}, {}, {}
5083
+ local rest , buttons , index , staff_sel , actions = {}, {}, {}, {}, {}
5066
5084
local follow
5067
- local max_measure , max_slot = score_limits (rgn )
5085
+ local max_measure , max_slot , staff_list = score_limits (rgn )
5068
5086
5069
5087
local md = { get_measure_details (rgn , true ), get_measure_details (rgn , false ) }
5070
5088
local function pos_to_index (side )
@@ -5073,7 +5091,7 @@ local function user_chooses(rgn)
5073
5091
index [1 ] = pos_to_index (1 )
5074
5092
index [2 ] = pos_to_index (2 )
5075
5093
5076
- local dialog = mixin .FCXCustomLuaWindow ():SetTitle (plugindef () )
5094
+ local dialog = mixin .FCXCustomLuaWindow ():SetTitle (name )
5077
5095
5078
5096
local function set_measure_pos (side )
5079
5097
if side == 1 then rgn .StartMeasurePos = md [side ].pos
@@ -5126,15 +5144,6 @@ local function user_chooses(rgn)
5126
5144
rgn :SetInDocument ()
5127
5145
rgn :Redraw ()
5128
5146
end
5129
- local function staff_button_visibility ()
5130
- for side = 1 , 2 do
5131
- buttons [side ].up :SetEnable (md [side ].slot > 1 )
5132
- buttons [side ].down :SetEnable (md [side ].slot < max_slot )
5133
- staff [side ]:SetText (get_staff_name (rgn , md [side ].slot ))
5134
- end
5135
- rgn :SetInDocument ()
5136
- rgn :Redraw ()
5137
- end
5138
5147
local function position_increment (side , add )
5139
5148
if (add > 0 and md [side ].pos < md [side ].dur )
5140
5149
or (add < 0 and md [side ].pos > 0 ) then
@@ -5147,36 +5156,36 @@ local function user_chooses(rgn)
5147
5156
end
5148
5157
5149
5158
actions = {
5150
- up = function (a_side )
5151
- if md [a_side ].slot > 1 then
5152
- md [a_side ].slot = md [a_side ].slot - 1
5153
- if a_side == 1 then
5154
- rgn .StartSlot = md [1 ].slot
5155
- else
5156
- rgn .EndSlot = md [2 ].slot
5157
- if md [1 ].slot > md [2 ].slot then
5158
- md [1 ].slot = md [2 ].slot
5159
- rgn .StartSlot = md [2 ].slot
5160
- end
5159
+ staff = function (a_side )
5160
+ local new_slot = staff_sel [a_side ]:GetSelectedItem () + 1
5161
+ if new_slot == md [a_side ].slot then return end
5162
+ if a_side == 1 then
5163
+ rgn .StartSlot = new_slot
5164
+ if new_slot > (staff_sel [2 ]:GetSelectedItem () + 1 ) then
5165
+ staff_sel [2 ]:SetSelectedItem (new_slot - 1 )
5166
+ md [2 ].slot = new_slot
5167
+ rgn .EndSlot = new_slot
5168
+ end
5169
+ else
5170
+ rgn .EndSlot = new_slot
5171
+ if new_slot < (staff_sel [1 ]:GetSelectedItem () + 1 ) then
5172
+ staff_sel [1 ]:SetSelectedItem (new_slot - 1 )
5173
+ md [1 ].slot = new_slot
5174
+ rgn .StartSlot = new_slot
5161
5175
end
5162
- staff_button_visibility ()
5163
5176
end
5177
+ staff_sel [a_side ]:SetSelectedItem (new_slot - 1 )
5178
+ md [a_side ].slot = new_slot
5179
+ rgn :SetInDocument ()
5180
+ rgn :Redraw ()
5164
5181
end ,
5165
5182
5166
- down = function (a_side )
5167
- if md [a_side ].slot < max_slot then
5168
- md [a_side ].slot = md [a_side ].slot + 1
5169
- if a_side == 1 then
5170
- rgn .StartSlot = md [1 ].slot
5171
- if md [2 ].slot < md [1 ].slot then
5172
- md [2 ].slot = md [1 ].slot
5173
- rgn .EndSlot = md [1 ].slot
5174
- end
5175
- else
5176
- rgn .EndSlot = md [2 ].slot
5177
- end
5178
- staff_button_visibility ()
5183
+ change_staff = function (a_side , diff )
5184
+ local slot = staff_sel [a_side ]:GetSelectedItem () + 1
5185
+ if (slot > 1 and diff < 0 ) or (slot < max_slot and diff > 0 ) then
5186
+ staff_sel [a_side ]:SetSelectedItem (slot + diff - 1 )
5179
5187
end
5188
+ actions .staff (a_side )
5180
5189
end ,
5181
5190
5182
5191
left = function (a_side )
@@ -5261,23 +5270,23 @@ local function user_chooses(rgn)
5261
5270
local s = offset [i ]:GetText ():lower ()
5262
5271
if s :find (" [^0-9]" ) then
5263
5272
if s :find (" [?q]" ) then show_info ()
5264
- elseif s :find (" w" ) then actions .up ( 1 )
5265
- elseif s :find (" s" ) then actions .down ( 1 )
5266
- elseif s :find (" a " ) then actions .left (1 )
5267
- elseif s :find (" d " ) then actions .right (1 )
5268
- elseif s :find (" e " ) then actions .thumb (1 , - 1 )
5269
- elseif s :find (" r " ) then actions .thumb (1 , 1 )
5270
- elseif s :find (" f " ) then actions .up ( 2 )
5271
- elseif s :find (" v " ) then actions .down ( 2 )
5272
- elseif s :find (" c " ) then actions .left (2 )
5273
- elseif s :find (" b " ) then actions .right (2 )
5274
- elseif s :find (" g " ) then actions .thumb (2 , - 1 )
5275
- elseif s :find (" h " ) then actions .thumb (2 , 1 )
5276
- elseif s :find (" [-_t ]" ) then position_increment (1 , - 1 )
5277
- elseif s :find (" [+=y ]" ) then position_increment (1 , 1 )
5278
- elseif s :find (" [%[j ]" ) then position_increment (2 , - 1 )
5279
- elseif s :find (" [%]k ]" ) then position_increment (2 , 1 )
5280
- elseif s :find (" z " ) then
5273
+ elseif s :find (" w" ) then actions .change_staff ( 1 , - 1 )
5274
+ elseif s :find (" s" ) then actions .change_staff ( 1 , 1 )
5275
+ elseif s :find (" d " ) then actions .left (1 )
5276
+ elseif s :find (" f " ) then actions .right (1 )
5277
+ elseif s :find (" g " ) then actions .thumb (1 , - 1 )
5278
+ elseif s :find (" h " ) then actions .thumb (1 , 1 )
5279
+ elseif s :find (" a " ) then actions .change_staff ( 2 , - 1 )
5280
+ elseif s :find (" z " ) then actions .change_staff ( 2 , 1 )
5281
+ elseif s :find (" x " ) then actions .left (2 )
5282
+ elseif s :find (" c " ) then actions .right (2 )
5283
+ elseif s :find (" b " ) then actions .thumb (2 , 1 )
5284
+ elseif s :find (" v " ) then actions .thumb (2 , - 1 )
5285
+ elseif s :find (" [-_j ]" ) then position_increment (1 , - 1 )
5286
+ elseif s :find (" [+=k ]" ) then position_increment (1 , 1 )
5287
+ elseif s :find (" [%[n ]" ) then position_increment (2 , - 1 )
5288
+ elseif s :find (" [%]m ]" ) then position_increment (2 , 1 )
5289
+ elseif s :find (" e " ) then
5281
5290
follow :SetCheck ((follow :GetCheck () + 1 ) % 2 )
5282
5291
end
5283
5292
offset [i ]:SetText (save_off [i ])
@@ -5297,17 +5306,12 @@ local function user_chooses(rgn)
5297
5306
}
5298
5307
local default_font = finale .FCFontInfo ()
5299
5308
default_font :LoadFontPrefs (finale .FONTPREF_MUSIC )
5300
- local button_x = (x_wide + rest_wide + 14 ) / 4
5301
- local bx12 = button_x + 12
5309
+ local button_x = (x_wide + rest_wide + 14 ) / 5
5302
5310
local function make_rest_text (i , y_off )
5303
5311
rest [i ] = dialog :CreateStatic (x_wide + 65 , y_off + md [i ].rests .vert )
5304
5312
:SetWidth (rest_wide ):SetHeight (80 ):SetFont (default_font )
5305
5313
:SetText (convert_edu_to_rest_string (index [i ], md [i ], false ))
5306
5314
end
5307
- local function make_staff_name (i )
5308
- staff [i ] = dialog :CreateStatic (bx12 + 25 , y ):SetWidth (rest_wide )
5309
- :SetText (get_staff_name (rgn , md [i ].slot ))
5310
- end
5311
5315
local function make_slider_and_offset (i )
5312
5316
sliders [i ] = dialog :CreateSlider (0 , y ):SetMinValue (0 )
5313
5317
:SetWidth (x_wide ):SetMaxValue (md [i ].divisions )
@@ -5317,45 +5321,56 @@ local function user_chooses(rgn)
5317
5321
:AddHandleCommand (function () actions .offset (i ) end ):SetWidth (50 )
5318
5322
end
5319
5323
local function make_buttons (i )
5324
+
5325
+ staff_sel [i ] = dialog :CreatePopup (0 , y )
5326
+ :AddStrings (table.unpack (staff_list )):SetWidth (button_x * 2 )
5327
+ :SetSelectedItem (md [i ].slot - 1 )
5328
+ :AddHandleCommand (function () actions .staff (i ) end )
5329
+
5320
5330
buttons [i ] = {}
5321
- for k , v in pairs ({
5322
- up = { bx12 , y , " Staff ↑" }, down = { bx12 , y + 20 , " Staff ↓" },
5323
- left = { 0 , y + 10 , " ← Measure" }, right = { bx12 * 2 , y + 10 , " Measure →" }
5324
- }) do
5325
- buttons [i ][k ] = dialog :CreateButton (v [1 ], v [2 ]):SetWidth (button_x )
5326
- :AddHandleCommand (function () actions [k ](i ) end ):SetText (v [3 ])
5327
- end
5328
- measure [i ] = dialog :CreateStatic (bx12 * 3 , y + 10 ):SetWidth (60 )
5331
+ for k , v in pairs {
5332
+ left = { button_x * 2 + 5 , " ← Measure" }, right = { button_x * 3 + 5 , " Measure →" }
5333
+ } do
5334
+ buttons [i ][k ] = dialog :CreateButton (v [1 ], y ):SetWidth (button_x - 5 )
5335
+ :AddHandleCommand (function () actions [k ](i ) end ):SetText (v [2 ])
5336
+ end
5337
+ measure [i ] = dialog :CreateStatic (button_x * 4 + 5 , y ):SetWidth (button_x - 5 )
5329
5338
:SetText (" m. " .. md [2 ].measure )
5330
5339
end
5331
5340
5332
5341
make_rest_text (1 , 0 )
5333
- make_rest_text (2 , 83 )
5334
- dialog : CreateStatic ( 0 , y ): SetText ( " START of Selection: " ): SetWidth ( x_wide )
5335
- make_staff_name ( 1 )
5336
- dialog :CreateButton (x_wide + rest_wide + 30 , y ):SetText (" ?" ):SetWidth (20 )
5342
+ make_rest_text (2 , 78 )
5343
+
5344
+ dialog : CreateStatic ( 0 , y , " head_1 " ): SetText ( " START of Selection: " ): SetWidth ( x_wide )
5345
+ dialog :CreateButton (x_wide + rest_wide + 30 , y , " q " ):SetText (" ?" ):SetWidth (20 )
5337
5346
:AddHandleCommand (function () show_info () end )
5338
5347
yd (14 )
5339
5348
make_slider_and_offset (1 )
5340
- yd (22 )
5349
+ yd (30 )
5341
5350
make_buttons (1 )
5342
- yd (42 )
5343
- dialog :CreateHorizontalLine (0 , y , button_x * 4 )
5351
+ yd (30 )
5352
+ dialog :CreateHorizontalLine (0 , y , button_x * 5 )
5344
5353
yd (5 )
5345
5354
5346
- dialog :CreateStatic (0 , y ):SetText (" END of Selection:" ):SetWidth (x_wide )
5347
- make_staff_name (2 )
5355
+ dialog :CreateStatic (0 , y , " head_2" ):SetText (" END of Selection:" ):SetWidth (x_wide )
5348
5356
yd (14 )
5349
5357
make_slider_and_offset (2 )
5350
- yd (22 )
5358
+ yd (30 )
5351
5359
make_buttons (2 )
5352
- yd (42 )
5360
+ yd (30 )
5353
5361
follow = dialog :CreateCheckbox (0 , y , " follow_measure" ):SetWidth (x_wide )
5354
5362
:SetText (" Follow selection to off-screen measures" ):SetCheck (config .follow_measure )
5355
5363
dialog :CreateOkButton ()
5356
5364
dialog :CreateCancelButton ()
5357
5365
dialog_set_position (dialog )
5358
5366
dialog :RegisterHandleOkButtonPressed (function () config .follow_measure = follow :GetCheck () end )
5367
+ dialog :RegisterInitWindow (function (self )
5368
+ local h = self :GetControl (" head_1" )
5369
+ local bold = h :CreateFontInfo ():SetBold (true )
5370
+ h :SetFont (bold )
5371
+ self :GetControl (" head_2" ):SetFont (bold )
5372
+ self :GetControl (" q" ):SetFont (bold )
5373
+ end )
5359
5374
dialog :RegisterCloseWindow (function (self ) dialog_save_position (self ) end )
5360
5375
return (dialog :ExecuteModal (nil ) == finale .EXECMODAL_OK )
5361
5376
end
0 commit comments