wip: migrate to gtk4

This commit is contained in:
Byson94
2025-09-29 17:21:38 +05:30
parent b3f2c3f8a9
commit fec83417f5
15 changed files with 1729 additions and 1443 deletions

658
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -24,7 +24,7 @@ derive_more = { version = "1", features = [
extend = "1.2"
futures = "0.3.30"
grass = "0.13.4"
gtk = "0.18.1"
gtk4 = "0.10.1"
itertools = "0.13.0"
libc = "0.2"
log = "0.4"

View File

@@ -12,16 +12,15 @@ edition = "2021"
[features]
default = ["x11", "wayland"]
x11 = ["gdkx11", "x11rb"]
wayland = ["gtk-layer-shell"]
wayland = ["gtk4-layer-shell"]
[dependencies]
shared_utils.workspace = true
rhai_impl.workspace = true
gtk-layer-shell = { version = "0.8.1", optional = true, features=["v0_6"] }
gtk4-layer-shell = { version = "0.6.3", optional = true }
gdkx11 = { version = "0.18", optional = true }
x11rb = { version = "0.13.1", features = ["randr"], optional = true }
gdk-sys = "0.18.0"
grass.workspace = true
thiserror.workspace = true
@@ -35,7 +34,7 @@ derive_more.workspace = true
extend.workspace = true
futures.workspace = true
smart-default.workspace = true
gtk.workspace = true
gtk4.workspace = true
itertools.workspace = true
log.workspace = true
nix = { workspace = true, features = ["process", "fs", "signal"] }

View File

@@ -3,8 +3,8 @@ use crate::{
daemon_response::DaemonResponseSender,
display_backend::DisplayBackend,
error_handling_ctx,
gtk::prelude::{
ContainerExt, CssProviderExt, GtkWindowExt, MonitorExt, StyleContextExt, WidgetExt,
gtk4::prelude::{
ContainerExt, CssProviderExt, GtkWindowExt, MonitorExt, StyleContextExt, WidgetExt, ObjectExt, ApplicationExt, CellAreaExt, GskRendererExt
},
paths::EwwiiPaths,
widgets::window::Window,
@@ -23,10 +23,9 @@ use crate::{
*,
};
use anyhow::{anyhow, bail};
use codespan_reporting::files::Files;
use gdk::Monitor;
use glib::ObjectExt;
use gtk::{gdk, glib};
use gtk4::{gdk, glib};
use itertools::Itertools;
use once_cell::sync::Lazy;
use rhai::Dynamic;
@@ -143,7 +142,7 @@ pub struct App<B: DisplayBackend> {
/// Window names that are supposed to be open, but failed.
/// When reloading the config, these should be opened again.
pub failed_windows: HashSet<String>,
pub css_provider: gtk::CssProvider,
pub css_provider: gtk4::CssProvider,
/// Sender to send [`DaemonCommand`]s
pub app_evt_send: UnboundedSender<DaemonCommand>,
@@ -160,6 +159,7 @@ pub struct App<B: DisplayBackend> {
pub rt_engine_config: EngineConfValues,
pub paths: EwwiiPaths,
pub gtk_app: gtk4::Application,
pub phantom: PhantomData<B>,
}
@@ -207,7 +207,7 @@ impl<B: DisplayBackend> App<B> {
match event {
DaemonCommand::NoOp => {}
DaemonCommand::OpenInspector => {
gtk::Window::set_interactive_debugging(true);
gtk4::Window::set_interactive_debugging(true);
}
DaemonCommand::ReloadConfigAndCss(sender) => {
// Wait for all monitor models to be set. When a new monitor gets added, this
@@ -364,7 +364,7 @@ impl<B: DisplayBackend> App<B> {
for (_, window) in self.open_windows.drain() {
window.close();
}
gtk::main_quit();
self.gtk_app.quit();
let _ = crate::application_lifecycle::send_exit();
}
@@ -599,10 +599,10 @@ impl<B: DisplayBackend> App<B> {
// handling users close request
ewwii_window.delete_event_handler_id =
Some(ewwii_window.gtk_window.connect_delete_event({
Some(ewwii_window.gtk_window.connect_close_request({
let handler = gtk_close_handler.clone();
let closed_by_user = closed_by_user.clone();
move |_, _| {
move |_| {
handler(false); // -- false: don't reopen window to respect users intent
closed_by_user.set(true);
glib::Propagation::Proceed
@@ -688,26 +688,10 @@ impl<B: DisplayBackend> App<B> {
}
/// Load a given CSS string into the gtk css provider, returning a nicely formatted [`DiagError`] when GTK errors out
pub fn load_css(&mut self, file_id: usize, css: &str) -> Result<()> {
if let Err(err) = self.css_provider.load_from_data(css.as_bytes()) {
static PATTERN: Lazy<regex::Regex> =
Lazy::new(|| regex::Regex::new(r"[^:]*:(\d+):(\d+)(.*)$").unwrap());
let nice_error_option: Option<_> = (|| {
let captures = PATTERN.captures(err.message())?;
let line = captures.get(1).unwrap().as_str().parse::<usize>().ok()?;
let msg = captures.get(3).unwrap().as_str();
let db = error_handling_ctx::FILE_DATABASE.read().ok()?;
let line_range = db.line_range(file_id, line - 1).ok()?;
let span = Span(line_range.start, line_range.end - 1, file_id);
Some(DiagError(gen_diagnostic!(msg, span)))
})();
match nice_error_option {
Some(error) => Err(anyhow!(error)),
None => Err(anyhow!("CSS error: {}", err.message())),
}
} else {
Ok(())
}
pub fn load_css(&mut self, _file_id: usize, css: &str) -> Result<()> {
self.css_provider.load_from_data(&css);
Ok(())
}
/// Trigger a UI update with the given flags.
@@ -847,7 +831,7 @@ where
fn initialize_window<B: DisplayBackend>(
window_init: &WindowInitiator,
monitor: Monitor,
root_widget: gtk::Widget,
root_widget: gtk4::Widget,
) -> Result<EwwiiWindow> {
let monitor_geometry = monitor.geometry();
let (actual_window_rect, x, y) = match window_init.geometry {
@@ -861,8 +845,8 @@ fn initialize_window<B: DisplayBackend>(
format!("monitor {} is unavailable", window_init.monitor.clone().unwrap())
})?;
window.set_title(&format!("Ewwii - {}", window_init.name));
window.set_position(gtk::WindowPosition::None);
window.set_title(Some(&format!("Ewwii - {}", window_init.name)));
// window.set_position(gtk4::WindowPosition::None);
window.set_gravity(gdk::Gravity::Center);
if let Some(actual_window_rect) = actual_window_rect {
@@ -968,21 +952,24 @@ fn apply_window_position(
monitor_geometry: gdk::Rectangle,
window: &Window,
) -> Result<()> {
let gdk_window = window.window().context("Failed to get gdk window from gtk window")?;
window_geometry.size = crate::window::window_geometry::Coords::from_pixels(window.size());
let actual_window_rect = get_window_rectangle(window_geometry, monitor_geometry);
let gdk_window = window.surface().context("Failed to get gdk surface from gtk window")?;
if let Some(x11_surface) = surface.downcast_ref::<gdkx11::X11Surface>() {
window_geometry.size = crate::window::window_geometry::Coords::from_pixels(window.default_size());
let actual_window_rect = get_window_rectangle(window_geometry, monitor_geometry);
let gdk_origin = gdk_window.origin();
let (origin_x, origin_y) = x11_surface.position();
if actual_window_rect.x() != gdk_origin.1 || actual_window_rect.y() != gdk_origin.2 {
gdk_window.move_(actual_window_rect.x(), actual_window_rect.y());
if actual_window_rect.x() != origin_x || actual_window_rect.y() != origin_y {
x11_surface.move_(actual_window_rect.x(), actual_window_rect.y());
}
}
Ok(())
}
fn on_screen_changed(window: &Window, _old_screen: Option<&gdk::Screen>) {
let visual = gtk::prelude::GtkWindowExt::screen(window).and_then(|screen| {
let visual = gtk4::prelude::GtkWindowExt::screen(window).and_then(|screen| {
screen.rgba_visual().filter(|_| screen.is_composited()).or_else(|| screen.system_visual())
});
window.set_visual(visual.as_ref());

View File

@@ -1,6 +1,6 @@
use crate::{widgets::window::Window, window_initiator::WindowInitiator};
use gtk::gdk;
use gtk4::gdk;
#[cfg(feature = "wayland")]
pub use platform_wayland::WaylandBackend;
@@ -35,7 +35,11 @@ impl DisplayBackend for NoBackend {
x: i32,
y: i32,
) -> Option<Window> {
Some(Window::new(gtk::WindowType::Toplevel, x, y))
// top level
let window = Window::new();
window.move_(x, y);
Some(window)
}
}
@@ -46,9 +50,9 @@ mod platform_wayland {
use crate::window::window_definition::WindowStacking;
use crate::window::window_geometry::AnchorAlignment;
use crate::{widgets::window::Window, window_initiator::WindowInitiator};
use gtk::gdk;
use gtk::prelude::*;
use gtk_layer_shell::{KeyboardMode, LayerShell};
use gtk4::gdk;
use gtk4::prelude::*;
use gtk4_layer_shell::{KeyboardMode, LayerShell};
pub struct WaylandBackend;
@@ -62,7 +66,9 @@ mod platform_wayland {
x: i32,
y: i32,
) -> Option<Window> {
let window = Window::new(gtk::WindowType::Toplevel, x, y);
// top level
let window = Window::new();
window.move_(x, y);
// Sets the keyboard interactivity
match window_init.backend_options.wayland.focusable {
@@ -88,12 +94,12 @@ mod platform_wayland {
// Sets the layer where the layer shell surface will spawn
match window_init.stacking {
WindowStacking::Foreground => window.set_layer(gtk_layer_shell::Layer::Top),
WindowStacking::Foreground => window.set_layer(gtk4_layer_shell::Layer::Top),
WindowStacking::Background => {
window.set_layer(gtk_layer_shell::Layer::Background)
window.set_layer(gtk4_layer_shell::Layer::Background)
}
WindowStacking::Bottom => window.set_layer(gtk_layer_shell::Layer::Bottom),
WindowStacking::Overlay => window.set_layer(gtk_layer_shell::Layer::Overlay),
WindowStacking::Bottom => window.set_layer(gtk4_layer_shell::Layer::Bottom),
WindowStacking::Overlay => window.set_layer(gtk4_layer_shell::Layer::Overlay),
}
if let Some(namespace) = &window_init.backend_options.wayland.namespace {
@@ -118,23 +124,23 @@ mod platform_wayland {
AnchorAlignment::END => bottom = true,
}
window.set_anchor(gtk_layer_shell::Edge::Left, left);
window.set_anchor(gtk_layer_shell::Edge::Right, right);
window.set_anchor(gtk_layer_shell::Edge::Top, top);
window.set_anchor(gtk_layer_shell::Edge::Bottom, bottom);
window.set_anchor(gtk4_layer_shell::Edge::Left, left);
window.set_anchor(gtk4_layer_shell::Edge::Right, right);
window.set_anchor(gtk4_layer_shell::Edge::Top, top);
window.set_anchor(gtk4_layer_shell::Edge::Bottom, bottom);
let xoffset = geometry.offset.x.pixels_relative_to(monitor.width());
let yoffset = geometry.offset.y.pixels_relative_to(monitor.height());
if left {
window.set_layer_shell_margin(gtk_layer_shell::Edge::Left, xoffset);
window.set_layer_shell_margin(gtk4_layer_shell::Edge::Left, xoffset);
} else {
window.set_layer_shell_margin(gtk_layer_shell::Edge::Right, xoffset);
window.set_layer_shell_margin(gtk4_layer_shell::Edge::Right, xoffset);
}
if bottom {
window.set_layer_shell_margin(gtk_layer_shell::Edge::Bottom, yoffset);
window.set_layer_shell_margin(gtk4_layer_shell::Edge::Bottom, yoffset);
} else {
window.set_layer_shell_margin(gtk_layer_shell::Edge::Top, yoffset);
window.set_layer_shell_margin(gtk4_layer_shell::Edge::Top, yoffset);
}
// https://github.com/elkowar/eww/issues/296
if window_init.backend_options.wayland.exclusive
@@ -162,8 +168,8 @@ mod platform_x11 {
use crate::{widgets::window::Window, window_initiator::WindowInitiator};
use anyhow::{Context, Result};
use gdk::Monitor;
use gtk::gdk;
use gtk::{self, prelude::*};
use gtk4::gdk;
use gtk4::{self, prelude::*};
use x11rb::protocol::xproto::ConnectionExt;
use x11rb::{
@@ -186,12 +192,13 @@ mod platform_x11 {
x: i32,
y: i32,
) -> Option<Window> {
let window = Window::new();
window.move_(x, y);
let window_type = if window_init.backend_options.x11.wm_ignore {
gtk::WindowType::Popup
} else {
gtk::WindowType::Toplevel
};
let window = Window::new(window_type, x, y);
window.modal(true);
}; // else: normal, which is toplevel
window.set_resizable(window_init.resizable);
window.set_keep_above(window_init.stacking == WindowStacking::Foreground);
window.set_keep_below(window_init.stacking == WindowStacking::Background);

View File

@@ -18,9 +18,9 @@
#![allow(rustdoc::private_intra_doc_links)]
// getting gtk stuff
extern crate gtk;
extern crate gtk4;
#[cfg(feature = "wayland")]
extern crate gtk_layer_shell as gtk_layer_shell;
extern crate gtk4_layer_shell as gtk4_layer_shell;
// imporing dependencies
use anyhow::{Context, Result};

View File

@@ -76,74 +76,80 @@ pub fn initialize_server<B: DisplayBackend>(
if B::IS_WAYLAND {
std::env::set_var("GDK_BACKEND", "wayland")
}
gtk::init()?;
let mut app: App<B> = app::App {
ewwii_config,
open_windows: HashMap::new(),
failed_windows: HashSet::new(),
instance_id_to_args: HashMap::new(),
css_provider: gtk::CssProvider::new(),
app_evt_send: ui_send.clone(),
window_close_timer_abort_senders: HashMap::new(),
widget_reg_store: std::rc::Rc::new(std::sync::Mutex::new(None)),
pl_handler_store: None,
rt_engine_config: EngineConfValues::default(),
paths,
phantom: PhantomData,
};
if let Some(screen) = gtk::gdk::Screen::default() {
gtk::StyleContext::add_provider_for_screen(
&screen,
&app.css_provider,
gtk::STYLE_PROVIDER_PRIORITY_APPLICATION,
);
}
if let Ok((file_id, css)) = config::scss::parse_scss_from_config(app.paths.get_config_dir()) {
if let Err(e) = app.load_css(file_id, &css) {
error_handling_ctx::print_error(e);
}
}
let gtk_app = gtk4::Application::builder()
.application_id("com.widgetsystem.ewwii")
.build();
connect_monitor_added(ui_send.clone());
// initialize all the handlers and tasks running asyncronously
let tokio_handle = init_async_part(app.paths.clone(), ui_send);
gtk::glib::MainContext::default().spawn_local(async move {
// if an action was given to the daemon initially, execute it first.
if let Some(action) = action {
app.handle_command(action).await;
}
loop {
tokio::select! {
// Some(scope_graph_evt) = scope_graph_evt_recv.recv() => {
// app.scope_graph.borrow_mut().handle_scope_graph_event(scope_graph_evt);
// },
Some(ui_event) = ui_recv.recv() => {
app.handle_command(ui_event).await;
}
else => break,
}
}
});
let tokio_handle = init_async_part(paths.clone(), ui_send);
// allow the GTK main thread to do tokio things
let _g = tokio_handle.enter();
gtk::main();
log::info!("main application thread finished");
gtk_app.connect_activate(move |gtk_app| {
let mut app: App<B> = app::App {
ewwii_config: ewwii_config.clone(),
open_windows: HashMap::new(),
failed_windows: HashSet::new(),
instance_id_to_args: HashMap::new(),
css_provider: gtk4::CssProvider::new(),
app_evt_send: ui_send.clone(),
window_close_timer_abort_senders: HashMap::new(),
widget_reg_store: std::rc::Rc::new(std::sync::Mutex::new(None)),
pl_handler_store: None,
rt_engine_config: EngineConfValues::default(),
paths: paths.clone(),
gtk_app: gtk_app.clone(),
phantom: PhantomData,
};
if let Some(screen) = gtk4::gdk::Screen::default() {
gtk4::StyleContext::add_provider_for_screen(
&screen,
&app.css_provider,
gtk4::STYLE_PROVIDER_PRIORITY_APPLICATION,
);
}
if let Ok((file_id, css)) = config::scss::parse_scss_from_config(app.paths.get_config_dir()) {
if let Err(e) = app.load_css(file_id, &css) {
error_handling_ctx::print_error(e);
}
}
gtk4::glib::MainContext::default().spawn_local(async move {
// if an action was given to the daemon initially, execute it first.
if let Some(action) = action {
app.handle_command(action).await;
}
loop {
tokio::select! {
// Some(scope_graph_evt) = scope_graph_evt_recv.recv() => {
// app.scope_graph.borrow_mut().handle_scope_graph_event(scope_graph_evt);
// },
Some(ui_event) = ui_recv.recv() => {
app.handle_command(ui_event).await;
}
else => break,
}
}
});
});
let exit_status = gtk_app.run();
log::info!("main application thread finished with exit status: {}", exit_status);
Ok(ForkResult::Child)
}
fn connect_monitor_added(ui_send: UnboundedSender<DaemonCommand>) {
let display = gtk::gdk::Display::default().expect("could not get default display");
let display = gtk4::gdk::Display::default().expect("could not get default display");
display.connect_monitor_added({
move |_display: &gtk::gdk::Display, _monitor: &gtk::gdk::Monitor| {
move |_display: &gtk4::gdk::Display, _monitor: &gtk4::gdk::Monitor| {
log::info!("New monitor connected, reloading configuration");
let _ = reload_config_and_css(&ui_send);
}

View File

@@ -1,5 +1,5 @@
use anyhow::Result;
use gtk::gdk::prelude::Cast;
use gtk4::gdk::prelude::Cast;
use crate::{config::WindowDefinition, widgets::widget_definitions::*};
@@ -17,7 +17,7 @@ pub enum WidgetInput<'a> {
pub fn build_gtk_widget<'a>(
input: &'a WidgetInput<'a>,
widget_reg: &mut WidgetRegistry,
) -> Result<gtk::Widget> {
) -> Result<gtk4::Widget> {
let node: &'a WidgetNode = match input {
WidgetInput::Node(n) => n,
WidgetInput::BorrowedNode(n) => n,
@@ -30,7 +30,7 @@ pub fn build_gtk_widget<'a>(
fn build_gtk_widget_from_node(
root_node: &WidgetNode,
widget_reg: &mut WidgetRegistry,
) -> Result<gtk::Widget> {
) -> Result<gtk4::Widget> {
/*
When a a new widget is added to the build process,
make sure to update get_id_to_props_map() found in
@@ -44,7 +44,7 @@ fn build_gtk_widget_from_node(
build_center_box(props, children, widget_reg)?.upcast()
}
WidgetNode::EventBox { props, children } => {
build_gtk_event_box(props, children, widget_reg)?.upcast()
build_event_box(props, children, widget_reg)?.upcast()
}
WidgetNode::ToolTip { props, children } => {
build_tooltip(props, children, widget_reg)?.upcast()

View File

@@ -1,273 +1,273 @@
use anyhow::{anyhow, Result};
use gtk::glib::{self, object_subclass, prelude::*, wrapper, Properties};
use gtk::{cairo, gdk, prelude::*, subclass::prelude::*};
use std::cell::RefCell;
// use anyhow::{anyhow, Result};
// use gtk4::glib::{self, object_subclass, prelude::*, wrapper, Properties};
// use gtk4::{cairo, gdk, prelude::*, subclass::prelude::*};
// use std::cell::RefCell;
use crate::error_handling_ctx;
// use crate::error_handling_ctx;
wrapper! {
pub struct CircProg(ObjectSubclass<CircProgPriv>)
@extends gtk::Bin, gtk::Container, gtk::Widget;
}
// wrapper! {
// pub struct CircProg(ObjectSubclass<CircProgPriv>)
// @extends gtk4::Bin, gtk4::Container, gtk4::Widget;
// }
#[derive(Properties)]
#[properties(wrapper_type = CircProg)]
pub struct CircProgPriv {
#[property(
get,
set,
nick = "Starting at",
blurb = "Starting at",
minimum = 0f64,
maximum = 100f64,
default = 0f64
)]
start_at: RefCell<f64>,
// #[derive(Properties)]
// #[properties(wrapper_type = CircProg)]
// pub struct CircProgPriv {
// #[property(
// get,
// set,
// nick = "Starting at",
// blurb = "Starting at",
// minimum = 0f64,
// maximum = 100f64,
// default = 0f64
// )]
// start_at: RefCell<f64>,
#[property(
get,
set,
nick = "Value",
blurb = "The value",
minimum = 0f64,
maximum = 100f64,
default = 0f64
)]
value: RefCell<f64>,
// #[property(
// get,
// set,
// nick = "Value",
// blurb = "The value",
// minimum = 0f64,
// maximum = 100f64,
// default = 0f64
// )]
// value: RefCell<f64>,
#[property(
get,
set,
nick = "Thickness",
blurb = "Thickness",
minimum = 0f64,
maximum = 100f64,
default = 1f64
)]
thickness: RefCell<f64>,
// #[property(
// get,
// set,
// nick = "Thickness",
// blurb = "Thickness",
// minimum = 0f64,
// maximum = 100f64,
// default = 1f64
// )]
// thickness: RefCell<f64>,
#[property(get, set, nick = "Clockwise", blurb = "Clockwise", default = true)]
clockwise: RefCell<bool>,
// #[property(get, set, nick = "Clockwise", blurb = "Clockwise", default = true)]
// clockwise: RefCell<bool>,
content: RefCell<Option<gtk::Widget>>,
}
// content: RefCell<Option<gtk4::Widget>>,
// }
// This should match the default values from the ParamSpecs
impl Default for CircProgPriv {
fn default() -> Self {
CircProgPriv {
start_at: RefCell::new(0.0),
value: RefCell::new(0.0),
thickness: RefCell::new(1.0),
clockwise: RefCell::new(true),
content: RefCell::new(None),
}
}
}
// // This should match the default values from the ParamSpecs
// impl Default for CircProgPriv {
// fn default() -> Self {
// CircProgPriv {
// start_at: RefCell::new(0.0),
// value: RefCell::new(0.0),
// thickness: RefCell::new(1.0),
// clockwise: RefCell::new(true),
// content: RefCell::new(None),
// }
// }
// }
impl ObjectImpl for CircProgPriv {
fn properties() -> &'static [glib::ParamSpec] {
Self::derived_properties()
}
// impl ObjectImpl for CircProgPriv {
// fn properties() -> &'static [glib::ParamSpec] {
// Self::derived_properties()
// }
fn set_property(&self, _id: usize, value: &glib::Value, pspec: &glib::ParamSpec) {
match pspec.name() {
"value" => {
self.value.replace(value.get().unwrap());
self.obj().queue_draw(); // Queue a draw call with the updated value
}
"thickness" => {
self.thickness.replace(value.get().unwrap());
}
"start-at" => {
self.start_at.replace(value.get().unwrap());
}
"clockwise" => {
self.clockwise.replace(value.get().unwrap());
}
x => panic!("Tried to set inexistant property of CircProg: {}", x,),
}
}
// fn set_property(&self, _id: usize, value: &glib::Value, pspec: &glib::ParamSpec) {
// match pspec.name() {
// "value" => {
// self.value.replace(value.get().unwrap());
// self.obj().queue_draw(); // Queue a draw call with the updated value
// }
// "thickness" => {
// self.thickness.replace(value.get().unwrap());
// }
// "start-at" => {
// self.start_at.replace(value.get().unwrap());
// }
// "clockwise" => {
// self.clockwise.replace(value.get().unwrap());
// }
// x => panic!("Tried to set inexistant property of CircProg: {}", x,),
// }
// }
fn property(&self, id: usize, pspec: &glib::ParamSpec) -> glib::Value {
self.derived_property(id, pspec)
}
}
// fn property(&self, id: usize, pspec: &glib::ParamSpec) -> glib::Value {
// self.derived_property(id, pspec)
// }
// }
#[object_subclass]
impl ObjectSubclass for CircProgPriv {
type ParentType = gtk::Bin;
type Type = CircProg;
// #[object_subclass]
// impl ObjectSubclass for CircProgPriv {
// type ParentType = gtk4::Bin;
// type Type = CircProg;
const NAME: &'static str = "CircProg";
// const NAME: &'static str = "CircProg";
fn class_init(klass: &mut Self::Class) {
klass.set_css_name("circular-progress");
}
}
// fn class_init(klass: &mut Self::Class) {
// klass.set_css_name("circular-progress");
// }
// }
impl Default for CircProg {
fn default() -> Self {
Self::new()
}
}
// impl Default for CircProg {
// fn default() -> Self {
// Self::new()
// }
// }
impl CircProg {
pub fn new() -> Self {
glib::Object::new::<Self>()
}
}
// impl CircProg {
// pub fn new() -> Self {
// glib::Object::new::<Self>()
// }
// }
impl ContainerImpl for CircProgPriv {
fn add(&self, widget: &gtk::Widget) {
if let Some(content) = &*self.content.borrow() {
// TODO: Handle this error when populating children widgets instead
error_handling_ctx::print_error(anyhow!(
"Error, trying to add multiple children to a circular-progress widget"
));
self.parent_remove(content);
}
self.parent_add(widget);
self.content.replace(Some(widget.clone()));
}
}
// impl ContainerImpl for CircProgPriv {
// fn add(&self, widget: &gtk4::Widget) {
// if let Some(content) = &*self.content.borrow() {
// // TODO: Handle this error when populating children widgets instead
// error_handling_ctx::print_error(anyhow!(
// "Error, trying to add multiple children to a circular-progress widget"
// ));
// self.parent_remove(content);
// }
// self.parent_add(widget);
// self.content.replace(Some(widget.clone()));
// }
// }
fn calc_widget_lowest_preferred_dimension(widget: &gtk::Widget) -> (i32, i32) {
let preferred_width = widget.preferred_width();
let preferred_height = widget.preferred_height();
let min_lowest = i32::min(preferred_width.0, preferred_height.0);
let natural_lowest = i32::min(preferred_width.1, preferred_height.1);
(min_lowest, natural_lowest)
}
// fn calc_widget_lowest_preferred_dimension(widget: &gtk4::Widget) -> (i32, i32) {
// let preferred_width = widget.preferred_width();
// let preferred_height = widget.preferred_height();
// let min_lowest = i32::min(preferred_width.0, preferred_height.0);
// let natural_lowest = i32::min(preferred_width.1, preferred_height.1);
// (min_lowest, natural_lowest)
// }
impl BinImpl for CircProgPriv {}
// impl BinImpl for CircProgPriv {}
impl WidgetImpl for CircProgPriv {
// We overwrite preferred_* so that overflowing content from the children gets cropped
// We return min(child_width, child_height)
fn preferred_width(&self) -> (i32, i32) {
let styles = self.obj().style_context();
let margin = styles.margin(gtk::StateFlags::NORMAL);
// impl WidgetImpl for CircProgPriv {
// // We overwrite preferred_* so that overflowing content from the children gets cropped
// // We return min(child_width, child_height)
// fn preferred_width(&self) -> (i32, i32) {
// let styles = self.obj().style_context();
// let margin = styles.margin(gtk4::StateFlags::NORMAL);
if let Some(child) = &*self.content.borrow() {
let (min_child, natural_child) = calc_widget_lowest_preferred_dimension(child);
(
min_child + margin.right as i32 + margin.left as i32,
natural_child + margin.right as i32 + margin.left as i32,
)
} else {
let empty_width =
(2 * *self.thickness.borrow() as i32) + margin.right as i32 + margin.left as i32;
(empty_width, empty_width)
}
}
// if let Some(child) = &*self.content.borrow() {
// let (min_child, natural_child) = calc_widget_lowest_preferred_dimension(child);
// (
// min_child + margin.right as i32 + margin.left as i32,
// natural_child + margin.right as i32 + margin.left as i32,
// )
// } else {
// let empty_width =
// (2 * *self.thickness.borrow() as i32) + margin.right as i32 + margin.left as i32;
// (empty_width, empty_width)
// }
// }
fn preferred_width_for_height(&self, _height: i32) -> (i32, i32) {
self.preferred_width()
}
// fn preferred_width_for_height(&self, _height: i32) -> (i32, i32) {
// self.preferred_width()
// }
fn preferred_height(&self) -> (i32, i32) {
let styles = self.obj().style_context();
let margin = styles.margin(gtk::StateFlags::NORMAL);
// fn preferred_height(&self) -> (i32, i32) {
// let styles = self.obj().style_context();
// let margin = styles.margin(gtk4::StateFlags::NORMAL);
if let Some(child) = &*self.content.borrow() {
let (min_child, natural_child) = calc_widget_lowest_preferred_dimension(child);
(
min_child + margin.bottom as i32 + margin.top as i32,
natural_child + margin.bottom as i32 + margin.top as i32,
)
} else {
let empty_height =
(2 * *self.thickness.borrow() as i32) + margin.right as i32 + margin.left as i32;
(empty_height, empty_height)
}
}
// if let Some(child) = &*self.content.borrow() {
// let (min_child, natural_child) = calc_widget_lowest_preferred_dimension(child);
// (
// min_child + margin.bottom as i32 + margin.top as i32,
// natural_child + margin.bottom as i32 + margin.top as i32,
// )
// } else {
// let empty_height =
// (2 * *self.thickness.borrow() as i32) + margin.right as i32 + margin.left as i32;
// (empty_height, empty_height)
// }
// }
fn preferred_height_for_width(&self, _width: i32) -> (i32, i32) {
self.preferred_height()
}
// fn preferred_height_for_width(&self, _width: i32) -> (i32, i32) {
// self.preferred_height()
// }
fn draw(&self, cr: &cairo::Context) -> glib::Propagation {
let res: Result<()> = (|| {
let value = *self.value.borrow();
let start_at = *self.start_at.borrow();
let thickness = *self.thickness.borrow();
let clockwise = *self.clockwise.borrow();
// fn draw(&self, cr: &cairo::Context) -> glib::Propagation {
// let res: Result<()> = (|| {
// let value = *self.value.borrow();
// let start_at = *self.start_at.borrow();
// let thickness = *self.thickness.borrow();
// let clockwise = *self.clockwise.borrow();
let styles = self.obj().style_context();
let margin = styles.margin(gtk::StateFlags::NORMAL);
// Padding is not supported yet
let fg_color: gdk::RGBA = styles.color(gtk::StateFlags::NORMAL);
let bg_color: gdk::RGBA = styles
.style_property_for_state("background-color", gtk::StateFlags::NORMAL)
.get()?;
let (start_angle, end_angle) = if clockwise {
(0.0, perc_to_rad(value))
} else {
(perc_to_rad(100.0 - value), 2f64 * std::f64::consts::PI)
};
// let styles = self.obj().style_context();
// let margin = styles.margin(gtk4::StateFlags::NORMAL);
// // Padding is not supported yet
// let fg_color: gdk::RGBA = styles.color(gtk4::StateFlags::NORMAL);
// let bg_color: gdk::RGBA = styles
// .style_property_for_state("background-color", gtk4::StateFlags::NORMAL)
// .get()?;
// let (start_angle, end_angle) = if clockwise {
// (0.0, perc_to_rad(value))
// } else {
// (perc_to_rad(100.0 - value), 2f64 * std::f64::consts::PI)
// };
let total_width = self.obj().allocated_width() as f64;
let total_height = self.obj().allocated_height() as f64;
let center = (total_width / 2.0, total_height / 2.0);
// let total_width = self.obj().allocated_width() as f64;
// let total_height = self.obj().allocated_height() as f64;
// let center = (total_width / 2.0, total_height / 2.0);
let circle_width = total_width - margin.left as f64 - margin.right as f64;
let circle_height = total_height - margin.top as f64 - margin.bottom as f64;
let outer_ring = f64::min(circle_width, circle_height) / 2.0;
let inner_ring = (f64::min(circle_width, circle_height) / 2.0) - thickness;
// let circle_width = total_width - margin.left as f64 - margin.right as f64;
// let circle_height = total_height - margin.top as f64 - margin.bottom as f64;
// let outer_ring = f64::min(circle_width, circle_height) / 2.0;
// let inner_ring = (f64::min(circle_width, circle_height) / 2.0) - thickness;
cr.save()?;
// cr.save()?;
// Centering
cr.translate(center.0, center.1);
cr.rotate(perc_to_rad(start_at));
cr.translate(-center.0, -center.1);
// // Centering
// cr.translate(center.0, center.1);
// cr.rotate(perc_to_rad(start_at));
// cr.translate(-center.0, -center.1);
// Background Ring
cr.move_to(center.0, center.1);
cr.arc(center.0, center.1, outer_ring, 0.0, perc_to_rad(100.0));
cr.set_source_rgba(bg_color.red(), bg_color.green(), bg_color.blue(), bg_color.alpha());
cr.move_to(center.0, center.1);
cr.arc(center.0, center.1, inner_ring, 0.0, perc_to_rad(100.0));
cr.set_fill_rule(cairo::FillRule::EvenOdd); // Substract one circle from the other
cr.fill()?;
// // Background Ring
// cr.move_to(center.0, center.1);
// cr.arc(center.0, center.1, outer_ring, 0.0, perc_to_rad(100.0));
// cr.set_source_rgba(bg_color.red(), bg_color.green(), bg_color.blue(), bg_color.alpha());
// cr.move_to(center.0, center.1);
// cr.arc(center.0, center.1, inner_ring, 0.0, perc_to_rad(100.0));
// cr.set_fill_rule(cairo::FillRule::EvenOdd); // Substract one circle from the other
// cr.fill()?;
// Foreground Ring
cr.move_to(center.0, center.1);
cr.arc(center.0, center.1, outer_ring, start_angle, end_angle);
cr.set_source_rgba(fg_color.red(), fg_color.green(), fg_color.blue(), fg_color.alpha());
cr.move_to(center.0, center.1);
cr.arc(center.0, center.1, inner_ring, start_angle, end_angle);
cr.set_fill_rule(cairo::FillRule::EvenOdd); // Substract one circle from the other
cr.fill()?;
cr.restore()?;
// // Foreground Ring
// cr.move_to(center.0, center.1);
// cr.arc(center.0, center.1, outer_ring, start_angle, end_angle);
// cr.set_source_rgba(fg_color.red(), fg_color.green(), fg_color.blue(), fg_color.alpha());
// cr.move_to(center.0, center.1);
// cr.arc(center.0, center.1, inner_ring, start_angle, end_angle);
// cr.set_fill_rule(cairo::FillRule::EvenOdd); // Substract one circle from the other
// cr.fill()?;
// cr.restore()?;
// Draw the children widget, clipping it to the inside
if let Some(child) = &*self.content.borrow() {
cr.save()?;
// // Draw the children widget, clipping it to the inside
// if let Some(child) = &*self.content.borrow() {
// cr.save()?;
// Center circular clip
cr.arc(center.0, center.1, inner_ring + 1.0, 0.0, perc_to_rad(100.0));
cr.set_source_rgba(bg_color.red(), 0.0, 0.0, bg_color.alpha());
cr.clip();
// // Center circular clip
// cr.arc(center.0, center.1, inner_ring + 1.0, 0.0, perc_to_rad(100.0));
// cr.set_source_rgba(bg_color.red(), 0.0, 0.0, bg_color.alpha());
// cr.clip();
// Children widget
self.obj().propagate_draw(child, cr);
// // Children widget
// self.obj().propagate_draw(child, cr);
cr.reset_clip();
cr.restore()?;
}
Ok(())
})();
// cr.reset_clip();
// cr.restore()?;
// }
// Ok(())
// })();
if let Err(error) = res {
error_handling_ctx::print_error(error)
};
// if let Err(error) = res {
// error_handling_ctx::print_error(error)
// };
glib::Propagation::Proceed
}
}
// glib::Propagation::Proceed
// }
// }
fn perc_to_rad(n: f64) -> f64 {
(n / 100f64) * 2f64 * std::f64::consts::PI
}
// fn perc_to_rad(n: f64) -> f64 {
// (n / 100f64) * 2f64 * std::f64::consts::PI
// }

View File

@@ -1,349 +1,349 @@
use std::{cell::RefCell, collections::VecDeque};
// https://www.figuiere.net/technotes/notes/tn002/
// https://github.com/gtk-rs/examples/blob/master/src/bin/listbox_model.rs
use anyhow::{anyhow, Result};
use gtk::glib::{self, object_subclass, wrapper, Properties};
use gtk::{cairo, gdk, prelude::*, subclass::prelude::*};
// use std::{cell::RefCell, collections::VecDeque};
// // https://www.figuiere.net/technotes/notes/tn002/
// // https://github.com/gtk-rs/examples/blob/master/src/bin/listbox_model.rs
// use anyhow::{anyhow, Result};
// use gtk4::glib::{self, object_subclass, wrapper, Properties};
// use gtk4::{cairo, gdk, prelude::*, subclass::prelude::*};
use crate::error_handling_ctx;
// use crate::error_handling_ctx;
// This widget shouldn't be a Bin/Container but I've not been
// able to subclass just a gtk::Widget
wrapper! {
pub struct Graph(ObjectSubclass<GraphPriv>)
@extends gtk::Bin, gtk::Container, gtk::Widget;
}
// // This widget shouldn't be a Bin/Container but I've not been
// // able to subclass just a gtk4::Widget
// wrapper! {
// pub struct Graph(ObjectSubclass<GraphPriv>)
// @extends gtk4::Bin, gtk4::Container, gtk4::Widget;
// }
#[derive(Properties)]
#[properties(wrapper_type = Graph)]
pub struct GraphPriv {
#[property(get, set, nick = "Value", blurb = "The value", minimum = 0f64, maximum = f64::MAX, default = 0f64)]
value: RefCell<f64>,
// #[derive(Properties)]
// #[properties(wrapper_type = Graph)]
// pub struct GraphPriv {
// #[property(get, set, nick = "Value", blurb = "The value", minimum = 0f64, maximum = f64::MAX, default = 0f64)]
// value: RefCell<f64>,
#[property(get, set, nick = "Thickness", blurb = "The Thickness", minimum = 0f64, maximum = f64::MAX, default = 1f64)]
thickness: RefCell<f64>,
// #[property(get, set, nick = "Thickness", blurb = "The Thickness", minimum = 0f64, maximum = f64::MAX, default = 1f64)]
// thickness: RefCell<f64>,
#[property(get, set, nick = "Line Style", blurb = "The Line Style", default = "miter")]
line_style: RefCell<String>,
// #[property(get, set, nick = "Line Style", blurb = "The Line Style", default = "miter")]
// line_style: RefCell<String>,
#[property(get, set, nick = "Maximum Value", blurb = "The Maximum Value", minimum = 0f64, maximum = f64::MAX, default = 100f64)]
min: RefCell<f64>,
// #[property(get, set, nick = "Maximum Value", blurb = "The Maximum Value", minimum = 0f64, maximum = f64::MAX, default = 100f64)]
// min: RefCell<f64>,
#[property(get, set, nick = "Minumum Value", blurb = "The Minimum Value", minimum = 0f64, maximum = f64::MAX, default = 0f64)]
max: RefCell<f64>,
// #[property(get, set, nick = "Minumum Value", blurb = "The Minimum Value", minimum = 0f64, maximum = f64::MAX, default = 0f64)]
// max: RefCell<f64>,
#[property(get, set, nick = "Dynamic", blurb = "If it is dynamic", default = true)]
dynamic: RefCell<bool>,
// #[property(get, set, nick = "Dynamic", blurb = "If it is dynamic", default = true)]
// dynamic: RefCell<bool>,
#[property(get, set, nick = "Time Range", blurb = "The Time Range", minimum = 0u64, maximum = u64::MAX, default = 10u64)]
time_range: RefCell<u64>,
// #[property(get, set, nick = "Time Range", blurb = "The Time Range", minimum = 0u64, maximum = u64::MAX, default = 10u64)]
// time_range: RefCell<u64>,
#[property(get, set, nick = "Flip X", blurb = "Flip the x axis", default = true)]
flip_x: RefCell<bool>,
#[property(get, set, nick = "Flip Y", blurb = "Flip the y axis", default = true)]
flip_y: RefCell<bool>,
#[property(get, set, nick = "Vertical", blurb = "Exchange the x and y axes", default = false)]
vertical: RefCell<bool>,
// #[property(get, set, nick = "Flip X", blurb = "Flip the x axis", default = true)]
// flip_x: RefCell<bool>,
// #[property(get, set, nick = "Flip Y", blurb = "Flip the y axis", default = true)]
// flip_y: RefCell<bool>,
// #[property(get, set, nick = "Vertical", blurb = "Exchange the x and y axes", default = false)]
// vertical: RefCell<bool>,
history: RefCell<VecDeque<(std::time::Instant, f64)>>,
extra_point: RefCell<Option<(std::time::Instant, f64)>>,
last_updated_at: RefCell<std::time::Instant>,
}
// history: RefCell<VecDeque<(std::time::Instant, f64)>>,
// extra_point: RefCell<Option<(std::time::Instant, f64)>>,
// last_updated_at: RefCell<std::time::Instant>,
// }
impl Default for GraphPriv {
fn default() -> Self {
Self {
value: RefCell::new(0.0),
thickness: RefCell::new(1.0),
line_style: RefCell::new("miter".to_string()),
min: RefCell::new(0.0),
max: RefCell::new(100.0),
dynamic: RefCell::new(true),
time_range: RefCell::new(10),
flip_x: RefCell::new(true),
flip_y: RefCell::new(true),
vertical: RefCell::new(false),
history: RefCell::new(VecDeque::new()),
extra_point: RefCell::new(None),
last_updated_at: RefCell::new(std::time::Instant::now()),
}
}
}
// impl Default for GraphPriv {
// fn default() -> Self {
// Self {
// value: RefCell::new(0.0),
// thickness: RefCell::new(1.0),
// line_style: RefCell::new("miter".to_string()),
// min: RefCell::new(0.0),
// max: RefCell::new(100.0),
// dynamic: RefCell::new(true),
// time_range: RefCell::new(10),
// flip_x: RefCell::new(true),
// flip_y: RefCell::new(true),
// vertical: RefCell::new(false),
// history: RefCell::new(VecDeque::new()),
// extra_point: RefCell::new(None),
// last_updated_at: RefCell::new(std::time::Instant::now()),
// }
// }
// }
impl GraphPriv {
// Updates the history, removing points ouside the range
fn update_history(&self, v: (std::time::Instant, f64)) {
let mut history = self.history.borrow_mut();
let mut last_value = self.extra_point.borrow_mut();
let mut last_updated_at = self.last_updated_at.borrow_mut();
*last_updated_at = std::time::Instant::now();
// impl GraphPriv {
// // Updates the history, removing points ouside the range
// fn update_history(&self, v: (std::time::Instant, f64)) {
// let mut history = self.history.borrow_mut();
// let mut last_value = self.extra_point.borrow_mut();
// let mut last_updated_at = self.last_updated_at.borrow_mut();
// *last_updated_at = std::time::Instant::now();
while let Some(entry) = history.front() {
if last_updated_at.duration_since(entry.0).as_millis() as u64
> *self.time_range.borrow()
{
*last_value = history.pop_front();
} else {
break;
}
}
history.push_back(v);
}
/**
* Receives normalized (0-1) coordinates `x` and `y` and convert them to the
* point on the widget.
*/
fn value_to_point(&self, width: f64, height: f64, x: f64, y: f64) -> (f64, f64) {
let x = if *self.flip_x.borrow() { 1.0 - x } else { x };
let y = if *self.flip_y.borrow() { 1.0 - y } else { y };
let (x, y) = if *self.vertical.borrow() { (y, x) } else { (x, y) };
(width * x, height * y)
}
}
// while let Some(entry) = history.front() {
// if last_updated_at.duration_since(entry.0).as_millis() as u64
// > *self.time_range.borrow()
// {
// *last_value = history.pop_front();
// } else {
// break;
// }
// }
// history.push_back(v);
// }
// /**
// * Receives normalized (0-1) coordinates `x` and `y` and convert them to the
// * point on the widget.
// */
// fn value_to_point(&self, width: f64, height: f64, x: f64, y: f64) -> (f64, f64) {
// let x = if *self.flip_x.borrow() { 1.0 - x } else { x };
// let y = if *self.flip_y.borrow() { 1.0 - y } else { y };
// let (x, y) = if *self.vertical.borrow() { (y, x) } else { (x, y) };
// (width * x, height * y)
// }
// }
impl ObjectImpl for GraphPriv {
fn properties() -> &'static [glib::ParamSpec] {
Self::derived_properties()
}
// impl ObjectImpl for GraphPriv {
// fn properties() -> &'static [glib::ParamSpec] {
// Self::derived_properties()
// }
fn set_property(&self, _id: usize, value: &glib::Value, pspec: &glib::ParamSpec) {
match pspec.name() {
"value" => {
let value = value.get().unwrap();
self.value.replace(value);
self.update_history((std::time::Instant::now(), value));
self.obj().queue_draw();
}
"thickness" => {
self.thickness.replace(value.get().unwrap());
}
"max" => {
self.max.replace(value.get().unwrap());
}
"min" => {
self.min.replace(value.get().unwrap());
}
"dynamic" => {
self.dynamic.replace(value.get().unwrap());
}
"time-range" => {
self.time_range.replace(value.get().unwrap());
}
"line-style" => {
self.line_style.replace(value.get().unwrap());
}
"flip-x" => {
self.flip_x.replace(value.get().unwrap());
}
"flip-y" => {
self.flip_y.replace(value.get().unwrap());
}
"vertical" => {
self.vertical.replace(value.get().unwrap());
}
x => panic!("Tried to set inexistant property of Graph: {}", x,),
}
}
// fn set_property(&self, _id: usize, value: &glib::Value, pspec: &glib::ParamSpec) {
// match pspec.name() {
// "value" => {
// let value = value.get().unwrap();
// self.value.replace(value);
// self.update_history((std::time::Instant::now(), value));
// self.obj().queue_draw();
// }
// "thickness" => {
// self.thickness.replace(value.get().unwrap());
// }
// "max" => {
// self.max.replace(value.get().unwrap());
// }
// "min" => {
// self.min.replace(value.get().unwrap());
// }
// "dynamic" => {
// self.dynamic.replace(value.get().unwrap());
// }
// "time-range" => {
// self.time_range.replace(value.get().unwrap());
// }
// "line-style" => {
// self.line_style.replace(value.get().unwrap());
// }
// "flip-x" => {
// self.flip_x.replace(value.get().unwrap());
// }
// "flip-y" => {
// self.flip_y.replace(value.get().unwrap());
// }
// "vertical" => {
// self.vertical.replace(value.get().unwrap());
// }
// x => panic!("Tried to set inexistant property of Graph: {}", x,),
// }
// }
fn property(&self, id: usize, pspec: &glib::ParamSpec) -> glib::Value {
self.derived_property(id, pspec)
}
}
// fn property(&self, id: usize, pspec: &glib::ParamSpec) -> glib::Value {
// self.derived_property(id, pspec)
// }
// }
#[object_subclass]
impl ObjectSubclass for GraphPriv {
type ParentType = gtk::Bin;
type Type = Graph;
// #[object_subclass]
// impl ObjectSubclass for GraphPriv {
// type ParentType = gtk4::Bin;
// type Type = Graph;
const NAME: &'static str = "Graph";
// const NAME: &'static str = "Graph";
fn class_init(klass: &mut Self::Class) {
klass.set_css_name("graph");
}
}
// fn class_init(klass: &mut Self::Class) {
// klass.set_css_name("graph");
// }
// }
impl Default for Graph {
fn default() -> Self {
Self::new()
}
}
// impl Default for Graph {
// fn default() -> Self {
// Self::new()
// }
// }
impl Graph {
pub fn new() -> Self {
glib::Object::new::<Self>()
}
}
// impl Graph {
// pub fn new() -> Self {
// glib::Object::new::<Self>()
// }
// }
impl ContainerImpl for GraphPriv {
fn add(&self, _widget: &gtk::Widget) {
error_handling_ctx::print_error(anyhow!("Error, Graph widget shoudln't have any children"));
}
}
// impl ContainerImpl for GraphPriv {
// fn add(&self, _widget: &gtk4::Widget) {
// error_handling_ctx::print_error(anyhow!("Error, Graph widget shoudln't have any children"));
// }
// }
impl BinImpl for GraphPriv {}
impl WidgetImpl for GraphPriv {
fn preferred_width(&self) -> (i32, i32) {
let thickness = *self.thickness.borrow() as i32;
(thickness, thickness)
}
// impl BinImpl for GraphPriv {}
// impl WidgetImpl for GraphPriv {
// fn preferred_width(&self) -> (i32, i32) {
// let thickness = *self.thickness.borrow() as i32;
// (thickness, thickness)
// }
fn preferred_width_for_height(&self, height: i32) -> (i32, i32) {
(height, height)
}
// fn preferred_width_for_height(&self, height: i32) -> (i32, i32) {
// (height, height)
// }
fn preferred_height(&self) -> (i32, i32) {
let thickness = *self.thickness.borrow() as i32;
(thickness, thickness)
}
// fn preferred_height(&self) -> (i32, i32) {
// let thickness = *self.thickness.borrow() as i32;
// (thickness, thickness)
// }
fn preferred_height_for_width(&self, width: i32) -> (i32, i32) {
(width, width)
}
// fn preferred_height_for_width(&self, width: i32) -> (i32, i32) {
// (width, width)
// }
fn draw(&self, cr: &cairo::Context) -> glib::Propagation {
let res: Result<()> = (|| {
let history = &*self.history.borrow();
let extra_point = *self.extra_point.borrow();
// fn draw(&self, cr: &cairo::Context) -> glib::Propagation {
// let res: Result<()> = (|| {
// let history = &*self.history.borrow();
// let extra_point = *self.extra_point.borrow();
// Calculate the max value
let (min, max) = {
let mut max = *self.max.borrow();
let min = *self.min.borrow();
let dynamic = *self.dynamic.borrow();
if dynamic {
// Check for points higher than max
for (_, value) in history {
if *value > max {
max = *value;
}
}
if let Some((_, value)) = extra_point {
if value > max {
max = value;
}
}
}
(min, max)
};
// // Calculate the max value
// let (min, max) = {
// let mut max = *self.max.borrow();
// let min = *self.min.borrow();
// let dynamic = *self.dynamic.borrow();
// if dynamic {
// // Check for points higher than max
// for (_, value) in history {
// if *value > max {
// max = *value;
// }
// }
// if let Some((_, value)) = extra_point {
// if value > max {
// max = value;
// }
// }
// }
// (min, max)
// };
let styles = self.obj().style_context();
let (margin_top, margin_right, margin_bottom, margin_left) = {
let margin = styles.margin(gtk::StateFlags::NORMAL);
(margin.top as f64, margin.right as f64, margin.bottom as f64, margin.left as f64)
};
let width = self.obj().allocated_width() as f64 - margin_left - margin_right;
let height = self.obj().allocated_height() as f64 - margin_top - margin_bottom;
// let styles = self.obj().style_context();
// let (margin_top, margin_right, margin_bottom, margin_left) = {
// let margin = styles.margin(gtk4::StateFlags::NORMAL);
// (margin.top as f64, margin.right as f64, margin.bottom as f64, margin.left as f64)
// };
// let width = self.obj().allocated_width() as f64 - margin_left - margin_right;
// let height = self.obj().allocated_height() as f64 - margin_top - margin_bottom;
// Calculate graph points once
// Separating this into another function would require pasing a
// GraphPriv that would hide interior mutability
let points = {
let value_range = max - min;
let time_range = *self.time_range.borrow() as f64;
let last_updated_at = self.last_updated_at.borrow();
let mut points = history
.iter()
.map(|(instant, value)| {
let t = last_updated_at.duration_since(*instant).as_millis() as f64;
self.value_to_point(
width,
height,
t / time_range,
(value - min) / value_range,
)
})
.collect::<VecDeque<(f64, f64)>>();
// // Calculate graph points once
// // Separating this into another function would require pasing a
// // GraphPriv that would hide interior mutability
// let points = {
// let value_range = max - min;
// let time_range = *self.time_range.borrow() as f64;
// let last_updated_at = self.last_updated_at.borrow();
// let mut points = history
// .iter()
// .map(|(instant, value)| {
// let t = last_updated_at.duration_since(*instant).as_millis() as f64;
// self.value_to_point(
// width,
// height,
// t / time_range,
// (value - min) / value_range,
// )
// })
// .collect::<VecDeque<(f64, f64)>>();
// Aad an extra point outside of the graph to extend the line to the left
if let Some((instant, value)) = extra_point {
let t = last_updated_at.duration_since(instant).as_millis() as f64;
let (x, y) = self.value_to_point(
width,
height,
(t - time_range) / time_range,
(value - min) / value_range,
);
points.push_front(if *self.vertical.borrow() { (x, -y) } else { (-x, y) });
}
points
};
// // Aad an extra point outside of the graph to extend the line to the left
// if let Some((instant, value)) = extra_point {
// let t = last_updated_at.duration_since(instant).as_millis() as f64;
// let (x, y) = self.value_to_point(
// width,
// height,
// (t - time_range) / time_range,
// (value - min) / value_range,
// );
// points.push_front(if *self.vertical.borrow() { (x, -y) } else { (-x, y) });
// }
// points
// };
// Actually draw the graph
cr.save()?;
cr.translate(margin_left, margin_top);
cr.rectangle(0.0, 0.0, width, height);
cr.clip();
// // Actually draw the graph
// cr.save()?;
// cr.translate(margin_left, margin_top);
// cr.rectangle(0.0, 0.0, width, height);
// cr.clip();
// Draw Background
let bg_color: gdk::RGBA = styles
.style_property_for_state("background-color", gtk::StateFlags::NORMAL)
.get()?;
if bg_color.alpha() > 0.0 {
if let Some(first_point) = points.front() {
cr.line_to(first_point.0, height + margin_bottom);
}
for (x, y) in points.iter() {
cr.line_to(*x, *y);
}
cr.line_to(width, height);
// // Draw Background
// let bg_color: gdk::RGBA = styles
// .style_property_for_state("background-color", gtk4::StateFlags::NORMAL)
// .get()?;
// if bg_color.alpha() > 0.0 {
// if let Some(first_point) = points.front() {
// cr.line_to(first_point.0, height + margin_bottom);
// }
// for (x, y) in points.iter() {
// cr.line_to(*x, *y);
// }
// cr.line_to(width, height);
cr.set_source_rgba(
bg_color.red(),
bg_color.green(),
bg_color.blue(),
bg_color.alpha(),
);
cr.fill()?;
}
// cr.set_source_rgba(
// bg_color.red(),
// bg_color.green(),
// bg_color.blue(),
// bg_color.alpha(),
// );
// cr.fill()?;
// }
// Draw Line
let line_color: gdk::RGBA = styles.color(gtk::StateFlags::NORMAL);
let thickness = *self.thickness.borrow();
if line_color.alpha() > 0.0 && thickness > 0.0 {
for (x, y) in points.iter() {
cr.line_to(*x, *y);
}
// // Draw Line
// let line_color: gdk::RGBA = styles.color(gtk4::StateFlags::NORMAL);
// let thickness = *self.thickness.borrow();
// if line_color.alpha() > 0.0 && thickness > 0.0 {
// for (x, y) in points.iter() {
// cr.line_to(*x, *y);
// }
let line_style = &*self.line_style.borrow();
apply_line_style(line_style.as_str(), cr)?;
cr.set_line_width(thickness);
cr.set_source_rgba(
line_color.red(),
line_color.green(),
line_color.blue(),
line_color.alpha(),
);
cr.stroke()?;
}
// let line_style = &*self.line_style.borrow();
// apply_line_style(line_style.as_str(), cr)?;
// cr.set_line_width(thickness);
// cr.set_source_rgba(
// line_color.red(),
// line_color.green(),
// line_color.blue(),
// line_color.alpha(),
// );
// cr.stroke()?;
// }
cr.reset_clip();
cr.restore()?;
Ok(())
})();
// cr.reset_clip();
// cr.restore()?;
// Ok(())
// })();
if let Err(error) = res {
error_handling_ctx::print_error(error)
};
// if let Err(error) = res {
// error_handling_ctx::print_error(error)
// };
glib::Propagation::Proceed
}
}
// glib::Propagation::Proceed
// }
// }
fn apply_line_style(style: &str, cr: &cairo::Context) -> Result<()> {
match style {
"miter" => {
cr.set_line_cap(cairo::LineCap::Butt);
cr.set_line_join(cairo::LineJoin::Miter);
}
"bevel" => {
cr.set_line_cap(cairo::LineCap::Square);
cr.set_line_join(cairo::LineJoin::Bevel);
}
"round" => {
cr.set_line_cap(cairo::LineCap::Round);
cr.set_line_join(cairo::LineJoin::Round);
}
_ => Err(anyhow!("Error, the value: {} for atribute join is not valid", style))?,
};
Ok(())
}
// fn apply_line_style(style: &str, cr: &cairo::Context) -> Result<()> {
// match style {
// "miter" => {
// cr.set_line_cap(cairo::LineCap::Butt);
// cr.set_line_join(cairo::LineJoin::Miter);
// }
// "bevel" => {
// cr.set_line_cap(cairo::LineCap::Square);
// cr.set_line_join(cairo::LineJoin::Bevel);
// }
// "round" => {
// cr.set_line_cap(cairo::LineCap::Round);
// cr.set_line_join(cairo::LineJoin::Round);
// }
// _ => Err(anyhow!("Error, the value: {} for atribute join is not valid", style))?,
// };
// Ok(())
// }

View File

@@ -1,214 +1,214 @@
use crate::window::coords::NumWithUnit;
use anyhow::{anyhow, Result};
use gtk::glib::{self, object_subclass, wrapper, Properties};
use gtk::{prelude::*, subclass::prelude::*};
use std::{cell::RefCell, str::FromStr};
// use crate::window::coords::NumWithUnit;
// use anyhow::{anyhow, Result};
// use gtk4::glib::{self, object_subclass, wrapper, Properties};
// use gtk4::{prelude::*, subclass::prelude::*};
// use std::{cell::RefCell, str::FromStr};
use crate::error_handling_ctx;
// use crate::error_handling_ctx;
wrapper! {
pub struct Transform(ObjectSubclass<TransformPriv>)
@extends gtk::Bin, gtk::Container, gtk::Widget;
}
// wrapper! {
// pub struct Transform(ObjectSubclass<TransformPriv>)
// @extends gtk4::Bin, gtk4::Container, gtk4::Widget;
// }
#[derive(Properties)]
#[properties(wrapper_type = Transform)]
pub struct TransformPriv {
#[property(get, set, nick = "Rotate", blurb = "The Rotation", minimum = f64::MIN, maximum = f64::MAX, default = 0f64)]
rotate: RefCell<f64>,
// #[derive(Properties)]
// #[properties(wrapper_type = Transform)]
// pub struct TransformPriv {
// #[property(get, set, nick = "Rotate", blurb = "The Rotation", minimum = f64::MIN, maximum = f64::MAX, default = 0f64)]
// rotate: RefCell<f64>,
#[property(get, set, nick = "Transform-Origin X", blurb = "X coordinate (%/px) for the Transform-Origin", default = None)]
transform_origin_x: RefCell<Option<String>>,
// #[property(get, set, nick = "Transform-Origin X", blurb = "X coordinate (%/px) for the Transform-Origin", default = None)]
// transform_origin_x: RefCell<Option<String>>,
#[property(get, set, nick = "Transform-Origin Y", blurb = "Y coordinate (%/px) for the Transform-Origin", default = None)]
transform_origin_y: RefCell<Option<String>>,
// #[property(get, set, nick = "Transform-Origin Y", blurb = "Y coordinate (%/px) for the Transform-Origin", default = None)]
// transform_origin_y: RefCell<Option<String>>,
#[property(get, set, nick = "Translate x", blurb = "The X Translation", default = None)]
translate_x: RefCell<Option<String>>,
// #[property(get, set, nick = "Translate x", blurb = "The X Translation", default = None)]
// translate_x: RefCell<Option<String>>,
#[property(get, set, nick = "Translate y", blurb = "The Y Translation", default = None)]
translate_y: RefCell<Option<String>>,
// #[property(get, set, nick = "Translate y", blurb = "The Y Translation", default = None)]
// translate_y: RefCell<Option<String>>,
#[property(get, set, nick = "Scale x", blurb = "The amount to scale in x", default = None)]
scale_x: RefCell<Option<String>>,
// #[property(get, set, nick = "Scale x", blurb = "The amount to scale in x", default = None)]
// scale_x: RefCell<Option<String>>,
#[property(get, set, nick = "Scale y", blurb = "The amount to scale in y", default = None)]
scale_y: RefCell<Option<String>>,
// #[property(get, set, nick = "Scale y", blurb = "The amount to scale in y", default = None)]
// scale_y: RefCell<Option<String>>,
content: RefCell<Option<gtk::Widget>>,
}
// content: RefCell<Option<gtk4::Widget>>,
// }
// This should match the default values from the ParamSpecs
impl Default for TransformPriv {
fn default() -> Self {
TransformPriv {
rotate: RefCell::new(0.0),
transform_origin_x: RefCell::new(None),
transform_origin_y: RefCell::new(None),
translate_x: RefCell::new(None),
translate_y: RefCell::new(None),
scale_x: RefCell::new(None),
scale_y: RefCell::new(None),
content: RefCell::new(None),
}
}
}
// // This should match the default values from the ParamSpecs
// impl Default for TransformPriv {
// fn default() -> Self {
// TransformPriv {
// rotate: RefCell::new(0.0),
// transform_origin_x: RefCell::new(None),
// transform_origin_y: RefCell::new(None),
// translate_x: RefCell::new(None),
// translate_y: RefCell::new(None),
// scale_x: RefCell::new(None),
// scale_y: RefCell::new(None),
// content: RefCell::new(None),
// }
// }
// }
impl ObjectImpl for TransformPriv {
fn properties() -> &'static [glib::ParamSpec] {
Self::derived_properties()
}
// impl ObjectImpl for TransformPriv {
// fn properties() -> &'static [glib::ParamSpec] {
// Self::derived_properties()
// }
fn set_property(&self, _id: usize, value: &glib::Value, pspec: &glib::ParamSpec) {
match pspec.name() {
"rotate" => {
self.rotate.replace(value.get().unwrap());
self.obj().queue_draw(); // Queue a draw call with the updated value
}
"transform-origin-x" => {
self.transform_origin_x.replace(value.get().unwrap());
self.obj().queue_draw(); // Queue a draw call with the updated value
}
"transform-origin-y" => {
self.transform_origin_y.replace(value.get().unwrap());
self.obj().queue_draw(); // Queue a draw call with the updated value
}
"translate-x" => {
self.translate_x.replace(value.get().unwrap());
self.obj().queue_draw(); // Queue a draw call with the updated value
}
"translate-y" => {
self.translate_y.replace(value.get().unwrap());
self.obj().queue_draw(); // Queue a draw call with the updated value
}
"scale-x" => {
self.scale_x.replace(value.get().unwrap());
self.obj().queue_draw(); // Queue a draw call with the updated value
}
"scale-y" => {
self.scale_y.replace(value.get().unwrap());
self.obj().queue_draw(); // Queue a draw call with the updated value
}
x => panic!("Tried to set inexistant property of Transform: {}", x,),
}
}
// fn set_property(&self, _id: usize, value: &glib::Value, pspec: &glib::ParamSpec) {
// match pspec.name() {
// "rotate" => {
// self.rotate.replace(value.get().unwrap());
// self.obj().queue_draw(); // Queue a draw call with the updated value
// }
// "transform-origin-x" => {
// self.transform_origin_x.replace(value.get().unwrap());
// self.obj().queue_draw(); // Queue a draw call with the updated value
// }
// "transform-origin-y" => {
// self.transform_origin_y.replace(value.get().unwrap());
// self.obj().queue_draw(); // Queue a draw call with the updated value
// }
// "translate-x" => {
// self.translate_x.replace(value.get().unwrap());
// self.obj().queue_draw(); // Queue a draw call with the updated value
// }
// "translate-y" => {
// self.translate_y.replace(value.get().unwrap());
// self.obj().queue_draw(); // Queue a draw call with the updated value
// }
// "scale-x" => {
// self.scale_x.replace(value.get().unwrap());
// self.obj().queue_draw(); // Queue a draw call with the updated value
// }
// "scale-y" => {
// self.scale_y.replace(value.get().unwrap());
// self.obj().queue_draw(); // Queue a draw call with the updated value
// }
// x => panic!("Tried to set inexistant property of Transform: {}", x,),
// }
// }
fn property(&self, id: usize, pspec: &glib::ParamSpec) -> glib::Value {
self.derived_property(id, pspec)
}
}
// fn property(&self, id: usize, pspec: &glib::ParamSpec) -> glib::Value {
// self.derived_property(id, pspec)
// }
// }
#[object_subclass]
impl ObjectSubclass for TransformPriv {
type ParentType = gtk::Bin;
type Type = Transform;
// #[object_subclass]
// impl ObjectSubclass for TransformPriv {
// type ParentType = gtk4::Bin;
// type Type = Transform;
const NAME: &'static str = "Transform";
// const NAME: &'static str = "Transform";
fn class_init(klass: &mut Self::Class) {
klass.set_css_name("transform");
}
}
// fn class_init(klass: &mut Self::Class) {
// klass.set_css_name("transform");
// }
// }
impl Default for Transform {
fn default() -> Self {
Self::new()
}
}
// impl Default for Transform {
// fn default() -> Self {
// Self::new()
// }
// }
impl Transform {
pub fn new() -> Self {
glib::Object::new::<Self>()
}
}
// impl Transform {
// pub fn new() -> Self {
// glib::Object::new::<Self>()
// }
// }
impl ContainerImpl for TransformPriv {
fn add(&self, widget: &gtk::Widget) {
if let Some(content) = &*self.content.borrow() {
// TODO: Handle this error when populating children widgets instead
error_handling_ctx::print_error(anyhow!(
"Error, trying to add multiple children to a circular-progress widget"
));
self.parent_remove(content);
}
self.parent_add(widget);
self.content.replace(Some(widget.clone()));
}
}
// impl ContainerImpl for TransformPriv {
// fn add(&self, widget: &gtk4::Widget) {
// if let Some(content) = &*self.content.borrow() {
// // TODO: Handle this error when populating children widgets instead
// error_handling_ctx::print_error(anyhow!(
// "Error, trying to add multiple children to a circular-progress widget"
// ));
// self.parent_remove(content);
// }
// self.parent_add(widget);
// self.content.replace(Some(widget.clone()));
// }
// }
impl BinImpl for TransformPriv {}
impl WidgetImpl for TransformPriv {
fn draw(&self, cr: &gtk::cairo::Context) -> glib::Propagation {
let res: Result<()> = (|| {
let rotate = *self.rotate.borrow();
let total_width = self.obj().allocated_width() as f64;
let total_height = self.obj().allocated_height() as f64;
// impl BinImpl for TransformPriv {}
// impl WidgetImpl for TransformPriv {
// fn draw(&self, cr: &gtk4::cairo::Context) -> glib::Propagation {
// let res: Result<()> = (|| {
// let rotate = *self.rotate.borrow();
// let total_width = self.obj().allocated_width() as f64;
// let total_height = self.obj().allocated_height() as f64;
cr.save()?;
// cr.save()?;
let transform_origin_x = match &*self.transform_origin_x.borrow() {
Some(rcx) => {
NumWithUnit::from_str(rcx)?.pixels_relative_to(total_width as i32) as f64
}
None => 0.0,
};
let transform_origin_y = match &*self.transform_origin_y.borrow() {
Some(rcy) => {
NumWithUnit::from_str(rcy)?.pixels_relative_to(total_height as i32) as f64
}
None => 0.0,
};
// let transform_origin_x = match &*self.transform_origin_x.borrow() {
// Some(rcx) => {
// NumWithUnit::from_str(rcx)?.pixels_relative_to(total_width as i32) as f64
// }
// None => 0.0,
// };
// let transform_origin_y = match &*self.transform_origin_y.borrow() {
// Some(rcy) => {
// NumWithUnit::from_str(rcy)?.pixels_relative_to(total_height as i32) as f64
// }
// None => 0.0,
// };
let translate_x = match &*self.translate_x.borrow() {
Some(tx) => {
NumWithUnit::from_str(tx)?.pixels_relative_to(total_width as i32) as f64
}
None => 0.0,
};
// let translate_x = match &*self.translate_x.borrow() {
// Some(tx) => {
// NumWithUnit::from_str(tx)?.pixels_relative_to(total_width as i32) as f64
// }
// None => 0.0,
// };
let translate_y = match &*self.translate_y.borrow() {
Some(ty) => {
NumWithUnit::from_str(ty)?.pixels_relative_to(total_height as i32) as f64
}
None => 0.0,
};
// let translate_y = match &*self.translate_y.borrow() {
// Some(ty) => {
// NumWithUnit::from_str(ty)?.pixels_relative_to(total_height as i32) as f64
// }
// None => 0.0,
// };
let scale_x = match &*self.scale_x.borrow() {
Some(sx) => {
NumWithUnit::from_str(sx)?.perc_relative_to(total_width as i32) as f64 / 100.0
}
None => 1.0,
};
// let scale_x = match &*self.scale_x.borrow() {
// Some(sx) => {
// NumWithUnit::from_str(sx)?.perc_relative_to(total_width as i32) as f64 / 100.0
// }
// None => 1.0,
// };
let scale_y = match &*self.scale_y.borrow() {
Some(sy) => {
NumWithUnit::from_str(sy)?.perc_relative_to(total_height as i32) as f64 / 100.0
}
None => 1.0,
};
// let scale_y = match &*self.scale_y.borrow() {
// Some(sy) => {
// NumWithUnit::from_str(sy)?.perc_relative_to(total_height as i32) as f64 / 100.0
// }
// None => 1.0,
// };
cr.translate(transform_origin_x, transform_origin_y);
cr.rotate(perc_to_rad(rotate));
cr.translate(translate_x - transform_origin_x, translate_y - transform_origin_y);
cr.scale(scale_x, scale_y);
// cr.translate(transform_origin_x, transform_origin_y);
// cr.rotate(perc_to_rad(rotate));
// cr.translate(translate_x - transform_origin_x, translate_y - transform_origin_y);
// cr.scale(scale_x, scale_y);
// Children widget
if let Some(child) = &*self.content.borrow() {
self.obj().propagate_draw(child, cr);
}
// // Children widget
// if let Some(child) = &*self.content.borrow() {
// self.obj().propagate_draw(child, cr);
// }
cr.restore()?;
Ok(())
})();
// cr.restore()?;
// Ok(())
// })();
if let Err(error) = res {
error_handling_ctx::print_error(error)
};
// if let Err(error) = res {
// error_handling_ctx::print_error(error)
// };
glib::Propagation::Proceed
}
}
// glib::Propagation::Proceed
// }
// }
fn perc_to_rad(n: f64) -> f64 {
(n / 100f64) * 2f64 * std::f64::consts::PI
}
// fn perc_to_rad(n: f64) -> f64 {
// (n / 100f64) * 2f64 * std::f64::consts::PI
// }

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
use crate::gtk::prelude::LabelExt;
use crate::gtk4::prelude::LabelExt;
use anyhow::{anyhow, Result};
use gtk::pango;
use gtk4::pango;
use rhai::Map;
use std::process::Command;
@@ -75,29 +75,29 @@ pub fn dynamic_eq(a: &rhai::Dynamic, b: &rhai::Dynamic) -> bool {
}
/// ALL WIDGETS
pub(super) fn parse_align(o: &str) -> Result<gtk::Align> {
pub(super) fn parse_align(o: &str) -> Result<gtk4::Align> {
match o.to_ascii_lowercase().as_str() {
"fill" => Ok(gtk::Align::Fill),
"baseline" => Ok(gtk::Align::Baseline),
"center" => Ok(gtk::Align::Center),
"start" => Ok(gtk::Align::Start),
"end" => Ok(gtk::Align::End),
"fill" => Ok(gtk4::Align::Fill),
"baseline" => Ok(gtk4::Align::Baseline),
"center" => Ok(gtk4::Align::Center),
"start" => Ok(gtk4::Align::Start),
"end" => Ok(gtk4::Align::End),
other => Err(anyhow!("Invalid alignment: {}", other)),
}
}
/// Gtk Box
pub(super) fn parse_orientation(ori: &str) -> Result<gtk::Orientation> {
pub(super) fn parse_orientation(ori: &str) -> Result<gtk4::Orientation> {
match ori.to_ascii_lowercase().as_str() {
"h" | "horizontal" => Ok(gtk::Orientation::Horizontal),
"v" | "vertical" => Ok(gtk::Orientation::Vertical),
"h" | "horizontal" => Ok(gtk4::Orientation::Horizontal),
"v" | "vertical" => Ok(gtk4::Orientation::Vertical),
other => Err(anyhow!("Invalid orientation: {}", other)),
}
}
/// Gtk Label
pub(super) fn apply_ellipsize_settings(
label: &gtk::Label,
label: &gtk4::Label,
truncate: bool,
limit_width: i32,
truncate_left: bool,
@@ -126,12 +126,12 @@ pub(super) fn parse_gravity(s: &str) -> Result<pango::Gravity> {
}
}
pub(super) fn parse_justification(s: &str) -> Result<gtk::Justification> {
pub(super) fn parse_justification(s: &str) -> Result<gtk4::Justification> {
match s.to_ascii_lowercase().as_str() {
"left" => Ok(gtk::Justification::Left),
"right" => Ok(gtk::Justification::Right),
"center" => Ok(gtk::Justification::Center),
"fill" => Ok(gtk::Justification::Fill),
"left" => Ok(gtk4::Justification::Left),
"right" => Ok(gtk4::Justification::Right),
"center" => Ok(gtk4::Justification::Center),
"fill" => Ok(gtk4::Justification::Fill),
_ => Err(anyhow!("Invalid justification: '{}'", s)),
}
}
@@ -146,12 +146,12 @@ pub(super) fn parse_wrap_mode(s: &str) -> Result<pango::WrapMode> {
}
/// Gtk scale (slider)
pub(super) fn parse_position_type(s: &str) -> Result<gtk::PositionType> {
pub(super) fn parse_position_type(s: &str) -> Result<gtk4::PositionType> {
match s.to_ascii_lowercase().as_str() {
"left" => Ok(gtk::PositionType::Left),
"right" => Ok(gtk::PositionType::Right),
"top" => Ok(gtk::PositionType::Top),
"bottom" => Ok(gtk::PositionType::Bottom),
"left" => Ok(gtk4::PositionType::Left),
"right" => Ok(gtk4::PositionType::Right),
"top" => Ok(gtk4::PositionType::Top),
"bottom" => Ok(gtk4::PositionType::Bottom),
_ => Err(anyhow!("Invalid position type: '{}'", s)),
}
}
@@ -172,28 +172,24 @@ where
}
/// Revealer
pub(super) fn parse_revealer_transition(t: &str) -> Result<gtk::RevealerTransitionType> {
pub(super) fn parse_revealer_transition(t: &str) -> Result<gtk4::RevealerTransitionType> {
match t.to_ascii_lowercase().as_str() {
"slideright" => Ok(gtk::RevealerTransitionType::SlideRight),
"slideleft" => Ok(gtk::RevealerTransitionType::SlideLeft),
"slideup" => Ok(gtk::RevealerTransitionType::SlideUp),
"slidedown" => Ok(gtk::RevealerTransitionType::SlideDown),
"fade" | "crossfade" => Ok(gtk::RevealerTransitionType::Crossfade),
"none" => Ok(gtk::RevealerTransitionType::None),
"slideright" => Ok(gtk4::RevealerTransitionType::SlideRight),
"slideleft" => Ok(gtk4::RevealerTransitionType::SlideLeft),
"slideup" => Ok(gtk4::RevealerTransitionType::SlideUp),
"slidedown" => Ok(gtk4::RevealerTransitionType::SlideDown),
"fade" | "crossfade" => Ok(gtk4::RevealerTransitionType::Crossfade),
"none" => Ok(gtk4::RevealerTransitionType::None),
_ => Err(anyhow!("Invalid transition: '{}'", t)),
}
}
/// Gtk Image
// icon-size - "menu", "small-toolbar", "toolbar", "large-toolbar", "button", "dnd", "dialog"
pub(super) fn parse_icon_size(o: &str) -> Result<gtk::IconSize> {
// icon-size - "normal", "large"
pub(super) fn parse_icon_size(o: &str) -> Result<gtk4::IconSize> {
match o.to_ascii_lowercase().as_str() {
"menu" => Ok(gtk::IconSize::Menu),
"small-toolbar" | "toolbar" => Ok(gtk::IconSize::SmallToolbar),
"large-toolbar" => Ok(gtk::IconSize::LargeToolbar),
"button" => Ok(gtk::IconSize::Button),
"dnd" => Ok(gtk::IconSize::Dnd),
"dialog" => Ok(gtk::IconSize::Dialog),
"normal" => Ok(gtk4::IconSize::Normal),
"large" => Ok(gtk4::IconSize::Large),
_ => Err(anyhow!("Invalid icon size: '{}'", o)),
}
}
@@ -215,14 +211,14 @@ pub(super) fn parse_dragtype(o: &str) -> Result<DragEntryType> {
/// Stack widget
// transition - "slideright", "slideleft", "slideup", "slidedown", "crossfade", "none"
pub(super) fn parse_stack_transition(t: &str) -> Result<gtk::StackTransitionType> {
pub(super) fn parse_stack_transition(t: &str) -> Result<gtk4::StackTransitionType> {
match t.to_ascii_lowercase().as_str() {
"slideright" => Ok(gtk::StackTransitionType::SlideRight),
"slideleft" => Ok(gtk::StackTransitionType::SlideLeft),
"slideup" => Ok(gtk::StackTransitionType::SlideUp),
"slidedown" => Ok(gtk::StackTransitionType::SlideDown),
"fade" | "crossfade" => Ok(gtk::StackTransitionType::Crossfade),
"none" => Ok(gtk::StackTransitionType::None),
"slideright" => Ok(gtk4::StackTransitionType::SlideRight),
"slideleft" => Ok(gtk4::StackTransitionType::SlideLeft),
"slideup" => Ok(gtk4::StackTransitionType::SlideUp),
"slidedown" => Ok(gtk4::StackTransitionType::SlideDown),
"fade" | "crossfade" => Ok(gtk4::StackTransitionType::Crossfade),
"none" => Ok(gtk4::StackTransitionType::None),
_ => Err(anyhow!("Invalid stack transition: '{}'", t)),
}
}

View File

@@ -1,10 +1,10 @@
use gtk::glib::{self, object_subclass, wrapper, Properties};
use gtk::{prelude::*, subclass::prelude::*};
use gtk4::glib::{self, object_subclass, wrapper, Properties};
use gtk4::{prelude::*, subclass::prelude::*};
use std::cell::RefCell;
wrapper! {
pub struct Window(ObjectSubclass<WindowPriv>)
@extends gtk::Window, gtk::Bin, gtk::Container, gtk::Widget, @implements gtk::Buildable;
@extends gtk4::Window, gtk4::Bin, gtk4::Container, gtk4::Widget, @implements gtk4::Buildable;
}
#[derive(Properties)]
@@ -26,7 +26,7 @@ impl Default for WindowPriv {
#[object_subclass]
impl ObjectSubclass for WindowPriv {
type ParentType = gtk::Window;
type ParentType = gtk4::Window;
type Type = Window;
const NAME: &'static str = "WindowEwwii";
@@ -38,15 +38,15 @@ impl Default for Window {
}
}
impl Window {
pub fn new(type_: gtk::WindowType, x_: i32, y_: i32) -> Self {
let w: Self = glib::Object::builder().property("type", type_).build();
let priv_ = w.imp();
priv_.x.replace(x_);
priv_.y.replace(y_);
w
}
}
// impl Window {
// pub fn new(type_: gtk4::WindowType, x_: i32, y_: i32) -> Self {
// let w: Self = glib::Object::builder().property("type", type_).build();
// let priv_ = w.imp();
// priv_.x.replace(x_);
// priv_.y.replace(y_);
// w
// }
// }
impl ObjectImpl for WindowPriv {
fn properties() -> &'static [glib::ParamSpec] {
@@ -57,7 +57,7 @@ impl ObjectImpl for WindowPriv {
self.derived_property(id, pspec)
}
}
impl WindowImpl for WindowPriv {}
impl BinImpl for WindowPriv {}
impl ContainerImpl for WindowPriv {}
impl WidgetImpl for WindowPriv {}
// impl WindowImpl for WindowPriv {}
// impl BinImpl for WindowPriv {}
// impl ContainerImpl for WindowPriv {}
// impl WidgetImpl for WindowPriv {}

View File

@@ -13,7 +13,6 @@ shared_utils.workspace = true
rhai = { workspace = true, features = ["internals"] }
anyhow.workspace = true
gtk.workspace = true
tokio = { workspace = true, features = ["full"] }
log.workspace = true
once_cell.workspace = true