refactor: icon styling and headerbar icon styling
Headerbar icons are transparent when their window is not focused, but otherwise share the same style as icons with selection. This updates the icon styles to match figma when selected.
This commit is contained in:
parent
6f6eeec0e7
commit
e47684ffdb
11 changed files with 121 additions and 115 deletions
|
|
@ -469,7 +469,6 @@ impl Application for Window {
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut header = header_bar()
|
let mut header = header_bar()
|
||||||
.window_id(window::Id::MAIN)
|
|
||||||
.title("COSMIC Design System - Iced")
|
.title("COSMIC Design System - Iced")
|
||||||
.on_close(Message::Close)
|
.on_close(Message::Close)
|
||||||
.on_drag(Message::Drag)
|
.on_drag(Message::Drag)
|
||||||
|
|
|
||||||
|
|
@ -131,7 +131,11 @@ impl cosmic::Application for MultiWindow {
|
||||||
let input = text_input("something", &w.input_value)
|
let input = text_input("something", &w.input_value)
|
||||||
.on_input(move |msg| Message::Input(input_id.clone(), msg))
|
.on_input(move |msg| Message::Input(input_id.clone(), msg))
|
||||||
.id(w.input_id.clone());
|
.id(w.input_id.clone());
|
||||||
|
let focused = self
|
||||||
|
.core()
|
||||||
|
.focused_window()
|
||||||
|
.map(|i| i == id)
|
||||||
|
.unwrap_or_default();
|
||||||
let new_window_button = button(text("New Window")).on_press(Message::NewWindow);
|
let new_window_button = button(text("New Window")).on_press(Message::NewWindow);
|
||||||
|
|
||||||
let content = scrollable(
|
let content = scrollable(
|
||||||
|
|
@ -151,7 +155,7 @@ impl cosmic::Application for MultiWindow {
|
||||||
if id == window::Id::MAIN {
|
if id == window::Id::MAIN {
|
||||||
window_content.into()
|
window_content.into()
|
||||||
} else {
|
} else {
|
||||||
column![header_bar().window_id(id), window_content].into()
|
column![header_bar().focused(focused), window_content].into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ use std::collections::HashMap;
|
||||||
use crate::config::CosmicTk;
|
use crate::config::CosmicTk;
|
||||||
use cosmic_config::CosmicConfigEntry;
|
use cosmic_config::CosmicConfigEntry;
|
||||||
use cosmic_theme::ThemeMode;
|
use cosmic_theme::ThemeMode;
|
||||||
|
use iced::window;
|
||||||
use iced_core::window::Id;
|
use iced_core::window::Id;
|
||||||
use palette::Srgba;
|
use palette::Srgba;
|
||||||
|
|
||||||
|
|
@ -57,6 +58,9 @@ pub struct Core {
|
||||||
/// Scaling factor used by the application
|
/// Scaling factor used by the application
|
||||||
scale_factor: f32,
|
scale_factor: f32,
|
||||||
|
|
||||||
|
/// Window focus state
|
||||||
|
pub(super) focused_window: Option<window::Id>,
|
||||||
|
|
||||||
pub(super) theme_sub_counter: u64,
|
pub(super) theme_sub_counter: u64,
|
||||||
/// Last known system theme
|
/// Last known system theme
|
||||||
pub(super) system_theme: Theme,
|
pub(super) system_theme: Theme,
|
||||||
|
|
@ -136,6 +140,7 @@ impl Default for Core {
|
||||||
height: 0,
|
height: 0,
|
||||||
width: 0,
|
width: 0,
|
||||||
},
|
},
|
||||||
|
focused_window: None,
|
||||||
#[cfg(feature = "applet")]
|
#[cfg(feature = "applet")]
|
||||||
applet: crate::applet::Context::default(),
|
applet: crate::applet::Context::default(),
|
||||||
#[cfg(feature = "single-instance")]
|
#[cfg(feature = "single-instance")]
|
||||||
|
|
@ -285,6 +290,12 @@ impl Core {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the current focused window if it exists
|
||||||
|
#[must_use]
|
||||||
|
pub fn focused_window(&self) -> Option<window::Id> {
|
||||||
|
self.focused_window.clone()
|
||||||
|
}
|
||||||
|
|
||||||
/// Whether the application should use a dark theme, according to the system
|
/// Whether the application should use a dark theme, according to the system
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn system_is_dark(&self) -> bool {
|
pub fn system_is_dark(&self) -> bool {
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,10 @@ pub enum Message {
|
||||||
ShowWindowMenu,
|
ShowWindowMenu,
|
||||||
#[cfg(feature = "xdg-portal")]
|
#[cfg(feature = "xdg-portal")]
|
||||||
DesktopSettings(crate::theme::portal::Desktop),
|
DesktopSettings(crate::theme::portal::Desktop),
|
||||||
|
/// Window focus changed
|
||||||
|
Focus(window::Id),
|
||||||
|
/// Window focus lost
|
||||||
|
Unfocus(window::Id),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
|
@ -159,6 +163,10 @@ where
|
||||||
iced::Event::Window(id, window::Event::Closed) => {
|
iced::Event::Window(id, window::Event::Closed) => {
|
||||||
return Some(Message::SurfaceClosed(id))
|
return Some(Message::SurfaceClosed(id))
|
||||||
}
|
}
|
||||||
|
iced::Event::Window(id, window::Event::Focused) => return Some(Message::Focus(id)),
|
||||||
|
iced::Event::Window(id, window::Event::Unfocused) => {
|
||||||
|
return Some(Message::Unfocus(id))
|
||||||
|
}
|
||||||
#[cfg(feature = "wayland")]
|
#[cfg(feature = "wayland")]
|
||||||
iced::Event::PlatformSpecific(PlatformSpecific::Wayland(event)) => match event {
|
iced::Event::PlatformSpecific(PlatformSpecific::Wayland(event)) => match event {
|
||||||
wayland::Event::Window(WindowEvent::State(state), _surface, id) => {
|
wayland::Event::Window(WindowEvent::State(state), _surface, id) => {
|
||||||
|
|
@ -557,6 +565,22 @@ impl<T: Application> Cosmic<T> {
|
||||||
Message::ToolkitConfig(config) => {
|
Message::ToolkitConfig(config) => {
|
||||||
self.app.core_mut().toolkit_config = config;
|
self.app.core_mut().toolkit_config = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Message::Focus(f) => {
|
||||||
|
self.app.core_mut().focused_window = Some(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
Message::Unfocus(id) => {
|
||||||
|
let core = self.app.core_mut();
|
||||||
|
if core
|
||||||
|
.focused_window
|
||||||
|
.as_ref()
|
||||||
|
.map(|cur| *cur == id)
|
||||||
|
.unwrap_or_default()
|
||||||
|
{
|
||||||
|
core.focused_window = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
iced::Command::none()
|
iced::Command::none()
|
||||||
|
|
|
||||||
|
|
@ -642,6 +642,10 @@ impl<App: Application> ApplicationExt for App {
|
||||||
fn view_main(&self) -> Element<Message<Self::Message>> {
|
fn view_main(&self) -> Element<Message<Self::Message>> {
|
||||||
let core = self.core();
|
let core = self.core();
|
||||||
let is_condensed = core.is_condensed();
|
let is_condensed = core.is_condensed();
|
||||||
|
let focused = core
|
||||||
|
.focused_window()
|
||||||
|
.map(|i| i == self.main_window_id())
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
let content_row = crate::widget::row::with_children({
|
let content_row = crate::widget::row::with_children({
|
||||||
let mut widgets = Vec::with_capacity(2);
|
let mut widgets = Vec::with_capacity(2);
|
||||||
|
|
@ -686,7 +690,7 @@ impl<App: Application> ApplicationExt for App {
|
||||||
.push_maybe(if core.window.show_headerbar {
|
.push_maybe(if core.window.show_headerbar {
|
||||||
Some({
|
Some({
|
||||||
let mut header = crate::widget::header_bar()
|
let mut header = crate::widget::header_bar()
|
||||||
.window_id(self.main_window_id())
|
.focused(focused)
|
||||||
.title(&core.window.header_title)
|
.title(&core.window.header_title)
|
||||||
.on_drag(Message::Cosmic(cosmic::Message::Drag))
|
.on_drag(Message::Cosmic(cosmic::Message::Drag))
|
||||||
.on_close(Message::Cosmic(cosmic::Message::Close))
|
.on_close(Message::Cosmic(cosmic::Message::Close))
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ pub enum Button {
|
||||||
Destructive,
|
Destructive,
|
||||||
Link,
|
Link,
|
||||||
Icon,
|
Icon,
|
||||||
|
HeaderBar,
|
||||||
IconVertical,
|
IconVertical,
|
||||||
Image,
|
Image,
|
||||||
#[default]
|
#[default]
|
||||||
|
|
@ -66,7 +67,7 @@ pub fn appearance(
|
||||||
appearance.icon_color = icon;
|
appearance.icon_color = icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
Button::Icon | Button::IconVertical => {
|
Button::Icon | Button::IconVertical | Button::HeaderBar => {
|
||||||
if matches!(style, Button::IconVertical) {
|
if matches!(style, Button::IconVertical) {
|
||||||
corner_radii = &cosmic.corner_radii.radius_m;
|
corner_radii = &cosmic.corner_radii.radius_m;
|
||||||
}
|
}
|
||||||
|
|
@ -146,14 +147,23 @@ pub fn appearance(
|
||||||
impl StyleSheet for crate::Theme {
|
impl StyleSheet for crate::Theme {
|
||||||
type Style = Button;
|
type Style = Button;
|
||||||
|
|
||||||
fn active(&self, focused: bool, style: &Self::Style) -> Appearance {
|
fn active(&self, focused: bool, selected: bool, style: &Self::Style) -> Appearance {
|
||||||
if let Button::Custom { active, .. } = style {
|
if let Button::Custom { active, .. } = style {
|
||||||
return active(focused, self);
|
return active(focused, self);
|
||||||
}
|
}
|
||||||
|
let accent = self.cosmic().accent_color();
|
||||||
|
|
||||||
appearance(self, focused, style, |component| {
|
appearance(self, focused, style, |component| {
|
||||||
let text_color = if let Button::Icon | Button::IconVertical = style {
|
let text_color = if matches!(
|
||||||
None
|
style,
|
||||||
|
Button::Icon | Button::IconVertical | Button::HeaderBar
|
||||||
|
) && selected
|
||||||
|
{
|
||||||
|
Some(accent.into())
|
||||||
|
} else if matches!(style, Button::HeaderBar) && !selected {
|
||||||
|
let mut c = Color::from(component.on);
|
||||||
|
c.a = 0.8;
|
||||||
|
Some(c)
|
||||||
} else {
|
} else {
|
||||||
Some(component.on.into())
|
Some(component.on.into())
|
||||||
};
|
};
|
||||||
|
|
@ -179,39 +189,61 @@ impl StyleSheet for crate::Theme {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn drop_target(&self, style: &Self::Style) -> Appearance {
|
fn drop_target(&self, style: &Self::Style) -> Appearance {
|
||||||
self.active(false, style)
|
self.active(false, false, style)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hovered(&self, focused: bool, style: &Self::Style) -> Appearance {
|
fn hovered(&self, focused: bool, selected: bool, style: &Self::Style) -> Appearance {
|
||||||
if let Button::Custom { hovered, .. } = style {
|
if let Button::Custom { hovered, .. } = style {
|
||||||
return hovered(focused, self);
|
return hovered(focused, self);
|
||||||
}
|
}
|
||||||
|
let accent = self.cosmic().accent_button.hover;
|
||||||
|
|
||||||
appearance(
|
appearance(
|
||||||
self,
|
self,
|
||||||
focused || matches!(style, Button::Image),
|
focused || matches!(style, Button::Image),
|
||||||
style,
|
style,
|
||||||
|component| {
|
|component| {
|
||||||
(
|
let text_color = if matches!(
|
||||||
component.hover.into(),
|
style,
|
||||||
Some(component.on.into()),
|
Button::Icon | Button::IconVertical | Button::HeaderBar
|
||||||
Some(component.on.into()),
|
) && selected
|
||||||
)
|
{
|
||||||
|
Some(accent.into())
|
||||||
|
} else if matches!(style, Button::HeaderBar) && !selected {
|
||||||
|
let mut c = Color::from(component.on);
|
||||||
|
c.a = 0.8;
|
||||||
|
Some(c)
|
||||||
|
} else {
|
||||||
|
Some(component.on.into())
|
||||||
|
};
|
||||||
|
|
||||||
|
(component.hover.into(), text_color, text_color)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pressed(&self, focused: bool, style: &Self::Style) -> Appearance {
|
fn pressed(&self, focused: bool, selected: bool, style: &Self::Style) -> Appearance {
|
||||||
if let Button::Custom { pressed, .. } = style {
|
if let Button::Custom { pressed, .. } = style {
|
||||||
return pressed(focused, self);
|
return pressed(focused, self);
|
||||||
}
|
}
|
||||||
|
let accent = self.cosmic().accent_button.pressed;
|
||||||
|
|
||||||
appearance(self, focused, style, |component| {
|
appearance(self, focused, style, |component| {
|
||||||
(
|
let text_color = if matches!(
|
||||||
component.pressed.into(),
|
style,
|
||||||
Some(component.on.into()),
|
Button::Icon | Button::IconVertical | Button::HeaderBar
|
||||||
Some(component.on.into()),
|
) && selected
|
||||||
)
|
{
|
||||||
|
Some(accent.into())
|
||||||
|
} else if matches!(style, Button::HeaderBar) && !selected {
|
||||||
|
let mut c = Color::from(component.on);
|
||||||
|
c.a = 0.8;
|
||||||
|
Some(c)
|
||||||
|
} else {
|
||||||
|
Some(component.on.into())
|
||||||
|
};
|
||||||
|
|
||||||
|
(component.pressed.into(), text_color, text_color)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,14 @@ pub type Button<'a, Message> = Builder<'a, Message, Icon>;
|
||||||
pub struct Icon {
|
pub struct Icon {
|
||||||
handle: Handle,
|
handle: Handle,
|
||||||
vertical: bool,
|
vertical: bool,
|
||||||
|
selected: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn icon<'a, Message>(handle: impl Into<Handle>) -> Button<'a, Message> {
|
pub fn icon<'a, Message>(handle: impl Into<Handle>) -> Button<'a, Message> {
|
||||||
Button::new(Icon {
|
Button::new(Icon {
|
||||||
handle: handle.into(),
|
handle: handle.into(),
|
||||||
vertical: false,
|
vertical: false,
|
||||||
|
selected: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -124,6 +126,11 @@ impl<'a, Message> Button<'a, Message> {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn selected(mut self, selected: bool) -> Self {
|
||||||
|
self.variant.selected = selected;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn vertical(mut self, vertical: bool) -> Self {
|
pub fn vertical(mut self, vertical: bool) -> Self {
|
||||||
self.variant.vertical = vertical;
|
self.variant.vertical = vertical;
|
||||||
self.style = Style::IconVertical;
|
self.style = Style::IconVertical;
|
||||||
|
|
@ -179,6 +186,7 @@ impl<'a, Message: Clone + 'static> From<Button<'a, Message>> for Element<'a, Mes
|
||||||
.padding(0)
|
.padding(0)
|
||||||
.id(builder.id)
|
.id(builder.id)
|
||||||
.on_press_maybe(builder.on_press)
|
.on_press_maybe(builder.on_press)
|
||||||
|
.selected(builder.variant.selected)
|
||||||
.style(builder.style);
|
.style(builder.style);
|
||||||
|
|
||||||
if builder.tooltip.is_empty() {
|
if builder.tooltip.is_empty() {
|
||||||
|
|
|
||||||
|
|
@ -68,21 +68,21 @@ pub trait StyleSheet {
|
||||||
type Style: Default;
|
type Style: Default;
|
||||||
|
|
||||||
/// Produces the active [`Appearance`] of a button.
|
/// Produces the active [`Appearance`] of a button.
|
||||||
fn active(&self, focused: bool, style: &Self::Style) -> Appearance;
|
fn active(&self, focused: bool, selected: bool, style: &Self::Style) -> Appearance;
|
||||||
|
|
||||||
/// Produces the disabled [`Appearance`] of a button.
|
/// Produces the disabled [`Appearance`] of a button.
|
||||||
fn disabled(&self, style: &Self::Style) -> Appearance;
|
fn disabled(&self, style: &Self::Style) -> Appearance;
|
||||||
|
|
||||||
/// [`Appearance`] when the button is the target of a DND operation.
|
/// [`Appearance`] when the button is the target of a DND operation.
|
||||||
fn drop_target(&self, style: &Self::Style) -> Appearance {
|
fn drop_target(&self, style: &Self::Style) -> Appearance {
|
||||||
self.hovered(false, style)
|
self.hovered(false, false, style)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Produces the hovered [`Appearance`] of a button.
|
/// Produces the hovered [`Appearance`] of a button.
|
||||||
fn hovered(&self, focused: bool, style: &Self::Style) -> Appearance;
|
fn hovered(&self, focused: bool, selected: bool, style: &Self::Style) -> Appearance;
|
||||||
|
|
||||||
/// Produces the pressed [`Appearance`] of a button.
|
/// Produces the pressed [`Appearance`] of a button.
|
||||||
fn pressed(&self, focused: bool, style: &Self::Style) -> Appearance;
|
fn pressed(&self, focused: bool, selected: bool, style: &Self::Style) -> Appearance;
|
||||||
|
|
||||||
/// Background color of the selection indicator
|
/// Background color of the selection indicator
|
||||||
fn selection_background(&self) -> Background;
|
fn selection_background(&self) -> Background;
|
||||||
|
|
|
||||||
|
|
@ -528,10 +528,10 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.on_press.is_none() {
|
if self.on_press.is_none() {
|
||||||
node.set_disabled()
|
node.set_disabled();
|
||||||
}
|
}
|
||||||
if is_hovered {
|
if is_hovered {
|
||||||
node.set_hovered()
|
node.set_hovered();
|
||||||
}
|
}
|
||||||
node.set_default_action_verb(DefaultActionVerb::Click);
|
node.set_default_action_verb(DefaultActionVerb::Click);
|
||||||
|
|
||||||
|
|
@ -696,12 +696,12 @@ where
|
||||||
style_sheet.disabled(style)
|
style_sheet.disabled(style)
|
||||||
} else if is_mouse_over {
|
} else if is_mouse_over {
|
||||||
if state.is_pressed {
|
if state.is_pressed {
|
||||||
style_sheet.pressed(state.is_focused || is_selected, style)
|
style_sheet.pressed(state.is_focused, is_selected, style)
|
||||||
} else {
|
} else {
|
||||||
style_sheet.hovered(state.is_focused || is_selected, style)
|
style_sheet.hovered(state.is_focused, is_selected, style)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
style_sheet.active(state.is_focused || is_selected, style)
|
style_sheet.active(state.is_focused, is_selected, style)
|
||||||
};
|
};
|
||||||
|
|
||||||
let doubled_border_width = styling.border_width * 2.0;
|
let doubled_border_width = styling.border_width * 2.0;
|
||||||
|
|
|
||||||
|
|
@ -799,7 +799,7 @@ pub fn color_button<'a, Message: 'static>(
|
||||||
} else {
|
} else {
|
||||||
(0.0, Color::TRANSPARENT)
|
(0.0, Color::TRANSPARENT)
|
||||||
};
|
};
|
||||||
let standard = theme.active(focused, &Button::Standard);
|
let standard = theme.active(focused, false, &Button::Standard);
|
||||||
button::Appearance {
|
button::Appearance {
|
||||||
shadow_offset: Vector::default(),
|
shadow_offset: Vector::default(),
|
||||||
background: color.map(Background::from).or(standard.background),
|
background: color.map(Background::from).or(standard.background),
|
||||||
|
|
@ -837,7 +837,7 @@ pub fn color_button<'a, Message: 'static>(
|
||||||
(0.0, Color::TRANSPARENT)
|
(0.0, Color::TRANSPARENT)
|
||||||
};
|
};
|
||||||
|
|
||||||
let standard = theme.hovered(focused, &Button::Standard);
|
let standard = theme.hovered(focused, false, &Button::Standard);
|
||||||
button::Appearance {
|
button::Appearance {
|
||||||
shadow_offset: Vector::default(),
|
shadow_offset: Vector::default(),
|
||||||
background: color.map(Background::from).or(standard.background),
|
background: color.map(Background::from).or(standard.background),
|
||||||
|
|
@ -859,7 +859,7 @@ pub fn color_button<'a, Message: 'static>(
|
||||||
(0.0, Color::TRANSPARENT)
|
(0.0, Color::TRANSPARENT)
|
||||||
};
|
};
|
||||||
|
|
||||||
let standard = theme.pressed(focused, &Button::Standard);
|
let standard = theme.pressed(focused, false, &Button::Standard);
|
||||||
button::Appearance {
|
button::Appearance {
|
||||||
shadow_offset: Vector::default(),
|
shadow_offset: Vector::default(),
|
||||||
background: color.map(Background::from).or(standard.background),
|
background: color.map(Background::from).or(standard.background),
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use crate::{ext::CollectionWidget, widget, Element};
|
||||||
use apply::Apply;
|
use apply::Apply;
|
||||||
use derive_setters::Setters;
|
use derive_setters::Setters;
|
||||||
use iced::{window, Length};
|
use iced::{window, Length};
|
||||||
use iced_core::{renderer::Quad, widget::tree, Background, Renderer, Widget};
|
use iced_core::{widget::tree, Widget};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
|
@ -20,7 +20,7 @@ pub fn header_bar<'a, Message>() -> HeaderBar<'a, Message> {
|
||||||
start: Vec::new(),
|
start: Vec::new(),
|
||||||
center: Vec::new(),
|
center: Vec::new(),
|
||||||
end: Vec::new(),
|
end: Vec::new(),
|
||||||
window_id: None,
|
focused: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -50,9 +50,8 @@ pub struct HeaderBar<'a, Message> {
|
||||||
#[setters(strip_option)]
|
#[setters(strip_option)]
|
||||||
on_right_click: Option<Message>,
|
on_right_click: Option<Message>,
|
||||||
|
|
||||||
/// The window id for the headerbar.
|
/// Focused state of the window
|
||||||
#[setters(strip_option)]
|
focused: bool,
|
||||||
window_id: Option<iced::window::Id>,
|
|
||||||
|
|
||||||
/// Elements packed at the start of the headerbar.
|
/// Elements packed at the start of the headerbar.
|
||||||
#[setters(skip)]
|
#[setters(skip)]
|
||||||
|
|
@ -100,7 +99,6 @@ impl<'a, Message: Clone + 'static> HeaderBar<'a, Message> {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn build(self) -> HeaderBarWidget<'a, Message> {
|
pub fn build(self) -> HeaderBarWidget<'a, Message> {
|
||||||
HeaderBarWidget {
|
HeaderBarWidget {
|
||||||
window_id: self.window_id,
|
|
||||||
header_bar_inner: self.into_element(),
|
header_bar_inner: self.into_element(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -108,7 +106,6 @@ impl<'a, Message: Clone + 'static> HeaderBar<'a, Message> {
|
||||||
|
|
||||||
pub struct HeaderBarWidget<'a, Message> {
|
pub struct HeaderBarWidget<'a, Message> {
|
||||||
header_bar_inner: Element<'a, Message>,
|
header_bar_inner: Element<'a, Message>,
|
||||||
window_id: Option<iced::window::Id>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Message: Clone + 'static> Widget<Message, crate::Theme, crate::Renderer>
|
impl<'a, Message: Clone + 'static> Widget<Message, crate::Theme, crate::Renderer>
|
||||||
|
|
@ -122,23 +119,6 @@ impl<'a, Message: Clone + 'static> Widget<Message, crate::Theme, crate::Renderer
|
||||||
self.header_bar_inner.as_widget().size()
|
self.header_bar_inner.as_widget().size()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tag(&self) -> tree::Tag {
|
|
||||||
tree::Tag::of::<MyState>()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn diff(&mut self, tree: &mut tree::Tree) {
|
|
||||||
tree.diff_children(&mut [&mut self.header_bar_inner]);
|
|
||||||
let prev = tree.state.downcast_mut::<MyState>();
|
|
||||||
if prev.window_id != self.window_id {
|
|
||||||
*prev = MyState::new(self.window_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn state(&self) -> tree::State {
|
|
||||||
let state = MyState::new(self.window_id);
|
|
||||||
tree::State::new(state)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn layout(
|
fn layout(
|
||||||
&self,
|
&self,
|
||||||
tree: &mut tree::Tree,
|
tree: &mut tree::Tree,
|
||||||
|
|
@ -174,28 +154,6 @@ impl<'a, Message: Clone + 'static> Widget<Message, crate::Theme, crate::Renderer
|
||||||
cursor,
|
cursor,
|
||||||
viewport,
|
viewport,
|
||||||
);
|
);
|
||||||
|
|
||||||
let state = tree.state.downcast_ref::<MyState>();
|
|
||||||
if !state.window_has_focus {
|
|
||||||
let header_bar_appearance =
|
|
||||||
<crate::Theme as crate::iced_style::container::StyleSheet>::appearance(
|
|
||||||
theme,
|
|
||||||
&crate::theme::Container::HeaderBar,
|
|
||||||
);
|
|
||||||
let cosmic = theme.cosmic();
|
|
||||||
let mut neutral_0 = cosmic.palette.neutral_0;
|
|
||||||
neutral_0.alpha = 0.3;
|
|
||||||
|
|
||||||
// draw overlay rectangle
|
|
||||||
renderer.fill_quad(
|
|
||||||
Quad {
|
|
||||||
bounds: layout.bounds(),
|
|
||||||
border: header_bar_appearance.border,
|
|
||||||
shadow: header_bar_appearance.shadow,
|
|
||||||
},
|
|
||||||
Background::Color(neutral_0.into()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_event(
|
fn on_event(
|
||||||
|
|
@ -209,14 +167,6 @@ impl<'a, Message: Clone + 'static> Widget<Message, crate::Theme, crate::Renderer
|
||||||
shell: &mut iced_core::Shell<'_, Message>,
|
shell: &mut iced_core::Shell<'_, Message>,
|
||||||
viewport: &iced_core::Rectangle,
|
viewport: &iced_core::Rectangle,
|
||||||
) -> iced_core::event::Status {
|
) -> iced_core::event::Status {
|
||||||
if let iced_core::Event::Window(id, iced_core::window::Event::Focused) = event {
|
|
||||||
let state = state.state.downcast_mut::<MyState>();
|
|
||||||
state.focus_window(id);
|
|
||||||
} else if let iced_core::Event::Window(id, iced_core::window::Event::Unfocused) = event {
|
|
||||||
let state = state.state.downcast_mut::<MyState>();
|
|
||||||
state.unfocus_window(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
let child_state = &mut state.children[0];
|
let child_state = &mut state.children[0];
|
||||||
let child_layout = layout.children().next().unwrap();
|
let child_layout = layout.children().next().unwrap();
|
||||||
self.header_bar_inner.as_widget_mut().on_event(
|
self.header_bar_inner.as_widget_mut().on_event(
|
||||||
|
|
@ -370,6 +320,8 @@ impl<'a, Message: Clone + 'static> HeaderBar<'a, Message> {
|
||||||
widget::icon::from_svg_bytes(icon_bytes)
|
widget::icon::from_svg_bytes(icon_bytes)
|
||||||
.symbolic(true)
|
.symbolic(true)
|
||||||
.apply(widget::button::icon)
|
.apply(widget::button::icon)
|
||||||
|
.style(crate::theme::Button::HeaderBar)
|
||||||
|
.selected(self.focused)
|
||||||
.icon_size(size)
|
.icon_size(size)
|
||||||
.on_press(on_press)
|
.on_press(on_press)
|
||||||
};
|
};
|
||||||
|
|
@ -415,31 +367,3 @@ impl<'a, Message: Clone + 'static> From<HeaderBarWidget<'a, Message>> for Elemen
|
||||||
Element::new(headerbar)
|
Element::new(headerbar)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MyState {
|
|
||||||
pub window_id: Option<window::Id>,
|
|
||||||
pub window_has_focus: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MyState {
|
|
||||||
pub fn new(id: Option<window::Id>) -> Self {
|
|
||||||
Self {
|
|
||||||
window_id: id,
|
|
||||||
window_has_focus: id.is_none(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn focus_window(&mut self, id: window::Id) {
|
|
||||||
if self.window_id != Some(id) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
self.window_has_focus = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn unfocus_window(&mut self, id: window::Id) {
|
|
||||||
if self.window_id != Some(id) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
self.window_has_focus = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue