diff --git a/README.md b/README.md
index 1fa6e77d..7d00c727 100644
--- a/README.md
+++ b/README.md
@@ -69,6 +69,17 @@ Touchpad: NEXTRELEASE
If out of range select custom color 0.21.0
+#### Size Selection NEXTRELEASE
+
+In the bottom toolbar the size can be edited directly or by + and - buttons.
+Minimum is 0.1 and maximum to 99.99.
+
+The bindings are:
+- Mouse left-button, wheel and key up/down step size is 0.1
+- Holding Shift will switch to 0.01 step size
+- Mouse middle-button and page up/page down step size is 1.0
+- Mouse right-button jumps to minimum/maximum
+
#### Tool Selection Shortcuts (configurable) 0.20.0
Default single-key shortcuts:
- p: Pointer tool
diff --git a/src/sketch_board.rs b/src/sketch_board.rs
index 61fa2e00..464a15fe 100644
--- a/src/sketch_board.rs
+++ b/src/sketch_board.rs
@@ -795,6 +795,10 @@ impl SketchBoard {
sender: ComponentSender,
) -> ToolUpdateResult {
match toolbar_event {
+ ToolbarEvent::FocusCanvas => {
+ self.renderer.grab_focus();
+ ToolUpdateResult::Unmodified
+ }
ToolbarEvent::ToolSelected(tool) => {
// deactivate old tool and save drawable, if any
let old_tool = self.active_tool.clone();
@@ -867,7 +871,7 @@ impl SketchBoard {
.borrow_mut()
.handle_event(ToolEvent::StyleChanged(self.style))
}
- ToolbarEvent::AnnotationSizeChanged(value) => {
+ ToolbarEvent::AnnotationSizeFactorChanged(value) => {
self.style.annotation_size_factor = value;
self.active_tool
.borrow_mut()
@@ -1232,6 +1236,12 @@ impl Component for SketchBoard {
}
}
} else {
+ if let InputEvent::Mouse(me) = &ie
+ && matches!(me.type_, MouseEventType::Click | MouseEventType::BeginDrag)
+ {
+ self.renderer.grab_focus();
+ }
+
ie.handle_event_mouse_input(&self.renderer);
let active_tool_result = self
.active_tool
diff --git a/src/ui/toolbars.rs b/src/ui/toolbars.rs
index 82ee61ac..fbbdda45 100644
--- a/src/ui/toolbars.rs
+++ b/src/ui/toolbars.rs
@@ -7,10 +7,13 @@ use crate::{
};
use gtk::ToggleButton;
-use relm4::gtk::gdk_pixbuf::{
- Pixbuf,
- gio::SimpleAction,
- glib::{Variant, VariantTy},
+use relm4::gtk::{
+ gdk::Key,
+ gdk_pixbuf::{
+ Pixbuf,
+ gio::SimpleAction,
+ glib::{Variant, VariantTy},
+ },
};
use relm4::{
actions::{ActionablePlus, RelmAction, RelmActionGroup},
@@ -30,18 +33,12 @@ pub struct StyleToolbar {
custom_color_pixbuf: Pixbuf,
color_action: SimpleAction,
visible: bool,
- annotation_size: f32,
- annotation_size_formatted: String,
- annotation_dialog_controller: Option>,
output_dimensions: String,
}
-pub struct AnnotationSizeDialog {
- annotation_size: f32,
-}
-
#[derive(Debug, Copy, Clone)]
pub enum ToolbarEvent {
+ FocusCanvas,
ToolSelected(Tools),
ColorSelected(Color),
SizeSelected(Size),
@@ -50,7 +47,7 @@ pub enum ToolbarEvent {
SaveFile,
CopyClipboard,
ToggleFill,
- AnnotationSizeChanged(f32),
+ AnnotationSizeFactorChanged(f32),
Reset,
SaveFileAs,
Resize,
@@ -72,26 +69,9 @@ pub enum StyleToolbarInput {
ColorDialogFinished(Option),
SetVisibility(bool),
ToggleVisibility,
- ShowAnnotationDialog,
- AdjustAnnotationSize(f32),
- AnnotationDialogFinished(Option),
DimensionsChanged((i32, i32)),
}
-#[derive(Debug, Copy, Clone)]
-pub enum AnnotationSizeDialogInput {
- ValueChanged(f32),
- Reset,
- Show(f32),
- Submit,
- Cancel,
-}
-
-#[derive(Debug, Copy, Clone)]
-pub enum AnnotationSizeDialogOutput {
- AnnotationSizeSubmitted(f32),
-}
-
fn create_icon_pixbuf(color: Color) -> Pixbuf {
let pixbuf = Pixbuf::new(relm4::gtk::gdk_pixbuf::Colorspace::Rgb, false, 8, 40, 40).unwrap();
pixbuf.fill(color.to_rgba_u32());
@@ -407,17 +387,6 @@ pub enum ColorButtons {
}
impl StyleToolbar {
- fn set_annotation_size(&mut self, value: f32) -> bool {
- let value = value.clamp(0.0, 100.0);
- if (self.annotation_size - value).abs() < f32::EPSILON {
- return false;
- }
-
- self.annotation_size = value;
- self.annotation_size_formatted = format!("{value:.2}");
- true
- }
-
fn show_color_dialog(&self, sender: ComponentSender, root: Option) {
let current_color: RGBA = self.custom_color.into();
relm4::spawn_local(async move {
@@ -475,33 +444,6 @@ impl StyleToolbar {
ColorButtons::Custom => self.custom_color,
}
}
-
- fn show_annotation_dialog(
- &mut self,
- sender: ComponentSender,
- root: Option,
- ) {
- if self.annotation_dialog_controller.is_none() {
- let mut builder = AnnotationSizeDialog::builder();
- if let Some(w) = root {
- builder = builder.transient_for(&w);
- }
-
- let connector = builder.launch(self.annotation_size);
-
- let mut controller = connector.forward(sender.input_sender(), |output| match output {
- AnnotationSizeDialogOutput::AnnotationSizeSubmitted(value) => {
- StyleToolbarInput::AnnotationDialogFinished(Some(value))
- }
- });
-
- controller.detach_runtime();
- self.annotation_dialog_controller = Some(controller);
- }
-
- let ctrl = self.annotation_dialog_controller.as_mut().unwrap();
- ctrl.emit(AnnotationSizeDialogInput::Show(self.annotation_size));
- }
}
#[relm4::component(pub)]
@@ -575,24 +517,45 @@ impl Component for StyleToolbar {
set_text: "x",
},
- gtk::Button {
- set_focusable: false,
+ #[name(size_spin_button)]
+ gtk::SpinButton {
+ set_focusable: true,
set_hexpand: false,
-
- #[watch]
- set_label: &model.annotation_size_formatted,
set_tooltip: "Edit Annotation Size Factor",
+ set_adjustment: >k::Adjustment::new(
+ APP_CONFIG.read().annotation_size_factor() as f64,
+ 0.1, 99.99, // min, max
+ 0.1, 1.0, // step sizes
+ 0.0),
+ set_numeric: true,
+ set_digits: 2,
+ set_width_chars: 4,
+ set_alignment: 1.0,
+
+ connect_value_changed[sender] => move |spin_button| {
+ let new_value = spin_button.value();
+ sender.output_sender().emit(ToolbarEvent::AnnotationSizeFactorChanged(new_value as f32));
+ },
+
+ add_controller = gtk::EventControllerKey {
+ set_propagation_phase: gtk::PropagationPhase::Capture,
+ connect_key_pressed[sender, size_spin_button] => move |_, keyval, _, _| {
+ if matches!(keyval, Key::Escape | Key::Return | Key::KP_Enter | Key::ISO_Enter) {
+ sender.output_sender().emit(ToolbarEvent::FocusCanvas);
+ return relm4::gtk::glib::Propagation::Stop;
+ }
+
+ if matches!(keyval, Key::Shift_L | Key::Shift_R) {
+ size_spin_button.adjustment().set_step_increment(0.01);
+ }
- connect_clicked => StyleToolbarInput::ShowAnnotationDialog,
- add_controller = gtk::EventControllerScroll {
- set_flags: gtk::EventControllerScrollFlags::VERTICAL,
- connect_scroll[sender] => move |_, _, dy| {
- if dy != 0.0 {
- sender.input(StyleToolbarInput::AdjustAnnotationSize(
- if dy.is_sign_positive() { -0.01 } else { 0.01 }
- ));
+ relm4::gtk::glib::Propagation::Proceed
+ },
+
+ connect_key_released[size_spin_button] => move |_, keyval, _, _| {
+ if matches!(keyval, Key::Shift_L | Key::Shift_R) {
+ size_spin_button.adjustment().set_step_increment(0.1);
}
- relm4::gtk::glib::Propagation::Stop
},
},
},
@@ -659,29 +622,6 @@ impl Component for StyleToolbar {
.emit(ToolbarEvent::ColorSelected(color));
}
- StyleToolbarInput::ShowAnnotationDialog => {
- self.show_annotation_dialog(sender, root.toplevel_window());
- }
-
- StyleToolbarInput::AdjustAnnotationSize(delta) => {
- let value = self.annotation_size + delta;
- if self.set_annotation_size(value) {
- sender
- .output_sender()
- .emit(ToolbarEvent::AnnotationSizeChanged(value));
- }
- }
-
- StyleToolbarInput::AnnotationDialogFinished(value) => {
- if let Some(value) = value
- && self.set_annotation_size(value)
- {
- sender
- .output_sender()
- .emit(ToolbarEvent::AnnotationSizeChanged(value));
- }
- }
-
StyleToolbarInput::SetVisibility(visible) => self.visible = visible,
StyleToolbarInput::ToggleVisibility => {
self.visible = !self.visible;
@@ -750,12 +690,6 @@ impl Component for StyleToolbar {
custom_color_pixbuf,
color_action: SimpleAction::from(color_action.clone()),
visible: !APP_CONFIG.read().default_hide_toolbars(),
- annotation_size: APP_CONFIG.read().annotation_size_factor(),
- annotation_size_formatted: format!(
- "{0:.2}",
- APP_CONFIG.read().annotation_size_factor()
- ),
- annotation_dialog_controller: None,
output_dimensions: String::new(),
};
@@ -814,149 +748,3 @@ impl FromVariant for ColorButtons {
})
}
}
-
-#[relm4::component(pub)]
-impl Component for AnnotationSizeDialog {
- type Init = f32;
- type Input = AnnotationSizeDialogInput;
- type Output = AnnotationSizeDialogOutput;
- type CommandOutput = ();
-
- view! {
- gtk::Window {
- set_modal: true,
- set_title: Some("Choose Annotation Size"),
- set_titlebar: Some(&header_bar),
-
- #[wrap(Some)]
- set_child = >k::Box {
- set_spacing: 10,
- set_margin_all: 12,
- set_orientation: gtk::Orientation::Horizontal,
-
- #[name = "spin"]
- gtk::SpinButton {
- set_editable: true,
- set_can_focus: true,
- set_hexpand: false,
-
- set_tooltip: "Annotation Size Factor",
- set_numeric: true,
- set_adjustment: >k::Adjustment::new(0.0, 0.0, 100.0, 0.01, 0.1, 0.0),
- set_climb_rate: 0.1,
- set_digits: 2,
- #[watch]
- #[block_signal(value_changed)]
- set_value: model.annotation_size.into(),
-
- connect_value_changed[sender] => move |button| {
- sender.input(AnnotationSizeDialogInput::ValueChanged(button.value() as f32));
- } @value_changed,
- },
- #[name = "spin_reset"]
- gtk::Button {
- set_focusable: false,
- set_hexpand: false,
-
- set_tooltip: "Reset Annotation Size Factor",
- set_icon_name: "arrow-counterclockwise-regular",
- connect_clicked[sender] => move |_| {
- sender.input(AnnotationSizeDialogInput::Reset);
- },
- },
-
- },
- }
- }
-
- fn init(
- init_value: f32,
- root: Self::Root,
- sender: ComponentSender,
- ) -> ComponentParts {
- let model = AnnotationSizeDialog {
- annotation_size: init_value,
- };
-
- // the title bar didn't really work within the view! macro.
- let title_label = gtk::Label::builder()
- .label("Choose Annotation Size")
- .margin_start(6)
- .build();
-
- let cancel_button = gtk::Button::builder().label("Cancel").build();
- let sender_clone = sender.clone();
- cancel_button.connect_clicked(move |_| {
- sender_clone.input(AnnotationSizeDialogInput::Cancel);
- });
-
- let ok_button = gtk::Button::builder().label("OK").build();
-
- let sender_clone = sender.clone();
- ok_button.connect_clicked(move |_| {
- sender_clone.input(AnnotationSizeDialogInput::Submit);
- });
-
- let header_bar = gtk::HeaderBar::builder().show_title_buttons(false).build();
-
- header_bar.set_title_widget(Some(&title_label));
- header_bar.pack_start(&cancel_button);
- header_bar.pack_end(&ok_button);
-
- let widgets = view_output!();
-
- let key_controller = gtk::EventControllerKey::builder()
- // not sure if this is the correct phase, but anything higher and Enter to close doesn't work consistently
- .propagation_phase(gtk::PropagationPhase::Capture)
- .build();
-
- key_controller.connect_key_pressed(move |_, keyval, _, _| {
- use gtk::gdk::Key;
- match keyval {
- Key::Return => {
- sender.input(AnnotationSizeDialogInput::Submit);
- relm4::gtk::glib::Propagation::Stop
- }
- Key::Escape => {
- sender.input(AnnotationSizeDialogInput::Cancel);
- relm4::gtk::glib::Propagation::Stop
- }
- _ => relm4::gtk::glib::Propagation::Proceed,
- }
- });
- root.add_controller(key_controller);
-
- ComponentParts { model, widgets }
- }
-
- fn update(
- &mut self,
- message: AnnotationSizeDialogInput,
- sender: ComponentSender,
- root: &Self::Root,
- ) {
- match message {
- AnnotationSizeDialogInput::ValueChanged(value) => self.annotation_size = value,
- AnnotationSizeDialogInput::Reset => {
- let a = APP_CONFIG.read().annotation_size_factor();
- self.annotation_size = a;
- }
- AnnotationSizeDialogInput::Show(value) => {
- self.annotation_size = value;
- root.show();
- }
- AnnotationSizeDialogInput::Cancel => {
- root.hide();
- }
- AnnotationSizeDialogInput::Submit => {
- // yeah, not sure if this can even happen.
- if let Err(e) = sender.output(AnnotationSizeDialogOutput::AnnotationSizeSubmitted(
- self.annotation_size,
- )) {
- eprintln!("Error submitting annotation size factor: {e:?}");
- }
- root.hide();
- }
- }
- }
-}