1use std::any::Any;
16
17use druid_shell::kurbo::{Line, Size};
18use druid_shell::piet::{Color, RenderContext};
19
20use druid_shell::{
21    Application, Cursor, FileDialogOptions, FileDialogToken, FileInfo, FileSpec, HotKey, KeyEvent,
22    Menu, MouseEvent, Region, SysMods, TimerToken, WinHandler, WindowBuilder, WindowHandle,
23};
24
25const BG_COLOR: Color = Color::rgb8(0x27, 0x28, 0x22);
26const FG_COLOR: Color = Color::rgb8(0xf0, 0xf0, 0xea);
27
28#[derive(Default)]
29struct HelloState {
30    size: Size,
31    handle: WindowHandle,
32}
33
34impl WinHandler for HelloState {
35    fn connect(&mut self, handle: &WindowHandle) {
36        self.handle = handle.clone();
37    }
38
39    fn prepare_paint(&mut self) {}
40
41    fn paint(&mut self, piet: &mut piet_common::Piet, _: &Region) {
42        let rect = self.size.to_rect();
43        piet.fill(rect, &BG_COLOR);
44        piet.stroke(Line::new((10.0, 50.0), (90.0, 90.0)), &FG_COLOR, 1.0);
45    }
46
47    fn command(&mut self, id: u32) {
48        match id {
49            0x100 => {
50                self.handle.close();
51                Application::global().quit()
52            }
53            0x101 => {
54                let options = FileDialogOptions::new().show_hidden().allowed_types(vec![
55                    FileSpec::new("Rust Files", &["rs", "toml"]),
56                    FileSpec::TEXT,
57                    FileSpec::JPG,
58                ]);
59                self.handle.open_file(options);
60            }
61            0x102 => {
62                let options = FileDialogOptions::new().show_hidden().allowed_types(vec![
63                    FileSpec::new("Rust Files", &["rs", "toml"]),
64                    FileSpec::TEXT,
65                    FileSpec::JPG,
66                ]);
67                self.handle.save_as(options);
68            }
69            _ => println!("unexpected id {id}"),
70        }
71    }
72
73    fn open_file(&mut self, _token: FileDialogToken, file_info: Option<FileInfo>) {
74        println!("open file result: {file_info:?}");
75    }
76
77    fn save_as(&mut self, _token: FileDialogToken, file: Option<FileInfo>) {
78        println!("save file result: {file:?}");
79    }
80
81    fn key_down(&mut self, event: KeyEvent) -> bool {
82        println!("keydown: {event:?}");
83        false
84    }
85
86    fn key_up(&mut self, event: KeyEvent) {
87        println!("keyup: {event:?}");
88    }
89
90    fn wheel(&mut self, event: &MouseEvent) {
91        println!("mouse_wheel {event:?}");
92    }
93
94    fn mouse_move(&mut self, event: &MouseEvent) {
95        self.handle.set_cursor(&Cursor::Arrow);
96        println!("mouse_move {event:?}");
97    }
98
99    fn mouse_down(&mut self, event: &MouseEvent) {
100        println!("mouse_down {event:?}");
101    }
102
103    fn mouse_up(&mut self, event: &MouseEvent) {
104        println!("mouse_up {event:?}");
105    }
106
107    fn timer(&mut self, id: TimerToken) {
108        println!("timer fired: {id:?}");
109    }
110
111    fn size(&mut self, size: Size) {
112        self.size = size;
113    }
114
115    fn got_focus(&mut self) {
116        println!("Got focus");
117    }
118
119    fn lost_focus(&mut self) {
120        println!("Lost focus");
121    }
122
123    fn request_close(&mut self) {
124        self.handle.close();
125    }
126
127    fn destroy(&mut self) {
128        Application::global().quit()
129    }
130
131    fn as_any(&mut self) -> &mut dyn Any {
132        self
133    }
134}
135
136fn main() {
137    tracing_subscriber::fmt().init();
138    let mut file_menu = Menu::new();
139    file_menu.add_item(
140        0x100,
141        "E&xit",
142        Some(&HotKey::new(SysMods::Cmd, "q")),
143        None,
144        true,
145    );
146    file_menu.add_item(
147        0x101,
148        "O&pen",
149        Some(&HotKey::new(SysMods::Cmd, "o")),
150        None,
151        true,
152    );
153    file_menu.add_item(
154        0x102,
155        "S&ave",
156        Some(&HotKey::new(SysMods::Cmd, "s")),
157        None,
158        true,
159    );
160    let mut menubar = Menu::new();
161    menubar.add_dropdown(Menu::new(), "Application", true);
162    menubar.add_dropdown(file_menu, "&File", true);
163
164    let app = Application::new().unwrap();
165    let mut builder = WindowBuilder::new(app.clone());
166    builder.set_handler(Box::<HelloState>::default());
167    builder.set_title("Hello example");
168    builder.set_menu(menubar);
169
170    let window = builder.build().unwrap();
171    window.show();
172
173    app.run(None);
174}