forked from 1b-agent/opencadstudio-upstream
Merge pull request #1299: Add Windows SpaceMouse navigation
This commit is contained in:
commit
af847ad92e
32 files changed
+3508
-12
No files matched your search
@@ -1,6 +1,7 @@
|
||||
//! Bottom status bar — Model/Layout tabs + OSNAP toggle + status info
|
||||
|
||||
pub mod status_menu;
|
||||
pub(crate) mod spacemouse;
|
||||
pub mod statusbar_config;
|
||||
pub mod statusbar_menu;
|
||||
|
||||
@@ -135,6 +136,7 @@ impl StatusBar {
|
||||
parametric_conflicts: usize,
|
||||
// What is drawing the scene. Only a degraded verdict shows anything.
|
||||
gpu_status: &'a crate::scene::pipeline::GpuStatus,
|
||||
spacemouse: Option<Element<'a, Message>>,
|
||||
) -> Element<'a, Message> {
|
||||
let StatusMenuData {
|
||||
layout_names,
|
||||
@@ -241,6 +243,11 @@ impl StatusBar {
|
||||
// when the width can't hold them all on one line.
|
||||
let vis = |p: StatusPill| config.is_visible(p);
|
||||
let mut pills: Vec<Element<'_, Message>> = Vec::new();
|
||||
if vis(StatusPill::SpaceMouse) {
|
||||
if let Some(pill) = spacemouse {
|
||||
pills.push(pill);
|
||||
}
|
||||
}
|
||||
// Not a `StatusPill` and not hideable: the scene is on a software
|
||||
// rasterizer or not drawn at all, and the popup that said so has been
|
||||
// dismissed. This stays for the session and reopens it. Many people
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
use super::status_menu::{self, Entry};
|
||||
use crate::app::Message;
|
||||
use crate::input::spacemouse::{NavigationMode, Preferences, Status};
|
||||
use iced::widget::{button, row, text};
|
||||
use iced::{Element, Fill};
|
||||
|
||||
pub(crate) fn view(
|
||||
preferences: Preferences,
|
||||
status: Status,
|
||||
paused: bool,
|
||||
label: String,
|
||||
sheet: bool,
|
||||
) -> Element<'static, Message> {
|
||||
let root = button(
|
||||
row![
|
||||
crate::ui::icons::themed(crate::ui::window::options::spacemouse::ICON, 15.),
|
||||
text(label).size(11),
|
||||
crate::ui::icons::themed_arrow_toggle(false, 8.)
|
||||
]
|
||||
.spacing(5)
|
||||
.align_y(iced::Center),
|
||||
)
|
||||
.padding([3, 6])
|
||||
.style(button::subtle);
|
||||
let mut entries = vec![Entry::stay(
|
||||
text(format!("SpaceMouse · {}", crate::t!(status.label()))).size(11),
|
||||
)];
|
||||
for mode in NavigationMode::ALL {
|
||||
let label = format!(
|
||||
"{} {}",
|
||||
if mode == preferences.mode {
|
||||
"●"
|
||||
} else {
|
||||
"○"
|
||||
},
|
||||
crate::t!(mode.label())
|
||||
);
|
||||
entries.push(Entry::close(
|
||||
button(text(label).size(12))
|
||||
.width(Fill)
|
||||
.padding([7, 10])
|
||||
.style(button::text)
|
||||
.on_press(Message::SpaceMouseMode(mode)),
|
||||
));
|
||||
}
|
||||
if sheet {
|
||||
entries.push(Entry::stay(
|
||||
text(crate::t!("Paper sheets keep rotation locked.")).size(11),
|
||||
));
|
||||
}
|
||||
entries.push(Entry::close(
|
||||
button(
|
||||
text(crate::t!(if paused {
|
||||
"Resume SpaceMouse"
|
||||
} else {
|
||||
"Pause SpaceMouse"
|
||||
}))
|
||||
.size(12),
|
||||
)
|
||||
.on_press(Message::SpaceMousePause)
|
||||
.style(button::text)
|
||||
.width(Fill)
|
||||
.padding([7, 10]),
|
||||
));
|
||||
for (label, message) in [
|
||||
("SpaceMouse preferences…", Message::SpaceMousePreferences),
|
||||
("3Dconnexion settings…", Message::SpaceMouseDriverSettings),
|
||||
] {
|
||||
entries.push(Entry::close(
|
||||
button(text(crate::t!(label)).size(12))
|
||||
.on_press(message)
|
||||
.style(button::text)
|
||||
.width(Fill)
|
||||
.padding([7, 10]),
|
||||
));
|
||||
}
|
||||
status_menu::menu_bar(root, entries, 260.)
|
||||
}
|
||||
@@ -11,6 +11,7 @@ use serde::{Deserialize, Serialize};
|
||||
/// Identifies a toggleable status-bar pill.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
|
||||
pub enum StatusPill {
|
||||
SpaceMouse,
|
||||
Coords,
|
||||
Ortho,
|
||||
Lwt,
|
||||
@@ -37,6 +38,7 @@ impl StatusPill {
|
||||
/// Every pill, in status-bar display order. Drives both the bar layout and
|
||||
/// the customization menu.
|
||||
pub const ALL: &'static [StatusPill] = &[
|
||||
StatusPill::SpaceMouse,
|
||||
StatusPill::Coords,
|
||||
StatusPill::Ortho,
|
||||
StatusPill::Lwt,
|
||||
@@ -62,6 +64,7 @@ impl StatusPill {
|
||||
/// Stable identifier used for persistence.
|
||||
pub fn id(self) -> &'static str {
|
||||
match self {
|
||||
StatusPill::SpaceMouse => "spacemouse",
|
||||
StatusPill::Coords => "coords",
|
||||
StatusPill::Ortho => "ortho",
|
||||
StatusPill::Lwt => "lwt",
|
||||
@@ -88,6 +91,7 @@ impl StatusPill {
|
||||
/// Label shown in the customization menu.
|
||||
pub fn label(self) -> &'static str {
|
||||
match self {
|
||||
StatusPill::SpaceMouse => "SpaceMouse",
|
||||
StatusPill::Coords => "Coordinates",
|
||||
StatusPill::Ortho => "Ortho Mode",
|
||||
StatusPill::Lwt => "Show Lineweight",
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
pub(crate) mod spacemouse;
|
||||
use crate::app::config::UiThemeConfig;
|
||||
use crate::app::settings::CursorType;
|
||||
use crate::app::Message;
|
||||
@@ -153,6 +154,7 @@ pub fn view_window<'a>(
|
||||
cursor_size: i32,
|
||||
selection: SelectionPrefs,
|
||||
prefs: AppPrefs,
|
||||
spacemouse: Element<'a, Message>,
|
||||
snap_angle_input: &'a str,
|
||||
drawing_prefs: DrawingPrefs,
|
||||
folders: Folders,
|
||||
@@ -1135,6 +1137,8 @@ pub fn view_window<'a>(
|
||||
let user_prefs = column![
|
||||
text(crate::t!("User Preferences")).size(15),
|
||||
Space::new().height(10),
|
||||
spacemouse,
|
||||
Space::new().height(12),
|
||||
text(crate::t!("Zoom")).size(15),
|
||||
Space::new().height(10),
|
||||
row![
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
use crate::app::Message;
|
||||
use crate::input::spacemouse::{NavigationMode, Preferences, Status};
|
||||
use iced::widget::{button, checkbox, column, container, pick_list, row, slider, text, Space};
|
||||
use iced::{Element, Fill};
|
||||
|
||||
pub(crate) const ICON: &[u8] = include_bytes!("../../../../assets/icons/ui/spacemouse.svg");
|
||||
|
||||
pub(crate) fn view(
|
||||
preferences: Preferences,
|
||||
status: Status,
|
||||
paused: bool,
|
||||
details: bool,
|
||||
) -> Element<'static, Message> {
|
||||
let supported = cfg!(windows);
|
||||
let mut enabled = checkbox(preferences.enabled).size(15);
|
||||
if supported {
|
||||
enabled = enabled.on_toggle(Message::SpaceMouseEnabled);
|
||||
}
|
||||
let mode = pick_list(Some(preferences.mode), NavigationMode::ALL, |mode| {
|
||||
crate::t!(mode.label()).into_owned()
|
||||
})
|
||||
.width(220);
|
||||
let mode = if supported {
|
||||
mode.on_select(Message::SpaceMouseMode)
|
||||
} else {
|
||||
mode
|
||||
};
|
||||
let status_text = if !preferences.enabled {
|
||||
crate::t!("Disabled").into_owned()
|
||||
} else if paused {
|
||||
crate::t!("Paused").into_owned()
|
||||
} else {
|
||||
crate::t!(status.label()).into_owned()
|
||||
};
|
||||
let mut content = column![
|
||||
row![
|
||||
crate::ui::icons::themed(ICON, 22.),
|
||||
text(crate::t!("SpaceMouse")).size(15)
|
||||
]
|
||||
.spacing(8)
|
||||
.align_y(iced::Center),
|
||||
row![enabled, text(crate::t!("Enable SpaceMouse")).size(12)]
|
||||
.spacing(8)
|
||||
.align_y(iced::Center),
|
||||
row![
|
||||
text(crate::t!("Status")).size(12).width(150),
|
||||
text(status_text).size(12)
|
||||
]
|
||||
.spacing(10),
|
||||
row![text(crate::t!("Navigation")).size(12).width(150), mode]
|
||||
.spacing(10)
|
||||
.align_y(iced::Center),
|
||||
text(crate::t!(preferences.mode.description()).into_owned())
|
||||
.size(11)
|
||||
.width(Fill),
|
||||
]
|
||||
.spacing(12);
|
||||
if preferences.mode != NavigationMode::Full3D && supported {
|
||||
content = content.push(
|
||||
row![
|
||||
checkbox(preferences.pan_reversed)
|
||||
.size(15)
|
||||
.on_toggle(Message::SpaceMousePanReversed),
|
||||
text(crate::t!("Reverse pan direction")).size(12),
|
||||
]
|
||||
.spacing(8)
|
||||
.align_y(iced::Center),
|
||||
);
|
||||
content = content.push(
|
||||
row![
|
||||
text(crate::t!("Pan speed")).size(12).width(150),
|
||||
slider(
|
||||
10..=300,
|
||||
preferences.pan_speed.clamp(10, 300),
|
||||
Message::SpaceMousePanSpeed
|
||||
)
|
||||
.step(10)
|
||||
.width(160),
|
||||
text(format!("{}%", preferences.pan_speed.clamp(10, 300))).size(11),
|
||||
]
|
||||
.spacing(10)
|
||||
.align_y(iced::Center),
|
||||
);
|
||||
}
|
||||
if paused {
|
||||
content = content.push(
|
||||
button(text(crate::t!("Resume SpaceMouse")).size(11))
|
||||
.on_press(Message::SpaceMousePause)
|
||||
.style(button::secondary),
|
||||
);
|
||||
}
|
||||
content = content.push(
|
||||
button(
|
||||
text(crate::t!(if supported {
|
||||
"Open 3Dconnexion settings…"
|
||||
} else {
|
||||
"SpaceMouse information…"
|
||||
}))
|
||||
.size(11),
|
||||
)
|
||||
.on_press(Message::SpaceMouseDriverSettings)
|
||||
.style(button::secondary)
|
||||
.padding([5, 10]),
|
||||
);
|
||||
content = content.push(
|
||||
text(crate::t!(
|
||||
"Configure 3D navigation, buttons, and radial menus in 3Dconnexion settings. Pan only and Pan and zoom share the push/tilt mapping and pan settings shown here."
|
||||
))
|
||||
.size(11)
|
||||
.width(Fill),
|
||||
);
|
||||
content = content.push(
|
||||
button(
|
||||
row![
|
||||
crate::ui::icons::themed_arrow_toggle(details, 9.),
|
||||
text(crate::t!("Connection details")).size(11)
|
||||
]
|
||||
.spacing(6),
|
||||
)
|
||||
.on_press(Message::SpaceMouseDetails)
|
||||
.style(button::text),
|
||||
);
|
||||
if details {
|
||||
let detail = match status {
|
||||
Status::Unavailable(reason) => reason,
|
||||
Status::Unsupported => "This version supports SpaceMouse through 3DxWare on Windows. Other platforms do not yet have a device adapter.".into(),
|
||||
Status::Disconnected => "3DxWare is running. Connect a SpaceMouse; Open CAD Studio reconnects automatically.".into(),
|
||||
_ => "Uses the installed 3DxWare driver. Navigation pauses while a dialog is open. Your selected navigation mode is saved across drawings and sessions.".into(),
|
||||
};
|
||||
content = content.push(text(crate::t!(&detail).into_owned()).size(11).width(Fill));
|
||||
}
|
||||
container(content.push(Space::new().height(8)))
|
||||
.width(Fill)
|
||||
.into()
|
||||
}
|
||||
Reference in new issue
Block a user