Last active
December 14, 2022 16:57
-
-
Save lll9p/dd465f1236f4db365c76984c9859f437 to your computer and use it in GitHub Desktop.
Custom widget
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pub fn create_widgets_on_window(app: &Application) -> ApplicationWindow { | |
let container = gtk::Box::new(gtk::Orientation::Vertical, 5); | |
let shape_widget = shape::Shape::new(); // create custom shape widget. | |
let class = 0; | |
let mut shape_data = shapes::Shape::new_polygon(class); | |
shape_widget.init_shape(shapes::Shape::new_polygon(class)); | |
use shapes::Point; | |
let path = [ | |
Point::new(209., 393., class), | |
Point::new(339., 207., class), | |
Point::new(37., 77., class), | |
Point::new(37., 16., class), | |
Point::new(391., 103., class), | |
Point::new(421., 263., class), | |
]; | |
path.into_iter().for_each(|point| { | |
shape_data.add_data(point); | |
shape_widget.update_shape(&shape_data); | |
}); | |
container.append(&shape_widget); | |
let shape_widget = shape::Shape::new();// create second custom shape widget. | |
let class = 1; | |
let mut shape_data = shapes::Shape::new_polygon(class); | |
shape_widget.init_shape(shapes::Shape::new_polygon(class)); | |
let path = [ | |
Point::new(40., 100., class), | |
Point::new(120., 500., class), | |
Point::new(150., 15., class), | |
]; | |
path.into_iter().for_each(|point| { | |
shape_data.add_data(point); | |
shape_widget.update_shape(&shape_data); | |
}); | |
container.append(&shape_widget); | |
let window = cascade! { | |
ApplicationWindow::new(app); | |
..add_css_class(if PROFILE == "Devel" { | |
"devel" | |
} else { | |
"" | |
}); | |
..set_show_menubar(true); | |
..set_child(Some(&container)); | |
}; | |
window.present(); | |
window | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use crate::shapes::{self, DrawBehavier, ShapeBehavier}; | |
use gtk::{ | |
glib::{self, subclass::Signal}, | |
prelude::{GestureExt, WidgetExt}, | |
subclass::prelude::{ | |
ObjectImpl, ObjectImplExt, ObjectSubclass, ObjectSubclassExt, ObjectSubclassIsExt, | |
WidgetClassSubclassExt, WidgetImpl, | |
}, | |
traits::SnapshotExt, | |
}; | |
use std::{cell::RefCell, rc::Rc}; | |
glib::wrapper! { | |
pub struct Shape(ObjectSubclass<ShapePrivate>) | |
@extends gtk::Widget, | |
@implements gtk::Accessible; | |
} | |
impl Default for Shape { | |
fn default() -> Self { | |
Self::new() | |
} | |
} | |
impl Shape { | |
pub fn new() -> Self { | |
glib::Object::new(&[]) | |
} | |
pub fn update_shape(&self, shape: &shapes::Shape) { | |
self.imp().shape.borrow_mut().translate_from(shape); | |
} | |
pub fn init_shape(&self, shape: shapes::Shape) { | |
*self.imp().shape.borrow_mut() = shape; | |
} | |
} | |
#[derive(Debug)] | |
pub struct ShapePrivate { | |
shape: Rc<RefCell<shapes::Shape>>, | |
} | |
impl ShapePrivate { | |
fn get_class(&self) -> usize { | |
self.shape.borrow().class() | |
} | |
} | |
impl Default for ShapePrivate { | |
fn default() -> Self { | |
Self { | |
shape: Rc::new(RefCell::new(shapes::Shape::default())), | |
} | |
} | |
} | |
// Trait shared by all GObjects. | |
#[glib::object_subclass] | |
impl ObjectSubclass for ShapePrivate { | |
const NAME: &'static str = "Shape"; | |
type Type = Shape; | |
type ParentType = gtk::Widget; | |
fn class_init(klass: &mut Self::Class) { | |
klass.set_css_name("shape"); | |
klass.set_accessible_role(gtk::AccessibleRole::Widget); | |
} | |
} | |
// Trait shared by all widgets. | |
impl ObjectImpl for ShapePrivate { | |
fn constructed(&self) { | |
let obj = self.obj(); | |
self.parent_constructed(); | |
obj.add_css_class("shape"); | |
// Connect a gesture to handle clicks. | |
let gesture = gtk::GestureClick::new(); | |
gesture.connect_released(|gesture, _n_pressed, x, y| { | |
gesture.set_state(gtk::EventSequenceState::Claimed); | |
println!("Pressed!"); | |
}); | |
obj.add_controller(&gesture); | |
let evt = gtk::EventControllerMotion::new(); | |
let shape = self.shape.clone(); | |
evt.connect_enter(move |_c, _x, _y| { | |
println!("enter shape {}", shape.borrow().class()); | |
}); | |
let shape = self.shape.clone(); | |
evt.connect_leave(move |_c| { | |
println!("leave shape {}", shape.borrow().class()); | |
}); | |
obj.add_controller(&evt); | |
} | |
fn signals() -> &'static [glib::subclass::Signal] { | |
Box::leak(Box::new([Signal::builder("update").build()])) | |
} | |
fn properties() -> &'static [glib::ParamSpec] { | |
Box::leak(Box::new([glib::ParamSpecUInt::new( | |
"shape-class", | |
"Shape-class", | |
"class of shape", | |
0, | |
u32::MAX, | |
0, | |
glib::ParamFlags::READWRITE, | |
)])) | |
} | |
fn set_property(&self, _id: usize, value: &glib::Value, pspec: &glib::ParamSpec) { | |
match pspec.name() { | |
"shape-class" => { | |
if let Ok(class) = value.get::<u32>() { | |
unimplemented!(); | |
}; | |
} | |
_ => unimplemented!(), | |
} | |
} | |
fn property(&self, _id: usize, _pspec: &glib::ParamSpec) -> glib::Value { | |
match _pspec.name() { | |
"shape-class" => unimplemented!(), | |
_ => unimplemented!(), | |
} | |
} | |
} | |
impl WidgetImpl for ShapePrivate { | |
fn contains(&self, x: f64, y: f64) -> bool { | |
let ret = self | |
.shape | |
.borrow() | |
.contains(x, y) | |
.map_or(false, |contains| contains); | |
ret | |
} | |
fn measure(&self, orientation: gtk::Orientation, for_size: i32) -> (i32, i32, i32, i32) { | |
if let Ok((min_x, min_y, max_x, max_y)) = self.shape.borrow().bounding_box() { | |
let width = max_x - min_x; | |
let height = max_y - min_y; | |
match orientation { | |
gtk::Orientation::Horizontal => (width as i32, width as i32, -1, -1), | |
gtk::Orientation::Vertical => (height as i32, height as i32, -1, -1), | |
_ => unreachable!(), | |
} | |
} else { | |
(0, 0, -1, -1) | |
} | |
} | |
fn snapshot(&self, snapshot: >k::Snapshot) { | |
// Save the original coordinate space | |
snapshot.save(); | |
self.shape.borrow().draw(snapshot).unwrap(); | |
// Restore original coordinate space | |
snapshot.restore(); | |
// End the clip of widget bounds | |
// snapshot.pop(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment