Skip to content

Commit

Permalink
High-level API: Add support for non-main actions
Browse files Browse the repository at this point in the history
  • Loading branch information
helgoboss committed Aug 24, 2024
1 parent 502c84c commit f86bc31
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 24 deletions.
63 changes: 48 additions & 15 deletions main/high/src/action.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
use crate::{ActionCharacter, Project, Reaper, ReaperError, ReaperResult, Section};
use c_str_macro::c_str;
use reaper_medium::{
AcceleratorBehavior, AcceleratorKeyCode, ActionValueChange, CommandId, ProjectContext,
AcceleratorBehavior, AcceleratorKeyCode, ActionValueChange, CommandId, Hwnd, ProjectContext,
ReaperStr, ReaperString, SectionContext, WindowContext,
};

use helgoboss_midi::{U14, U7};
use reaper_medium::ProjectContext::{CurrentProject, Proj};
use reaper_medium::SectionContext::Sec;
use reaper_medium::WindowContext::Win;
use std::borrow::Cow;
use std::cell::{Ref, RefCell};

use enumflags2::BitFlags;
use reaper_low::{raw, Swell};
use std::ffi::CString;

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
Expand Down Expand Up @@ -209,19 +209,28 @@ impl Action {
Ok(name)
}

pub fn invoke_as_trigger(&self, project: Option<Project>) -> ReaperResult<()> {
self.invoke_absolute(1.0, project, false)
pub fn invoke_as_trigger(
&self,
project: Option<Project>,
window: Option<Hwnd>,
) -> ReaperResult<()> {
self.invoke_absolute(1.0, project, false, window)
}

pub fn invoke_relative(&self, amount: i32, project: Option<Project>) -> ReaperResult<()> {
pub fn invoke_relative(
&self,
amount: i32,
project: Option<Project>,
window: Option<Hwnd>,
) -> ReaperResult<()> {
let relative_value = 64 + amount;
let cropped_relative_value =
unsafe { U7::new_unchecked(relative_value.clamp(0, 127) as u8) };
// reaper::kbd_RunCommandThroughHooks(section_.sectionInfo(), &actionCommandId, &val,
// &valhw, &relmode, reaper::GetMainHwnd());
self.invoke_directly(
ActionValueChange::Relative2(cropped_relative_value),
Win(Reaper::get().medium_reaper().get_main_hwnd()),
window,
match project {
None => CurrentProject,
Some(p) => Proj(p.raw()),
Expand All @@ -234,6 +243,7 @@ impl Action {
normalized_value: f64,
project: Option<Project>,
enforce_7_bit_control: bool,
window: Option<Hwnd>,
) -> ReaperResult<()> {
// TODO-low I have no idea how to launch an action in a specific section. The first function
// doesn't seem to launch the action :(
Expand All @@ -255,7 +265,7 @@ impl Action {
};
self.invoke_directly(
value_change,
Win(Reaper::get().medium_reaper().get_main_hwnd()),
window,
match project {
None => CurrentProject,
Some(p) => Proj(p.raw()),
Expand All @@ -269,18 +279,41 @@ impl Action {
pub fn invoke_directly(
&self,
value_change: ActionValueChange,
window: WindowContext,
window: Option<Hwnd>,
project: ProjectContext,
) -> ReaperResult<()> {
let rd = self.load_if_necessary_or_complain()?;
let action_command_id = rd.command_id;
unsafe {
Reaper::get().medium_reaper.kbd_on_main_action_ex(
action_command_id,
value_change,
window,
project,
);
let window_context = window
.map(WindowContext::Win)
.unwrap_or(WindowContext::NoWindow);
let reaper = &Reaper::get().medium_reaper;
match rd.section.id().get() {
32060 | 32061 => {
// MIDI editor
let hwnd = window.ok_or("no MIDI editor window available")?;
reaper.midi_editor_on_command(hwnd, action_command_id)?
}
32063 => {
// Media explorer
let hwnd = window.ok_or("no media explorer window available")?;
unsafe {
Swell::get().PostMessage(
hwnd.as_ptr(),
raw::WM_COMMAND,
action_command_id.get() as _,
0,
);
}
}
_ => unsafe {
reaper.kbd_on_main_action_ex(
action_command_id,
value_change,
window_context,
project,
);
},
}
Ok(())
}
Expand Down
8 changes: 6 additions & 2 deletions main/high/src/reaper_simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,11 @@ impl Reaper {
}

pub fn main_section(&self) -> Section {
Section::new(SectionId::new(0))
self.section_by_id(SectionId::new(0))
}

pub fn section_by_id(&self, id: SectionId) -> Section {
Section::new(id)
}

pub fn monitoring_fx_chain(&self) -> FxChain {
Expand Down Expand Up @@ -344,7 +348,7 @@ impl Reaper {
pub fn create_empty_project_in_new_tab(&self) -> Project {
self.main_section()
.action_by_command_id(CommandId::new(41929))
.invoke_as_trigger(None)
.invoke_as_trigger(None, None)
.expect("built-in action for creating empty project must exist");
self.current_project()
}
Expand Down
39 changes: 35 additions & 4 deletions main/medium/src/reaper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3077,6 +3077,32 @@ impl<UsageScope> Reaper<UsageScope> {
Ok(())
}

/// Sends an action command to the given MIDI editor.
///
/// # Errors
///
/// Returns an error if the supplied MIDI editor pointer is not valid (not an open MIDI editor).
pub fn midi_editor_on_command(
&self,
midi_editor: Hwnd,
command_id: CommandId,
) -> ReaperFunctionResult<()>
where
UsageScope: MainThreadOnly,
{
self.require_main_thread();
let successful = unsafe {
self.low
.MIDIEditor_OnCommand(midi_editor.as_ptr(), command_id.to_raw())
};
if !successful {
return Err(ReaperFunctionError::new(
"given window is not an open MIDI editor",
));
}
Ok(())
}

/// Informs control surfaces that the given track's mute state has changed.
///
/// Doesn't actually change the mute state.
Expand Down Expand Up @@ -8287,16 +8313,21 @@ impl<UsageScope> Reaper<UsageScope> {
/// play=true will play the file immediately (or toggle playback if mediafn was already open), =false will just select it.
///
/// When in doubt, it returns 0.0 (center).
pub fn open_media_explorer(&self, file_name: &Utf8Path, mode: OpenMediaExplorerMode)
pub fn open_media_explorer(
&self,
file_name: &Utf8Path,
mode: OpenMediaExplorerMode,
) -> Option<Hwnd>
where
UsageScope: MainThreadOnly,
{
self.require_main_thread();
let file_name_reaper_string = convert_path_to_reaper_string(file_name);
unsafe {
let ptr = unsafe {
self.low
.OpenMediaExplorer(file_name_reaper_string.as_ptr(), mode.to_raw());
}
.OpenMediaExplorer(file_name_reaper_string.as_ptr(), mode.to_raw())
};
Hwnd::new(ptr)
}

// TODO-high document
Expand Down
6 changes: 3 additions & 3 deletions test/test/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -473,7 +473,7 @@ fn register_and_unregister_toggle_action() -> TestStep {
assert!(action.is_available());
assert_eq!(mock.invocation_count(), 0);
assert_eq!(action.is_on()?, Some(false));
action.invoke_as_trigger(None)?;
action.invoke_as_trigger(None, None)?;
assert_eq!(mock.invocation_count(), 1);
assert_eq!(mock.last_arg(), 43);
assert_eq!(action.is_on()?, Some(true));
Expand Down Expand Up @@ -511,7 +511,7 @@ fn register_and_unregister_action() -> TestStep {
// Then
assert!(action.is_available());
assert_eq!(mock.invocation_count(), 0);
action.invoke_as_trigger(None)?;
action.invoke_as_trigger(None, None)?;
assert_eq!(mock.invocation_count(), 1);
assert_eq!(mock.last_arg(), 42);
assert_eq!(action.character()?, ActionCharacter::Trigger);
Expand Down Expand Up @@ -710,7 +710,7 @@ fn invoke_action() -> TestStep {
mock.invoke(t);
});
});
action.invoke_as_trigger(None)?;
action.invoke_as_trigger(None, None)?;
// Then
assert_eq!(action.is_on()?, Some(true));
assert!(track.is_muted());
Expand Down

0 comments on commit f86bc31

Please sign in to comment.