How to create new window through window menu in Tauri? - rust

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

Related

RUST + FLTK: accessing another widget from widget on_push() function

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.

How can I create a MessageDialog using winrt-rs?

I am attempting to show a MessageDialog upon keypress. So far, it doesn't seem to do anything. The code does compile, but does not function. The code verifies that the keypress works, but the dialog simply wont display. I have tried taking the returned IAsyncOperation and using 'get()' but that seems to freeze the application completely. What am I missing?
//#![windows_subsystem = "windows"]
use winit::{
event::{Event, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::WindowBuilder,
};
use winrt::*;
import!(
dependencies
os
modules
"windows.data.xml.dom"
"windows.foundation"
"windows.ui"
"windows.ui.popups"
);
fn main() {
let event_loop = EventLoop::new();
let window = WindowBuilder::new().build(&event_loop).unwrap();
event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;
match event {
Event::WindowEvent {
event: WindowEvent::CloseRequested,
window_id,
} if window_id == window.id() => *control_flow = ControlFlow::Exit,
Event::WindowEvent {
event: WindowEvent::Resized (_size),
..
} => (),
Event::WindowEvent {
event: WindowEvent::KeyboardInput {input,..},
..
} if input.state == winit::event::ElementState::Pressed => {
use windows::ui::popups::MessageDialog;
let mymsg = MessageDialog::create("Test").unwrap().show_async();
println!("KeyState-{}",input.scancode);
},
_ => (),
}
});
}
This highlights one of the differences in using some WinRT APIs in a Win32 application. In a UWP application, your app has a CoreWindow associated with its main thread. Normally, dialogs query for this window and display themselves as modal to it. However, in a Win32 application the system can't make an assumption about what window you want to use. In these instances, you need to QI for the IInitializeWithWindow interface and call the initialize function with your window handle.
Since the IInitializeWithWindow interface is a pure COM interface and not a WinRT one, winrt-rs doesn't have a projection for it. Instead you'll need to define it yourself (make sure you get the GUID right!):
#[repr(C)]
pub struct abi_IInitializeWithWindow {
__base: [usize; 3],
initialize: extern "system" fn(
winrt::NonNullRawComPtr<InitializeWithWindowInterop>,
*mut c_void,
) -> winrt::ErrorCode,
}
unsafe impl winrt::ComInterface for InitializeWithWindowInterop {
type VTable = abi_IInitializeWithWindow;
fn iid() -> winrt::Guid {
winrt::Guid::from_values(1047057597, 28981, 19728, [128, 24, 159, 182, 217, 243, 63, 161])
}
}
#[repr(transparent)]
#[derive(Default, Clone)]
pub struct InitializeWithWindowInterop {
ptr: winrt::ComPtr<InitializeWithWindowInterop>,
}
impl InitializeWithWindowInterop {
pub fn initialize(
&self,
window: *mut c_void,
) -> winrt::Result<()> {
match self.ptr.abi() {
None => panic!("The `this` pointer was null when calling method"),
Some(this) => unsafe {
(this.vtable().initialize)(
this,
window,
)
.ok()?;
Ok(())
},
}
}
}
To get the window handle from your winit Window, you'll need the raw-window-handle crate. From there you can create a helper trait for anything that implements HasRawWindowHandle:
trait InitializeWithWindow {
fn initialize_with_window<O: RuntimeType + ComInterface>(&self, object: &O) -> winrt::Result<()>;
}
impl<T> InitializeWithWindow for T
where
T: HasRawWindowHandle,
{
fn initialize_with_window<O: RuntimeType + ComInterface>(
&self,
object: &O,
) -> winrt::Result<()> {
// Get the window handle
let window_handle = self.raw_window_handle();
let window_handle = match window_handle {
raw_window_handle::RawWindowHandle::Windows(window_handle) => window_handle.hwnd,
_ => panic!("Unsupported platform!"),
};
let init: InitializeWithWindowInterop = object.try_into()?;
init.initialize(window_handle)?;
Ok(())
}
}
Now in your event loop you can call it using the following:
let dialog = MessageDialog::create("Test").unwrap();
window.initialize_with_window(&dialog).unwrap();
dialog.show_async().unwrap();
println!("KeyState-{}",input.scancode);
Note that I'm not waiting on the result of the IAsyncOperation that is retunred by show_async. The reason is because only synchronous waiting it supported by the projection right now, and that would tie up your message pump and cause the window to hang. This means that the print statement will run before the dialog returns. This should improve once broader async support is up and running in the projection.
You can now use your initialize_with_window method on dialogs and pickers (e.g. FileSavePicker, GraphicsCapturePicker).

delwin does not delete the window

I'm using Rust for my ncurses app.
When the user presses F5, line numbers window should be toggled. When the user presses the F5 key for the first time, the window appears as it is supposed to. However, on second key press, the window does not go away, it's still there, as if the delwin call does not succeed. I tried refreshing the screen after it, but have had no success.
Here's a minimal example:
use ncurses::*;
struct LineNumbers {
window: WINDOW,
shown: bool
}
impl LineNumbers {
fn new() -> LineNumbers {
LineNumbers {
window: newwin(LINES(), 5, 0, 0),
shown: false
}
}
fn toggle(&mut self) {
if self.shown == true {
self.hide();
} else {
self.show();
}
}
fn show(&mut self) {
self.shown = true;
wbkgd(self.window, COLOR_PAIR(1));
wrefresh(self.window);
}
fn hide(&mut self) {
self.shown = false;
delwin(self.window);
refresh();
}
}
fn main() {
setlocale(LcCategory::all, "");
initscr();
keypad(stdscr(), true);
start_color();
init_pair(1, COLOR_RED, COLOR_RED);
let mut ln = LineNumbers::new();
loop {
let user_input = get_wch();
match user_input.unwrap() {
WchResult::Char(ch) => {
match ch {
27 => break,
_ => {}
}
},
WchResult::KeyCode(code) => {
match code {
KEY_F5 => {
ln.toggle();
},
_ => {}
}
}
}
}
endwin();
}
What could be the issue?
You could touch the main window before doing a refresh.
Deleting a window won't do that for you (man delwin):
Calling delwin deletes the named window, freeing all memory associated
with it (it does not actually erase the window's screen image). Sub-
windows must be deleted before the main window can be deleted.
It seems that ncurses-rs has no documentation, but is a "thin layer" (a binding). Use the ncurses manpages.

Gtk-rs application crashes at window.show_all() function

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?

How to connect Buttons to Actions in custom SimpleActionGroups in gtk-rs?

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<_>>());
}

Resources