Giter Site home page Giter Site logo

gabdube / native-windows-gui Goto Github PK

View Code? Open in Web Editor NEW
1.9K 39.0 125.0 5.36 MB

A light windows GUI toolkit for rust

Home Page: https://gabdube.github.io/native-windows-gui/

License: MIT License

Rust 99.87% GLSL 0.13%
gui rust native native-windows-gui

native-windows-gui's Introduction

Native Windows GUI

Welcome to Native Windows GUI (aka NWG). A rust library to develop native GUI applications on the desktop for Microsoft Windows.

NWG is a very light wrapper over WINAPI. It allows you, the developer, to handle the quirks and rough edges of the API by providing a simple, safe and rust-like interface.

Native Windows GUI keeps things simple. This means small compile times, minimal resource usage, less time searching the documentation and more time for you to develop your application.

Of course, you don't have to take my word for it, check out the showcase and the examples.

This is the 3rd and final version of NWG. It is considered "mature" or, as I would say "the backlog is empty, and it will most likely stay that way". This version implements pretty much everything required to develop applications on Windows. Don't bother using the older versions as they have "irreconcilable design decisions" and cannot support some key features. Future development will be done in other libraries.

If you've managed to read through this introduction, you should know that my twitter handle is #gdube_dev and you can support this project with GitHub Sponsors.

Any support is greatly appreciated.

Installation

To use NWG in your project add it to cargo.toml:

[dependencies]
native-windows-gui = "1.0.12"
native-windows-derive = "1.0.3" # Optional. Only if the derive macro is used.

And then, in main.rs or lib.rs :

extern crate native_windows_gui as nwg;
extern crate native_windows_derive as nwd;  // Optional. Only if the derive macro is used.

Rust 2018 aliasing

You can skip the extern crate define in your source code by adding the following code in Cargo.toml Note that procedural macros still require an extern crate definition, so this wont work with native-windows-derive

[dependencies]
nwg = {version = "^1.0.12", package = "native-windows-gui"}

Trying it out

See it for yourself. NWG has plenty of examples and a fully interactive test suite. The only thing you need to do is:

git clone [email protected]:gabdube/native-windows-gui.git

cd native-windows-gui/native-windows-gui # Running the tests from the workspace screws up the features

cargo test everything --features "all"  # For the test suite
cargo run --example basic
cargo run --example calculator
cargo run --example message_bank
cargo run --example image_decoder_d --features "extern-canvas"
cargo run --example partials --features "listbox frame combobox"
cargo run --example system_tray --features "tray-notification message-window menu cursor"
cargo run --example dialog_multithreading_d --features "notice"
cargo run --example image_decoder_d --features "image-decoder file-dialog"
cargo run --example month_name_d --features "winnls textbox"
cargo run --example splash_screen_d --features "image-decoder"
cargo run --example drop_files_d --features "textbox"

cd examples/opengl_canvas
cargo run

# The closest thing to a real application in the examples
cd ../examples/sync-draw
cargo run

# Requires the console to be run as Admin because of the embed resource
cd ../examples/embed_resources
cargo run

Cross-compiling from Ubuntu

Requirement: MinGW compiler

sudo apt install gcc-mingw-w64-x86-64

Requirement: Rust support

rustup target add x86_64-pc-windows-gnu

Compiling and running basic example:

cargo build --release --target=x86_64-pc-windows-gnu
cargo build --release --target=x86_64-pc-windows-gnu --example basic
wine target/x86_64-pc-windows-gnu/release/examples/basic.exe

Project structure

This is the main project git. It is separated in multiple sections

  • native-windows-gui
    • The base library. Includes an interactive test suite and plenty of examples
  • native-windows-derive
    • A procedural macro that generates the GUI application from rust structure (pretty cool stuff IMO)
  • docs/native-windows-docs read it online
    • Hefty documentation that goes over everything you need to know about NWG
  • showcase
    • Images of the examples. If you've made an NWG application and want to share it here, send me a message or open a PR. It's free real estate.

Supported features

  • The WHOLE winapi control library (reference)
    • Some very niche controls are not supported: flat scroll bar, ip control, rebar, and pager.
  • Menus and menu bar
  • Image and font resource
    • BMP
    • ICO
    • CUR
    • PNG*
    • GIF*
    • JPG*
    • TIFF*
    • DDS*
    • *: Extended image formats with the Windows Imaging Component (WIC).
  • Localization support
    • Uses Windows National Language Support internally (reference)
  • Tooltip
  • System tray notification
  • Cursor handling
  • A full clipboard wrapper
  • Partial templates support
    • Split large application into chunks
  • Dynamic controls support
    • Add/Remove controls at runtime
    • Bind or unbind new events at runtime
  • Multithreaded application support
    • Communicate to the GUI thread from another thread
    • Run multiple windows on different threads
  • Simple layout configurations
    • FlexboxLayout
    • GridLayout
  • Drag and drop
    • Drop files from the desktop to a window
  • The most common dialog boxes
    • File dialog (save, open, open folder)
    • Font dialog
    • Color dialog
  • A canvas that can be used by external rendering APIs
  • High-DPI aware
  • Support for accessibility functions
    • Tab navigation
  • Support for low level system message capture (HWND, MSG, WPARAM, LPARAM)
  • Cross compiling and testing from Linux to Windows with Wine and mingw.
    • Not all features are supported (but the majority are, thanks WINE!)
    • See https://zork.net/~st/jottings/rust-windows-and-debian.html for the steps to follow

Performance

This was measured on a Intel(R) Core(TM) i7-3770 CPU @ 3.40GHz, 3401 Mhz, 4 Core(s), 8 Logical Processor(s)

In release mode, the basic example weighs 163kb on disk and takes 900kb in memory. Launch time is instantaneous.

The interactive test suite (with every feature and 100s of tests) weighs 931 kb on disk and takes 8MB in memory. Launch time is still instantaneous.

Initial build time takes around 22 seconds for a basic application. This is mainly due to winapi-rs initial compile time. Subsequent compile time takes around 0.7 seconds.

Development

The development of this library is considered "done". By that, I mean that there won't be any change to the API. Issues can be raised if a bug is found or if some area in the documentation is unclear. If I overlooked a very important feature, it will most likely be added.

License

NWG uses the MIT license

Code example

With native windows derive

#![windows_subsystem = "windows"]
/*!
    A very simple application that shows your name in a message box.
    Unlike `basic_d`, this example uses layout to position the controls in the window
*/


extern crate native_windows_gui as nwg;
extern crate native_windows_derive as nwd;

use nwd::NwgUi;
use nwg::NativeUi;


#[derive(Default, NwgUi)]
pub struct BasicApp {
    #[nwg_control(size: (300, 115), position: (300, 300), title: "Basic example", flags: "WINDOW|VISIBLE")]
    #[nwg_events( OnWindowClose: [BasicApp::say_goodbye] )]
    window: nwg::Window,

    #[nwg_layout(parent: window, spacing: 1)]
    grid: nwg::GridLayout,

    #[nwg_control(text: "Heisenberg", focus: true)]
    #[nwg_layout_item(layout: grid, row: 0, col: 0)]
    name_edit: nwg::TextInput,

    #[nwg_control(text: "Say my name")]
    #[nwg_layout_item(layout: grid, col: 0, row: 1, row_span: 2)]
    #[nwg_events( OnButtonClick: [BasicApp::say_hello] )]
    hello_button: nwg::Button
}

impl BasicApp {

    fn say_hello(&self) {
        nwg::modal_info_message(&self.window, "Hello", &format!("Hello {}", self.name_edit.text()));
    }
    
    fn say_goodbye(&self) {
        nwg::modal_info_message(&self.window, "Goodbye", &format!("Goodbye {}", self.name_edit.text()));
        nwg::stop_thread_dispatch();
    }

}

fn main() {
    nwg::init().expect("Failed to init Native Windows GUI");
    nwg::Font::set_global_family("Segoe UI").expect("Failed to set default font");
    let _app = BasicApp::build_ui(Default::default()).expect("Failed to build UI");
    nwg::dispatch_thread_events();
}

Barebone example. Suitable if you only need a simple static UI

#![windows_subsystem = "windows"]
/**
    A very simple application that show your name in a message box.

    This demo shows how to use NWG without the NativeUi trait boilerplate.
    Note that this way of doing things is alot less extensible and cannot make use of native windows derive.

    See `basic` for the NativeUi version and `basic_d` for the derive version
*/
extern crate native_windows_gui as nwg;
use std::rc::Rc;

fn main() {
    nwg::init().expect("Failed to init Native Windows GUI");
    nwg::Font::set_global_family("Segoe UI").expect("Failed to set default font");

    let mut window = Default::default();
    let mut name_edit = Default::default();
    let mut hello_button = Default::default();
    let layout = Default::default();

    nwg::Window::builder()
        .size((300, 115))
        .position((300, 300))
        .title("Basic example")
        .build(&mut window)
        .unwrap();

    nwg::TextInput::builder()
        .text("Heisenberg")
        .focus(true)
        .parent(&window)
        .build(&mut name_edit)
        .unwrap();

    nwg::Button::builder()
        .text("Say my name")
        .parent(&window)
        .build(&mut hello_button)
        .unwrap();

    nwg::GridLayout::builder()
        .parent(&window)
        .spacing(1)
        .child(0, 0, &name_edit)
        .child_item(nwg::GridLayoutItem::new(&hello_button, 0, 1, 1, 2))
        .build(&layout)
        .unwrap();

    let window = Rc::new(window);
    let events_window = window.clone();

    let handler = nwg::full_bind_event_handler(&window.handle, move |evt, _evt_data, handle| {
        use nwg::Event as E;

        match evt {
            E::OnWindowClose => 
                if &handle == &events_window as &nwg::Window {
                    nwg::modal_info_message(&events_window.handle, "Goodbye", &format!("Goodbye {}", name_edit.text()));
                    nwg::stop_thread_dispatch();
                },
            E::OnButtonClick => 
                if &handle == &hello_button {
                    nwg::modal_info_message(&events_window.handle, "Hello", &format!("Hello {}", name_edit.text()));
                },
            _ => {}
        }
    });

    nwg::dispatch_thread_events();
    nwg::unbind_event_handler(&handler);
}

With the NativeUi boilerplate

#![windows_subsystem = "windows"]
/*!
    A very simple application that shows your name in a message box.
    Uses layouts to position the controls in the window
*/

extern crate native_windows_gui as nwg;
use nwg::NativeUi;


#[derive(Default)]
pub struct BasicApp {
    window: nwg::Window,
    layout: nwg::GridLayout,
    name_edit: nwg::TextInput,
    hello_button: nwg::Button
}

impl BasicApp {

    fn say_hello(&self) {
        nwg::modal_info_message(&self.window, "Hello", &format!("Hello {}", self.name_edit.text()));
    }
    
    fn say_goodbye(&self) {
        nwg::modal_info_message(&self.window, "Goodbye", &format!("Goodbye {}", self.name_edit.text()));
        nwg::stop_thread_dispatch();
    }

}

//
// ALL of this stuff is handled by native-windows-derive
//
mod basic_app_ui {
    use native_windows_gui as nwg;
    use super::*;
    use std::rc::Rc;
    use std::cell::RefCell;
    use std::ops::Deref;

    pub struct BasicAppUi {
        inner: Rc<BasicApp>,
        default_handler: RefCell<Option<nwg::EventHandler>>
    }

    impl nwg::NativeUi<BasicAppUi> for BasicApp {
        fn build_ui(mut data: BasicApp) -> Result<BasicAppUi, nwg::NwgError> {
            use nwg::Event as E;
            
            // Controls
            nwg::Window::builder()
                .flags(nwg::WindowFlags::WINDOW | nwg::WindowFlags::VISIBLE)
                .size((300, 115))
                .position((300, 300))
                .title("Basic example")
                .build(&mut data.window)?;

            nwg::TextInput::builder()
                .text("Heisenberg")
                .parent(&data.window)
                .focus(true)
                .build(&mut data.name_edit)?;

            nwg::Button::builder()
                .text("Say my name")
                .parent(&data.window)
                .build(&mut data.hello_button)?;

            // Wrap-up
            let ui = BasicAppUi {
                inner: Rc::new(data),
                default_handler: Default::default(),
            };

            // Events
            let evt_ui = Rc::downgrade(&ui.inner);
            let handle_events = move |evt, _evt_data, handle| {
                if let Some(ui) = evt_ui.upgrade() {
                    match evt {
                        E::OnButtonClick => 
                            if &handle == &ui.hello_button {
                                BasicApp::say_hello(&ui);
                            },
                        E::OnWindowClose => 
                            if &handle == &ui.window {
                                BasicApp::say_goodbye(&ui);
                            },
                        _ => {}
                    }
                }
            };

           *ui.default_handler.borrow_mut() = Some(nwg::full_bind_event_handler(&ui.window.handle, handle_events));

           // Layouts
           nwg::GridLayout::builder()
            .parent(&ui.window)
            .spacing(1)
            .child(0, 0, &ui.name_edit)
            .child_item(nwg::GridLayoutItem::new(&ui.hello_button, 0, 1, 1, 2))
            .build(&ui.layout)?;

            return Ok(ui);
        }
    }

    impl Drop for BasicAppUi {
        /// To make sure that everything is freed without issues, the default handler must be unbound.
        fn drop(&mut self) {
            let handler = self.default_handler.borrow();
            if handler.is_some() {
                nwg::unbind_event_handler(handler.as_ref().unwrap());
            }
        }
    }

    impl Deref for BasicAppUi {
        type Target = BasicApp;

        fn deref(&self) -> &BasicApp {
            &self.inner
        }
    }
}

fn main() {
    nwg::init().expect("Failed to init Native Windows GUI");
    nwg::Font::set_global_family("Segoe UI").expect("Failed to set default font");
    let _ui = BasicApp::build_ui(Default::default()).expect("Failed to build UI");
    nwg::dispatch_thread_events();
}

Attributions

For the icons used in the test suite (and only there):

native-windows-gui's People

Contributors

aaasuoliweng avatar alexander-xin avatar alfmar avatar amionsky avatar bingen13 avatar cg31 avatar dnlmlr avatar doumanash avatar evshiron avatar fschutt avatar gabdube avatar harryjph avatar havvy avatar i509vcb avatar iainnicol avatar kolsky avatar martinmolin avatar newam avatar ricorodriges avatar roblabla avatar serranya avatar shimusa avatar skyfloogle avatar talagrand avatar tdecking avatar voragain avatar warwolt avatar wtodd1 avatar wuyb66 avatar yakov-bakhmatov avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

native-windows-gui's Issues

No `SetWindowLongPtrW` in `user32`

I tried compiling the library with the hello world program, but could not get past compiling native-windows-gui v0.1.0. There are multiple errors, but they seem to boil down to one specific problem: unable to import GetWindowLongPtrW and SetWindowLongPtrW from user32.

I’m running Rust 1.13.0 MSVC on Windows 7 (32-bit) with C++ Build Tools (as advised on rustlang.org) and Windows 8 API installed.

(Sorry if this is a dumb problem; I’m not familiar at all with Windows.)

   Compiling native-windows-gui v0.1.0
     Running `rustc C:\Users\uranusjr\.cargo\registry\src\github.com-1ecc6299db9ec823\native-windows-gui-0.1.0\src\lib.rs --crate-name native_windows_gui --crate-type lib -g -C metadata=7fc996e319240eae -C extra-filename=-7fc996e319240eae --out-dir C:\Users\uranusjr\Desktop\pepsi-nsis-builder\target\debug\deps --emit=dep-info,link -L dependency=C:\Users\uranusjr\Desktop\pepsi-nsis-builder\target\debug\deps --extern kernel32=C:\Users\uranusjr\Desktop\pepsi-nsis-builder\target\debug\deps\libkernel32-509fa9765cc5df81.rlib --extern user32=C:\Users\uranusjr\Desktop\pepsi-nsis-builder\target\debug\deps\libuser32-5ec5fd1838282aa7.rlib --extern winapi=C:\Users\uranusjr\Desktop\pepsi-nsis-builder\target\debug\deps\libwinapi-cadf002e62789fde.rlib --extern comctl32=C:\Users\uranusjr\Desktop\pepsi-nsis-builder\target\debug\deps\libcomctl32-974ac6e60a832e8e.rlib --cap-lints allow`
error[E0432]: unresolved import `user32::SetWindowLongPtrW`
  --> C:\Users\uranusjr\.cargo\registry\src\github.com-1ecc6299db9ec823\native-windows-gui-0.1.0\src\controls\base\helper.rs:42:14
   |
42 | use user32::{SetWindowLongPtrW, GetWindowLongPtrW, EnumChildWindows, ShowWindow,
   |              ^^^^^^^^^^^^^^^^^ no `SetWindowLongPtrW` in `user32`. Did you mean to use `SetWindowLongW`?

error[E0432]: unresolved import `user32::GetWindowLongPtrW`
  --> C:\Users\uranusjr\.cargo\registry\src\github.com-1ecc6299db9ec823\native-windows-gui-0.1.0\src\controls\base\helper.rs:42:33
   |
42 | use user32::{SetWindowLongPtrW, GetWindowLongPtrW, EnumChildWindows, ShowWindow,
   |                                 ^^^^^^^^^^^^^^^^^ no `GetWindowLongPtrW` in `user32`. Did you mean to use `GetWindowLongW`?

error[E0432]: unresolved import `user32::SetWindowLongPtrW`
  --> C:\Users\uranusjr\.cargo\registry\src\github.com-1ecc6299db9ec823\native-windows-gui-0.1.0\src\controls\base/mod.rs:33:31
   |
33 | use user32::{CreateWindowExW, SetWindowLongPtrW, GetWindowLongPtrW, DestroyWindow, EnumChildWindows};
   |                               ^^^^^^^^^^^^^^^^^ no `SetWindowLongPtrW` in `user32`. Did you mean to use `SetWindowLongW`?

error[E0432]: unresolved import `user32::GetWindowLongPtrW`
  --> C:\Users\uranusjr\.cargo\registry\src\github.com-1ecc6299db9ec823\native-windows-gui-0.1.0\src\controls\base/mod.rs:33:50
   |
33 | use user32::{CreateWindowExW, SetWindowLongPtrW, GetWindowLongPtrW, DestroyWindow, EnumChildWindows};
   |                                                  ^^^^^^^^^^^^^^^^^ no `GetWindowLongPtrW` in `user32`. Did you mean to use `GetWindowLongW`?

error[E0432]: unresolved import `user32::GetWindowLongPtrW`
   --> C:\Users\uranusjr\.cargo\registry\src\github.com-1ecc6299db9ec823\native-windows-gui-0.1.0\src\controls\textinput.rs:141:5
    |
141 | use user32::GetWindowLongPtrW;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ no `GetWindowLongPtrW` in `user32`. Did you mean to use `GetWindowLongW`?

error[E0432]: unresolved import `user32::GetWindowLongPtrW`
   --> C:\Users\uranusjr\.cargo\registry\src\github.com-1ecc6299db9ec823\native-windows-gui-0.1.0\src\controls\textbox.rs:123:5
    |
123 | use user32::GetWindowLongPtrW;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ no `GetWindowLongPtrW` in `user32`. Did you mean to use `GetWindowLongW`?

error: aborting due to 6 previous errors

error: Could not compile `native-windows-gui`.

Caused by:
  process didn't exit successfully: `rustc C:\Users\uranusjr\.cargo\registry\src\github.com-1ecc6299db9ec823\native-windows-gui-0.1.0\src\lib.rs --crate-name native_windows_gui --crate-type lib -g -C metadata=7fc996e319240eae -C extra-filename=-7fc996e319240eae --out-dir C:\Users\uranusjr\Desktop\pepsi-nsis-builder\target\debug\deps --emit=dep-info,link -L dependency=C:\Users\uranusjr\Desktop\pepsi-nsis-builder\target\debug\deps --extern kernel32=C:\Users\uranusjr\Desktop\pepsi-nsis-builder\target\debug\deps\libkernel32-509fa9765cc5df81.rlib --extern user32=C:\Users\uranusjr\Desktop\pepsi-nsis-builder\target\debug\deps\libuser32-5ec5fd1838282aa7.rlib --extern winapi=C:\Users\uranusjr\Desktop\pepsi-nsis-builder\target\debug\deps\libwinapi-cadf002e62789fde.rlib --extern comctl32=C:\Users\uranusjr\Desktop\pepsi-nsis-builder\target\debug\deps\libcomctl32-974ac6e60a832e8e.rlib --cap-lints allow` (exit code: 101)

Flickerless controls

Enable double buffering by rendering to a offscreen DC when painting a window.

This will be added as an option double_buffer to the WindowT template.

Events 2.0

Replace the Events enum because it's not suitable to handle custom events or specific events related to built-in controls.

It might be a good solution to use a (TypeID, UserID) pair to define events. Then, in each control module, each event will be defined under a constant.

Require Debug for UI ID type

This will make error much more user friendly. Ie: "Key AppId::MainWindow was not found" is much more descriptive than The key was not found in the ui.

Module 'events' is private

Hi, I'm getting the following error when trying to run the Hello World example given in the docs:

error: module 'events' is private
 --> src\main.rs:8:5
  |
8 | use nwg::events as nwge;
  |     ^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error
error: Could not compile `filetag`.

Caused by:
  process didn't exit successfully: `rustc --crate-name filetag src\main.rs --crate-type bin --emit=dep-info,link -C debuginfo=2 -C metadata=ce45a017d507ce61 -C extra-filename=-ce45a017d507ce61 --out-dir C:\msys64\home\Declan\Code\rust\filetag\target\debug\deps -L dependency=C:\msys64\home\Declan\Code\rust\filetag\target\debug\deps --extern native_windows_gui=C:\msys64\home\Declan\Code\rust\filetag\target\debug\deps\libnative_windows_gui-a0afd57132c386a5.rlib` (exit code: 101)

Am I doing something stupid? All the examples work if i run them through cargo 'cargo run --example ...' but not if i start a new project and copy the code over.
I'm on W7 64bit and this is my rust version:

stable-x86_64-pc-windows-msvc (default)
rustc 1.17.0 (56124baa9 2017-04-24)

main.rs.txt
Cargo.toml.txt

dynamic combobox

Sorry for stupid quiestion, i want to ask how to create dynamic combobox. For example, i have mutable array and want to show it in combobox via templating. Does it possible? Or could you guess how make it better? Thanks.

SpVoice interface.

Hi,

I have a windows gui written in rust that uses the SpVoice Interface. I use the SetNotifyWindowMessage to pass events back to my window. I'd love to be using the nwg, it looks way more ergonomic. I just cannot figure how to do that one peace. How do I listen for custom window messages?

Thanks!

Undefined reference to GetWindowSubclass

I'm trying to compile the example showcase.rs but when I try using cargo build --target x86_64-pc-windows-gnu I get the following error:

In function `native_windows_gui::low::events::unhook_window_evets<&str>`:
undefined reference to `GetWindowSubclass'

Cargo.toml

[dependencies.native-windows-gui]
git = "https://github.com/gabdude/native-windows.gui.git"
rev = "31df500"

Versions

cargo 0.19.0-nightly (472917504 2017-04-01)
rustc 1.18.0-nigtly (c58c92e6 2017-04-11)
Linux 4.9.21
x86_64-w64-mingw32-gcc (GCC) 6.3.0 20170321

Get/Set Font

Set the font used in a window or get the font used in a window

No longer restric events on controls

Now that events are no longer hardcoded, I think that it would be better to remove the event is supported check on the controls.

Pro:

  • Ability to add custom events to built-in controls without having to redefine a control
  • Will make the Control trait easier to implement

Cons:

  • It will be possible to bind not callable events to some controls.

Embedding Ui into another Ui

Basically, implements the Control trait for the Ui struct or maybe use a proxy struct (UiControl) it its too much trouble to do it directly.

This will allow to create much bigger Ui without having to worry about scaling issues.

The top level window of the Ui will be converted as children window for the parent Ui mainwindow... or something like this.

examples wont compile.

Hello.

Sorry if this is in fact my fault but I seem to get this same error for all the examples I try.
( I am using ubuntu 16.04 with rustc 1.16.0-nightly (2782e8f8f 2017-01-12) )

$ cargo build && cargo run --example canvas --verbose
Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
Fresh winapi-build v0.1.1
Fresh winapi v0.2.8
Fresh ole32-sys v0.2.0
Fresh gdi32-sys v0.2.0
Fresh user32-sys v0.2.0
Fresh comctl32-sys v0.2.0
Fresh kernel32-sys v0.2.2
Compiling native-windows-gui v0.2.0 (file:///home/userd/Workspace/git-local-repos/rust-projects/native-windows-gui)
Running rustc --crate-name canvas examples/canvas.rs --crate-type bin --emit=dep-info,link -g -C metadata=f368be4115be0f31 -C extra-filename=-f368be4115be0f31 --out-dir /home/userd/Workspace/git-local-repos/rust-projects/native-windows-gui/target/debug/examples -L dependency=/home/userd/Workspace/git-local-repos/rust-projects/native-windows-gui/target/debug/deps --extern gdi32=/home/userd/Workspace/git-local-repos/rust-projects/native-windows-gui/target/debug/deps/libgdi32-87959dd4125f07e0.rlib --extern winapi=/home/userd/Workspace/git-local-repos/rust-projects/native-windows-gui/target/debug/deps/libwinapi-3f4827e2e513c3d9.rlib --extern comctl32=/home/userd/Workspace/git-local-repos/rust-projects/native-windows-gui/target/debug/deps/libcomctl32-3f24f77d74a3ac76.rlib --extern user32=/home/userd/Workspace/git-local-repos/rust-projects/native-windows-gui/target/debug/deps/libuser32-e816280001024a43.rlib --extern kernel32=/home/userd/Workspace/git-local-repos/rust-projects/native-windows-gui/target/debug/deps/libkernel32-7cda898cd53d6f66.rlib --extern ole32=/home/userd/Workspace/git-local-repos/rust-projects/native-windows-gui/target/debug/deps/libole32-e3aeb471ded09a78.rlib --extern native_windows_gui=/home/userd/Workspace/git-local-repos/rust-projects/native-windows-gui/target/debug/deps/libnative_windows_gui-5ec02c6c8cc8d552.rlib
error: macro undefined: 'nwg_template!'
--> examples/canvas.rs:27:1
|
27 | nwg_template!(
| ^^^^^^^^^^^^

error: macro undefined: 'nwg_get_mut!'
--> examples/canvas.rs:75:22
|
75 | let mut canvas = nwg_get_mut!(app; (Canvas, nwg::Canvas));
| ^^^^^^^^^^^

error: aborting due to 2 previous errors

error: Could not compile native-windows-gui.

Caused by:
process didn't exit successfully: rustc --crate-name canvas examples/canvas.rs --crate-type bin --emit=dep-info,link -g -C metadata=f368be4115be0f31 -C extra-filename=-f368be4115be0f31 --out-dir /home/userd/Workspace/git-local-repos/rust-projects/native-windows-gui/target/debug/examples -L dependency=/home/userd/Workspace/git-local-repos/rust-projects/native-windows-gui/target/debug/deps --extern gdi32=/home/userd/Workspace/git-local-repos/rust-projects/native-windows-gui/target/debug/deps/libgdi32-87959dd4125f07e0.rlib --extern winapi=/home/userd/Workspace/git-local-repos/rust-projects/native-windows-gui/target/debug/deps/libwinapi-3f4827e2e513c3d9.rlib --extern comctl32=/home/userd/Workspace/git-local-repos/rust-projects/native-windows-gui/target/debug/deps/libcomctl32-3f24f77d74a3ac76.rlib --extern user32=/home/userd/Workspace/git-local-repos/rust-projects/native-windows-gui/target/debug/deps/libuser32-e816280001024a43.rlib --extern kernel32=/home/userd/Workspace/git-local-repos/rust-projects/native-windows-gui/target/debug/deps/libkernel32-7cda898cd53d6f66.rlib --extern ole32=/home/userd/Workspace/git-local-repos/rust-projects/native-windows-gui/target/debug/deps/libole32-e3aeb471ded09a78.rlib --extern native_windows_gui=/home/userd/Workspace/git-local-repos/rust-projects/native-windows-gui/target/debug/deps/libnative_windows_gui-5ec02c6c8cc8d552.rlib (exit code: 101)

Opengl Canvas control

Create a canvas control that use opengl for drawing.

It should allow the creation of modern context from the template

Problem with macros

Ok, I have a "minimal" repro case here: https://gist.github.com/winks/a65d5f6661718803305b71f12c373230

I started with the showcase example and stripped it down, this works (as it is pasted above).

If you uncomment lines 7,10,34 and run cargo run or cargo build:

λ cargo build
   Compiling nw2 v0.1.0 (file:///C:/Users/Florian/code/winks/WastedTime/nw2)
error[E0244]: wrong number of type arguments: expected 0, found 2
  --> src/main.rs:12:1
   |
12 | / nwg_template!(
13 | |     head: setup_ui<&'static str>,
14 | |     controls: [
15 | |         ("MainWindow", nwg_window!(title="WastedTime"; position=(100, 100); size=(300, 50))),
...  |
52 | |     values: []
53 | | );
   | |__^ expected no type arguments
   |
   = note: this error originates in a macro outside of the current crate

error: aborting due to previous error(s)

error: Could not compile `nw2`.

To learn more, run the command again with --verbose.

I tried everything from #[macro_use(json, json_internal)] for serde_json to #[macro_use(nwg_template, ...)] for native-windows-gui to all combinations I can think of - as soon as I have a second macro_use I can't compile anymore.
I originally had everything in one file as well, but tried to split it out to get a better on/off - no change

Building using mingw

Does it supported?

Currently I'm getting:

ld: cannot find -ld2d1

Windows 7 32bit

Drag and Drop

A feature I noticed missing when using a UI made in NWG was drag and drop of text or files. e.g. dragging a text file into an input text box on a window and have the path filled out for me. I wondered if this was a possibility for this library.

I found the following links... if they're any use.

https://msdn.microsoft.com/en-us/library/windows/desktop/ms645533(v=vs.85).aspx
https://msdn.microsoft.com/en-us/library/windows/desktop/ms678405(v=vs.85).aspx
http://www.codeguru.com/cpp/misc/misc/draganddrop/article.php/c349/Drag-And-Drop-between-Window-Controls.htm

nwg_combobox macro with data=... does not work

Using nwg_combobox with data=... will cause two compiler errors, E0243 and E0308. E0243 appears to be caused by the macro giving ComboBoxT one type parameter (data) when it needs three, and E0308 appears to be caused by the macro assigning [] to the collection field of ComboBoxT. On a side note, thanks for making this crate, it's really useful!

End of Text

Is there an event to show when text input ended?

I assumed SetTextLimit would do this:

When a TextInput is given the SetTextLimit it will limit the number of input characters to that value but a MaxValue event is never triggered. The TextInput just stops accepting input.

My main issue is I can call GetText on every ValueChanged, but there is no way I can tell the text is ending without another thread buffering text/comparing timing (also how do I then trigger an even back in my main loop lol). Or having a user click something (breaking flow).

Simplify GUI construction by nesting control code

Instead of setting parent, we can use nesting:

let main_window = Window {
    caption: "Hello".to_string(),
    size: (200, 200),
    position: (100, 100),
    visible: true,
    resizable: false,
    exit_on_close: true,
    children: vec![
      TextInput {
          name: "Name",
          text: "".to_string(),
          size: (180, 20),
          position: (10, 10),
          placeholder: Some("Your name Here".to_string()),
          text_align: HTextAlign::Left,
          password: false,
          readonly: false
      },
      Button {
          text: "Say Hello!".to_string(),
          size: (180, 130),
          position: (10, 50),
          text_align: (HTextAlign::Center, VTextAlign::Center),
          on_click: Box::new(|ui, caller|{
              println!("Caller is: {:?}", caller);
              if let Ok(ActionReturn::Text(name)) = ui.exec("Name", Action::GetText) {
                  let msg = actions_help::message(
                      "Hello!", format!("Hello {}!", name),
                      MessageButtons::Ok, MessageIcons::None
                  );
                  ui.exec("MainWindow", msg).unwrap();
              }
        })
      }
    ]
};
main_window.run();

Please take a look at https://github.com/lxn/walk and borrow some ideas from there.

black padding with groupbox

Simple example:

#[macro_use] extern crate native_windows_gui as nwg;

use nwg::{Ui, simple_message, fatal_message, dispatch_events};
use nwg::events as nwge;
use nwg::constants::{FONT_WEIGHT_BLACK, FONT_DECO_ITALIC, CheckState, FileDialogAction, HTextAlign, PickerDate, ImageType};

nwg_template!(
    head: setup_ui<&'static str>,
    controls: [
        ("MainWindow", nwg_window!( title="Template Example"; size=(800, 600) )),
        ("YesNoGroup", nwg_groupbox!(parent="MainWindow"; text="Choose one"; position=(360, 40); size=(130, 80);  align=HTextAlign::Center; font=Some("TextFont") )),
        ("YesRadio", nwg_radiobutton!(parent="YesNoGroup"; text="Yes"; position=(10, 20); size=(110, 30); font=Some("TextFont"))),
        ("NoRadio", nwg_radiobutton!(parent="YesNoGroup"; text="No"; position=(10, 45); size=(110, 30); font=Some("TextFont")))
        
    ];
    events: [
    ];
    resources: [
        ("TextFont", nwg_font!(family="Arial"; size=17))
    ];
    values: []
);

fn main() {
    let app: Ui<&'static str>;

    match Ui::new() {
        Ok(_app) => { app = _app; },
        Err(e) => { fatal_message("Fatal Error", &format!("{:?}", e) ); }
    }

    if let Err(e) = setup_ui(&app) {
        fatal_message("Fatal Error", &format!("{:?}", e));
    }

    dispatch_events();
}

show this:

image

Another way to reduce it, double click "showcase" title bar:

image

Save user data in the UI

Allow a user to save custom data somewhere in NWG. Not sure about how to proceed with this one.

Idea 1
Allow the user to save a single type of custom objects per controls using the ui.

ui.get_user_data<TYPE>(ID) -> Option<Box<TYPE>>
ui.set_user_data<TYPE>(ID, TYPE)

where ID is the ID of the control

Idea 2
Allow the user to save multiple custom objects per UI . The data would be identified like controls

ui.get_user_data<TYPE>(ID) -> Option<Box<TYPE>>
ui.set_user_data<TYPE>(ID, TYPE)

where ID is a unique identifier for the saved data

Idea 3

Allow the user to save multiple custom objects per controls . The data would be identified like controls

ui.get_user_data<TYPE>(ID1, ID2) -> Option<Box<TYPE>>
ui.set_user_data<TYPE>(ID1, ID2, TYPE)

where ID1 is the ID of the control and ID2 is the unique ID of the data

I need your help(about the listview)

I'm trying to the add listview support. But failed.
Can you test my fork?
https://github.com/zoumi/native-windows-gui
The problem is:
1,after add the listview to the window , all the control will blink
2,can't add the full string to listview cell.(If i add "what is this" it will show "xhat is this")

Here is the code to test the listview:

//#![windows_subsystem = "windows"]
//#![feature(link_args)]
//#[link_args = "-Wl,--subsystem,windows"]
//#[link_args = "/SUBSYSTEM:WINDOWS"]
#[macro_use] extern crate native_windows_gui as nwg;

use nwg::{Event, Ui, simple_message, fatal_message, dispatch_events};
extern crate winapi;
use winapi::{LPCWSTR,HWND};

extern "system"{
pub fn SetWindowTheme(hwnd: HWND,
                      pszSubAppName: LPCWSTR,
                      pszSubIdList: LPCWSTR);
}

/// Custom enums are the preferred way to define ui ids. 
/// It's clearer and more extensible than any other types (such as &'str).
#[derive(Debug, Clone, Hash)]
pub enum AppId {
    // Controls
    MainWindow,
    NameInput, 
    HelloButton,
    Label(u8),   // Ids for static controls that won't be referenced in the Ui logic can be shortened this way.
    MyListView,

    // Events
    SayHello,

    // Resources
    MainFont,
    TextFont
}

use AppId::*; // Shortcut

nwg_template!(
    head: setup_ui<AppId>,
    controls: [
        (MainWindow, nwg_window!( title="Template Example"; size=(280, 305) )),
        (Label(0), nwg_label!(
             parent=MainWindow;
             text="Your Name: ";
             position=(5,15); size=(80, 25);
             font=Some(TextFont) )),

        (NameInput, nwg_textinput!( 
             parent=MainWindow; 
             position=(85,13); size=(185,22); 
             font=Some(TextFont) )),

        (HelloButton, nwg_button!( 
             parent=MainWindow; 
             text="Hello World!"; 
             position=(5, 45); size=(270, 50); 
             font=Some(MainFont) )),

        (MyListView, nwg_list_view!(
                parent=MainWindow;
                text="oh my list view";
                position=(5,100);size=(270,200);
                font=Some(MainFont) ))
    ];

    events: [
        (HelloButton, SayHello, Event::Click, |ui,_,_,_| {

            let my_list_view = nwg_get!(ui; (MyListView,nwg::ListView));
           // unsafe { SetWindowTheme}
            my_list_view.insert_col(0,"FIRST",50);
            my_list_view.insert_col(1,"wsec",50);
            my_list_view.insert_col(2,"wtrd",50);
            my_list_view.add(vec!["1fsafas".to_owned(),"ewheh2".to_owned(),"3sfsaga".to_owned()]);
            my_list_view.insert(1,
                vec!["1o8u53b".to_owned(),"iluou2".to_owned(),"3wvrwr".to_owned()]);
            my_list_view.insert(2,
                vec!["1333".to_owned(),"266666".to_owned(),"00003".to_owned()]);
            println!("list_view hwnd: {:?}",my_list_view);
            //let your_name = nwg_get!(ui; (NameInput, nwg::TextInput));
            //simple_message("Hello", &format!("Hello {}!", your_name.get_text()) );
        }),
        (MyListView, SayHello, Event::Notify, |ui,hwnd,wpara,lpara| {
        
        })
    ];
    resources: [
        (MainFont, nwg_font!(family="Arial"; size=27)),
        (TextFont, nwg_font!(family="Arial"; size=17))
    ];
    values: []
);

fn main() {
    let app: Ui<AppId>;

    match Ui::new() {
        Ok(_app) => { app = _app; },
        Err(e) => { fatal_message("Fatal Error", &format!("{:?}", e) ); }
    }

    if let Err(e) = setup_ui(&app) {
        //fatal_message("Fatal Error", &format!("{:?}", e));
    }


    dispatch_events();
}

Support for creating child windows

It would be very useful to have support for creating child windows with a given parent handle.
I implemented support for child windows on Windows in my glutin fork like half a year ago:
https://github.com/Boscop/glutin/blob/master/src/window.rs#L205
https://github.com/Boscop/glutin/blob/master/src/api/win32/init.rs#L76-L84
https://github.com/Boscop/glutin/blob/master/src/api/win32/callback.rs#L23
https://github.com/Boscop/glutin/blob/master/src/api/win32/mod.rs#L471-L473
(Child windows have to run in the same thread as the parent window, so I'm using a HashMap with HWND as key for event dispatching of all the windows in the same thread.)

It would also be useful to have support for timers on the window via a callback:
https://github.com/Boscop/glutin/blob/master/src/window.rs#L508-L516

I implemented this because it's necessary to create a child window for writing GUIs for VST plugins. The plugin host creates a window and passes it to the plugin, which has to create a child window on that for it's GUI and register a timer on the HWND so that it refreshes it's GUI every few milliseconds.
This is what I do in the plugin:

impl<'a> Editor for MyPlugin<'a> {
	fn open(&mut self, parent: *mut c_void) {
		let mut display = WindowBuilder::new().with_dimensions(WINDOW_WIDTH, WINDOW_HEIGHT).with_parent(WindowID::new(parent)).build_glium().unwrap();
		{
			let window = display.get_window().unwrap();
			unsafe { user32::SetWindowLongA(window.platform_window() as winapi::HWND, winapi::winuser::GWLP_USERDATA, self as *mut _ as winapi::LONG); }
			window.set_timer(WIN_GUI_FRAME_TIMER, 25 /* ms */, Some(handle_timer)).unwrap();
		}
// ...
const WIN_GUI_FRAME_TIMER: winapi::UINT_PTR = 4242;
unsafe extern "system" fn handle_timer(hwnd: winapi::HWND, _: winapi::UINT, timer_id: winapi::UINT_PTR, elapsed_ms: winapi::DWORD) {
	if timer_id != WIN_GUI_FRAME_TIMER {
		return;
	}
	let plugin = &mut *(user32::GetWindowLongA(hwnd, winapi::winuser::GWLP_USERDATA) as *mut MyPlugin);
	plugin.render_ui_frame();
}

It would be very useful to have support for creating child windows in NWG which can be rendered one frame at a time.
So that NWG can be used to write GUIs for VST plugins, completely in Rust :)

support byte array "image"

I want to use include_bytes!() to put image file into source code, so need "image" have an interface to use this byte array.

Hide console

Hello folks, I'm able to cross-compile using mingw32 but the resulting executable also opens a console when run:

screenshot 2016-12-10 19 47 53

Does someone know how to hide it?

cargo 0.13.0-nightly (eca9e15 2016-11-01)
rustc 1.13.0 (2c6933acc 2016-11-07)
x86_64-w64-mingw32-gcc (GCC) 6.2.1 20160830

My Cargo.lock

[root]
name = "sdl2"
version = "0.1.0"
dependencies = [
 "native-windows-gui 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "comctl32-sys"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
 "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "kernel32-sys"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
 "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "native-windows-gui"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "comctl32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
 "user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
 "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "user32-sys"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
 "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
 "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]

[[package]]
name = "winapi"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "winapi-build"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"

[metadata]
"checksum comctl32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "501059297403e29a57d29692180bb40acadf8dd4d05f9d55dff4fdf3fcc5b125"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum native-windows-gui 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e9df8e55b19d55e75fab81922452d9a5d5c85a5ec60e197be86d88431fc3dfb0"
"checksum user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ef4711d107b21b410a3a974b1204d9accc8b10dad75d8324b5d755de1617d47"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.