aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRubén Beltrán del Río <jj@r.bdr.sh>2026-03-26 23:18:11 +0100
committerRubén Beltrán del Río <jj@r.bdr.sh>2026-03-26 23:26:01 +0100
commit1f28cbdf1dbe26e4c7da27323a0202a3276cb3a7 (patch)
treef5a707ed5671d0345b21c935f5a46099b12b8f19 /src
parent9a472115e594e28f4e3bd95b10800bf2b690febf (diff)
Move footer to its own component
Diffstat (limited to 'src')
-rw-r--r--src/components/footer.rs97
-rw-r--r--src/components/mod.rs1
-rw-r--r--src/handlers/zoom.rs10
-rw-r--r--src/main.rs59
4 files changed, 117 insertions, 50 deletions
diff --git a/src/components/footer.rs b/src/components/footer.rs
new file mode 100644
index 0000000..2576163
--- /dev/null
+++ b/src/components/footer.rs
@@ -0,0 +1,97 @@
+use gtk::prelude::*;
+use relm4::prelude::*;
+use relm4::actions::ActionablePlus;
+
+use crate::tr;
+use crate::constants;
+
+use crate::{
+ ZoomInAction, ZoomOutAction, actions::Action
+};
+use crate::icon_names::shipped::{ ZOOM_IN_REGULAR, ZOOM_OUT_REGULAR };
+
+// Model and Input Messages
+
+pub struct Footer {
+ zoom: f64,
+}
+
+pub struct FooterInit {
+ pub zoom: f64,
+}
+
+#[derive(Debug, Clone)]
+pub enum FooterAction {
+ SetZoom(f64)
+}
+
+#[relm4::component(pub)]
+impl SimpleComponent for Footer {
+ type Init = FooterInit;
+ type Input = FooterAction;
+ type Output = Action;
+
+ view! {
+ &gtk::ActionBar {
+ pack_end = &gtk::Box {
+ set_orientation: gtk::Orientation::Horizontal,
+
+ gtk::Label {
+ #[watch]
+ set_label: &format!("{:.1}x", model.zoom),
+ set_margin_end: 5
+ },
+
+ gtk::Button::with_label(&tr!("command.view.zoom_out")) {
+ set_icon_name: ZOOM_OUT_REGULAR,
+ set_margin_end: 5,
+ add_css_class: "flat",
+ add_css_class: "zoom",
+ add_css_class: "zoom-out",
+ ActionablePlus::set_stateless_action::<ZoomOutAction>: &(),
+ },
+
+ gtk::Scale {
+ set_orientation: gtk::Orientation::Horizontal,
+ set_range: (constants::MIN_ZOOM, constants::MAX_ZOOM),
+ #[watch]
+ set_value: model.zoom,
+ set_draw_value: false,
+ set_increments: (constants::ZOOM_STEP, constants::ZOOM_STEP),
+ set_value_pos: gtk::PositionType::Left,
+ set_width_request: 100,
+ connect_value_changed[sender] => move |scale| {
+ let _ = sender.output(Action::Zoom(scale.value()));
+ }
+ },
+
+ gtk::Button::with_label(&tr!("command.view.zoom_in")) {
+ set_icon_name: ZOOM_IN_REGULAR,
+ add_css_class: "flat",
+ add_css_class: "zoom",
+ add_css_class: "zoom-in",
+ ActionablePlus::set_stateless_action::<ZoomInAction>: &(),
+ },
+ }
+ }
+ }
+
+ fn init(
+ init: Self::Init,
+ root: Self::Root,
+ sender: ComponentSender<Self>,
+ ) -> ComponentParts<Self> {
+ let model = Footer {
+ zoom: init.zoom
+ };
+ let widgets = view_output!();
+
+ ComponentParts { model, widgets }
+ }
+
+ fn update(&mut self, message: Self::Input, _sender: ComponentSender<Self>) {
+ match message {
+ FooterAction::SetZoom(zoom) => self.zoom = zoom
+ }
+ }
+}
diff --git a/src/components/mod.rs b/src/components/mod.rs
index d32bbea..1194b9f 100644
--- a/src/components/mod.rs
+++ b/src/components/mod.rs
@@ -13,4 +13,5 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
+pub mod footer;
pub mod header;
diff --git a/src/handlers/zoom.rs b/src/handlers/zoom.rs
index 575f5f9..59a54a7 100644
--- a/src/handlers/zoom.rs
+++ b/src/handlers/zoom.rs
@@ -13,28 +13,30 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
+use relm4::prelude::*;
+
use crate::AppModel;
use crate::constants;
+use crate::components::footer::FooterAction;
/// Sets the zoom level and updates the rendered image.
pub fn zoom(model: &mut AppModel, level: f64) {
model.zoom = level;
model.update_image();
+ model.footer.emit(FooterAction::SetZoom(level));
}
/// Decreases zoom by one step if above minimum.
pub fn zoom_out(model: &mut AppModel) {
let new_zoom = model.zoom - constants::ZOOM_STEP;
if new_zoom >= constants::MIN_ZOOM {
- model.zoom = new_zoom;
- model.update_image();
+ zoom(model, new_zoom);
}
}
/// Increases zoom by one step if below maximum.
pub fn zoom_in(model: &mut AppModel) {
if model.zoom < constants::MAX_ZOOM {
- model.zoom += constants::ZOOM_STEP;
- model.update_image();
+ zoom(model, model.zoom + constants::ZOOM_STEP);
}
}
diff --git a/src/main.rs b/src/main.rs
index c9393f4..f661df9 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -38,11 +38,10 @@ use std::convert::identity;
use std::path::PathBuf;
use crate::actions::Action;
-use crate::icon_names::shipped::{ ZOOM_IN_REGULAR, ZOOM_OUT_REGULAR };
use cairo::ImageSurface;
use gtk::glib;
use relm4::prelude::*;
-use relm4::actions::{AccelsPlus, ActionablePlus, RelmAction, RelmActionGroup};
+use relm4::actions::{AccelsPlus, RelmAction, RelmActionGroup};
use adw::prelude::*;
use sourceview5::LanguageManager;
@@ -53,6 +52,7 @@ use wmap_parser::{Map, parse};
use wmap_renderer::{Configuration, StageType, render_to_surface};
use components::header::{Header, HeaderInit};
+use components::footer::{Footer, FooterInit};
/// Macro to reduce boilerplate when registering actions with accelerators.
macro_rules! register_action {
@@ -136,7 +136,8 @@ struct AppModel {
editor_css_provider: gtk::CssProvider,
horizontal_layout_enabled: bool,
// Child Components
- header: Controller<Header>
+ header: Controller<Header>,
+ footer: Controller<Footer>,
}
impl AppModel {
@@ -355,48 +356,7 @@ impl SimpleComponent for AppModel {
}
},
- add_bottom_bar = &gtk::ActionBar {
- pack_end = &gtk::Box {
- set_orientation: gtk::Orientation::Horizontal,
-
- gtk::Label {
- #[watch]
- set_label: &format!("{:.1}x", model.zoom),
- set_margin_end: 5
- },
-
- gtk::Button::with_label(&tr!("command.view.zoom_out")) {
- set_icon_name: ZOOM_OUT_REGULAR,
- set_margin_end: 5,
- add_css_class: "flat",
- add_css_class: "zoom",
- add_css_class: "zoom-out",
- ActionablePlus::set_stateless_action::<ZoomOutAction>: &(),
- },
-
- gtk::Scale {
- set_orientation: gtk::Orientation::Horizontal,
- #[watch]
- set_value: model.zoom,
- set_draw_value: false,
- set_range: (constants::MIN_ZOOM, constants::MAX_ZOOM),
- set_increments: (constants::ZOOM_STEP, constants::ZOOM_STEP),
- set_value_pos: gtk::PositionType::Left,
- set_width_request: 100,
- connect_value_changed[sender] => move |scale| {
- sender.input(Action::Zoom(scale.value()));
- }
- },
-
- gtk::Button::with_label(&tr!("command.view.zoom_in")) {
- set_icon_name: ZOOM_IN_REGULAR,
- add_css_class: "flat",
- add_css_class: "zoom",
- add_css_class: "zoom-in",
- ActionablePlus::set_stateless_action::<ZoomInAction>: &(),
- },
- }
- }
+ add_bottom_bar = model.footer.widget(),
}
}
}
@@ -478,6 +438,12 @@ impl SimpleComponent for AppModel {
})
.forward(sender.input_sender(), identity);
+ let footer = Footer::builder()
+ .launch(FooterInit {
+ zoom: init.zoom
+ })
+ .forward(sender.input_sender(), identity);
+
let mut model = AppModel {
orientation,
stage_type,
@@ -499,7 +465,8 @@ impl SimpleComponent for AppModel {
preferences_window: None,
editor_css_provider,
horizontal_layout_enabled: true,
- header
+ header,
+ footer
};
model.apply_preferences();