I'd like to use a SimpleActionGroup registered to a Widget that handles SimpleActions. But anyhow every Button that targets to Actions with my custom prefix are grayed out and can't be clicked. However Buttons that are targeting the action prefixes "app" and "win" are working as expected.
Application with two Buttons
Here is the part in my code where my custom prefix is defined.
// Create action group for view
let view_action_group = gio::SimpleActionGroup::new();
view.insert_action_group("view", &view_action_group);
// SimpleAction for view
let view_action = gio::SimpleAction::new("test", None);
view_action.connect_activate(|_, _| println!("view.test"));
view_action_group.add_action(&view_action);
Here I respond to SimpleActions with prefix "app"
// SimpleAction for app
let app_action = gio::SimpleAction::new("test", None);
app_action.connect_activate(|_, _| println!("app.test"));
app.add_action(&app_action);
The SimpleAction itself should be ok, because if I start the application with GTK Inspector I can activate it.
GTK Inspector invoking actions
So what am I missing that the secound Button is not greyed out and responds to my SimpleAction?
Here is the full code:
extern crate gtk;
extern crate gio;
use std::env::args;
use gtk::{GtkApplicationExt, GtkWindowExt, ContainerExt, WidgetExt, HeaderBarExt, ActionableExt};
use gio::{SimpleActionExt, ActionMapExt, ApplicationExt, ApplicationExtManual};
struct Window {
pub window: gtk::Window,
}
impl Window {
pub fn new() -> Self {
// Create Widgets and window
let header_bar = gtk::HeaderBar::new();
let window = gtk::Window::new(gtk::WindowType::Toplevel);
let view = gtk::Box::new(gtk::Orientation::Horizontal, 5);
let app_button = gtk::Button::new_with_label("App-Action-Button");
let view_button = gtk::Button::new_with_label("View-Action-Button");
// Create Action Group for view
let view_action_group = gio::SimpleActionGroup::new();
view.insert_action_group("view", &view_action_group);
// SimpleAction for view
let view_action = gio::SimpleAction::new("test", None);
view_action.connect_activate(|_, _| println!("view.test"));
view_action_group.add_action(&view_action);
// Set Action for Buttons
app_button.set_action_name("app.test");
view_button.set_action_name("view.test");
// Configure HeaderBar and add Buttons to it
header_bar.set_show_close_button(true);
header_bar.pack_start(&app_button);
header_bar.pack_start(&view_button);
// Window Stuff
window.set_titlebar(&header_bar);
window.add(&view);
window.show_all();
Self { window }
}
}
struct App {
app: gtk::Application
}
impl App {
pub fn new () -> Self {
// Create app and window
let app = gtk::Application::new(Some("com.example.test"), gio::ApplicationFlags::FLAGS_NONE).unwrap();
let window = Window::new();
// SimpleAction for app
let app_action = gio::SimpleAction::new("test", None);
app_action.connect_activate(|_, _| println!("app.test"));
app.add_action(&app_action);
// add Signal
let cloned_window = window.window.clone();
app.connect_activate(move |app| app.add_window(&cloned_window));
Self { app }
}
pub fn run(&self, args: &[String]) {
self.app.run(args);
}
}
fn main() {
let app = App::new();
app.run(&args().collect::<Vec<_>>());
}
Related
I've tried to create new app window through window menu. But there i faced with issue that method
create_window
is not available
How can i do that?
#![cfg_attr(
all(not(debug_assertions), target_os = "windows"),
windows_subsystem = "windows"
)]
use tauri::{Menu, WindowMenuEvent, Wry, Submenu, CustomMenuItem, WindowUrl, WindowBuilder};
pub fn create() -> Menu {
let test_menu = Menu::new()
.add_item(CustomMenuItem::new("new_window", "Create new window"));
Menu::new()
.add_submenu(Submenu::new("Test", test_menu))
}
pub fn handler(event: WindowMenuEvent<Wry>) {
match event.menu_item_id() {
"new_window" => {
let mut window = event.window().clone();
}
_ => {}
}
}
fn main() {
tauri::Builder::default()
.menu(create())
.on_menu_event(handler)
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
I created menu and cloned main window(i need to create same window) in event
I have created my first egui app. The update loop looks like
impl eframe::App for App {
fn update(&mut self, ctx: &Context, _frame: &mut Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
ui.with_layout(Layout::top_down(Align::Center), |ui| {
ui.add(Label::new("bacon"));
let clicked = ui.add(Button::new("foo")).clicked();
if clicked {
println!("foo")
}
let clicked = ui.add(FurnaceGraph::default()).clicked();
if clicked {
println!("clicked");
}
})
});
}
and the ui for FurnaceGraph looks like
impl Widget for FurnaceGraph {
fn ui(mut self, ui: &mut Ui) -> Response {
let (_id, rect) = ui.allocate_space(Vec2::new(self.width as f32, self.height as f32));
let response = ui.allocate_response(rect.size(), Sense::click());
// println!("enabled? {}", ui.is_enabled());
let texture = self.get_texture(ui);
let texture_size = texture.size_vec2();
let img = Image::new(texture, texture_size);
img.paint_at(ui, Rect::from_min_max(rect.min, rect.min + img.size()));
response
}
}
I think I am asking to Sense::click()s when I allocate_response, but it never prints "clicked" when I click on the graph. I do get "foo" when I click on the foo button.
What do I have to tweak to not miss clicks?
I eventually discovered that the rect returned by allocate_space is different than the one returned by allocate_response. I was allocating one rectangle to draw in, and a different one to harvest clicks from. I got rid of the call to allocate_space because allocate_response calls it for me.
I'm trying to learn rust with its gtk4 bindings and decided to try ListStore as a model for ListBox. In order to bind the model, function which returns Widget is needed, but i need a Label. Why doesn't Label, which inherits Widget (implements IsA<Widget>), satisfy also Widget type?
Error:
error[E0308]: mismatched types
--> src/main.rs:22:5
|
21 | fn create_widget<'r>(label: &'r Object) -> Widget {
| ------ expected `gtk4::Widget` because of return type
22 | Label::new(Some(label.property_value("name").get().unwrap()))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `gtk4::Widget`, found struct `gtk4::Label`
Full code:
use gtk::prelude::*;
use gtk::{Application, ApplicationWindow, Paned, Label, Orientation, ListBox, ListBoxRow, Widget};
use gtk::gio::ListStore;
use gtk::glib::Type;
use gtk::glib::Object;
fn main() {
println!("Hello, world!");// Create a new application
let app = Application::builder()
.application_id("org.gtk-rs.example")
.build();
// Connect to "activate" signal of `app`
app.connect_activate(build_ui);
// Run the application
app.run();
}
fn create_widget<'r>(label: &'r Object) -> Widget {
Label::new(Some(label.property_value("name").get().unwrap()))
}
fn build_ui(app: &Application) {
let listbox_left = ListBox::new();
let listbox_right = ListBox::new();
let list_model = ListStore::new(Type::STRING);
listbox_right.bind_model(Some(&list_model), create_widget);
let paned = Paned::builder()
.start_child(&listbox_left)
.end_child(&listbox_right)
.orientation(Orientation::Horizontal)
.build();
// Create a window
let window = ApplicationWindow::builder()
.application(app)
.title("My GTK App")
.child(&paned)
.build();
for n in 1..11 {
let n_as_string =(n as u32).to_string();
let mut my = String::from("Left:");
my.push_str(&n_as_string);
let m = Object::with_values(Type::STRING, &[("name", my.to_value())]);
list_model.append(&m.unwrap());
}
// Present window
window.present();
}
Inheritance is not a language feature in Rust. Instead, the gtk4 crate has Label impl IsA<Widget> (here) which allows you to call Cast::upcast like this:
Label::new(Some(label.property_value("name").get().unwrap())).upcast()
You might need to add
use gtk4::glib::object::Cast;
to the top of your file.
Instead you can also make your method return impl IsA<Widget> instead.
I used FLTK to create a window and two buttons inside, the btn_A has a callback and should change the btn_B label, but I dont see any non-monstrous approach do to this, ples halp? =''[
fn main() {
showMainWindow();
}
pub fn showMainWindow() {
//WINDOW
let application=app::App::default();
let mut win = window::Window::default().with_size(500,300);
//BTN_A
let mut btn_A:Listener<_> = button::Button::new(100,100,100,50,"btn_A").into();
//BTN_B
let mut btn_B:Listener<_> = button::Button::new(300,100,100,50,"btn_B").into();
//BTN_A_CALLBACK
btn_A.handle(|elem,evt| match evt {
enums::Event::Push => { btn_A(elem); true }
_ => { false }
});
win.end();
win.show();
application.run().unwrap();
}
pub fn btn_A(elem:&mut button::Button) {
elem.deactivate(); //deactivate itself
//but how do I access btn_B here?
}
In principle all that is needed is to pass a mutable reference to btn_B to your handler function:
pub fn btn_A(elem:&mut button::Button, btn_B: &mut button::Button) {
...
}
However there is one slight problem with your code: You named the function the same as the variable that holds your button.
Apart from that in the most recent version of the fltk crate (v.1.2.23, that I used because you did not specify which version you used in your question) there does not seem to be a Listener<_> type.
Here is an example based on the snippet you posted for changing the label of btn_B:
use fltk::{prelude::{WidgetExt, GroupExt, WidgetBase}, window, app, button, enums};
fn main() {
showMainWindow();
}
pub fn showMainWindow() {
//WINDOW
let application = app::App::default();
let mut win = window::Window::default().with_size(500, 300);
//BTN_A
let mut btn_A = button::Button::new(100, 100, 100, 50, "btn_A");
//BTN_B
let mut btn_B = button::Button::new(300, 100, 100, 50, "btn_B");
//BTN_A_CALLBACK
btn_A.handle(move |elem, evt| match evt {
enums::Event::Push => {
btn_A_click(elem, &mut btn_B);
true
}
_ => false,
});
win.end();
win.show();
application.run().unwrap();
}
pub fn btn_A_click(elem: &mut button::Button, btn_B: &mut button::Button) {
elem.deactivate(); //deactivate itself
//but how do I access btn_B here?
btn_B.set_label("New title.")
}
Also note, that the handle closure now takes ownership of btn_B because of the move keyword.
My Gtk-rs application crashes whenever I try calling the show_all() function.
In a simple application window, I have added a headerbar and a label. If I compile without adding the headerbar, the window works and shows the label as intended. However if I add the headerbar the window crashes.
use gio::prelude::*;
use gtk::{
prelude::*,
HeaderBarExt,
GtkWindowExt
};
fn gen_header_bar(subtitle: Option<String>) -> gtk::HeaderBar {
let header_bar = gtk::HeaderBar::new();
header_bar.set_title(Some(crate::consts::APP_NAME));
header_bar.set_show_close_button(true);
match subtitle {
Some(subtitle) => {
header_bar.set_subtitle(Some(&subtitle));
},
_ => {
}
}
header_bar
}
pub fn build_application_window() -> Result<(), Box<dyn std::error::Error>> {
let application = gtk::Application::new(
Some(crate::consts::APP_ID),
gio::ApplicationFlags::FLAGS_NONE,
)?;
application.connect_activate(move |app| {
let window = gtk::ApplicationWindow::new(app);
window.set_title(crate::consts::APP_NAME);
window.set_default_size(32 * 10, 200); // golden ratio
window.set_position(gtk::WindowPosition::Center);
let header_bar = gen_header_bar(None);
window.set_titlebar(Some(&header_bar));
window.add(&{
let label = gtk::Label::new(Some("Welcome!"));
label
});
window.show_all(); // crashes here
});
application.run(&std::env::args().collect::<Vec<_>>());
Ok(())
}
What is causing this?