@@ -124,6 +124,95 @@ macro_rules! file_dialog_builder {
124124 } ;
125125}
126126
127+ macro_rules! message_dialog_builder {
128+ ( ) => {
129+ /// A builder for message dialogs.
130+ pub struct MessageDialogBuilder ( rfd:: MessageDialog ) ;
131+
132+ impl MessageDialogBuilder {
133+ /// Creates a new message dialog builder.
134+ pub fn new( title: impl AsRef <str >, message: impl AsRef <str >) -> Self {
135+ let title = title. as_ref( ) . to_string( ) ;
136+ let message = message. as_ref( ) . to_string( ) ;
137+ Self (
138+ rfd:: MessageDialog :: new( )
139+ . set_title( & title)
140+ . set_description( & message) ,
141+ )
142+ }
143+
144+ /// Set parent windows explicitly (optional)
145+ ///
146+ /// ## Platform-specific
147+ ///
148+ /// - **Linux:** Unsupported.
149+ pub fn parent<W : raw_window_handle:: HasRawWindowHandle >( mut self , parent: & W ) -> Self {
150+ self . 0 = self . 0 . set_parent( parent) ;
151+ self
152+ }
153+
154+ /// Set the set of button that will be displayed on the dialog.
155+ pub fn buttons( mut self , buttons: MessageDialogButtons ) -> Self {
156+ self . 0 = self . 0 . set_buttons( buttons. into( ) ) ;
157+ self
158+ }
159+
160+ /// Set type of a dialog.
161+ ///
162+ /// Depending on the system it can result in type specific icon to show up,
163+ /// the will inform user it message is a error, warning or just information.
164+ pub fn kind( mut self , kind: MessageDialogKind ) -> Self {
165+ self . 0 = self . 0 . set_level( kind. into( ) ) ;
166+ self
167+ }
168+ }
169+ } ;
170+ }
171+
172+ /// Options for action buttons on message dialogs.
173+ #[ non_exhaustive]
174+ #[ derive( Debug , Copy , Clone , PartialEq , Eq , Hash ) ]
175+ pub enum MessageDialogButtons {
176+ /// Ok button.
177+ Ok ,
178+ /// Ok and Cancel buttons.
179+ OkCancel ,
180+ /// Yes and No buttons.
181+ YesNo ,
182+ }
183+
184+ impl From < MessageDialogButtons > for rfd:: MessageButtons {
185+ fn from ( kind : MessageDialogButtons ) -> Self {
186+ match kind {
187+ MessageDialogButtons :: Ok => Self :: Ok ,
188+ MessageDialogButtons :: OkCancel => Self :: OkCancel ,
189+ MessageDialogButtons :: YesNo => Self :: YesNo ,
190+ }
191+ }
192+ }
193+
194+ /// Types of message, ask and confirm dialogs.
195+ #[ non_exhaustive]
196+ #[ derive( Debug , Copy , Clone , PartialEq , Eq , Hash ) ]
197+ pub enum MessageDialogKind {
198+ /// Information dialog.
199+ Info ,
200+ /// Warning dialog.
201+ Warning ,
202+ /// Error dialog.
203+ Error ,
204+ }
205+
206+ impl From < MessageDialogKind > for rfd:: MessageLevel {
207+ fn from ( kind : MessageDialogKind ) -> Self {
208+ match kind {
209+ MessageDialogKind :: Info => Self :: Info ,
210+ MessageDialogKind :: Warning => Self :: Warning ,
211+ MessageDialogKind :: Error => Self :: Error ,
212+ }
213+ }
214+ }
215+
127216/// Blocking interfaces for the dialog APIs.
128217///
129218/// The blocking APIs will block the current thread to execute instead of relying on callback closures,
@@ -132,11 +221,13 @@ macro_rules! file_dialog_builder {
132221/// **NOTE:** You cannot block the main thread when executing the dialog APIs, so you must use the [`crate::api::dialog`] methods instead.
133222/// Examples of main thread context are the [`crate::App::run`] closure and non-async commmands.
134223pub mod blocking {
224+ use super :: { MessageDialogButtons , MessageDialogKind } ;
135225 use crate :: { Runtime , Window } ;
136226 use std:: path:: { Path , PathBuf } ;
137227 use std:: sync:: mpsc:: sync_channel;
138228
139229 file_dialog_builder ! ( ) ;
230+ message_dialog_builder ! ( ) ;
140231
141232 impl FileDialogBuilder {
142233 /// Shows the dialog to select a single file.
@@ -233,6 +324,22 @@ pub mod blocking {
233324 }
234325 }
235326
327+ impl MessageDialogBuilder {
328+ //// Shows a message dialog.
329+ ///
330+ /// - In `Ok` dialog, it will return `true` when `OK` was pressed.
331+ /// - In `OkCancel` dialog, it will return `true` when `OK` was pressed.
332+ /// - In `YesNo` dialog, it will return `true` when `Yes` was pressed.
333+ pub fn show ( self ) -> bool {
334+ let ( tx, rx) = sync_channel ( 1 ) ;
335+ let f = move |response| {
336+ tx. send ( response) . unwrap ( ) ;
337+ } ;
338+ run_dialog ! ( self . 0 . show( ) , f) ;
339+ rx. recv ( ) . unwrap ( )
340+ }
341+ }
342+
236343 /// Displays a dialog with a message and an optional title with a "yes" and a "no" button and wait for it to be closed.
237344 ///
238345 /// This is a blocking operation,
@@ -314,6 +421,7 @@ pub mod blocking {
314421 title,
315422 message,
316423 buttons,
424+ MessageDialogKind :: Info ,
317425 move |response| {
318426 tx. send ( response) . unwrap ( ) ;
319427 } ,
@@ -323,10 +431,12 @@ pub mod blocking {
323431}
324432
325433mod nonblocking {
434+ use super :: { MessageDialogButtons , MessageDialogKind } ;
326435 use crate :: { Runtime , Window } ;
327436 use std:: path:: { Path , PathBuf } ;
328437
329438 file_dialog_builder ! ( ) ;
439+ message_dialog_builder ! ( ) ;
330440
331441 impl FileDialogBuilder {
332442 /// Shows the dialog to select a single file.
@@ -431,6 +541,17 @@ mod nonblocking {
431541 }
432542 }
433543
544+ impl MessageDialogBuilder {
545+ /// Shows a message dialog:
546+ ///
547+ /// - In `Ok` dialog, it will call the closure with `true` when `OK` was pressed
548+ /// - In `OkCancel` dialog, it will call the closure with `true` when `OK` was pressed
549+ /// - In `YesNo` dialog, it will call the closure with `true` when `Yes` was pressed
550+ pub fn show < F : FnOnce ( bool ) + Send + ' static > ( self , f : F ) {
551+ run_dialog ! ( self . 0 . show( ) , f) ;
552+ }
553+ }
554+
434555 /// Displays a non-blocking dialog with a message and an optional title with a "yes" and a "no" button.
435556 ///
436557 /// This is not a blocking operation,
@@ -453,7 +574,14 @@ mod nonblocking {
453574 message : impl AsRef < str > ,
454575 f : F ,
455576 ) {
456- run_message_dialog ( parent_window, title, message, rfd:: MessageButtons :: YesNo , f)
577+ run_message_dialog (
578+ parent_window,
579+ title,
580+ message,
581+ rfd:: MessageButtons :: YesNo ,
582+ MessageDialogKind :: Info ,
583+ f,
584+ )
457585 }
458586
459587 /// Displays a non-blocking dialog with a message and an optional title with an "ok" and a "cancel" button.
@@ -483,6 +611,7 @@ mod nonblocking {
483611 title,
484612 message,
485613 rfd:: MessageButtons :: OkCancel ,
614+ MessageDialogKind :: Info ,
486615 f,
487616 )
488617 }
@@ -511,6 +640,7 @@ mod nonblocking {
511640 title,
512641 message,
513642 rfd:: MessageButtons :: Ok ,
643+ MessageDialogKind :: Info ,
514644 |_| { } ,
515645 )
516646 }
@@ -521,6 +651,7 @@ mod nonblocking {
521651 title : impl AsRef < str > ,
522652 message : impl AsRef < str > ,
523653 buttons : rfd:: MessageButtons ,
654+ level : MessageDialogKind ,
524655 f : F ,
525656 ) {
526657 let title = title. as_ref ( ) . to_string ( ) ;
@@ -530,7 +661,7 @@ mod nonblocking {
530661 . set_title ( & title)
531662 . set_description ( & message)
532663 . set_buttons ( buttons)
533- . set_level ( rfd :: MessageLevel :: Info ) ;
664+ . set_level ( level . into ( ) ) ;
534665
535666 #[ cfg( any( windows, target_os = "macos" ) ) ]
536667 {
0 commit comments