Skip to content

Commit 895b9b5

Browse files
authored
Add support for opening multiple editor windows (#5)
Also remove log statements found during debugging
1 parent 459484f commit 895b9b5

File tree

5 files changed

+101
-54
lines changed

5 files changed

+101
-54
lines changed

src-tauri/capabilities/default.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"identifier": "default",
44
"description": "Capability for the main window",
55
"windows": [
6-
"main",
6+
"main*",
77
"settings"
88
],
99
"permissions": [

src-tauri/src/lib.rs

+76-37
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,35 @@ use crate::scripts::commands::{get_script_commands, reply_editor_request, run_sc
66
use crate::scripts::loader::scripts::ScriptManager;
77
use crate::settings::{get_settings, set_preferred_language, set_theme, set_wrap_lines, Settings};
88
use crate::window::Windows;
9-
use tauri::async_runtime::Mutex;
10-
use tauri::menu::{AboutMetadataBuilder, Menu, MenuItemBuilder, SubmenuBuilder};
9+
use tauri::async_runtime::{spawn, Mutex};
10+
use tauri::menu::{AboutMetadataBuilder, Menu, MenuItemBuilder, Submenu, SubmenuBuilder};
1111
use tauri::path::BaseDirectory;
1212
use tauri::Error::WebviewLabelAlreadyExists;
13-
use tauri::{AppHandle, Emitter, Manager, WebviewUrl, WebviewWindowBuilder, WindowEvent};
13+
use tauri::{
14+
AppHandle, Emitter, Manager, State, WebviewUrl, WebviewWindowBuilder, WindowEvent, Wry,
15+
};
1416
use tauri_plugin_store::StoreExt;
1517

18+
const MENU_ITEM_ID_SETTINGS: &str = "settings";
19+
const MENU_ITEM_ID_NEW_WINDOW: &str = "window_new";
20+
const MENU_ITEM_ID_SCRIPTS_OPEN_PICKER: &str = "scripts_open_picker";
21+
const MENU_ITEM_ID_SCRIPTS_REEXECUTE_LAST: &str = "scripts_reexecute_last";
22+
23+
fn get_file_sub_menu(app: &AppHandle, in_settings: bool) -> Result<Submenu<Wry>, tauri::Error> {
24+
let mut builder = SubmenuBuilder::new(app, "File");
25+
if !in_settings {
26+
let new_window_item = MenuItemBuilder::new("New Window")
27+
.id(MENU_ITEM_ID_NEW_WINDOW)
28+
.accelerator("CmdOrCtrl+N")
29+
.build(app)?;
30+
builder = builder.item(&new_window_item).separator();
31+
}
32+
builder.close_window().build()
33+
}
34+
1635
fn setup_menu(app: &AppHandle, in_settings: bool) -> Result<(), tauri::Error> {
1736
let settings = MenuItemBuilder::new("Settings...")
18-
.id("settings")
37+
.id(MENU_ITEM_ID_SETTINGS)
1938
.accelerator("CmdOrCtrl+,")
2039
.enabled(!in_settings)
2140
.build(app)?;
@@ -38,8 +57,8 @@ fn setup_menu(app: &AppHandle, in_settings: bool) -> Result<(), tauri::Error> {
3857
.separator()
3958
.quit()
4059
.build()?;
41-
let file_sub_menu = SubmenuBuilder::new(app, "File").close_window().build()?;
4260

61+
let file_sub_menu = get_file_sub_menu(app, in_settings)?;
4362
let app_menu = Menu::new(app)?;
4463

4564
if !in_settings {
@@ -54,11 +73,11 @@ fn setup_menu(app: &AppHandle, in_settings: bool) -> Result<(), tauri::Error> {
5473
.build()?;
5574

5675
let open_script_picker_item = MenuItemBuilder::new("Open Picker")
57-
.id("scripts_open_picker")
76+
.id(MENU_ITEM_ID_SCRIPTS_OPEN_PICKER)
5877
.accelerator("CmdOrCtrl+B")
5978
.build(app)?;
6079
let reexecute_last_script_item = MenuItemBuilder::new("Re-execute Last Script")
61-
.id("scripts_reexecute_last")
80+
.id(MENU_ITEM_ID_SCRIPTS_REEXECUTE_LAST)
6281
.accelerator("CmdOrCtrl+Shift+B")
6382
.enabled(false)
6483
.build(app)?;
@@ -73,34 +92,6 @@ fn setup_menu(app: &AppHandle, in_settings: bool) -> Result<(), tauri::Error> {
7392
&edit_sub_menu,
7493
&scripts_sub_menu,
7594
])?;
76-
77-
app.on_menu_event(move |app, event| {
78-
if event.id() == settings.id() {
79-
let settings_window_result = WebviewWindowBuilder::new(
80-
app,
81-
"settings".to_string(),
82-
WebviewUrl::App("windows/settings.html".parse().unwrap()),
83-
)
84-
.min_inner_size(200.0, 400.0)
85-
.title("Snip Settings")
86-
.build();
87-
if let Err(WebviewLabelAlreadyExists(_)) = settings_window_result {
88-
let webview_windows = app.webview_windows();
89-
let settings_window = webview_windows.get("settings").unwrap();
90-
settings_window.unminimize().unwrap(); // Must use it if window is minimized
91-
settings_window.set_focus().unwrap();
92-
settings_window.show().unwrap();
93-
}
94-
} else if event.id() == open_script_picker_item.id() {
95-
let focused_window = app.get_focused_window();
96-
if let Some(focused_window) = focused_window {
97-
if focused_window.label() != "settings" {
98-
app.emit_to(focused_window.label(), "open_picker", true)
99-
.unwrap()
100-
}
101-
}
102-
}
103-
});
10495
} else {
10596
app_menu.append_items(&[&app_sub_menu, &file_sub_menu])?;
10697
}
@@ -113,7 +104,14 @@ fn setup_menu(app: &AppHandle, in_settings: bool) -> Result<(), tauri::Error> {
113104
pub fn run() {
114105
tauri::Builder::default()
115106
.plugin(tauri_plugin_os::init())
116-
.plugin(tauri_plugin_single_instance::init(|_, _, _| {}))
107+
.plugin(tauri_plugin_single_instance::init(|app, _, _| {
108+
let app = app.clone();
109+
spawn(async move {
110+
let windows: State<'_, Mutex<Windows>> = app.state();
111+
let mut windows = windows.lock().await;
112+
windows.create_window(&app).unwrap();
113+
});
114+
}))
117115
.plugin(
118116
tauri_plugin_log::Builder::new()
119117
.clear_targets()
@@ -151,13 +149,54 @@ pub fn run() {
151149
app.manage(Mutex::new(settings));
152150
app.manage(Mutex::new(windows));
153151
app.manage(Mutex::new(script_manager));
152+
153+
app.on_menu_event(move |app, event| {
154+
match event.id().0.as_str() {
155+
MENU_ITEM_ID_SETTINGS => {
156+
let settings_window_result = WebviewWindowBuilder::new(
157+
app,
158+
"settings".to_string(),
159+
WebviewUrl::App("windows/settings.html".parse().unwrap()),
160+
)
161+
.min_inner_size(200.0, 400.0)
162+
.title("Snip Settings")
163+
.build();
164+
if let Err(WebviewLabelAlreadyExists(_)) = settings_window_result {
165+
let webview_windows = app.webview_windows();
166+
let settings_window = webview_windows.get("settings").unwrap();
167+
settings_window.unminimize().unwrap(); // Must use it if window is minimized
168+
settings_window.set_focus().unwrap();
169+
settings_window.show().unwrap();
170+
}
171+
}
172+
MENU_ITEM_ID_SCRIPTS_OPEN_PICKER => {
173+
let focused_window = app.get_focused_window();
174+
if let Some(focused_window) = focused_window {
175+
if focused_window.label() != "settings" {
176+
app.emit_to(focused_window.label(), "open_picker", true)
177+
.unwrap()
178+
}
179+
}
180+
}
181+
MENU_ITEM_ID_NEW_WINDOW => {
182+
let windows: State<'_, Mutex<Windows>> = app.state();
183+
let mut windows = windows.blocking_lock();
184+
windows.create_window(app).unwrap();
185+
}
186+
_ => {}
187+
}
188+
});
189+
154190
setup_menu(app.handle(), false)?;
155191

156192
Ok(())
157193
})
158194
.on_window_event(|window, event| match event {
159195
WindowEvent::Destroyed => {
160-
if window.label() == "main" {
196+
let windows: State<'_, Mutex<Windows>> = window.app_handle().state();
197+
let windows = &mut windows.blocking_lock();
198+
windows.destroy_window(window.label());
199+
if !windows.has_open() {
161200
window.app_handle().exit(0);
162201
}
163202
}

src-tauri/src/scripts/commands.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ pub async fn reply_editor_request(
186186
) -> Result<(), String> {
187187
let state = &mut state.lock().await;
188188
let script_state = state
189-
.get_script_state(&webview_window.label().to_string())
189+
.get_script_state(webview_window.label())
190190
.expect("Window should have script state");
191191

192192
let reply_sender = script_state.reply_senders.remove(&reply.id);

src-tauri/src/window.rs

+22-3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use tokio::sync::mpsc::{channel, Receiver, Sender};
99

1010
pub enum WindowTask {
1111
Script(ScriptTask),
12+
Close,
1213
}
1314

1415
pub struct WindowState {
@@ -19,6 +20,7 @@ pub struct WindowState {
1920

2021
pub struct Windows {
2122
window_states: HashMap<String, WindowState>,
23+
last_window_id: u32,
2224
}
2325

2426
fn window_task_listener(mut task_receiver: Receiver<WindowTask>) {
@@ -32,6 +34,7 @@ fn window_task_listener(mut task_receiver: Receiver<WindowTask>) {
3234
if let Some(task) = task {
3335
match task {
3436
WindowTask::Script(script_event) => handle_script_task(script_event).await,
37+
WindowTask::Close => break,
3538
}
3639
} else {
3740
break;
@@ -44,11 +47,13 @@ impl Windows {
4447
pub fn new() -> Self {
4548
Self {
4649
window_states: HashMap::new(),
50+
last_window_id: 0,
4751
}
4852
}
4953

5054
pub fn create_window(&mut self, app_handle: &AppHandle) -> Result<(), Error> {
51-
let id = String::from("main");
55+
self.last_window_id += 1;
56+
let id = format!("main_{}", self.last_window_id);
5257

5358
let (task_sender, task_receiver) = channel(8);
5459

@@ -71,7 +76,7 @@ impl Windows {
7176
WebviewUrl::App("windows/index.html".parse().unwrap()),
7277
)
7378
.min_inner_size(800.0, 600.0)
74-
.title("Snip")
79+
.title(format!("Snip - Untitled {}", self.last_window_id))
7580
.build()?;
7681

7782
Ok(())
@@ -91,12 +96,26 @@ impl Windows {
9196
}
9297
}
9398

94-
pub fn get_script_state(&mut self, window_id: &String) -> Option<&mut WindowScriptState> {
99+
pub fn get_script_state(&mut self, window_id: &str) -> Option<&mut WindowScriptState> {
95100
let window_state = self.window_states.get_mut(window_id);
96101
if let Some(window_state) = window_state {
97102
Some(&mut window_state.script_state)
98103
} else {
99104
None
100105
}
101106
}
107+
108+
pub fn destroy_window(&mut self, window_id: &str) {
109+
if let Some(window_state) = self.window_states.remove(window_id) {
110+
window_state
111+
.task_sender
112+
.blocking_send(WindowTask::Close)
113+
.unwrap();
114+
window_state.thread_join_handle.join().unwrap();
115+
}
116+
}
117+
118+
pub fn has_open(&self) -> bool {
119+
!self.window_states.is_empty()
120+
}
102121
}

src/modules/getShades.ts

+1-12
Original file line numberDiff line numberDiff line change
@@ -118,25 +118,14 @@ function convertHexToHsl(hex: string) {
118118

119119
function convertHslToHex(hue: number, saturation: number, luminosity: number) {
120120
const { r, g, b } = convertHslToRgb(hue, saturation, luminosity)
121-
const result = convertRgbToHex(r, g, b)
122-
console.log({
123-
hue,
124-
saturation,
125-
luminosity,
126-
r,
127-
g,
128-
b,
129-
result,
130-
})
131-
return result
121+
return convertRgbToHex(r, g, b)
132122
}
133123

134124
export default function getShades(
135125
baseColorHex: string,
136126
darkMode: boolean = false,
137127
) {
138128
const baseHSL = convertHexToHsl(baseColorHex)
139-
console.log(baseHSL)
140129
const {
141130
hue: baseHue,
142131
saturation: baseSaturation,

0 commit comments

Comments
 (0)