1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
use crate::aliases::BoxResult;
use crate::co;
use crate::funcs::{InitCommonControls, IsWindowsVistaOrGreater, SetProcessDPIAware};
use crate::gui::base::Base;
use crate::gui::dlg_main::DlgMain;
use crate::gui::events::WindowEvents;
use crate::gui::privs::{create_ui_font, delete_ui_font};
use crate::gui::raw_main::{WindowMainOpts, RawMain};
use crate::handles::HWND;
#[derive(Clone)]
enum RawDlg { Raw(RawMain), Dlg(DlgMain) }
/// An user main window, which can handle events. Usually, this is the first
/// window of your application, launched directly from the `main` function. Can
/// be programmatically created or load a dialog resource from a `.res` file.
///
/// Implements [`Parent`](crate::gui::Parent) trait.
///
/// # Examples
///
/// The two examples below show how to create the main window: programmatically,
/// or by loading a dialog resource from a `.res` file.
///
/// ## Programmaticaly creating a window
///
/// Below is a full application based on a non-dialog `WindowMain`, whose
/// instance is kept within `MyMain` struct. This is not necessary, but is
/// highly recommended, because it makes it easier to manage the window
/// contents.
///
/// The `main` function instantiates `MyMain` by calling `MyMain::new`, which
/// then calls `WindowMain::new`. Note how it receives a `WindowMainOpts`
/// argument, who defines all the options.
///
/// The window is handling the
/// [mouse click event](https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-lbuttondown)
/// with a closure, and it displays the clicked coordinates in the
/// [title bar](https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowtextw).
///
/// ```rust,ignore
/// #![windows_subsystem = "windows"]
///
/// use winsafe::{gui, msg, BoxResult};
///
/// fn main() {
/// let my_main = MyMain::new();
/// if let Err(e) = my_main.wnd.run_main(None) {
/// eprintln!("{}", e);
/// }
/// }
///
/// pub struct MyMain {
/// wnd: gui::WindowMain,
/// }
///
/// impl MyMain {
/// pub fn new() -> MyMain {
/// let wnd = gui::WindowMain::new(
/// gui::WindowMainOpts {
/// title: "My window".to_owned(),
/// ..Default::default()
/// },
/// );
///
/// let new_self = Self { wnd };
/// new_self.events();
/// new_self
/// }
///
/// fn events(&self) {
/// self.wnd.on().wm_l_button_down({
/// let wnd = self.wnd.clone(); // clone to pass it to the closure
/// move |p: msg::wm::LButtonDown| -> BoxResult<()> {
/// let txt = &format!("Coords {} x {}", p.coords.x, p.coords.y);
/// wnd.hwnd().SetWindowText(txt)?;
/// Ok(())
/// }
/// });
/// }
/// }
/// ```
///
/// ## Loading a window resource from a `.res` file
///
/// A window can also be loaded from a Win32 resource file (usually a `.res`
/// file). Below, a full aplication where `WindowMain` loads a window resource,
/// instead of creating the window programmatically. Note how
/// `WindowMain::new_dlg` instead of `WindowMain::new`.
///
/// ```rust,ignore
/// #![windows_subsystem = "windows"]
///
/// use winsafe::gui;
///
/// const ID_DLG_MAIN: i32 = 101; // in our .res file, this is the dialog ID
///
/// fn main() {
/// let my_main = MyDlg::new();
/// if let Err(e) = my_main.dlg.run_main(None) {
/// eprintln!("{}", e);
/// }
/// }
///
/// pub struct MyDlg {
/// dlg: gui::WindowMain,
/// }
///
/// impl MyDlg {
/// pub fn new() -> MyDlg {
/// let dlg = gui::WindowMain::new_dlg(ID_DLG_MAIN, None, None);
///
/// let new_self = Self { dlg };
/// new_self.events();
/// new_self
/// }
///
/// fn events(&self) {
///
/// }
/// }
/// ```
#[derive(Clone)]
pub struct WindowMain {
raw_dlg: RawDlg,
}
unsafe impl Send for WindowMain {}
unsafe impl Sync for WindowMain {}
impl_debug!(WindowMain);
impl_parent!(WindowMain);
impl WindowMain {
/// Instantiates a new `WindowMain` object, to be created with
/// [`HWND::CreateWindowEx`](crate::HWND::CreateWindowEx).
pub fn new(opts: WindowMainOpts) -> WindowMain {
Self {
raw_dlg: RawDlg::Raw(
RawMain::new(opts),
),
}
}
/// Instantiates a new `WindowMain` object, to be loaded from a dialog
/// resource with [`HWND::GetDlgItem`](crate::HWND::GetDlgItem).
pub fn new_dlg(
dialog_id: u16,
icon_id: Option<u16>,
accel_table_id: Option<u16>) -> WindowMain
{
Self {
raw_dlg: RawDlg::Dlg(
DlgMain::new(dialog_id, icon_id, accel_table_id),
),
}
}
fn_base_ref!();
pub_fn_hwnd!();
pub_fn_on!();
pub_fn_run_ui_thread!();
/// Physically creates the window, then runs the main application loop. This
/// method will block until the window is closed.
///
/// The `cmd_show` parameter defaults to
/// [`co::SW::SHOW`](crate::co::SW::SHOW).
///
/// # Panics
///
/// Panics if the window is already created.
pub fn run_main(&self, cmd_show: Option<co::SW>) -> BoxResult<i32> {
if IsWindowsVistaOrGreater()? {
SetProcessDPIAware()?;
}
InitCommonControls();
create_ui_font()?;
let res = match &self.raw_dlg {
RawDlg::Raw(r) => r.run_main(cmd_show),
RawDlg::Dlg(d) => d.run_main(cmd_show),
};
delete_ui_font()?; // cleanup
res
}
}