forked from gtk-rs/gtk4-rs
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
examples: Add new widget that squeezes his child
- Loading branch information
Showing
8 changed files
with
250 additions
and
0 deletions.
There are no files selected for viewing
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
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# Squeeze Widget | ||
|
||
This example shows a basic widget that squeezes its child to fit in the parent. The widget has a property which allows the child to keep its aspect ratio. | ||
|
||
Note that is implementation only supports one child. | ||
|
||
#### Screenshot with `keep_aspect_ratio` set to `true` | ||
|
||
![Screenshot](screenshot1.png) | ||
|
||
#### Screenshot with `keep_aspect_ratio` set to `false` | ||
|
||
![Screenshot](screenshot2.png) |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
mod squeezer_bin; | ||
|
||
use gtk::prelude::*; | ||
use squeezer_bin::SqueezerBin; | ||
|
||
fn main() { | ||
let application = gtk::Application::builder() | ||
.application_id("com.github.gtk-rs.examples.squeezer_bin") | ||
.build(); | ||
|
||
application.connect_activate(|app| { | ||
let window = gtk::ApplicationWindow::new(app); | ||
let headerbar = gtk::HeaderBar::new(); | ||
let mode_switch = gtk::Switch::new(); | ||
let switch_label = gtk::Label::new(Some("keep aspect ratio")); | ||
let squeezer = SqueezerBin::new(); | ||
squeezer.set_child(Some(>k::Label::new(Some("Hello World!")))); | ||
|
||
headerbar.pack_start(&mode_switch); | ||
headerbar.pack_start(&switch_label); | ||
|
||
mode_switch | ||
.bind_property("state", &squeezer, "keep-aspect-ratio") | ||
.build(); | ||
|
||
window.set_titlebar(Some(&headerbar)); | ||
window.set_child(Some(&squeezer)); | ||
window.show(); | ||
}); | ||
|
||
application.run(); | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
use gtk::glib; | ||
use gtk::glib::{ParamSpec, Value}; | ||
use gtk::gsk; | ||
use gtk::prelude::*; | ||
use gtk::subclass::prelude::*; | ||
|
||
use once_cell::sync::Lazy; | ||
use std::cell::{Cell, RefCell}; | ||
|
||
fn child_size(child: &impl IsA<gtk::Widget>) -> ((i32, i32), (i32, i32)) { | ||
let (horizontal_minimal, horizontal_natural, _, _) = | ||
child.measure(gtk::Orientation::Horizontal, -1); | ||
let (vertical_minimal, vertical_natural, _, _) = child.measure(gtk::Orientation::Vertical, -1); | ||
|
||
( | ||
(horizontal_minimal, horizontal_natural), | ||
(vertical_minimal, vertical_natural), | ||
) | ||
} | ||
|
||
#[derive(Debug, Default)] | ||
pub struct SqueezerBin { | ||
child: RefCell<Option<gtk::Widget>>, | ||
keep_aspect_ratio: Cell<bool>, | ||
} | ||
|
||
#[glib::object_subclass] | ||
impl ObjectSubclass for SqueezerBin { | ||
const NAME: &'static str = "SqueezerBin"; | ||
type ParentType = gtk::Widget; | ||
type Type = super::SqueezerBin; | ||
} | ||
|
||
impl ObjectImpl for SqueezerBin { | ||
fn properties() -> &'static [glib::ParamSpec] { | ||
static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| { | ||
vec![ | ||
glib::ParamSpecObject::new( | ||
"child", | ||
"Child", | ||
"The child of the widget", | ||
gtk::Widget::static_type(), | ||
glib::ParamFlags::READWRITE | glib::ParamFlags::EXPLICIT_NOTIFY, | ||
), | ||
glib::ParamSpecBoolean::new( | ||
"keep-aspect-ratio", | ||
"Keep aspect ratio", | ||
"If true it keeps the aspect ratio of the widget", | ||
false, | ||
glib::ParamFlags::READWRITE | glib::ParamFlags::EXPLICIT_NOTIFY, | ||
), | ||
] | ||
}); | ||
|
||
PROPERTIES.as_ref() | ||
} | ||
|
||
fn property(&self, obj: &Self::Type, _id: usize, pspec: &ParamSpec) -> Value { | ||
match pspec.name() { | ||
"child" => self.child(obj).to_value(), | ||
"keep-aspect-ratio" => self.keep_aspect_ratio(obj).to_value(), | ||
_ => unimplemented!(), | ||
} | ||
} | ||
|
||
fn set_property(&self, obj: &Self::Type, _id: usize, value: &Value, pspec: &ParamSpec) { | ||
match pspec.name() { | ||
"child" => { | ||
self.set_child(obj, value.get::<gtk::Widget>().ok().as_ref()); | ||
} | ||
"keep-aspect-ratio" => { | ||
self.set_keep_aspect_ratio(obj, value.get().unwrap()); | ||
} | ||
_ => unimplemented!(), | ||
} | ||
} | ||
|
||
fn constructed(&self, obj: &Self::Type) { | ||
obj.set_halign(gtk::Align::Fill); | ||
obj.set_valign(gtk::Align::Fill); | ||
obj.set_hexpand(true); | ||
obj.set_vexpand(true); | ||
|
||
self.parent_constructed(obj); | ||
} | ||
|
||
fn dispose(&self, obj: &Self::Type) { | ||
if let Some(child) = obj.child() { | ||
child.unparent(); | ||
} | ||
} | ||
} | ||
|
||
impl WidgetImpl for SqueezerBin { | ||
fn size_allocate(&self, widget: &Self::Type, width: i32, height: i32, baseline: i32) { | ||
if let Some(child) = widget.child() { | ||
let ((_, horizontal_size), (_, vertical_size)) = child_size(widget); | ||
|
||
let (mut horizontal_zoom, mut vertical_zoom) = ( | ||
width as f32 / horizontal_size as f32, | ||
height as f32 / vertical_size as f32, | ||
); | ||
|
||
if widget.keep_aspect_ratio() { | ||
if horizontal_zoom < vertical_zoom { | ||
vertical_zoom = horizontal_zoom; | ||
} else { | ||
horizontal_zoom = vertical_zoom; | ||
} | ||
} | ||
|
||
let transform = gsk::Transform::new() | ||
.scale(horizontal_zoom, vertical_zoom) | ||
.unwrap(); | ||
|
||
child.allocate( | ||
(width as f32 / horizontal_zoom) as i32, | ||
(height as f32 / vertical_zoom) as i32, | ||
baseline, | ||
Some(&transform), | ||
); | ||
} | ||
} | ||
} | ||
|
||
impl SqueezerBin { | ||
pub(super) fn child(&self, _obj: &super::SqueezerBin) -> Option<gtk::Widget> { | ||
self.child.borrow().clone() | ||
} | ||
|
||
pub(super) fn set_child( | ||
&self, | ||
obj: &super::SqueezerBin, | ||
widget: Option<&impl IsA<gtk::Widget>>, | ||
) { | ||
let widget = widget.map(|w| w.as_ref()); | ||
if widget == self.child.borrow().as_ref() { | ||
return; | ||
} | ||
|
||
if let Some(child) = self.child.borrow_mut().take() { | ||
child.unparent(); | ||
} | ||
|
||
if let Some(w) = widget { | ||
self.child.replace(Some(w.clone())); | ||
w.set_parent(obj); | ||
} | ||
|
||
obj.queue_resize(); | ||
obj.notify("child") | ||
} | ||
|
||
pub(super) fn keep_aspect_ratio(&self, _obj: &super::SqueezerBin) -> bool { | ||
self.keep_aspect_ratio.get() | ||
} | ||
|
||
pub(super) fn set_keep_aspect_ratio(&self, obj: &super::SqueezerBin, keep_aspect_ratio: bool) { | ||
if self.keep_aspect_ratio.get() == keep_aspect_ratio { | ||
return; | ||
} | ||
|
||
self.keep_aspect_ratio.set(keep_aspect_ratio); | ||
|
||
obj.queue_resize(); | ||
obj.notify("keep-aspect-ratio") | ||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
mod imp; | ||
|
||
use gtk::glib; | ||
use gtk::prelude::*; | ||
use gtk::subclass::prelude::*; | ||
|
||
glib::wrapper! { | ||
pub struct SqueezerBin(ObjectSubclass<imp::SqueezerBin>) @extends gtk::Widget; | ||
} | ||
|
||
impl SqueezerBin { | ||
#[allow(clippy::new_without_default)] | ||
pub fn new() -> Self { | ||
glib::Object::new(&[]).unwrap() | ||
} | ||
|
||
pub fn keep_aspect_ratio(&self) -> bool { | ||
self.imp().keep_aspect_ratio(self) | ||
} | ||
|
||
pub fn set_keep_aspect_ratio(&self, keep_aspect_ratio: bool) { | ||
self.imp().set_keep_aspect_ratio(self, keep_aspect_ratio) | ||
} | ||
|
||
pub fn child(&self) -> Option<gtk::Widget> { | ||
self.imp().child(self) | ||
} | ||
|
||
pub fn set_child(&self, widget: Option<&impl IsA<gtk::Widget>>) { | ||
self.imp().set_child(self, widget); | ||
} | ||
} |