comparison src/main.rs @ 13:97e543f50f62

Split GTK UI into another module.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Sun, 01 Nov 2020 16:08:29 +0100
parents d43c31aff57c
children adab13145994
comparison
equal deleted inserted replaced
12:d43c31aff57c 13:97e543f50f62
12 // GNU Affero General Public License for more details. 12 // GNU Affero General Public License for more details.
13 // 13 //
14 // You should have received a copy of the GNU Affero General Public License 14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <https://www.gnu.org/licenses/>. 15 // along with this program. If not, see <https://www.gnu.org/licenses/>.
16 16
17 use gio::prelude::*; 17 mod gtk;
18 use glib::clone;
19 use gtk::prelude::*;
20
21 use std::env::args;
22 use std::io::ErrorKind;
23 use std::sync::Arc;
24 use input_linux::Key;
25
26 mod uinput; 18 mod uinput;
27 mod state; 19 mod state;
28 use state::State;
29
30 const WIDTH: i32 = 320;
31 const HEIGHT: i32 = 180;
32 20
33 const MAX_X: i32 = 69920; 21 const MAX_X: i32 = 69920;
34 const MAX_Y: i32 = 39980; 22 const MAX_Y: i32 = 39980;
35 23
36 fn build_main_menu(application: &gtk::Application) { 24 const DEFAULT_WIDTH: i32 = 320;
37 let quit = gio::SimpleAction::new("quit", None); 25 const DEFAULT_HEIGHT: i32 = 180;
38 application.set_accels_for_action("app.quit", &["<Control>q"]);
39 application.add_action(&quit);
40 quit.connect_activate(clone!(@weak application => move |_, _| application.quit()));
41
42 let about = gio::SimpleAction::new("about", None);
43 application.add_action(&about);
44 about.connect_activate(|_, _| {
45 let about = gtk::AboutDialog::new();
46 about.set_program_name("TabletEmu");
47 about.set_logo_icon_name(Some("input-tablet"));
48 about.set_website(Some("https://hg.linkmauve.fr/tablet-emu"));
49 about.set_version(Some("0.1"));
50 about.set_license_type(gtk::License::Agpl30);
51 about.set_copyright(Some("© 2020 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>"));
52 about.run();
53 unsafe {
54 about.destroy();
55 }
56 });
57
58 let menu = gio::Menu::new();
59 {
60 let file = gio::Menu::new();
61 file.append(Some("_Quit"), Some("app.quit"));
62 menu.append_submenu(Some("_File"), &file);
63 }
64 {
65 let help = gio::Menu::new();
66 help.append(Some("_About"), Some("app.about"));
67 menu.append_submenu(Some("_Help"), &help);
68 }
69 application.set_menubar(Some(&menu));
70 }
71
72 fn build_ui(application: &gtk::Application) {
73 build_main_menu(application);
74
75 let state = match State::new() {
76 Ok(state) => state,
77 Err(err) => {
78 match err.kind() {
79 ErrorKind::NotFound => {
80 eprintln!("Couldn’t find /dev/uinput: {}", err);
81 eprintln!("Maybe you forgot to `modprobe uinput`?");
82 }
83 ErrorKind::PermissionDenied => {
84 eprintln!("Couldn’t open /dev/uinput for writing: {}", err);
85 eprintln!("Maybe you aren’t allowed to create input devices?");
86 }
87 _ => eprintln!("Couldn’t open /dev/uinput for writing: {}", err),
88 }
89 std::process::exit(1);
90 }
91 };
92
93 let window = gtk::ApplicationWindow::new(application);
94 window.set_title("tablet-emu");
95 window.set_position(gtk::WindowPosition::Center);
96
97 let hbox = gtk::Box::new(gtk::Orientation::Horizontal, 0);
98 let tools_box = gtk::Box::new(gtk::Orientation::Vertical, 0);
99
100 macro_rules! impl_tool {
101 ($tool:tt) => {
102 let tool = gtk::Button::with_mnemonic($tool);
103 let state_weak = Arc::downgrade(&state);
104 tool.connect_clicked(move |b| {
105 let state = state_weak.upgrade().unwrap();
106 let mut state = state.lock().unwrap();
107 let tool = match b.get_label().unwrap().as_str() {
108 "_Pen" => Key::ButtonToolPen,
109 "_Rubber" => Key::ButtonToolRubber,
110 "_Brush" => Key::ButtonToolBrush,
111 "P_encil" => Key::ButtonToolPencil,
112 "_Airbrush" => Key::ButtonToolAirbrush,
113 _ => unreachable!(),
114 };
115 state.select_tool(tool);
116 });
117 tools_box.add(&tool);
118 };
119 };
120 impl_tool!("_Pen");
121 impl_tool!("_Rubber");
122 impl_tool!("_Brush");
123 impl_tool!("P_encil");
124 impl_tool!("_Airbrush");
125
126 let drawing_area = gtk::DrawingArea::new();
127 drawing_area.set_size_request(WIDTH, HEIGHT);
128 drawing_area.set_hexpand(true);
129 drawing_area.set_events(
130 gdk::EventMask::BUTTON_PRESS_MASK
131 | gdk::EventMask::BUTTON_RELEASE_MASK
132 | gdk::EventMask::POINTER_MOTION_MASK,
133 );
134 let state_weak = Arc::downgrade(&state);
135 drawing_area.connect_configure_event(move |_, event| {
136 let state = state_weak.upgrade().unwrap();
137 let mut state = state.lock().unwrap();
138 state.set_size(event.get_size());
139 true
140 });
141 let state_weak = Arc::downgrade(&state);
142 drawing_area.connect_button_press_event(move |_, event| {
143 if event.get_button() != 1 {
144 return Inhibit(false);
145 }
146
147 let state = state_weak.upgrade().unwrap();
148 let mut state = state.lock().unwrap();
149 let (x, y) = event.get_position();
150 state.press(x, y).unwrap();
151 Inhibit(false)
152 });
153 let state_weak = Arc::downgrade(&state);
154 drawing_area.connect_button_release_event(move |_, event| {
155 if event.get_button() != 1 {
156 return Inhibit(false);
157 }
158
159 let state = state_weak.upgrade().unwrap();
160 let mut state = state.lock().unwrap();
161 let (x, y) = event.get_position();
162 state.release(x, y).unwrap();
163 Inhibit(false)
164 });
165 drawing_area.connect_motion_notify_event(move |_, event| {
166 let mut state = state.lock().unwrap();
167 let (x, y) = event.get_position();
168 state.motion(x, y).unwrap();
169 Inhibit(false)
170 });
171 drawing_area.connect_draw(move |_, ctx| {
172 //println!("drawing {}", drawing_area);
173 ctx.set_source_rgb(1., 0., 0.);
174 ctx.set_operator(cairo::Operator::Screen);
175 ctx.paint();
176 Inhibit(false)
177 });
178
179 hbox.add(&tools_box);
180 hbox.add(&drawing_area);
181
182 window.add(&hbox);
183
184 window.show_all();
185 }
186 26
187 fn main() { 27 fn main() {
188 let application = gtk::Application::new( 28 gtk::main();
189 Some("fr.linkmauve.TabletEmu"),
190 gio::ApplicationFlags::empty(),
191 )
192 .expect("Initialisation failed…");
193 application.connect_activate(build_ui);
194 application.run(&args().collect::<Vec<_>>());
195 } 29 }