diff --git a/src/hyprland_binds.rs b/src/hyprland_binds.rs index d500749..4ec74b8 100644 --- a/src/hyprland_binds.rs +++ b/src/hyprland_binds.rs @@ -158,6 +158,7 @@ pub fn register_hyprland_binds(config: &ScytheConfig) { "float, class:^(scythe-toast)$", "pin, class:^(scythe-toast)$", "noborder, class:^(scythe-toast)$", + "move 100%-w 16, class:^(scythe-toast)$", "float, class:^(vrec-overlay)$", "move 0 0, class:^(vrec-overlay)$", "size 100% 100%, class:^(vrec-overlay)$", diff --git a/src/overlay.rs b/src/overlay.rs index 57c31f4..3b56c66 100644 --- a/src/overlay.rs +++ b/src/overlay.rs @@ -199,7 +199,7 @@ pub fn show_shadowplay_toast(title: &str, subtitle: &str, icon: ToastIcon) { _ => ("#38bdf8", (0.220, 0.741, 0.973)), }; - let (active_accent_hex, active_accent) = if icon == ToastIcon::Record { + let (_active_accent_hex, active_accent) = if icon == ToastIcon::Record { ("#ef4444", (0.937, 0.267, 0.267)) } else { (accent_hex, accent_rgb) @@ -229,8 +229,8 @@ pub fn show_shadowplay_toast(title: &str, subtitle: &str, icon: ToastIcon) { app.connect_activate(move |app| { let window = ApplicationWindow::builder() .application(app) - .default_width(360) - .default_height(64) + .default_width(320) + .default_height(56) .build(); #[cfg(target_os = "linux")] @@ -250,8 +250,8 @@ pub fn show_shadowplay_toast(title: &str, subtitle: &str, icon: ToastIcon) { } window.set_anchor(gtk_layer_shell::Edge::Top, true); window.set_anchor(gtk_layer_shell::Edge::Right, true); - window.set_layer_shell_margin(gtk_layer_shell::Edge::Top, 28); - window.set_layer_shell_margin(gtk_layer_shell::Edge::Right, 28); + window.set_layer_shell_margin(gtk_layer_shell::Edge::Top, 16); + window.set_layer_shell_margin(gtk_layer_shell::Edge::Right, 0); // flush on screen right edge window.set_keyboard_interactivity(false); } else { window.set_decorated(false); @@ -260,8 +260,8 @@ pub fn show_shadowplay_toast(title: &str, subtitle: &str, icon: ToastIcon) { window.set_accept_focus(false); if let Some(ref mon) = active_monitor { let geom = mon.geometry(); - let x = geom.x() + geom.width() - 360 - 28; - let y = geom.y() + 28; + let x = geom.x() + geom.width() - 320; + let y = geom.y() + 16; window.move_(x, y); } } @@ -289,14 +289,12 @@ pub fn show_shadowplay_toast(title: &str, subtitle: &str, icon: ToastIcon) { box-shadow: none; }} .toast-card {{ - background-color: rgba(14, 16, 21, 0.96); - border: 1px solid rgba(255, 255, 255, 0.14); - border-left: 4px solid {accent}; + background-color: rgba(10, 10, 10, 0.65); + border: 1px solid rgba(255, 255, 255, 0.08); border-radius: 0px; - box-shadow: 0px 8px 24px rgba(0, 0, 0, 0.75); + box-shadow: none; }} "#, - accent = active_accent_hex ); let _ = css_provider.load_from_data(css.as_bytes()); if let Some(screen) = gdk::Screen::default() { @@ -316,31 +314,20 @@ pub fn show_shadowplay_toast(title: &str, subtitle: &str, icon: ToastIcon) { hbox.connect_draw(move |widget, cr| { let w = widget.allocated_width() as f64; let h = widget.allocated_height() as f64; - let card_h = (h - 4.0).max(10.0); cr.set_operator(gtk::cairo::Operator::Over); - // 1. Drop shadow (soft dark shadow offset down by 4px) - cr.set_source_rgba(0.0, 0.0, 0.0, 0.60); - cr.rectangle(0.0, 4.0, w, card_h); + // Sleek translucent neutral dark glass background (matching HUD cards) + cr.set_source_rgba(10.0 / 255.0, 10.0 / 255.0, 10.0 / 255.0, 0.65); + cr.rectangle(0.0, 0.0, w, h); let _ = cr.fill(); - // 2. Solid obsidian dark slate background (matching egui rgba(14, 16, 21, 0.96)) - cr.set_source_rgba(14.0 / 255.0, 16.0 / 255.0, 21.0 / 255.0, 0.96); - cr.rectangle(0.0, 0.0, w, card_h); - let _ = cr.fill(); - - // 3. Subtle white border (1px inside) - cr.set_source_rgba(1.0, 1.0, 1.0, 0.14); + // Refined subtle accent stroke framing the card + cr.set_source_rgba(active_accent.0, active_accent.1, active_accent.2, 0.55); cr.set_line_width(1.0); - cr.rectangle(0.5, 0.5, w - 1.0, card_h - 1.0); + cr.rectangle(0.5, 0.5, w - 1.0, h - 1.0); let _ = cr.stroke(); - // 4. Left accent bar (4.0px width) - cr.set_source_rgb(active_accent.0, active_accent.1, active_accent.2); - cr.rectangle(0.0, 0.0, 4.0, card_h); - let _ = cr.fill(); - gtk::glib::Propagation::Proceed }); @@ -355,75 +342,75 @@ pub fn show_shadowplay_toast(title: &str, subtitle: &str, icon: ToastIcon) { let cy = 16.0; match icon_type { ToastIcon::Replay => { - let r = 10.0; cr.set_source_rgb(accent_rgb.0, accent_rgb.1, accent_rgb.2); - cr.set_line_width(2.2); - cr.arc(cx, cy, r, 0.25 * PI, 1.80 * PI); - let _ = cr.stroke(); - - let a_x = cx + r * (0.25 * PI).cos(); - let a_y = cy + r * (0.25 * PI).sin(); - cr.move_to(a_x, a_y); - cr.line_to(a_x - 4.5, a_y + 0.5); - cr.line_to(a_x - 0.5, a_y - 4.5); - cr.close_path(); - let _ = cr.fill(); - - let tri_r = 4.0; - cr.move_to(cx + tri_r + 0.5, cy); - cr.line_to(cx - tri_r * 0.6 + 0.5, cy - tri_r * 0.86); - cr.line_to(cx - tri_r * 0.6 + 0.5, cy + tri_r * 0.86); - cr.close_path(); - let _ = cr.fill(); + cr.set_line_width(1.8); + cr.set_line_cap(gtk::cairo::LineCap::Round); + cr.set_line_join(gtk::cairo::LineJoin::Round); + let ch_h = 7.0; + let ch_w = 4.4; + let gap = 4.2; + let start_x = cx - (ch_w + gap) * 0.5; + for i in 0..2 { + let tip_x = start_x + (i as f64) * gap; + let base_x = tip_x + ch_w; + cr.move_to(base_x, cy - ch_h); + cr.line_to(tip_x, cy); + cr.line_to(base_x, cy + ch_h); + let _ = cr.stroke(); + } } ToastIcon::Record => { - cr.set_source_rgba(0.937, 0.267, 0.267, 0.25); - cr.arc(cx, cy, 13.0, 0.0, PI * 2.0); - let _ = cr.fill(); - - cr.set_source_rgb(0.937, 0.267, 0.267); - cr.set_line_width(1.8); - cr.arc(cx, cy, 10.0, 0.0, PI * 2.0); + let red = (0.937, 0.267, 0.267); + cr.set_source_rgb(red.0, red.1, red.2); + cr.set_line_width(1.6); + let half = 8.5; + let arm = 3.2; + cr.move_to(cx - half + arm, cy - half); cr.line_to(cx - half, cy - half); cr.line_to(cx - half, cy - half + arm); + cr.move_to(cx + half - arm, cy - half); cr.line_to(cx + half, cy - half); cr.line_to(cx + half, cy - half + arm); + cr.move_to(cx - half + arm, cy + half); cr.line_to(cx - half, cy + half); cr.line_to(cx - half, cy + half - arm); + cr.move_to(cx + half - arm, cy + half); cr.line_to(cx + half, cy + half); cr.line_to(cx + half, cy + half - arm); let _ = cr.stroke(); - - cr.arc(cx, cy, 5.0, 0.0, PI * 2.0); + cr.arc(cx, cy, 3.5, 0.0, PI * 2.0); let _ = cr.fill(); } ToastIcon::Save => { cr.set_source_rgb(accent_rgb.0, accent_rgb.1, accent_rgb.2); - cr.set_line_width(2.5); + cr.set_line_width(2.0); cr.set_line_cap(gtk::cairo::LineCap::Round); cr.set_line_join(gtk::cairo::LineJoin::Round); - cr.move_to(cx - 7.0, cy); - cr.line_to(cx - 2.0, cy + 5.0); - cr.line_to(cx + 7.0, cy - 5.0); + cr.move_to(cx - 6.0, cy + 0.5); + cr.line_to(cx - 2.0, cy + 4.5); + cr.line_to(cx + 6.0, cy - 4.5); let _ = cr.stroke(); } ToastIcon::Cursor => { cr.set_source_rgb(accent_rgb.0, accent_rgb.1, accent_rgb.2); cr.set_line_width(1.8); - cr.move_to(cx - 6.0, cy - 8.0); - cr.line_to(cx + 6.0, cy - 1.0); - cr.line_to(cx, cy + 1.0); - cr.line_to(cx + 2.0, cy + 7.0); - cr.line_to(cx - 1.0, cy + 8.0); - cr.line_to(cx - 3.0, cy + 2.0); - cr.line_to(cx - 6.0, cy + 4.0); + cr.set_line_cap(gtk::cairo::LineCap::Round); + cr.set_line_join(gtk::cairo::LineJoin::Round); + cr.move_to(cx - 5.0, cy - 7.0); + cr.line_to(cx - 5.0, cy + 5.0); + cr.line_to(cx - 1.5, cy + 2.0); + cr.line_to(cx + 1.5, cy + 7.0); + cr.line_to(cx + 3.5, cy + 6.0); + cr.line_to(cx + 0.5, cy + 1.0); + cr.line_to(cx + 5.0, cy + 1.0); cr.close_path(); - let _ = cr.fill(); + let _ = cr.stroke(); } ToastIcon::Error => { cr.set_source_rgb(0.937, 0.267, 0.267); - cr.set_line_width(2.2); - cr.move_to(cx - 6.0, cy - 6.0); - cr.line_to(cx + 6.0, cy + 6.0); - cr.move_to(cx + 6.0, cy - 6.0); - cr.line_to(cx - 6.0, cy + 6.0); + cr.set_line_width(2.0); + cr.set_line_cap(gtk::cairo::LineCap::Round); + cr.move_to(cx - 5.0, cy - 5.0); + cr.line_to(cx + 5.0, cy + 5.0); + cr.move_to(cx + 5.0, cy - 5.0); + cr.line_to(cx - 5.0, cy + 5.0); let _ = cr.stroke(); } ToastIcon::Info => { cr.set_source_rgb(accent_rgb.0, accent_rgb.1, accent_rgb.2); - cr.arc(cx, cy, 6.0, 0.0, PI * 2.0); + cr.arc(cx, cy, 4.5, 0.0, PI * 2.0); let _ = cr.fill(); } } @@ -437,14 +424,14 @@ pub fn show_shadowplay_toast(title: &str, subtitle: &str, icon: ToastIcon) { let title_lbl = Label::new(None); title_lbl.set_markup(&format!( - "{}", + "{}", gtk::glib::markup_escape_text(&title_text) )); title_lbl.set_halign(gtk::Align::Start); let sub_lbl = Label::new(None); sub_lbl.set_markup(&format!( - "{}", + "{}", gtk::glib::markup_escape_text(&sub_text) )); sub_lbl.set_halign(gtk::Align::Start); @@ -456,8 +443,8 @@ pub fn show_shadowplay_toast(title: &str, subtitle: &str, icon: ToastIcon) { hbox.pack_start(&vbox, true, true, 0); let fixed = Fixed::new(); - fixed.set_size_request(360, 64); - fixed.put(&hbox, 360, 4); + fixed.set_size_request(320, 56); + fixed.put(&hbox, 320, 0); window.add(&fixed); window.show_all(); @@ -476,17 +463,17 @@ pub fn show_shadowplay_toast(title: &str, subtitle: &str, icon: ToastIcon) { let slide_x = if elapsed < 0.35 { let t = (elapsed / 0.35).min(1.0); let ease = 1.0 - (1.0 - t).powi(3); - (1.0 - ease) * 360.0 + (1.0 - ease) * 320.0 } else if elapsed < 2.40 { 0.0 } else { let t = ((elapsed - 2.40) / 0.40).min(1.0); let ease = t.powi(3); - ease * 360.0 + ease * 320.0 }; - let target_x = (slide_x + 14.0).round() as i32; - fixed_clone.move_(&hbox_clone, target_x, 4); + let target_x = slide_x.round() as i32; + fixed_clone.move_(&hbox_clone, target_x, 0); window_clone.queue_draw(); gtk::glib::ControlFlow::Continue }); diff --git a/src/overlay_egui.rs b/src/overlay_egui.rs index 470db09..8876009 100644 --- a/src/overlay_egui.rs +++ b/src/overlay_egui.rs @@ -525,7 +525,7 @@ fn draw_replay_icon(painter: &egui::Painter, center: egui::Pos2, radius: f32, is }; // Minimalist Line Chevrons (≪) - Crisp, high-tech stroked rewind glyph - let stroke_w = 2.4_f32; + let stroke_w = (radius * 0.10).clamp(1.7, 2.4); let stroke = Stroke::new(stroke_w, color); let chevron_h = radius * 0.62; let chevron_w = radius * 0.38; @@ -2173,72 +2173,91 @@ impl ScytheOverlayApp { let card_w = 320.0; let card_h = 56.0; let toast_rect = egui::Rect::from_min_size( - egui::pos2(screen_w - card_w - 28.0 + slide_x, 28.0), + egui::pos2(screen_w - card_w + slide_x, 16.0), egui::vec2(card_w, card_h), ); let painter = ui.painter(); - // Drop shadow + // Sleek translucent neutral dark glass toast card (matching HUD cards) painter.rect_filled( - toast_rect.translate(Vec2::new(0.0, 4.0)), - CornerRadius::ZERO, - Color32::from_rgba_unmultiplied(0, 0, 0, 140), - ); - - // Modern sleek dark glass toast card - painter.rect( toast_rect, CornerRadius::ZERO, - Color32::from_rgba_unmultiplied(12, 13, 16, 252), - Stroke::new(1.0_f32, Color32::from_rgba_unmultiplied(255, 255, 255, 30)), + Color32::from_rgba_unmultiplied(10, 10, 10, 165), + ); + + // Refined subtle accent stroke framing the card + let stroke_color = if notif.icon == crate::overlay::ToastIcon::Record || notif.icon == crate::overlay::ToastIcon::Error { + Color32::from_rgba_unmultiplied(239, 68, 68, 140) + } else { + Color32::from_rgba_unmultiplied(accent.r(), accent.g(), accent.b(), 140) + }; + painter.rect_stroke( + toast_rect, + CornerRadius::ZERO, + Stroke::new(1.0_f32, stroke_color), egui::StrokeKind::Inside, ); - // Left vertical accent bar - let line_color = if notif.icon == crate::overlay::ToastIcon::Record { - Color32::from_rgb(239, 68, 68) - } else { - accent - }; - let accent_line = egui::Rect::from_min_size(toast_rect.min + Vec2::new(1.0, 1.0), Vec2::new(3.5, toast_rect.height() - 2.0)); - painter.rect_filled(accent_line, CornerRadius::ZERO, line_color); - - // Left icon area (32x32 at center-left) + // Left icon area (centered vertically at x = 24.0) let icon_center = egui::pos2(toast_rect.left() + 24.0, toast_rect.center().y); match notif.icon { crate::overlay::ToastIcon::Replay => { - draw_replay_icon(painter, icon_center, 9.5, true, accent); + draw_replay_icon(painter, icon_center, 12.0, true, accent); } crate::overlay::ToastIcon::Record => { - painter.circle_filled(icon_center, 5.5, Color32::from_rgb(239, 68, 68)); - painter.circle_stroke(icon_center, 9.5, Stroke::new(1.2_f32, Color32::from_rgba_unmultiplied(239, 68, 68, 120))); + let red_bright = Color32::from_rgb(239, 68, 68); + let half = 8.5; + let arm = 3.2; + let stroke = Stroke::new(1.6_f32, red_bright); + painter.line_segment([icon_center + Vec2::new(-half + arm, -half), icon_center + Vec2::new(-half, -half)], stroke); + painter.line_segment([icon_center + Vec2::new(-half, -half), icon_center + Vec2::new(-half, -half + arm)], stroke); + painter.line_segment([icon_center + Vec2::new(half - arm, -half), icon_center + Vec2::new(half, -half)], stroke); + painter.line_segment([icon_center + Vec2::new(half, -half), icon_center + Vec2::new(half, -half + arm)], stroke); + painter.line_segment([icon_center + Vec2::new(-half + arm, half), icon_center + Vec2::new(-half, half)], stroke); + painter.line_segment([icon_center + Vec2::new(-half, half), icon_center + Vec2::new(-half, half - arm)], stroke); + painter.line_segment([icon_center + Vec2::new(half - arm, half), icon_center + Vec2::new(half, half)], stroke); + painter.line_segment([icon_center + Vec2::new(half, half), icon_center + Vec2::new(half, half - arm)], stroke); + painter.circle_filled(icon_center, 3.5, red_bright); } crate::overlay::ToastIcon::Save => { - let c = icon_center; - let p1 = c + Vec2::new(-5.5, 0.0); - let p2 = c + Vec2::new(-1.5, 4.0); - let p3 = c + Vec2::new(5.5, -4.0); - painter.line_segment([p1, p2], Stroke::new(2.2_f32, accent)); - painter.line_segment([p2, p3], Stroke::new(2.2_f32, accent)); + painter.add(egui::epaint::PathShape::line( + vec![ + icon_center + Vec2::new(-6.0, 0.5), + icon_center + Vec2::new(-2.0, 4.5), + icon_center + Vec2::new(6.0, -4.5), + ], + Stroke::new(2.0_f32, accent), + )); } crate::overlay::ToastIcon::Cursor => { - let c = icon_center; - painter.text(c, egui::Align2::CENTER_CENTER, "⯈", FontId::proportional(14.0), accent); + painter.add(egui::epaint::PathShape::line( + vec![ + icon_center + Vec2::new(-5.0, -7.0), + icon_center + Vec2::new(-5.0, 5.0), + icon_center + Vec2::new(-1.5, 2.0), + icon_center + Vec2::new(1.5, 7.0), + icon_center + Vec2::new(3.5, 6.0), + icon_center + Vec2::new(0.5, 1.0), + icon_center + Vec2::new(5.0, 1.0), + icon_center + Vec2::new(-5.0, -7.0), + ], + Stroke::new(1.8_f32, accent), + )); } crate::overlay::ToastIcon::Error => { - let c = icon_center; let red = Color32::from_rgb(239, 68, 68); - painter.line_segment([c + Vec2::new(-4.0, -4.0), c + Vec2::new(4.0, 4.0)], Stroke::new(2.0_f32, red)); - painter.line_segment([c + Vec2::new(4.0, -4.0), c + Vec2::new(-4.0, 4.0)], Stroke::new(2.0_f32, red)); + let stroke = Stroke::new(2.0_f32, red); + painter.line_segment([icon_center + Vec2::new(-5.0, -5.0), icon_center + Vec2::new(5.0, 5.0)], stroke); + painter.line_segment([icon_center + Vec2::new(5.0, -5.0), icon_center + Vec2::new(-5.0, 5.0)], stroke); } crate::overlay::ToastIcon::Info => { - painter.circle_filled(icon_center, 5.0, accent); + painter.circle_filled(icon_center, 4.5, accent); } } // Text stack (Title + Subtitle) - let text_left = toast_rect.left() + 48.0; + let text_left = toast_rect.left() + 46.0; painter.text( egui::pos2(text_left, toast_rect.top() + 19.0), egui::Align2::LEFT_CENTER, @@ -2251,7 +2270,7 @@ impl ScytheOverlayApp { egui::Align2::LEFT_CENTER, ¬if.subtitle, FontId::proportional(11.0), - Color32::from_rgb(160, 160, 168), + Color32::from_rgb(175, 180, 190), ); } else { self.hud_notification = None; @@ -2641,13 +2660,13 @@ impl eframe::App for ShadowPlayToastApp { let slide_x = if elapsed < 0.35 { let t = (elapsed / 0.35).min(1.0); let ease = 1.0 - (1.0 - t).powi(3); - (1.0 - ease) * 340.0 + (1.0 - ease) * 320.0 } else if elapsed < total_dur - 0.40 { 0.0 } else { let t = ((elapsed - (total_dur - 0.40)) / 0.40).min(1.0); let ease = t.powi(3); - ease * 340.0 + ease * 320.0 }; let mut visuals = egui::Visuals::dark(); @@ -2659,71 +2678,90 @@ impl eframe::App for ShadowPlayToastApp { .frame(egui::Frame::NONE.fill(Color32::TRANSPARENT)) .show(ctx, |ui| { let rect = egui::Rect::from_min_size( - egui::pos2(slide_x + 10.0, 4.0), + egui::pos2(slide_x, 0.0), Vec2::new(320.0, 56.0), ); let painter = ui.painter(); - // Drop shadow + // Sleek translucent neutral dark glass toast card (matching HUD cards) painter.rect_filled( - rect.translate(Vec2::new(0.0, 4.0)), - CornerRadius::ZERO, - Color32::from_rgba_unmultiplied(0, 0, 0, 140), - ); - - // Modern sleek dark glass toast card - painter.rect( rect, CornerRadius::ZERO, - Color32::from_rgba_unmultiplied(12, 13, 16, 252), - Stroke::new(1.0_f32, Color32::from_rgba_unmultiplied(255, 255, 255, 30)), + Color32::from_rgba_unmultiplied(10, 10, 10, 165), + ); + + // Refined subtle accent stroke framing the card + let stroke_color = if self.icon == crate::overlay::ToastIcon::Record || self.icon == crate::overlay::ToastIcon::Error { + Color32::from_rgba_unmultiplied(239, 68, 68, 140) + } else { + Color32::from_rgba_unmultiplied(self.accent.r(), self.accent.g(), self.accent.b(), 140) + }; + painter.rect_stroke( + rect, + CornerRadius::ZERO, + Stroke::new(1.0_f32, stroke_color), egui::StrokeKind::Inside, ); - // Left accent line - let line_color = if self.icon == crate::overlay::ToastIcon::Record { - Color32::from_rgb(239, 68, 68) - } else { - self.accent - }; - let accent_line = egui::Rect::from_min_size(rect.min + Vec2::new(1.0, 1.0), Vec2::new(3.5, rect.height() - 2.0)); - painter.rect_filled(accent_line, CornerRadius::ZERO, line_color); - - // Left icon area (32x32 at center-left) + // Left icon area (centered vertically at x = 24.0) let icon_center = egui::pos2(rect.left() + 24.0, rect.center().y); match self.icon { crate::overlay::ToastIcon::Replay => { - draw_replay_icon(painter, icon_center, 9.5, true, self.accent); + draw_replay_icon(painter, icon_center, 12.0, true, self.accent); } crate::overlay::ToastIcon::Record => { - painter.circle_filled(icon_center, 5.5, Color32::from_rgb(239, 68, 68)); - painter.circle_stroke(icon_center, 9.5, Stroke::new(1.2_f32, Color32::from_rgba_unmultiplied(239, 68, 68, 120))); + let red_bright = Color32::from_rgb(239, 68, 68); + let half = 8.5; + let arm = 3.2; + let stroke = Stroke::new(1.6_f32, red_bright); + painter.line_segment([icon_center + Vec2::new(-half + arm, -half), icon_center + Vec2::new(-half, -half)], stroke); + painter.line_segment([icon_center + Vec2::new(-half, -half), icon_center + Vec2::new(-half, -half + arm)], stroke); + painter.line_segment([icon_center + Vec2::new(half - arm, -half), icon_center + Vec2::new(half, -half)], stroke); + painter.line_segment([icon_center + Vec2::new(half, -half), icon_center + Vec2::new(half, -half + arm)], stroke); + painter.line_segment([icon_center + Vec2::new(-half + arm, half), icon_center + Vec2::new(-half, half)], stroke); + painter.line_segment([icon_center + Vec2::new(-half, half), icon_center + Vec2::new(-half, half - arm)], stroke); + painter.line_segment([icon_center + Vec2::new(half - arm, half), icon_center + Vec2::new(half, half)], stroke); + painter.line_segment([icon_center + Vec2::new(half, half), icon_center + Vec2::new(half, half - arm)], stroke); + painter.circle_filled(icon_center, 3.5, red_bright); } crate::overlay::ToastIcon::Save => { - let c = icon_center; - let p1 = c + Vec2::new(-5.5, 0.0); - let p2 = c + Vec2::new(-1.5, 4.0); - let p3 = c + Vec2::new(5.5, -4.0); - painter.line_segment([p1, p2], Stroke::new(2.2_f32, self.accent)); - painter.line_segment([p2, p3], Stroke::new(2.2_f32, self.accent)); + painter.add(egui::epaint::PathShape::line( + vec![ + icon_center + Vec2::new(-6.0, 0.5), + icon_center + Vec2::new(-2.0, 4.5), + icon_center + Vec2::new(6.0, -4.5), + ], + Stroke::new(2.0_f32, self.accent), + )); } crate::overlay::ToastIcon::Cursor => { - let c = icon_center; - painter.text(c, egui::Align2::CENTER_CENTER, "⯈", FontId::proportional(14.0), self.accent); + painter.add(egui::epaint::PathShape::line( + vec![ + icon_center + Vec2::new(-5.0, -7.0), + icon_center + Vec2::new(-5.0, 5.0), + icon_center + Vec2::new(-1.5, 2.0), + icon_center + Vec2::new(1.5, 7.0), + icon_center + Vec2::new(3.5, 6.0), + icon_center + Vec2::new(0.5, 1.0), + icon_center + Vec2::new(5.0, 1.0), + icon_center + Vec2::new(-5.0, -7.0), + ], + Stroke::new(1.8_f32, self.accent), + )); } crate::overlay::ToastIcon::Error => { - let c = icon_center; let red = Color32::from_rgb(239, 68, 68); - painter.line_segment([c + Vec2::new(-4.0, -4.0), c + Vec2::new(4.0, 4.0)], Stroke::new(2.0_f32, red)); - painter.line_segment([c + Vec2::new(4.0, -4.0), c + Vec2::new(-4.0, 4.0)], Stroke::new(2.0_f32, red)); + let stroke = Stroke::new(2.0_f32, red); + painter.line_segment([icon_center + Vec2::new(-5.0, -5.0), icon_center + Vec2::new(5.0, 5.0)], stroke); + painter.line_segment([icon_center + Vec2::new(5.0, -5.0), icon_center + Vec2::new(-5.0, 5.0)], stroke); } crate::overlay::ToastIcon::Info => { - painter.circle_filled(icon_center, 5.0, self.accent); + painter.circle_filled(icon_center, 4.5, self.accent); } } // Text stack (Title + Subtitle) - let text_left = rect.left() + 48.0; + let text_left = rect.left() + 46.0; painter.text( egui::pos2(text_left, rect.top() + 19.0), egui::Align2::LEFT_CENTER, @@ -2736,7 +2774,7 @@ impl eframe::App for ShadowPlayToastApp { egui::Align2::LEFT_CENTER, &self.subtitle, FontId::proportional(11.0), - Color32::from_rgb(160, 160, 168), + Color32::from_rgb(175, 180, 190), ); }); } @@ -2746,8 +2784,8 @@ pub fn run_egui_toast(title: &str, subtitle: &str, icon: crate::overlay::ToastIc let cfg = ScytheConfig::load(); let accent = resolve_accent_color(&cfg.accent_color); - let toast_w: f32 = 340.0; - let toast_h: f32 = 64.0; + let toast_w: f32 = 320.0; + let toast_h: f32 = 56.0; let toast_pid_path = crate::ipc::get_toast_pid_path(); if let Ok(prev_pid_str) = std::fs::read_to_string(&toast_pid_path) @@ -2778,8 +2816,8 @@ pub fn run_egui_toast(title: &str, subtitle: &str, icon: crate::overlay::ToastIc #[cfg(not(target_os = "windows"))] let (mon_x, _mon_y, screen_w, _screen_h) = query_focused_monitor_rect(); - let pos_x = (mon_x + screen_w - toast_w - 28.0).max(10.0); - let pos_y = 28.0; + let pos_x = (mon_x + screen_w - toast_w).max(0.0); + let pos_y = 16.0; let options = eframe::NativeOptions { viewport: egui::ViewportBuilder::default()