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}