Skip to content

Commit

Permalink
#1331 Automatically disable Playtime toolbar button when manually rem…
Browse files Browse the repository at this point in the history
…oved
  • Loading branch information
helgoboss committed Dec 9, 2024
1 parent ed4db95 commit 3de9f41
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 30 deletions.
48 changes: 43 additions & 5 deletions main/src/infrastructure/plugin/backbone_shell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ use crate::base::notification::notify_user_about_anyhow_error;
use crate::infrastructure::plugin::actions::ACTION_DEFS;
use crate::infrastructure::plugin::api_impl::{register_api, unregister_api};
use crate::infrastructure::plugin::debug_util::resolve_symbols_from_clipboard;
use crate::infrastructure::plugin::dynamic_toolbar::add_or_remove_toolbar_button;
use crate::infrastructure::plugin::dynamic_toolbar::{
add_or_remove_toolbar_button, custom_toolbar_api_is_available, ToolbarChangeDetector,
};
use crate::infrastructure::plugin::helgobox_plugin::HELGOBOX_UNIQUE_VST_PLUGIN_ADD_STRING;
use crate::infrastructure::plugin::hidden_helper_panel::HiddenHelperPanel;
use crate::infrastructure::plugin::persistent_toolbar::add_toolbar_button_persistently;
Expand Down Expand Up @@ -194,6 +196,7 @@ pub struct BackboneShell {
osc_feedback_processor: Rc<RefCell<OscFeedbackProcessor>>,
proto_hub: crate::infrastructure::proto::ProtoHub,
welcome_panel: RefCell<Option<SharedView<WelcomePanel>>>,
toolbar_change_detector: Option<RefCell<ToolbarChangeDetector>>,
/// We need to keep this panel in memory in order to be informed when it's destroyed.
_shutdown_detection_panel: SharedView<HiddenHelperPanel>,
}
Expand Down Expand Up @@ -442,11 +445,30 @@ impl BackboneShell {
// Must be called after registering actions and waking REAPER up, otherwise it won't find the command IDs.
let _ = Self::register_extension_menu();
let _ = Self::register_toolbar_icon_map();
for (key, value) in &config.toolbar {
if *value > 0 {
let _ = add_or_remove_toolbar_button(key, true);
let toolbar_change_detector = if custom_toolbar_api_is_available() {
// Auto-add previously enabled dynamic toolbar buttons, if not present already
for (command_name, enabled) in &config.toolbar {
if *enabled > 0 {
let _ = add_or_remove_toolbar_button(command_name, true);
}
}
}
// Create change detector to automatically disable a dynamic toolbar button if the user removes the
// button manually.
let observed_commands = ACTION_DEFS.iter().filter_map(|def| {
if !def.add_toolbar_button {
return None;
}
let command_id = Reaper::get()
.action_by_command_name(def.command_name)
.command_id()
.ok()?;
Some((command_id, def.command_name.to_string()))
});
let detector = ToolbarChangeDetector::new(observed_commands.collect());
Some(RefCell::new(detector))
} else {
None
};
// Detect shutdown via hidden child window as suggested by Justin
let shutdown_detection_panel = SharedView::new(HiddenHelperPanel::new());
shutdown_detection_panel.clone().open(reaper_main_window());
Expand Down Expand Up @@ -479,6 +501,7 @@ impl BackboneShell {
osc_feedback_processor: Rc::new(RefCell::new(osc_feedback_processor)),
proto_hub: crate::infrastructure::proto::ProtoHub::new(),
welcome_panel: Default::default(),
toolbar_change_detector,
_shutdown_detection_panel: shutdown_detection_panel,
}
}
Expand Down Expand Up @@ -1071,6 +1094,20 @@ impl BackboneShell {
})
}

/// To be called regularly, maybe once a second.
///
/// See https://github.com/helgoboss/helgobox/issues/1331.
pub fn disable_manually_removed_dynamic_toolbar_buttons(&self) {
let Some(detector) = &self.toolbar_change_detector else {
return;
};
for command_name in detector.borrow_mut().detect_manually_removed_commands() {
self.change_config(|config| {
config.toolbar.insert(command_name.to_string(), 0);
})
}
}

/// Logging debug info is always initiated by a particular session.
pub fn log_debug_info(&self, session_id: &str) {
let msg = format!(
Expand Down Expand Up @@ -2159,6 +2196,7 @@ impl Drop for BackboneShell {
#[serde(default)]
pub struct BackboneConfig {
main: MainConfig,
// Map from command name (e.g. HB_SHOW_HIDE_PLAYTIME to state integer, 0 for disabled , 1 for enabled)
toolbar: HashMap<String, u8>,
}

Expand Down
47 changes: 44 additions & 3 deletions main/src/infrastructure/plugin/dynamic_toolbar.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
use base::hash_util::{NonCryptoHashMap, NonCryptoHashSet};
use reaper_high::Reaper;
use reaper_medium::{CommandId, MenuOrToolbarItem, PositionDescriptor, UiRefreshBehavior};

/// Dynamically adds or removes a toolbar button without persisting it.
pub fn custom_toolbar_api_is_available() -> bool {
Reaper::get()
.medium_reaper()
.low()
.pointers()
.GetCustomMenuOrToolbarItem
.is_some()
}

/// Dynamically adds or removes a toolbar button without persisting it, returning the command ID.
///
/// Requires REAPER version >= 711+dev0305.
///
Expand All @@ -12,7 +22,7 @@ use reaper_medium::{CommandId, MenuOrToolbarItem, PositionDescriptor, UiRefreshB
/// # Panics
///
/// Panics if the REAPER version is too low.
pub fn add_or_remove_toolbar_button(command_name: &str, add: bool) -> anyhow::Result<()> {
pub fn add_or_remove_toolbar_button(command_name: &str, add: bool) -> anyhow::Result<CommandId> {
let action = Reaper::get().action_by_command_name(command_name);
let command_id = action.command_id()?;
let reaper = Reaper::get().medium_reaper();
Expand Down Expand Up @@ -40,7 +50,38 @@ pub fn add_or_remove_toolbar_button(command_name: &str, add: bool) -> anyhow::Re
}
}
}
Ok(())
Ok(command_id)
}

#[derive(Debug)]
pub struct ToolbarChangeDetector {
/// Map from command ID to command name.
observed_commands: NonCryptoHashMap<CommandId, String>,
present_commands: NonCryptoHashSet<CommandId>,
}

impl ToolbarChangeDetector {
pub fn new(observed_commands: NonCryptoHashMap<CommandId, String>) -> Self {
Self {
observed_commands,
present_commands: Default::default(),
}
}

pub fn detect_manually_removed_commands(&mut self) -> Vec<&str> {
self.observed_commands
.iter()
.filter(|(command_id, _)| {
if scan_toolbar_for_command_id(**command_id).is_some() {
self.present_commands.insert(**command_id);
false
} else {
self.present_commands.remove(command_id)
}
})
.map(|(_, command_name)| command_name.as_str())
.collect()
}
}

fn scan_toolbar_for_command_id(command_id: CommandId) -> Option<u32> {
Expand Down
30 changes: 19 additions & 11 deletions main/src/infrastructure/plugin/hidden_helper_panel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ pub struct HiddenHelperPanel {
view: ViewContext,
}

const TIMER_ID: usize = 322;
const PLAYTIME_ENGINE_STATS_TIMER_ID: usize = 322;
const HELGOBOX_TOOLBAR_CHECK_TIMER_ID: usize = 323;

impl HiddenHelperPanel {
pub fn new() -> Self {
Expand All @@ -30,7 +31,8 @@ impl View for HiddenHelperPanel {
}

fn opened(self: SharedView<Self>, window: Window) -> bool {
window.set_timer(TIMER_ID, Duration::from_millis(200));
window.set_timer(PLAYTIME_ENGINE_STATS_TIMER_ID, Duration::from_millis(200));
window.set_timer(HELGOBOX_TOOLBAR_CHECK_TIMER_ID, Duration::from_millis(3000));
false
}

Expand All @@ -39,15 +41,21 @@ impl View for HiddenHelperPanel {
}

fn timer(&self, id: usize) -> bool {
if id != TIMER_ID {
return false;
match id {
PLAYTIME_ENGINE_STATS_TIMER_ID => {
#[cfg(feature = "playtime")]
{
BackboneShell::get()
.proto_hub()
.notify_engine_stats_changed();
}
true
}
HELGOBOX_TOOLBAR_CHECK_TIMER_ID => {
BackboneShell::get().disable_manually_removed_dynamic_toolbar_buttons();
true
}
_ => false,
}
#[cfg(feature = "playtime")]
{
BackboneShell::get()
.proto_hub()
.notify_engine_stats_changed()
}
true
}
}
2 changes: 1 addition & 1 deletion main/src/infrastructure/plugin/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ mod actions;
mod ini_util;
pub use actions::*;

mod dynamic_toolbar;
pub mod dynamic_toolbar;
mod hidden_helper_panel;
pub mod persistent_toolbar;
mod sandbox;
Expand Down
11 changes: 1 addition & 10 deletions main/src/infrastructure/ui/welcome_panel.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use enumset::EnumSet;
use reaper_high::Reaper;
use reaper_low::raw;
use std::fmt::Debug;

use crate::base::notification::alert;
use crate::infrastructure::plugin::dynamic_toolbar::custom_toolbar_api_is_available;
use crate::infrastructure::plugin::{
BackboneShell, ACTION_SHOW_HIDE_PLAYTIME_COMMAND_NAME, ACTION_SHOW_WELCOME_SCREEN_LABEL,
};
Expand Down Expand Up @@ -86,15 +86,6 @@ impl View for WelcomePanel {
}
}

fn custom_toolbar_api_is_available() -> bool {
Reaper::get()
.medium_reaper()
.low()
.pointers()
.GetCustomMenuOrToolbarItem
.is_some()
}

impl WelcomePanel {
fn invalidate_controls(&self) {
if custom_toolbar_api_is_available() {
Expand Down

0 comments on commit 3de9f41

Please sign in to comment.