From 9b4a5a1e5a5fdd942b8a76d2aecf7660eb26e93b Mon Sep 17 00:00:00 2001 From: cv-on-hub <105578039+cv-on-hub@users.noreply.github.com> Date: Sun, 17 Jul 2022 10:08:22 +1000 Subject: [PATCH 1/4] Create hairpin_creator_configuration.lua A companion program for direct configuration of user_settings for hairpin_creator --- src/hairpin_creator_configuration.lua | 136 ++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 src/hairpin_creator_configuration.lua diff --git a/src/hairpin_creator_configuration.lua b/src/hairpin_creator_configuration.lua new file mode 100644 index 00000000..17c4521b --- /dev/null +++ b/src/hairpin_creator_configuration.lua @@ -0,0 +1,136 @@ +function plugindef() + finaleplugin.RequireSelection = true + finaleplugin.Author = "Carl Vine after CJ Garcia" + finaleplugin.AuthorURL = "http://carlvine.com/lua" + finaleplugin.Copyright = "CC0 https://creativecommons.org/publicdomain/zero/1.0/" + finaleplugin.Version = "v0.52" + finaleplugin.Date = "2022/07/17" + finaleplugin.Notes = [[ + This is a companion script for `hairpin_creator.lua`, listed in the + `finalelua.com` repository by its primary menu name, "Hairpin create crescendo". + + If you use a macro program like KeyboardMaestro (MacOS) to trigger menu items in Finale, + using the `alt` or `option` key in `hairpin_creator.lua` won't allow access to its configuration. + If so, use this script to change the configuration file directly. + The result will affect the behaviour of all four of hairpin_creator's actions: + + ``` + Crescendo | Diminuendo | Swell | Unswell + ``` + ]] + return "Hairpin creator configuration", "Hairpin creator configuration", "Configuration utitlity for the hairpin_creator.lua script" +end + +-- global variables for modeless operation +global_dialog = nil +global_dialog_options = { -- key value in config, explanation, dialog control holder + { "dynamics_match_hairpin", "move dynamics vertically to match hairpin height", nil}, + { "include_trailing_items", "consider notes and dynamics past the end of selection", nil}, + { "attach_over_end_barline", "attach right end of hairpin across the final barline", nil}, + { "attach_over_system_break", "attach across final barline even over a system break", nil}, + { "inclusions_EDU_margin", "(EDUs) the marginal duration for included trailing items", nil}, + { "shape_vert_adjust", "(EVPUs) vertical adjustment for hairpin to match dynamics", nil}, + { "below_note_cushion", "(EVPUs) extra gap below notes", nil}, + { "downstem_cushion", "(EVPUs) extra gap below down-stems", nil}, + { "below_artic_cushion", "(EVPUs) extra gap below articulations", nil}, + { "left_horiz_offset", "(EVPUs) gap between the start of selection and hairpin (no dynamics)", nil}, + { "right_horiz_offset", "(EVPUs) gap between end of hairpin and end of selection (no dynamics)", nil}, + { "left_dynamic_cushion", "(EVPUs) gap between first dynamic and start of hairpin", nil}, + { "right_dynamic_cushion", "(EVPUs) gap between end of the hairpin and ending dynamic", nil}, +} + +local config = { + dynamics_match_hairpin = true, + include_trailing_items = true, + attach_over_end_barline = true, + attach_over_system_break = false, + inclusions_EDU_margin = 256, + shape_vert_adjust = 13, + below_note_cushion = 56, + downstem_cushion = 44, + below_artic_cushion = 40, + left_horiz_offset = 10, + right_horiz_offset = -14, + left_dynamic_cushion = 16, + right_dynamic_cushion = -16, + window_pos_x = 0, + window_pos_y = 0, + number_of_booleans = 4, -- number of boolean values at start of global_dialog_options +} + +local configuration = require("library.configuration") + +function create_user_dialog() -- attempting MODELESS operation + local y_step = 20 + local max_text_width = 385 + local x_offset = {0, 130, 155, 190} + local mac_offset = finenv.UI():IsOnMac() and 3 or 0 -- extra horizontal offset for Mac edit boxes + local str = finale.FCString() + local dialog = finale.FCCustomLuaWindow() + str.LuaString = "HAIRPIN CREATOR CONFIGURATION" + dialog:SetTitle(str) + + local function make_static(msg, horiz, vert, width, sepia) + local str2 = finale.FCString() + local static = dialog:CreateStatic(horiz, vert) + str2.LuaString = msg + static:SetText(str2) + static:SetWidth(width) + if sepia then + static:SetTextColor(204, 102, 51) + end + end + + for i, v in ipairs(global_dialog_options) do -- run through config parameters + local y_current = y_step * i + str.LuaString = string.gsub(v[1], "_", " ") + if i <= config.number_of_booleans then -- boolean checkboxes + v[3] = dialog:CreateCheckbox(x_offset[1], y_current) + v[3]:SetText(str) + v[3]:SetWidth(x_offset[3]) + local checked = config[v[1]] and 1 or 0 + v[3]:SetCheck(checked) + make_static(v[2], x_offset[3], y_current, max_text_width, true) -- parameter explanation + else -- integer value + y_current = y_current + 10 + str.LuaString = str.LuaString .. ":" + make_static(str.LuaString, x_offset[1], y_current, x_offset[2], false) -- parameter name + v[3] = dialog:CreateEdit(x_offset[2], y_current - mac_offset) + v[3]:SetInteger(config[v[1]]) + v[3]:SetWidth(50) + make_static(v[2], x_offset[4], y_current, max_text_width, true) -- parameter explanation + end + end + dialog:CreateOkButton() + dialog:CreateCancelButton() + return dialog +end + +function on_ok() -- config changed, now do the work + for i, v in ipairs(global_dialog_options) do + if i > config.number_of_booleans then + config[v[1]] = v[3]:GetInteger() + else + config[v[1]] = (v[3]:GetCheck() == 1) -- "true" for checked + end + end + global_dialog:StorePosition() + config.window_pos_x = global_dialog.StoredX + config.window_pos_y = global_dialog.StoredY + configuration.save_user_settings("hairpin_creator", config) +end + +function user_changes_configuration() + configuration.get_user_settings("hairpin_creator", config) -- overwrite default preferences + global_dialog = create_user_dialog() + if config.window_pos_x > 0 and config.window_pos_y > 0 then + global_dialog:StorePosition() + global_dialog:SetRestorePositionOnlyData(config.window_pos_x, config.window_pos_y) + global_dialog:RestorePosition() + end + global_dialog:RegisterHandleOkButtonPressed(on_ok) + finenv.RegisterModelessDialog(global_dialog) + global_dialog:ShowModeless() +end + +user_changes_configuration() From 803947e2139c8d15fa60349ab2977a7c04cb3e22 Mon Sep 17 00:00:00 2001 From: cv-on-hub <105578039+cv-on-hub@users.noreply.github.com> Date: Mon, 18 Jul 2022 09:20:44 +1000 Subject: [PATCH 2/4] Revert "Create hairpin_creator_configuration.lua" This reverts commit 9b4a5a1e5a5fdd942b8a76d2aecf7660eb26e93b. --- src/hairpin_creator_configuration.lua | 136 -------------------------- 1 file changed, 136 deletions(-) delete mode 100644 src/hairpin_creator_configuration.lua diff --git a/src/hairpin_creator_configuration.lua b/src/hairpin_creator_configuration.lua deleted file mode 100644 index 17c4521b..00000000 --- a/src/hairpin_creator_configuration.lua +++ /dev/null @@ -1,136 +0,0 @@ -function plugindef() - finaleplugin.RequireSelection = true - finaleplugin.Author = "Carl Vine after CJ Garcia" - finaleplugin.AuthorURL = "http://carlvine.com/lua" - finaleplugin.Copyright = "CC0 https://creativecommons.org/publicdomain/zero/1.0/" - finaleplugin.Version = "v0.52" - finaleplugin.Date = "2022/07/17" - finaleplugin.Notes = [[ - This is a companion script for `hairpin_creator.lua`, listed in the - `finalelua.com` repository by its primary menu name, "Hairpin create crescendo". - - If you use a macro program like KeyboardMaestro (MacOS) to trigger menu items in Finale, - using the `alt` or `option` key in `hairpin_creator.lua` won't allow access to its configuration. - If so, use this script to change the configuration file directly. - The result will affect the behaviour of all four of hairpin_creator's actions: - - ``` - Crescendo | Diminuendo | Swell | Unswell - ``` - ]] - return "Hairpin creator configuration", "Hairpin creator configuration", "Configuration utitlity for the hairpin_creator.lua script" -end - --- global variables for modeless operation -global_dialog = nil -global_dialog_options = { -- key value in config, explanation, dialog control holder - { "dynamics_match_hairpin", "move dynamics vertically to match hairpin height", nil}, - { "include_trailing_items", "consider notes and dynamics past the end of selection", nil}, - { "attach_over_end_barline", "attach right end of hairpin across the final barline", nil}, - { "attach_over_system_break", "attach across final barline even over a system break", nil}, - { "inclusions_EDU_margin", "(EDUs) the marginal duration for included trailing items", nil}, - { "shape_vert_adjust", "(EVPUs) vertical adjustment for hairpin to match dynamics", nil}, - { "below_note_cushion", "(EVPUs) extra gap below notes", nil}, - { "downstem_cushion", "(EVPUs) extra gap below down-stems", nil}, - { "below_artic_cushion", "(EVPUs) extra gap below articulations", nil}, - { "left_horiz_offset", "(EVPUs) gap between the start of selection and hairpin (no dynamics)", nil}, - { "right_horiz_offset", "(EVPUs) gap between end of hairpin and end of selection (no dynamics)", nil}, - { "left_dynamic_cushion", "(EVPUs) gap between first dynamic and start of hairpin", nil}, - { "right_dynamic_cushion", "(EVPUs) gap between end of the hairpin and ending dynamic", nil}, -} - -local config = { - dynamics_match_hairpin = true, - include_trailing_items = true, - attach_over_end_barline = true, - attach_over_system_break = false, - inclusions_EDU_margin = 256, - shape_vert_adjust = 13, - below_note_cushion = 56, - downstem_cushion = 44, - below_artic_cushion = 40, - left_horiz_offset = 10, - right_horiz_offset = -14, - left_dynamic_cushion = 16, - right_dynamic_cushion = -16, - window_pos_x = 0, - window_pos_y = 0, - number_of_booleans = 4, -- number of boolean values at start of global_dialog_options -} - -local configuration = require("library.configuration") - -function create_user_dialog() -- attempting MODELESS operation - local y_step = 20 - local max_text_width = 385 - local x_offset = {0, 130, 155, 190} - local mac_offset = finenv.UI():IsOnMac() and 3 or 0 -- extra horizontal offset for Mac edit boxes - local str = finale.FCString() - local dialog = finale.FCCustomLuaWindow() - str.LuaString = "HAIRPIN CREATOR CONFIGURATION" - dialog:SetTitle(str) - - local function make_static(msg, horiz, vert, width, sepia) - local str2 = finale.FCString() - local static = dialog:CreateStatic(horiz, vert) - str2.LuaString = msg - static:SetText(str2) - static:SetWidth(width) - if sepia then - static:SetTextColor(204, 102, 51) - end - end - - for i, v in ipairs(global_dialog_options) do -- run through config parameters - local y_current = y_step * i - str.LuaString = string.gsub(v[1], "_", " ") - if i <= config.number_of_booleans then -- boolean checkboxes - v[3] = dialog:CreateCheckbox(x_offset[1], y_current) - v[3]:SetText(str) - v[3]:SetWidth(x_offset[3]) - local checked = config[v[1]] and 1 or 0 - v[3]:SetCheck(checked) - make_static(v[2], x_offset[3], y_current, max_text_width, true) -- parameter explanation - else -- integer value - y_current = y_current + 10 - str.LuaString = str.LuaString .. ":" - make_static(str.LuaString, x_offset[1], y_current, x_offset[2], false) -- parameter name - v[3] = dialog:CreateEdit(x_offset[2], y_current - mac_offset) - v[3]:SetInteger(config[v[1]]) - v[3]:SetWidth(50) - make_static(v[2], x_offset[4], y_current, max_text_width, true) -- parameter explanation - end - end - dialog:CreateOkButton() - dialog:CreateCancelButton() - return dialog -end - -function on_ok() -- config changed, now do the work - for i, v in ipairs(global_dialog_options) do - if i > config.number_of_booleans then - config[v[1]] = v[3]:GetInteger() - else - config[v[1]] = (v[3]:GetCheck() == 1) -- "true" for checked - end - end - global_dialog:StorePosition() - config.window_pos_x = global_dialog.StoredX - config.window_pos_y = global_dialog.StoredY - configuration.save_user_settings("hairpin_creator", config) -end - -function user_changes_configuration() - configuration.get_user_settings("hairpin_creator", config) -- overwrite default preferences - global_dialog = create_user_dialog() - if config.window_pos_x > 0 and config.window_pos_y > 0 then - global_dialog:StorePosition() - global_dialog:SetRestorePositionOnlyData(config.window_pos_x, config.window_pos_y) - global_dialog:RestorePosition() - end - global_dialog:RegisterHandleOkButtonPressed(on_ok) - finenv.RegisterModelessDialog(global_dialog) - global_dialog:ShowModeless() -end - -user_changes_configuration() From 1644c365e3ed6a5334335eb2d54971a122c857bb Mon Sep 17 00:00:00 2001 From: cv-on-hub <105578039+cv-on-hub@users.noreply.github.com> Date: Mon, 18 Jul 2022 09:23:38 +1000 Subject: [PATCH 3/4] Update hairpin_creator.lua Revision of hairpin_creator using MIXIN. Failed to get mixin to correctly handle prefs_dialog:RestorePosition(). --- src/hairpin_creator.lua | 157 ++++++++++++++++++---------------------- 1 file changed, 72 insertions(+), 85 deletions(-) diff --git a/src/hairpin_creator.lua b/src/hairpin_creator.lua index 263c0193..cb6d2cd2 100644 --- a/src/hairpin_creator.lua +++ b/src/hairpin_creator.lua @@ -3,8 +3,8 @@ function plugindef() finaleplugin.Author = "Carl Vine after CJ Garcia" finaleplugin.AuthorURL = "http://carlvine.com/lua" finaleplugin.Copyright = "CC0 https://creativecommons.org/publicdomain/zero/1.0/" - finaleplugin.Version = "v0.52" - finaleplugin.Date = "2022/07/14" + finaleplugin.Version = "v0.54" -- (now with Mixin) + finaleplugin.Date = "2022/07/18" finaleplugin.AdditionalMenuOptions = [[ Hairpin create diminuendo Hairpin create swell @@ -26,6 +26,7 @@ function plugindef() hairpin_type = -2 -- "unswell" ]] finaleplugin.MinJWLuaVersion = 0.62 + finaleplugin.ScriptGroupName = "Hairpin creator" finaleplugin.Notes = [[ This script creates hairpins spanning the currently selected music region. The default hairpin type is `CRESCENDO`, with three additional menu items provided to create: @@ -42,7 +43,7 @@ function plugindef() Hairpin positions in Finale are more accurate when attached to these "trailing" notes and dynamics, but this can be a problem if trailing items fall across a barline and especially if they are on a different system from the end of the hairpin. - (Elaine Gould - "Behind Bars" pp.103-106 - outlines multiple hairpin scenarios in which they +7 (Elaine Gould - "Behind Bars" pp.103-106 - outlines multiple hairpin scenarios in which they should or shouldn't "attach" across barlines. Your preferences may differ.) You should get the best results by entering dynamic markings before running the script. @@ -59,22 +60,20 @@ end hairpin_type = hairpin_type or finale.SMARTSHAPE_CRESCENDO --- global variables for modeless operation -global_dialog = nil -global_dialog_options = { -- key value in config, explanation, dialog control holder - { "dynamics_match_hairpin", "move dynamics vertically to match hairpin height", nil}, - { "include_trailing_items", "consider notes and dynamics past the end of selection", nil}, - { "attach_over_end_barline", "attach right end of hairpin across the final barline", nil}, - { "attach_over_system_break", "attach across final barline even over a system break", nil}, - { "inclusions_EDU_margin", "(EDUs) the marginal duration for included trailing items", nil}, - { "shape_vert_adjust", "(EVPUs) vertical adjustment for hairpin to match dynamics", nil}, - { "below_note_cushion", "(EVPUs) extra gap below notes", nil}, - { "downstem_cushion", "(EVPUs) extra gap below down-stems", nil}, - { "below_artic_cushion", "(EVPUs) extra gap below articulations", nil}, - { "left_horiz_offset", "(EVPUs) gap between the start of selection and hairpin (no dynamics)", nil}, - { "right_horiz_offset", "(EVPUs) gap between end of hairpin and end of selection (no dynamics)", nil}, - { "left_dynamic_cushion", "(EVPUs) gap between first dynamic and start of hairpin", nil}, - { "right_dynamic_cushion", "(EVPUs) gap between end of the hairpin and ending dynamic", nil}, +local prefs_dialog_options = { -- key value in config, explanation, dialog control holder + { "dynamics_match_hairpin", "move dynamics vertically to match hairpin height" }, + { "include_trailing_items", "consider notes and dynamics past the end of selection" }, + { "attach_over_end_barline", "attach right end of hairpin across the final barline" }, + { "attach_over_system_break", "attach across final barline even over a system break" }, + { "inclusions_EDU_margin", "(EDUs) the marginal duration for included trailing items" }, + { "shape_vert_adjust", "(EVPUs) vertical adjustment for hairpin to match dynamics" }, + { "below_note_cushion", "(EVPUs) extra gap below notes" }, + { "downstem_cushion", "(EVPUs) extra gap below down-stems" }, + { "below_artic_cushion", "(EVPUs) extra gap below articulations" }, + { "left_horiz_offset", "(EVPUs) gap between the start of selection and hairpin (no dynamics)" }, + { "right_horiz_offset", "(EVPUs) gap between end of hairpin and end of selection (no dynamics)" }, + { "left_dynamic_cushion", "(EVPUs) gap between first dynamic and start of hairpin" }, + { "right_dynamic_cushion", "(EVPUs) gap between end of the hairpin and ending dynamic" }, } local config = { @@ -93,12 +92,14 @@ local config = { right_dynamic_cushion = -16, window_pos_x = 0, window_pos_y = 0, - number_of_booleans = 4, -- number of boolean values at start of global_dialog_options + number_of_booleans = 4, -- number of boolean values at start of prefs_dialog_options } local configuration = require("library.configuration") local expression = require("library.expression") +local mixin = require("library.mixin") +-- ================= HAIRPIN CREATOR BEGINS ================================= local function measure_width(measure_number) local m = finale.FCMeasure() m:Load(measure_number) @@ -525,100 +526,86 @@ local function create_hairpin(shape_type) end end -function create_user_dialog() -- MODELESS dialog +function activity_selector() + if hairpin_type < 0 then -- SWELL / UNSWELL + create_swell(hairpin_type == -1) -- true for SWELL, otherwise UNSWELL + else + create_hairpin(hairpin_type) -- preset CRESC / DIM + end +end + +function create_dialog_box() + local dialog = mixin.FCXCustomLuaWindow():SetTitle("HAIRPIN CREATOR CONFIGURATION") local y_step = 20 local max_text_width = 385 local x_offset = {0, 130, 155, 190} local mac_offset = finenv.UI():IsOnMac() and 3 or 0 -- extra horizontal offset for Mac edit boxes - local str = finale.FCString() - local dialog = finale.FCCustomLuaWindow() - str.LuaString = "HAIRPIN CREATOR CONFIGURATION" - dialog:SetTitle(str) local function make_static(msg, horiz, vert, width, sepia) - local str2 = finale.FCString() - str2.LuaString = msg - local static = dialog:CreateStatic(horiz, vert) - static:SetText(str2) + local static = dialog:CreateStatic(horiz, vert):SetText(msg) static:SetWidth(width) if sepia then static:SetTextColor(204, 102, 51) end end - for i, v in ipairs(global_dialog_options) do -- run through config parameters + for i, v in ipairs(prefs_dialog_options) do -- run through config parameters local y_current = y_step * i - str.LuaString = string.gsub(v[1], "_", " ") + local msg = string.gsub(v[1], "_", " ") if i <= config.number_of_booleans then -- boolean checkboxes - v[3] = dialog:CreateCheckbox(x_offset[1], y_current) - v[3]:SetText(str) - v[3]:SetWidth(x_offset[3]) - local checked = config[v[1]] and 1 or 0 - v[3]:SetCheck(checked) + local check = dialog:CreateCheckbox(x_offset[1], y_current, v[1]):SetText(msg) + check:SetWidth(x_offset[3]) + check:SetCheck(config[v[1]] and 1 or 0) make_static(v[2], x_offset[3], y_current, max_text_width, true) -- parameter explanation else -- integer value y_current = y_current + 10 -- gap before the integer variables - make_static(str.LuaString .. ":", x_offset[1], y_current, x_offset[2], false) -- parameter name - v[3] = dialog:CreateEdit(x_offset[2], y_current - mac_offset) - v[3]:SetInteger(config[v[1]]) - v[3]:SetWidth(50) + make_static(msg .. ":", x_offset[1], y_current, x_offset[2], false) -- parameter name + local edit = dialog:CreateEdit(x_offset[2], y_current - mac_offset, v[1]):SetInteger(config[v[1]]) + edit:SetWidth(50) make_static(v[2], x_offset[4], y_current, max_text_width, true) -- parameter explanation end end + dialog:CreateOkButton() dialog:CreateCancelButton() - return dialog -end - -function activity_selector() - if hairpin_type < 0 then -- SWELL / UNSWELL - create_swell(hairpin_type == -1) -- true for SWELL, otherwise UNSWELL - else - create_hairpin(hairpin_type) -- preset CRESC / DIM - end -end - -function on_ok() -- config changed, save prefs and do the work - for i, v in ipairs(global_dialog_options) do - if i > config.number_of_booleans then - config[v[1]] = v[3]:GetInteger() - else - config[v[1]] = (v[3]:GetCheck() == 1) -- "true" for checked + dialog:RegisterHandleOkButtonPressed(function(self) + for i, v in ipairs(prefs_dialog_options) do + if i > config.number_of_booleans then + config[v[1]] = self:GetControl(v[1]):GetInteger() + else + config[v[1]] = (self:GetControl(v[1]):GetCheck() == 1) + end + end + self:StorePosition() + config.window_pos_x = self.StoredX + config.window_pos_y = self.StoredY --]] + configuration.save_user_settings("hairpin_creator", config) + finenv.StartNewUndoBlock("Hairpin creator", false) + activity_selector() -- **** DO THE WORK HERE! **** + if finenv.EndUndoBlock then + finenv.EndUndoBlock(true) + finenv.Region():Redraw() + else + finenv.StartNewUndoBlock("Hairpin creator", true) + end end - end - global_dialog:StorePosition() -- save current dialog window position - config.window_pos_x = global_dialog.StoredX - config.window_pos_y = global_dialog.StoredY - configuration.save_user_settings("hairpin_creator", config) - - finenv.StartNewUndoBlock("Hairpin Creator", false) - activity_selector() -- ******** DO THE WORK HERE! *********** - if finenv.EndUndoBlock then - finenv.EndUndoBlock(true) - finenv.Region():Redraw() - else - finenv.StartNewUndoBlock("Hairpin Creator", true) - end -end - -function user_changes_configuration() - global_dialog = create_user_dialog() - if config.window_pos_x > 0 and config.window_pos_y > 0 then - global_dialog:StorePosition() - global_dialog:SetRestorePositionOnlyData(config.window_pos_x, config.window_pos_y) - global_dialog:RestorePosition() - end - global_dialog:RegisterHandleOkButtonPressed(on_ok) - finenv.RegisterModelessDialog(global_dialog) - global_dialog:ShowModeless() + ) + return dialog end function action_type() configuration.get_user_settings("hairpin_creator", config, true) -- overwrite default preferences if finenv.QueryInvokedModifierKeys and finenv.QueryInvokedModifierKeys(finale.CMDMODKEY_ALT) then - user_changes_configuration() + local prefs_dialog = create_dialog_box() + prefs_dialog.OkButtonCanClose = true + if config.window_pos_x > 0 and config.window_pos_y > 0 then + prefs_dialog:StorePosition() + prefs_dialog:SetRestorePositionOnlyData(config.window_pos_x, config.window_pos_y) + prefs_dialog:RestorePosition() + end --]] + prefs_dialog:RunModeless() else - activity_selector() + activity_selector() -- just go do the work end end From 8551bdf9bf3b336de0e48773392c8b6ea2f2ec94 Mon Sep 17 00:00:00 2001 From: cv-on-hub <105578039+cv-on-hub@users.noreply.github.com> Date: Mon, 18 Jul 2022 20:14:11 +1000 Subject: [PATCH 4/4] Revert "Update hairpin_creator.lua" This reverts commit 1644c365e3ed6a5334335eb2d54971a122c857bb. --- src/hairpin_creator.lua | 157 ++++++++++++++++++++++------------------ 1 file changed, 85 insertions(+), 72 deletions(-) diff --git a/src/hairpin_creator.lua b/src/hairpin_creator.lua index cb6d2cd2..263c0193 100644 --- a/src/hairpin_creator.lua +++ b/src/hairpin_creator.lua @@ -3,8 +3,8 @@ function plugindef() finaleplugin.Author = "Carl Vine after CJ Garcia" finaleplugin.AuthorURL = "http://carlvine.com/lua" finaleplugin.Copyright = "CC0 https://creativecommons.org/publicdomain/zero/1.0/" - finaleplugin.Version = "v0.54" -- (now with Mixin) - finaleplugin.Date = "2022/07/18" + finaleplugin.Version = "v0.52" + finaleplugin.Date = "2022/07/14" finaleplugin.AdditionalMenuOptions = [[ Hairpin create diminuendo Hairpin create swell @@ -26,7 +26,6 @@ function plugindef() hairpin_type = -2 -- "unswell" ]] finaleplugin.MinJWLuaVersion = 0.62 - finaleplugin.ScriptGroupName = "Hairpin creator" finaleplugin.Notes = [[ This script creates hairpins spanning the currently selected music region. The default hairpin type is `CRESCENDO`, with three additional menu items provided to create: @@ -43,7 +42,7 @@ function plugindef() Hairpin positions in Finale are more accurate when attached to these "trailing" notes and dynamics, but this can be a problem if trailing items fall across a barline and especially if they are on a different system from the end of the hairpin. -7 (Elaine Gould - "Behind Bars" pp.103-106 - outlines multiple hairpin scenarios in which they + (Elaine Gould - "Behind Bars" pp.103-106 - outlines multiple hairpin scenarios in which they should or shouldn't "attach" across barlines. Your preferences may differ.) You should get the best results by entering dynamic markings before running the script. @@ -60,20 +59,22 @@ end hairpin_type = hairpin_type or finale.SMARTSHAPE_CRESCENDO -local prefs_dialog_options = { -- key value in config, explanation, dialog control holder - { "dynamics_match_hairpin", "move dynamics vertically to match hairpin height" }, - { "include_trailing_items", "consider notes and dynamics past the end of selection" }, - { "attach_over_end_barline", "attach right end of hairpin across the final barline" }, - { "attach_over_system_break", "attach across final barline even over a system break" }, - { "inclusions_EDU_margin", "(EDUs) the marginal duration for included trailing items" }, - { "shape_vert_adjust", "(EVPUs) vertical adjustment for hairpin to match dynamics" }, - { "below_note_cushion", "(EVPUs) extra gap below notes" }, - { "downstem_cushion", "(EVPUs) extra gap below down-stems" }, - { "below_artic_cushion", "(EVPUs) extra gap below articulations" }, - { "left_horiz_offset", "(EVPUs) gap between the start of selection and hairpin (no dynamics)" }, - { "right_horiz_offset", "(EVPUs) gap between end of hairpin and end of selection (no dynamics)" }, - { "left_dynamic_cushion", "(EVPUs) gap between first dynamic and start of hairpin" }, - { "right_dynamic_cushion", "(EVPUs) gap between end of the hairpin and ending dynamic" }, +-- global variables for modeless operation +global_dialog = nil +global_dialog_options = { -- key value in config, explanation, dialog control holder + { "dynamics_match_hairpin", "move dynamics vertically to match hairpin height", nil}, + { "include_trailing_items", "consider notes and dynamics past the end of selection", nil}, + { "attach_over_end_barline", "attach right end of hairpin across the final barline", nil}, + { "attach_over_system_break", "attach across final barline even over a system break", nil}, + { "inclusions_EDU_margin", "(EDUs) the marginal duration for included trailing items", nil}, + { "shape_vert_adjust", "(EVPUs) vertical adjustment for hairpin to match dynamics", nil}, + { "below_note_cushion", "(EVPUs) extra gap below notes", nil}, + { "downstem_cushion", "(EVPUs) extra gap below down-stems", nil}, + { "below_artic_cushion", "(EVPUs) extra gap below articulations", nil}, + { "left_horiz_offset", "(EVPUs) gap between the start of selection and hairpin (no dynamics)", nil}, + { "right_horiz_offset", "(EVPUs) gap between end of hairpin and end of selection (no dynamics)", nil}, + { "left_dynamic_cushion", "(EVPUs) gap between first dynamic and start of hairpin", nil}, + { "right_dynamic_cushion", "(EVPUs) gap between end of the hairpin and ending dynamic", nil}, } local config = { @@ -92,14 +93,12 @@ local config = { right_dynamic_cushion = -16, window_pos_x = 0, window_pos_y = 0, - number_of_booleans = 4, -- number of boolean values at start of prefs_dialog_options + number_of_booleans = 4, -- number of boolean values at start of global_dialog_options } local configuration = require("library.configuration") local expression = require("library.expression") -local mixin = require("library.mixin") --- ================= HAIRPIN CREATOR BEGINS ================================= local function measure_width(measure_number) local m = finale.FCMeasure() m:Load(measure_number) @@ -526,86 +525,100 @@ local function create_hairpin(shape_type) end end -function activity_selector() - if hairpin_type < 0 then -- SWELL / UNSWELL - create_swell(hairpin_type == -1) -- true for SWELL, otherwise UNSWELL - else - create_hairpin(hairpin_type) -- preset CRESC / DIM - end -end - -function create_dialog_box() - local dialog = mixin.FCXCustomLuaWindow():SetTitle("HAIRPIN CREATOR CONFIGURATION") +function create_user_dialog() -- MODELESS dialog local y_step = 20 local max_text_width = 385 local x_offset = {0, 130, 155, 190} local mac_offset = finenv.UI():IsOnMac() and 3 or 0 -- extra horizontal offset for Mac edit boxes + local str = finale.FCString() + local dialog = finale.FCCustomLuaWindow() + str.LuaString = "HAIRPIN CREATOR CONFIGURATION" + dialog:SetTitle(str) local function make_static(msg, horiz, vert, width, sepia) - local static = dialog:CreateStatic(horiz, vert):SetText(msg) + local str2 = finale.FCString() + str2.LuaString = msg + local static = dialog:CreateStatic(horiz, vert) + static:SetText(str2) static:SetWidth(width) if sepia then static:SetTextColor(204, 102, 51) end end - for i, v in ipairs(prefs_dialog_options) do -- run through config parameters + for i, v in ipairs(global_dialog_options) do -- run through config parameters local y_current = y_step * i - local msg = string.gsub(v[1], "_", " ") + str.LuaString = string.gsub(v[1], "_", " ") if i <= config.number_of_booleans then -- boolean checkboxes - local check = dialog:CreateCheckbox(x_offset[1], y_current, v[1]):SetText(msg) - check:SetWidth(x_offset[3]) - check:SetCheck(config[v[1]] and 1 or 0) + v[3] = dialog:CreateCheckbox(x_offset[1], y_current) + v[3]:SetText(str) + v[3]:SetWidth(x_offset[3]) + local checked = config[v[1]] and 1 or 0 + v[3]:SetCheck(checked) make_static(v[2], x_offset[3], y_current, max_text_width, true) -- parameter explanation else -- integer value y_current = y_current + 10 -- gap before the integer variables - make_static(msg .. ":", x_offset[1], y_current, x_offset[2], false) -- parameter name - local edit = dialog:CreateEdit(x_offset[2], y_current - mac_offset, v[1]):SetInteger(config[v[1]]) - edit:SetWidth(50) + make_static(str.LuaString .. ":", x_offset[1], y_current, x_offset[2], false) -- parameter name + v[3] = dialog:CreateEdit(x_offset[2], y_current - mac_offset) + v[3]:SetInteger(config[v[1]]) + v[3]:SetWidth(50) make_static(v[2], x_offset[4], y_current, max_text_width, true) -- parameter explanation end end - dialog:CreateOkButton() dialog:CreateCancelButton() - dialog:RegisterHandleOkButtonPressed(function(self) - for i, v in ipairs(prefs_dialog_options) do - if i > config.number_of_booleans then - config[v[1]] = self:GetControl(v[1]):GetInteger() - else - config[v[1]] = (self:GetControl(v[1]):GetCheck() == 1) - end - end - self:StorePosition() - config.window_pos_x = self.StoredX - config.window_pos_y = self.StoredY --]] - configuration.save_user_settings("hairpin_creator", config) - finenv.StartNewUndoBlock("Hairpin creator", false) - activity_selector() -- **** DO THE WORK HERE! **** - if finenv.EndUndoBlock then - finenv.EndUndoBlock(true) - finenv.Region():Redraw() - else - finenv.StartNewUndoBlock("Hairpin creator", true) - end - end - ) return dialog end +function activity_selector() + if hairpin_type < 0 then -- SWELL / UNSWELL + create_swell(hairpin_type == -1) -- true for SWELL, otherwise UNSWELL + else + create_hairpin(hairpin_type) -- preset CRESC / DIM + end +end + +function on_ok() -- config changed, save prefs and do the work + for i, v in ipairs(global_dialog_options) do + if i > config.number_of_booleans then + config[v[1]] = v[3]:GetInteger() + else + config[v[1]] = (v[3]:GetCheck() == 1) -- "true" for checked + end + end + global_dialog:StorePosition() -- save current dialog window position + config.window_pos_x = global_dialog.StoredX + config.window_pos_y = global_dialog.StoredY + configuration.save_user_settings("hairpin_creator", config) + + finenv.StartNewUndoBlock("Hairpin Creator", false) + activity_selector() -- ******** DO THE WORK HERE! *********** + if finenv.EndUndoBlock then + finenv.EndUndoBlock(true) + finenv.Region():Redraw() + else + finenv.StartNewUndoBlock("Hairpin Creator", true) + end +end + +function user_changes_configuration() + global_dialog = create_user_dialog() + if config.window_pos_x > 0 and config.window_pos_y > 0 then + global_dialog:StorePosition() + global_dialog:SetRestorePositionOnlyData(config.window_pos_x, config.window_pos_y) + global_dialog:RestorePosition() + end + global_dialog:RegisterHandleOkButtonPressed(on_ok) + finenv.RegisterModelessDialog(global_dialog) + global_dialog:ShowModeless() +end + function action_type() configuration.get_user_settings("hairpin_creator", config, true) -- overwrite default preferences if finenv.QueryInvokedModifierKeys and finenv.QueryInvokedModifierKeys(finale.CMDMODKEY_ALT) then - local prefs_dialog = create_dialog_box() - prefs_dialog.OkButtonCanClose = true - if config.window_pos_x > 0 and config.window_pos_y > 0 then - prefs_dialog:StorePosition() - prefs_dialog:SetRestorePositionOnlyData(config.window_pos_x, config.window_pos_y) - prefs_dialog:RestorePosition() - end --]] - prefs_dialog:RunModeless() + user_changes_configuration() else - activity_selector() -- just go do the work + activity_selector() end end