Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Examples: Dialog's response signal handling #1514

Merged
merged 13 commits into from
Jan 29, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ path = "column_view_datagrid/main.rs"
name = "composite_template"
path = "composite_template/main.rs"

[[bin]]
name = "composite_dialog"
path = "composite_dialog/main.rs"

[[bin]]
name = "confetti_snapshot_animation"
path = "confetti_snapshot_animation/main.rs"
Expand Down Expand Up @@ -187,4 +191,3 @@ path = "video_player/main.rs"
[[bin]]
name = "virtual_methods"
path = "virtual_methods/main.rs"

6 changes: 6 additions & 0 deletions examples/composite_dialog/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Composite Template Dialog

This example shows the use of callbacks, custom and bind property, notify and response signal in a composite
template situation.

![Screenshot](screenshot.png)
17 changes: 17 additions & 0 deletions examples/composite_dialog/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
mod my_app_window;

use gtk::glib;
use gtk::prelude::*;
jobale marked this conversation as resolved.
Show resolved Hide resolved
use my_app_window::MyAppWindow;

fn main() -> glib::ExitCode {
let application = gtk::Application::builder()
.application_id("com.github.gtk-rs.examples.composite_dialog")
.build();

application.connect_activate(|app| {
let win = MyAppWindow::new(app);
win.present();
});
application.run()
}
43 changes: 43 additions & 0 deletions examples/composite_dialog/my_app_window/imp.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use std::cell::Cell;

use gtk::{glib, prelude::*, subclass::prelude::*};

// Object holding the state
jobale marked this conversation as resolved.
Show resolved Hide resolved
#[derive(Default, gtk::CompositeTemplate, glib::Properties)]
#[template(file = "window.ui")]
#[properties(wrapper_type = super::MyAppWindow)]
pub struct MyAppWindow {
#[property(get, set)]
counter: Cell<i32>,
#[template_child]
pub count_label: TemplateChild<gtk::Label>,
#[template_child]
pub plus: TemplateChild<gtk::Button>,
#[template_child]
pub minus: TemplateChild<gtk::Button>,
#[template_child]
pub popup: TemplateChild<gtk::Dialog>,
jobale marked this conversation as resolved.
Show resolved Hide resolved
}

#[glib::object_subclass]
impl ObjectSubclass for MyAppWindow {
const NAME: &'static str = "MyAppWindow";
type Type = super::MyAppWindow;
type ParentType = gtk::ApplicationWindow;

fn class_init(klass: &mut Self::Class) {
klass.bind_template();
klass.bind_template_instance_callbacks();
}

fn instance_init(obj: &glib::subclass::InitializingObject<Self>) {
obj.init_template();
}
}

#[glib::derived_properties]
impl ObjectImpl for MyAppWindow {}

jobale marked this conversation as resolved.
Show resolved Hide resolved
impl WidgetImpl for MyAppWindow {}
impl WindowImpl for MyAppWindow {}
impl ApplicationWindowImpl for MyAppWindow {}
64 changes: 64 additions & 0 deletions examples/composite_dialog/my_app_window/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Since Gtk4 v4.10 gtk4::Dialog is deprecated and gtk4-rs's examples minimum version is v4.10
#[allow(deprecated)]
mod imp;

use gtk::{glib, prelude::*, subclass::prelude::ObjectSubclassIsExt};
jobale marked this conversation as resolved.
Show resolved Hide resolved

glib::wrapper! {
pub struct MyAppWindow(ObjectSubclass<imp::MyAppWindow>)
@extends gtk::Widget, gtk::Window, gtk::ApplicationWindow;
}

#[gtk::template_callbacks]
impl MyAppWindow {
pub fn new<P: IsA<gtk::Application>>(app: &P) -> Self {
glib::Object::builder().property("application", app).build()
}

/// Callback handler for notify::label signal.
jobale marked this conversation as resolved.
Show resolved Hide resolved
///
/// When counter property reach 3, a dialog pops up and present the user
/// with 2 choices: Set the counter to 6 or reset the counter to 0.
#[template_callback]
fn popup_dialog(&self, _p: &glib::ParamSpec) {
jobale marked this conversation as resolved.
Show resolved Hide resolved
// Check counter property and create a Dialog.
if self.counter() == 3 {
self.imp().popup.present();
}
}

/// Handler for popup dialog's response.
///
/// In the callback handler, response type is i32 instead of gtk::ResponseType.
jobale marked this conversation as resolved.
Show resolved Hide resolved
#[template_callback]
fn counter_choice(&self, response: i32) {
match gtk::ResponseType::from(response) {
gtk::ResponseType::Ok => {
self.set_counter(0);
self.imp().popup.set_visible(false);
}
gtk::ResponseType::Other(35) => {
self.set_counter(6);
self.imp().popup.set_visible(false);
}
gtk::ResponseType::DeleteEvent => {
self.imp().popup.set_visible(false);
}
_ => unimplemented!(),
}
jobale marked this conversation as resolved.
Show resolved Hide resolved
}

/// Callback handler for gtk::Button plus.
#[template_callback]
fn add_to_counter(&self, _button: &gtk::Button) {
let n = self.counter() + 1;
self.set_counter(n);
}

/// Callback handler for gtk::Button minus.
#[template_callback]
fn sub_to_counter(&self, _button: &gtk::Button) {
let n = self.counter() - 1;
self.set_counter(n);
}
}
84 changes: 84 additions & 0 deletions examples/composite_dialog/my_app_window/window.ui
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<?xml version='1.0' encoding='UTF-8'?>
<interface>
<template class="MyAppWindow" parent="GtkApplicationWindow">
<property name="default-height">300</property>
<property name="default-width">400</property>
<property name="hexpand">True</property>
<property name="show-menubar">True</property>
<property name="title">Composite Template Dialog</property>
<property name="vexpand">True</property>
<signal name="notify::counter" handler="popup_dialog" swapped="true"/>
<child>
<object class="GtkBox">
<property name="halign">center</property>
<property name="margin-top">10</property>
<property name="spacing">5</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel">
<property name="label">Click until you reach 3</property>
<style>
<class name="large-title"/>
</style>
</object>
</child>
<child>
<object class="GtkBox">
<property name="halign">center</property>
<property name="valign">center</property>
<property name="spacing">10</property>
<child>
<object class="GtkButton" id="plus">
<signal name="clicked" handler="add_to_counter" swapped="true"/>
<property name="label">+</property>
<property name="focus-on-click">True</property>
</object>
</child>
<child>
<object class="GtkButton" id="minus">
<signal name="clicked" handler="sub_to_counter" swapped="true"/>
<property name="label">-</property>
<property name="focus-on-click">True</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkLabel" id="count_label">
<property name="label"
bind-source="MyAppWindow"
bind-property="counter"
bind-flags="sync-create"/>
<property name="justify">center</property>
<property name="margin-end">5</property>
<property name="margin-start">5</property>
<property name="margin-top">20</property>
<property name="margin-bottom">5</property>
</object>
</child>
</object>
</child>
</template>
<object class="GtkDialog" id="popup">
<property name="transient-for">MyAppWindow</property>
<property name="title">Counter reach 3</property>
<property name="modal">True</property>
<signal name="response" handler="counter_choice" swapped="true"/>
<child type="action">
<object class="GtkButton" id="button_six">
<property name="visible">True</property>
<property name="label">Set counter to 6</property>
</object>
</child>
<child type="action">
<object class="GtkButton" id="button_reset">
<property name="visible">True</property>
<property name="label">Reset counter</property>
</object>
</child>
<action-widgets>
<action-widget response="35">button_six</action-widget>
<action-widget response="ok">button_reset</action-widget>
</action-widgets>
</object>
</interface>
Binary file added examples/composite_dialog/screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading