wip: example applet
This commit is contained in:
parent
45ccc8c3d2
commit
b1c3a52589
18 changed files with 525 additions and 103 deletions
|
|
@ -62,6 +62,4 @@ branch = "sctk-cosmic"
|
|||
[workspace]
|
||||
members = [
|
||||
"examples/*",
|
||||
"gtk4",
|
||||
"gtk4/widgets"
|
||||
]
|
||||
|
|
|
|||
14
examples/cosmic-applet-graphics/Cargo.toml
Normal file
14
examples/cosmic-applet-graphics/Cargo.toml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
[package]
|
||||
name = "cosmic-applet-graphics"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
zbus = "3.4"
|
||||
libcosmic = { path = "../..", default-features = false, features = ["debug", "wayland"] }
|
||||
# cosmic-panel-config = {git = "https://github.com/pop-os/cosmic-panel" }
|
||||
cosmic-panel-config = { path = "../../../cosmic-panel/cosmic-panel-config", default-features = false }
|
||||
iced_sctk = { git = "https://github.com/pop-os/iced-sctk" }
|
||||
sctk = { package = "smithay-client-toolkit", git = "https://github.com/Smithay/client-toolkit" }
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
[Desktop Entry]
|
||||
Name=Cosmic Applet Graphics
|
||||
Comment=Write a GTK + Rust application
|
||||
Type=Application
|
||||
Exec=cosmic-applet-graphics
|
||||
Terminal=false
|
||||
Categories=GNOME;GTK;
|
||||
Keywords=Gnome;GTK;
|
||||
# Translators: Do NOT translate or transliterate this text (this is an icon file name)!
|
||||
Icon=com.system76.CosmicAppletGraphics.svg
|
||||
StartupNotify=true
|
||||
NoDisplay=true
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="128px" height="128px" viewBox="0 0 128 128" version="1.1">
|
||||
<defs>
|
||||
<filter id="alpha" filterUnits="objectBoundingBox" x="0%" y="0%" width="100%" height="100%">
|
||||
<feColorMatrix type="matrix" in="SourceGraphic" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/>
|
||||
</filter>
|
||||
<mask id="mask0">
|
||||
<g filter="url(#alpha)">
|
||||
<rect x="0" y="0" width="128" height="128" style="fill:rgb(0%,0%,0%);fill-opacity:0.1;stroke:none;"/>
|
||||
</g>
|
||||
</mask>
|
||||
<clipPath id="clip1">
|
||||
<rect x="0" y="0" width="192" height="152"/>
|
||||
</clipPath>
|
||||
<g id="surface10632" clip-path="url(#clip1)">
|
||||
<path style="fill:none;stroke-width:0.99;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:0.99,0.99;stroke-miterlimit:4;" d="M 123.503906 236 C 123.503906 268.863281 96.863281 295.503906 64 295.503906 C 31.136719 295.503906 4.496094 268.863281 4.496094 236 C 4.496094 203.136719 31.136719 176.496094 64 176.496094 C 96.863281 176.496094 123.503906 203.136719 123.503906 236 Z M 123.503906 236 " transform="matrix(1,0,0,1,8,-156)"/>
|
||||
</g>
|
||||
<mask id="mask1">
|
||||
<g filter="url(#alpha)">
|
||||
<rect x="0" y="0" width="128" height="128" style="fill:rgb(0%,0%,0%);fill-opacity:0.1;stroke:none;"/>
|
||||
</g>
|
||||
</mask>
|
||||
<clipPath id="clip2">
|
||||
<rect x="0" y="0" width="192" height="152"/>
|
||||
</clipPath>
|
||||
<g id="surface10635" clip-path="url(#clip2)">
|
||||
<path style="fill:none;stroke-width:0.99;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:0.99,0.99;stroke-miterlimit:4;" d="M 29.195312 180.496094 L 98.804688 180.496094 C 103.609375 180.496094 107.503906 184.046875 107.503906 188.425781 L 107.503906 283.574219 C 107.503906 287.953125 103.609375 291.503906 98.804688 291.503906 L 29.195312 291.503906 C 24.390625 291.503906 20.496094 287.953125 20.496094 283.574219 L 20.496094 188.425781 C 20.496094 184.046875 24.390625 180.496094 29.195312 180.496094 Z M 29.195312 180.496094 " transform="matrix(1,0,0,1,8,-156)"/>
|
||||
</g>
|
||||
<mask id="mask2">
|
||||
<g filter="url(#alpha)">
|
||||
<rect x="0" y="0" width="128" height="128" style="fill:rgb(0%,0%,0%);fill-opacity:0.1;stroke:none;"/>
|
||||
</g>
|
||||
</mask>
|
||||
<clipPath id="clip3">
|
||||
<rect x="0" y="0" width="192" height="152"/>
|
||||
</clipPath>
|
||||
<g id="surface10638" clip-path="url(#clip3)">
|
||||
<path style="fill:none;stroke-width:0.99;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:0.99,0.99;stroke-miterlimit:4;" d="M 20.417969 184.496094 L 107.582031 184.496094 C 111.957031 184.496094 115.503906 188.042969 115.503906 192.417969 L 115.503906 279.582031 C 115.503906 283.957031 111.957031 287.503906 107.582031 287.503906 L 20.417969 287.503906 C 16.042969 287.503906 12.496094 283.957031 12.496094 279.582031 L 12.496094 192.417969 C 12.496094 188.042969 16.042969 184.496094 20.417969 184.496094 Z M 20.417969 184.496094 " transform="matrix(1,0,0,1,8,-156)"/>
|
||||
</g>
|
||||
<mask id="mask3">
|
||||
<g filter="url(#alpha)">
|
||||
<rect x="0" y="0" width="128" height="128" style="fill:rgb(0%,0%,0%);fill-opacity:0.1;stroke:none;"/>
|
||||
</g>
|
||||
</mask>
|
||||
<clipPath id="clip4">
|
||||
<rect x="0" y="0" width="192" height="152"/>
|
||||
</clipPath>
|
||||
<g id="surface10641" clip-path="url(#clip4)">
|
||||
<path style="fill:none;stroke-width:0.99;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-dasharray:0.99,0.99;stroke-miterlimit:4;" d="M 16.425781 200.496094 L 111.574219 200.496094 C 115.953125 200.496094 119.503906 204.390625 119.503906 209.195312 L 119.503906 278.804688 C 119.503906 283.609375 115.953125 287.503906 111.574219 287.503906 L 16.425781 287.503906 C 12.046875 287.503906 8.496094 283.609375 8.496094 278.804688 L 8.496094 209.195312 C 8.496094 204.390625 12.046875 200.496094 16.425781 200.496094 Z M 16.425781 200.496094 " transform="matrix(1,0,0,1,8,-156)"/>
|
||||
</g>
|
||||
</defs>
|
||||
<g id="surface10578">
|
||||
<rect x="0" y="0" width="128" height="128" style="fill:rgb(94.117647%,94.117647%,94.117647%);fill-opacity:1;stroke:none;"/>
|
||||
<use xlink:href="#surface10632" transform="matrix(1,0,0,1,-8,-16)" mask="url(#mask0)"/>
|
||||
<use xlink:href="#surface10635" transform="matrix(1,0,0,1,-8,-16)" mask="url(#mask1)"/>
|
||||
<use xlink:href="#surface10638" transform="matrix(1,0,0,1,-8,-16)" mask="url(#mask2)"/>
|
||||
<use xlink:href="#surface10641" transform="matrix(1,0,0,1,-8,-16)" mask="url(#mask3)"/>
|
||||
<path style="fill:none;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(38.431373%,62.7451%,91.764706%);stroke-opacity:1;stroke-miterlimit:4;" d="M 0 289 L 128 289 " transform="matrix(1,0,0,1,0,-172)"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.5 KiB |
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<gresources>
|
||||
<gresource prefix="/com/System76/CosmicDockAppList/">
|
||||
<!-- see https://gtk-rs.org/gtk4-rs/git/docs/gtk4/struct.Application.html#automatic-resources -->
|
||||
</gresource>
|
||||
</gresources>
|
||||
90
examples/cosmic-applet-graphics/src/dbus.rs
Normal file
90
examples/cosmic-applet-graphics/src/dbus.rs
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
//! # DBus interface proxy for: `com.system76.PowerDaemon`
|
||||
//!
|
||||
//! This code was generated by `zbus-xmlgen` `3.0.0` from DBus introspection data.
|
||||
//! Source: `Interface '/com/system76/PowerDaemon' from service 'com.system76.PowerDaemon' on system bus`.
|
||||
//!
|
||||
//! You may prefer to adapt it, instead of using it verbatim.
|
||||
//!
|
||||
//! More information can be found in the
|
||||
//! [Writing a client proxy](https://dbus.pages.freedesktop.org/zbus/client.html)
|
||||
//! section of the zbus documentation.
|
||||
//!
|
||||
//! This DBus object implements
|
||||
//! [standard DBus interfaces](https://dbus.freedesktop.org/doc/dbus-specification.html),
|
||||
//! (`org.freedesktop.DBus.*`) for which the following zbus proxies can be used:
|
||||
//!
|
||||
//! * [`zbus::fdo::IntrospectableProxy`]
|
||||
//!
|
||||
//! …consequently `zbus-xmlgen` did not generate code for the above interfaces.
|
||||
|
||||
use zbus::{dbus_proxy, Connection};
|
||||
|
||||
#[dbus_proxy(interface = "com.system76.PowerDaemon", default_path = "/com/system76/PowerDaemon")]
|
||||
trait PowerDaemon {
|
||||
/// Balanced method
|
||||
fn balanced(&self) -> zbus::Result<()>;
|
||||
|
||||
/// Battery method
|
||||
fn battery(&self) -> zbus::Result<()>;
|
||||
|
||||
/// GetChargeProfiles method
|
||||
fn get_charge_profiles(
|
||||
&self,
|
||||
) -> zbus::Result<Vec<std::collections::HashMap<String, zbus::zvariant::OwnedValue>>>;
|
||||
|
||||
/// GetChargeThresholds method
|
||||
fn get_charge_thresholds(&self) -> zbus::Result<(u8, u8)>;
|
||||
|
||||
/// GetDefaultGraphics method
|
||||
fn get_default_graphics(&self) -> zbus::Result<String>;
|
||||
|
||||
/// GetExternalDisplaysRequireDGPU method
|
||||
fn get_external_displays_require_dgpu(&self) -> zbus::Result<bool>;
|
||||
|
||||
/// GetGraphics method
|
||||
fn get_graphics(&self) -> zbus::Result<String>;
|
||||
|
||||
/// GetGraphicsPower method
|
||||
fn get_graphics_power(&self) -> zbus::Result<bool>;
|
||||
|
||||
/// GetProfile method
|
||||
fn get_profile(&self) -> zbus::Result<String>;
|
||||
|
||||
/// GetSwitchable method
|
||||
fn get_switchable(&self) -> zbus::Result<bool>;
|
||||
|
||||
/// Performance method
|
||||
fn performance(&self) -> zbus::Result<()>;
|
||||
|
||||
/// SetChargeThresholds method
|
||||
fn set_charge_thresholds(&self, thresholds: &(u8, u8)) -> zbus::Result<()>;
|
||||
|
||||
/// SetGraphics method
|
||||
fn set_graphics(&self, vendor: &str) -> zbus::Result<()>;
|
||||
|
||||
/// SetGraphicsPower method
|
||||
fn set_graphics_power(&self, power: bool) -> zbus::Result<()>;
|
||||
|
||||
/// HotPlugDetect signal
|
||||
#[dbus_proxy(signal)]
|
||||
fn hot_plug_detect(&self, port: u64) -> zbus::Result<()>;
|
||||
|
||||
/// PowerProfileSwitch signal
|
||||
#[dbus_proxy(signal)]
|
||||
fn power_profile_switch(&self, profile: &str) -> zbus::Result<()>;
|
||||
}
|
||||
|
||||
pub async fn init() -> Option<(Connection, PowerDaemonProxy<'static>)> {
|
||||
let conn = match Connection::system().await {
|
||||
Ok(conn) => conn,
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
let proxy = match PowerDaemonProxy::new(&conn).await {
|
||||
Ok(p) => p,
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
Some((conn, proxy))
|
||||
}
|
||||
32
examples/cosmic-applet-graphics/src/graphics.rs
Normal file
32
examples/cosmic-applet-graphics/src/graphics.rs
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
use crate::dbus::PowerDaemonProxy;
|
||||
use zbus::Result;
|
||||
|
||||
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
|
||||
pub enum Graphics {
|
||||
Integrated,
|
||||
Hybrid,
|
||||
Nvidia,
|
||||
Compute,
|
||||
}
|
||||
|
||||
pub async fn get_current_graphics(daemon: PowerDaemonProxy<'_>) -> Result<Graphics> {
|
||||
let graphics = daemon.get_graphics().await?;
|
||||
match graphics.as_str() {
|
||||
"integrated" => Ok(Graphics::Integrated),
|
||||
"hybrid" => Ok(Graphics::Hybrid),
|
||||
"nvidia" => Ok(Graphics::Nvidia),
|
||||
"compute" => Ok(Graphics::Compute),
|
||||
_ => panic!("Unknown graphics profile: {}", graphics),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn set_graphics(daemon: PowerDaemonProxy<'_>, graphics: Graphics) -> Result<()> {
|
||||
let graphics_str = match graphics {
|
||||
Graphics::Integrated => "integrated",
|
||||
Graphics::Hybrid => "hybrid",
|
||||
Graphics::Nvidia => "nvidia",
|
||||
Graphics::Compute => "compute",
|
||||
};
|
||||
daemon.set_graphics(graphics_str).await
|
||||
}
|
||||
37
examples/cosmic-applet-graphics/src/main.rs
Normal file
37
examples/cosmic-applet-graphics/src/main.rs
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
mod dbus;
|
||||
mod graphics;
|
||||
mod window;
|
||||
|
||||
use cosmic::{
|
||||
iced::{sctk_settings::InitialSurface, Application},
|
||||
iced_native::window::Settings,
|
||||
iced_winit::command::platform_specific::wayland::window::SctkWindowSettings,
|
||||
settings,
|
||||
};
|
||||
use cosmic_panel_config::PanelSize;
|
||||
use window::*;
|
||||
|
||||
pub fn main() -> cosmic::iced::Result {
|
||||
let mut settings = settings();
|
||||
let pixels = std::env::var("COSMIC_PANEL_SIZE")
|
||||
.ok()
|
||||
.and_then(|size| match size.parse::<PanelSize>() {
|
||||
Ok(PanelSize::XL) => Some(64),
|
||||
Ok(PanelSize::L) => Some(48),
|
||||
Ok(PanelSize::M) => Some(36),
|
||||
Ok(PanelSize::S) => Some(24),
|
||||
Ok(PanelSize::XS) => Some(18),
|
||||
Err(_) => Some(36),
|
||||
})
|
||||
.unwrap_or(36);
|
||||
settings.initial_surface = InitialSurface::XdgWindow(SctkWindowSettings {
|
||||
iced_settings: Settings {
|
||||
size: (pixels + 32, pixels + 16),
|
||||
min_size: Some((pixels + 32, pixels + 16)),
|
||||
max_size: Some((pixels + 32, pixels + 16)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
});
|
||||
Window::run(settings)
|
||||
}
|
||||
218
examples/cosmic-applet-graphics/src/window.rs
Normal file
218
examples/cosmic-applet-graphics/src/window.rs
Normal file
|
|
@ -0,0 +1,218 @@
|
|||
use crate::dbus::{self, PowerDaemonProxy};
|
||||
use crate::graphics::{get_current_graphics, Graphics};
|
||||
use cosmic::widget::{expander, icon, nav_bar, nav_bar_page, nav_bar_section};
|
||||
use cosmic::{
|
||||
iced::widget::{
|
||||
checkbox, column, container, horizontal_space, pick_list, progress_bar, radio, row, slider,
|
||||
text,
|
||||
},
|
||||
iced::{self, Alignment, Application, Color, Command, Length},
|
||||
iced_lazy::responsive,
|
||||
iced_native::window,
|
||||
iced_winit::window::{drag, maximize, minimize},
|
||||
list_view, list_view_item, list_view_row, list_view_section, scrollable,
|
||||
theme::{self, Theme},
|
||||
widget::{button, header_bar, list_box, list_row, list_view::*, toggler},
|
||||
Element,
|
||||
};
|
||||
use cosmic::{iced_native, separator};
|
||||
use cosmic_panel_config::PanelSize;
|
||||
use iced_sctk::alignment::Horizontal;
|
||||
use iced_sctk::command::platform_specific::wayland::popup::{SctkPopupSettings, SctkPositioner};
|
||||
use iced_sctk::commands::popup::{destroy_popup, get_popup};
|
||||
use iced_sctk::{Point, Rectangle, Size};
|
||||
use sctk::reexports::protocols::xdg::shell::client::xdg_positioner::{Anchor, Gravity};
|
||||
use zbus::Connection;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Window {
|
||||
popup: Option<window::Id>,
|
||||
graphics_mode: Option<Graphics>,
|
||||
id_ctr: u32,
|
||||
icon_size: u16,
|
||||
theme: Theme,
|
||||
dbus: Option<(Connection, PowerDaemonProxy<'static>)>,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Message {
|
||||
CurrentGraphics(Option<Graphics>),
|
||||
DBusInit(Option<(Connection, PowerDaemonProxy<'static>)>),
|
||||
SelectGraphicsMode(Graphics),
|
||||
TogglePopup,
|
||||
}
|
||||
|
||||
impl Application for Window {
|
||||
type Executor = iced::executor::Default;
|
||||
type Flags = ();
|
||||
type Message = Message;
|
||||
type Theme = Theme;
|
||||
|
||||
fn new(_flags: ()) -> (Self, Command<Self::Message>) {
|
||||
let mut window = Window::default();
|
||||
let pixels = std::env::var("COSMIC_PANEL_SIZE")
|
||||
.ok()
|
||||
.and_then(|size| match size.parse::<PanelSize>() {
|
||||
Ok(PanelSize::XL) => Some(64),
|
||||
Ok(PanelSize::L) => Some(36),
|
||||
Ok(PanelSize::M) => Some(24),
|
||||
Ok(PanelSize::S) => Some(16),
|
||||
Ok(PanelSize::XS) => Some(12),
|
||||
Err(_) => Some(12),
|
||||
})
|
||||
.unwrap_or(16);
|
||||
window.icon_size = pixels;
|
||||
(
|
||||
window,
|
||||
Command::perform(dbus::init(), |dbus_init| Message::DBusInit(dbus_init)),
|
||||
)
|
||||
}
|
||||
|
||||
fn title(&self) -> String {
|
||||
String::from("Cosmic Graphics Applet")
|
||||
}
|
||||
|
||||
fn update(&mut self, message: Message) -> iced::Command<Self::Message> {
|
||||
match message {
|
||||
Message::SelectGraphicsMode(_) => {}
|
||||
Message::TogglePopup => {
|
||||
if let Some(p) = self.popup.take() {
|
||||
return destroy_popup(p);
|
||||
} else {
|
||||
self.id_ctr += 1;
|
||||
let new_id = window::Id::new(self.id_ctr);
|
||||
self.popup.replace(new_id);
|
||||
let mut commands = Vec::new();
|
||||
if let Some((_, proxy)) = self.dbus.as_ref() {
|
||||
commands.push(Command::perform(
|
||||
get_current_graphics(proxy.clone()),
|
||||
|cur_graphics| Message::CurrentGraphics(cur_graphics.ok()),
|
||||
));
|
||||
}
|
||||
commands.push(Command::batch(vec![get_popup(SctkPopupSettings {
|
||||
parent: window::Id::new(0),
|
||||
id: new_id,
|
||||
positioner: SctkPositioner {
|
||||
size: (200, 200),
|
||||
anchor_rect: Rectangle {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 32 + self.icon_size as i32,
|
||||
height: 16 + self.icon_size as i32,
|
||||
},
|
||||
anchor: Anchor::Bottom,
|
||||
gravity: Gravity::Bottom,
|
||||
reactive: true,
|
||||
..Default::default()
|
||||
},
|
||||
parent_size: None,
|
||||
grab: true,
|
||||
})]));
|
||||
return Command::batch(commands);
|
||||
}
|
||||
}
|
||||
Message::DBusInit(dbus) => {
|
||||
self.dbus = dbus;
|
||||
return Command::perform(
|
||||
get_current_graphics(self.dbus.as_ref().unwrap().1.clone()),
|
||||
|cur_graphics| {
|
||||
Message::CurrentGraphics(match cur_graphics {
|
||||
Ok(g) => Some(g),
|
||||
Err(err) => {
|
||||
dbg!(err);
|
||||
None
|
||||
},
|
||||
})
|
||||
},
|
||||
);
|
||||
}
|
||||
Message::CurrentGraphics(g) => {
|
||||
if let Some(g) = g {
|
||||
self.graphics_mode.replace(g);
|
||||
}
|
||||
}
|
||||
}
|
||||
Command::none()
|
||||
}
|
||||
|
||||
fn view_popup(&self, _: window::Id) -> Element<Message> {
|
||||
let content = column(vec![
|
||||
text("Graphics Mode")
|
||||
.width(Length::Fill)
|
||||
.horizontal_alignment(Horizontal::Center)
|
||||
.size(24)
|
||||
.into(),
|
||||
separator!(1).into(),
|
||||
column(vec![
|
||||
radio(
|
||||
"Integrated Graphics",
|
||||
Graphics::Integrated,
|
||||
self.graphics_mode,
|
||||
|g| Message::SelectGraphicsMode(g),
|
||||
)
|
||||
.into(),
|
||||
radio(
|
||||
"Nvidia Graphics",
|
||||
Graphics::Nvidia,
|
||||
self.graphics_mode,
|
||||
|g| Message::SelectGraphicsMode(g),
|
||||
)
|
||||
.into(),
|
||||
radio(
|
||||
"Hybrid Graphics",
|
||||
Graphics::Hybrid,
|
||||
self.graphics_mode,
|
||||
|g| Message::SelectGraphicsMode(g),
|
||||
)
|
||||
.into(),
|
||||
radio(
|
||||
"Compute Graphics",
|
||||
Graphics::Compute,
|
||||
self.graphics_mode,
|
||||
|g| Message::SelectGraphicsMode(g),
|
||||
)
|
||||
.into(),
|
||||
])
|
||||
.padding([8, 0])
|
||||
.spacing(8)
|
||||
.into(),
|
||||
])
|
||||
.padding(4)
|
||||
.spacing(4)
|
||||
.into();
|
||||
content
|
||||
}
|
||||
|
||||
fn view_layer_surface(
|
||||
&self,
|
||||
_: cosmic::iced_native::window::Id,
|
||||
) -> iced::Element<'_, Self::Message, iced::Renderer<Self::Theme>> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn close_window_requested(&self, _: cosmic::iced_native::window::Id) -> Self::Message {
|
||||
unimplemented!()
|
||||
}
|
||||
fn popup_done(&self, _: cosmic::iced_native::window::Id) -> Self::Message {
|
||||
unimplemented!()
|
||||
}
|
||||
fn layer_surface_done(&self, _: cosmic::iced_native::window::Id) -> Self::Message {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn view_window(&self, id: window::Id) -> Element<Message> {
|
||||
// TODO use panel config crate after resolving version mismatch
|
||||
|
||||
button!(icon("input-gaming-symbolic", self.icon_size).style(theme::Svg::Accent))
|
||||
.on_press(Message::TogglePopup)
|
||||
.into()
|
||||
}
|
||||
|
||||
fn should_exit(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn theme(&self) -> Theme {
|
||||
self.theme
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,7 @@
|
|||
use cosmic::{iced::{Application, sctk_settings::InitialSurface}, settings};
|
||||
use cosmic::{
|
||||
iced::{sctk_settings::InitialSurface, Application},
|
||||
settings,
|
||||
};
|
||||
|
||||
mod window;
|
||||
pub use window::*;
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ use cosmic::{
|
|||
},
|
||||
iced::{self, Alignment, Application, Color, Command, Length},
|
||||
iced_lazy::responsive,
|
||||
iced_winit::window::{drag, maximize, minimize},
|
||||
iced_native::window,
|
||||
iced_winit::window::{drag, maximize, minimize},
|
||||
list_view, list_view_item, list_view_row, list_view_section, scrollable,
|
||||
theme::{self, Theme},
|
||||
widget::{button, header_bar, list_box, list_row, list_view::*, toggler},
|
||||
|
|
@ -15,7 +15,6 @@ use cosmic::{
|
|||
};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Window {
|
||||
page: u8,
|
||||
|
|
@ -112,8 +111,8 @@ impl Application for Window {
|
|||
unimplemented!()
|
||||
}
|
||||
fn view_layer_surface(
|
||||
&self,
|
||||
window: cosmic::iced_native::window::Id,
|
||||
&self,
|
||||
window: cosmic::iced_native::window::Id,
|
||||
) -> iced::Element<'_, Self::Message, iced::Renderer<Self::Theme>> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
|
@ -184,9 +183,7 @@ impl Application for Window {
|
|||
vec![nav_bar_page("Wi-Fi")],
|
||||
),
|
||||
(
|
||||
nav_bar_section()
|
||||
.title("Bluetooth")
|
||||
.icon("cs-bluetooth"),
|
||||
nav_bar_section().title("Bluetooth").icon("cs-bluetooth"),
|
||||
vec![nav_bar_page("Devices")],
|
||||
),
|
||||
(
|
||||
|
|
@ -213,9 +210,7 @@ impl Application for Window {
|
|||
vec![nav_bar_page("Keyboard")],
|
||||
),
|
||||
(
|
||||
nav_bar_section()
|
||||
.title("Power & Battery")
|
||||
.icon("battery"),
|
||||
nav_bar_section().title("Power & Battery").icon("battery"),
|
||||
vec![nav_bar_page("Status")],
|
||||
),
|
||||
(
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ use cosmic::{
|
|||
},
|
||||
iced::{self, Alignment, Application, Color, Command, Length},
|
||||
iced_lazy::responsive,
|
||||
iced_winit::window::{drag, maximize, minimize},
|
||||
iced_native::window,
|
||||
iced_winit::window::{drag, maximize, minimize},
|
||||
list_view, list_view_item, list_view_row, list_view_section, scrollable,
|
||||
theme::{self, Theme},
|
||||
widget::{button, header_bar, list_box, list_row, list_view::*, toggler},
|
||||
|
|
@ -165,9 +165,7 @@ impl Application for Window {
|
|||
vec![nav_bar_page("Wi-Fi")],
|
||||
),
|
||||
(
|
||||
nav_bar_section()
|
||||
.title("Bluetooth")
|
||||
.icon("cs-bluetooth"),
|
||||
nav_bar_section().title("Bluetooth").icon("cs-bluetooth"),
|
||||
vec![nav_bar_page("Devices")],
|
||||
),
|
||||
(
|
||||
|
|
@ -194,9 +192,7 @@ impl Application for Window {
|
|||
vec![nav_bar_page("Keyboard")],
|
||||
),
|
||||
(
|
||||
nav_bar_section()
|
||||
.title("Power & Battery")
|
||||
.icon("battery"),
|
||||
nav_bar_section().title("Power & Battery").icon("battery"),
|
||||
vec![nav_bar_page("Status")],
|
||||
),
|
||||
(
|
||||
|
|
|
|||
|
|
@ -174,11 +174,7 @@ impl Default for Checkbox {
|
|||
impl checkbox::StyleSheet for Theme {
|
||||
type Style = Checkbox;
|
||||
|
||||
fn active(
|
||||
&self,
|
||||
style: &Self::Style,
|
||||
is_checked: bool,
|
||||
) -> checkbox::Appearance {
|
||||
fn active(&self, style: &Self::Style, is_checked: bool) -> checkbox::Appearance {
|
||||
let palette = self.extended_palette();
|
||||
|
||||
match style {
|
||||
|
|
@ -209,11 +205,7 @@ impl checkbox::StyleSheet for Theme {
|
|||
}
|
||||
}
|
||||
|
||||
fn hovered(
|
||||
&self,
|
||||
style: &Self::Style,
|
||||
is_checked: bool,
|
||||
) -> checkbox::Appearance {
|
||||
fn hovered(&self, style: &Self::Style, is_checked: bool) -> checkbox::Appearance {
|
||||
let palette = self.extended_palette();
|
||||
|
||||
match style {
|
||||
|
|
@ -252,11 +244,7 @@ fn checkbox_appearance(
|
|||
is_checked: bool,
|
||||
) -> checkbox::Appearance {
|
||||
checkbox::Appearance {
|
||||
background: Background::Color(if is_checked {
|
||||
accent.color
|
||||
} else {
|
||||
base.color
|
||||
}),
|
||||
background: Background::Color(if is_checked { accent.color } else { base.color }),
|
||||
checkmark_color,
|
||||
border_radius: 4.0,
|
||||
border_width: if is_checked { 0.0 } else { 1.0 },
|
||||
|
|
@ -355,21 +343,17 @@ impl slider::StyleSheet for Theme {
|
|||
Color::TRANSPARENT,
|
||||
),
|
||||
handle: slider::Handle {
|
||||
shape: slider::HandleShape::Circle {
|
||||
radius: 10.0,
|
||||
},
|
||||
shape: slider::HandleShape::Circle { radius: 10.0 },
|
||||
color: cosmic.accent.base.into(),
|
||||
border_color: Color::TRANSPARENT,
|
||||
border_width: 0.0,
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn hovered(&self, style: &Self::Style) -> slider::Appearance {
|
||||
let mut style = self.active(&style);
|
||||
style.handle.shape = slider::HandleShape::Circle {
|
||||
radius: 16.0
|
||||
};
|
||||
style.handle.shape = slider::HandleShape::Circle { radius: 16.0 };
|
||||
style.handle.border_width = 6.0;
|
||||
style.handle.border_color = match self {
|
||||
Theme::Dark => Color::from_rgba8(0xFF, 0xFF, 0xFF, 0.1),
|
||||
|
|
@ -475,11 +459,7 @@ impl radio::StyleSheet for Theme {
|
|||
impl toggler::StyleSheet for Theme {
|
||||
type Style = ();
|
||||
|
||||
fn active(
|
||||
&self,
|
||||
_style: &Self::Style,
|
||||
is_active: bool,
|
||||
) -> toggler::Appearance {
|
||||
fn active(&self, _style: &Self::Style, is_active: bool) -> toggler::Appearance {
|
||||
let palette = self.palette();
|
||||
|
||||
toggler::Appearance {
|
||||
|
|
@ -502,14 +482,10 @@ impl toggler::StyleSheet for Theme {
|
|||
}
|
||||
}
|
||||
|
||||
fn hovered(
|
||||
&self,
|
||||
style: &Self::Style,
|
||||
is_active: bool,
|
||||
) -> toggler::Appearance {
|
||||
fn hovered(&self, style: &Self::Style, is_active: bool) -> toggler::Appearance {
|
||||
//TODO: grab colors from palette
|
||||
match self {
|
||||
Theme::Dark => toggler::Appearance {
|
||||
Theme::Dark => toggler::Appearance {
|
||||
background: if is_active {
|
||||
Color::from_rgb8(0x9f, 0xed, 0xed)
|
||||
} else {
|
||||
|
|
@ -517,14 +493,14 @@ impl toggler::StyleSheet for Theme {
|
|||
},
|
||||
..self.active(&style, is_active)
|
||||
},
|
||||
Theme::Light => toggler::Appearance {
|
||||
Theme::Light => toggler::Appearance {
|
||||
background: if is_active {
|
||||
Color::from_rgb8(0x00, 0x42, 0x62)
|
||||
} else {
|
||||
Color::from_rgb8(0x54, 0x54, 0x54)
|
||||
},
|
||||
..self.active(&style, is_active)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -666,7 +642,6 @@ impl scrollable::StyleSheet for Theme {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Default, Clone, Copy)]
|
||||
pub enum Svg {
|
||||
Custom(fn(&Theme) -> svg::Appearance),
|
||||
|
|
@ -715,7 +690,7 @@ impl text::StyleSheet for Theme {
|
|||
fn appearance(&self, style: Self::Style) -> text::Appearance {
|
||||
match style {
|
||||
Text::Accent => text::Appearance {
|
||||
color: Some(self.cosmic().accent.base.into())
|
||||
color: Some(self.cosmic().accent.base.into()),
|
||||
},
|
||||
Text::Default => Default::default(),
|
||||
Text::Color(c) => text::Appearance { color: Some(c) },
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ impl Palette {
|
|||
background: Color::from_rgb(
|
||||
0x1e as f32 / 255.0,
|
||||
0x1e as f32 / 255.0,
|
||||
0x1e as f32 / 255.0
|
||||
0x1e as f32 / 255.0,
|
||||
),
|
||||
text: Color::from_rgb(
|
||||
0xe4 as f32 / 255.0,
|
||||
|
|
@ -80,8 +80,7 @@ pub struct Extended {
|
|||
}
|
||||
|
||||
lazy_static! {
|
||||
pub static ref EXTENDED_LIGHT: Extended =
|
||||
Extended::generate(Palette::LIGHT);
|
||||
pub static ref EXTENDED_LIGHT: Extended = Extended::generate(Palette::LIGHT);
|
||||
pub static ref EXTENDED_DARK: Extended = Extended::generate(Palette::DARK);
|
||||
}
|
||||
|
||||
|
|
@ -89,22 +88,10 @@ impl Extended {
|
|||
pub fn generate(palette: Palette) -> Self {
|
||||
Self {
|
||||
background: Background::new(palette.background, palette.text),
|
||||
primary: Primary::generate(
|
||||
palette.primary,
|
||||
palette.background,
|
||||
palette.text,
|
||||
),
|
||||
primary: Primary::generate(palette.primary, palette.background, palette.text),
|
||||
secondary: Secondary::generate(palette.background, palette.text),
|
||||
success: Success::generate(
|
||||
palette.success,
|
||||
palette.background,
|
||||
palette.text,
|
||||
),
|
||||
danger: Danger::generate(
|
||||
palette.danger,
|
||||
palette.background,
|
||||
palette.text,
|
||||
),
|
||||
success: Success::generate(palette.success, palette.background, palette.text),
|
||||
danger: Danger::generate(palette.danger, palette.background, palette.text),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
use crate::{theme, Element, Renderer};
|
||||
use apply::Apply;
|
||||
use derive_setters::*;
|
||||
use iced::{self, alignment::Vertical, widget, Length};
|
||||
use iced_lazy::Component;
|
||||
use crate::{theme, Element, Renderer};
|
||||
|
||||
#[derive(Setters)]
|
||||
pub struct HeaderBar<Message> {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
pub use iced::{widget, Background, Color};
|
||||
pub use crate::Theme;
|
||||
pub use iced::{widget, Background, Color};
|
||||
|
||||
pub mod list_view {
|
||||
#[macro_export]
|
||||
|
|
@ -82,8 +82,8 @@ pub mod list_view {
|
|||
}
|
||||
|
||||
use crate::widget::{Background, Color};
|
||||
use iced::widget;
|
||||
use crate::Theme;
|
||||
use iced::widget;
|
||||
|
||||
pub use list_view;
|
||||
pub use list_view_item;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
pub mod nav_bar {
|
||||
use iced::{widget, Background, Color};
|
||||
use crate::Theme;
|
||||
use iced::{widget, Background, Color};
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! nav_button {
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ where
|
|||
<<Renderer as iced_native::Renderer>::Theme as container::StyleSheet>::Style:
|
||||
From<theme::Container>,
|
||||
<<Renderer as iced_native::Renderer>::Theme as text::StyleSheet>::Style: From<theme::Text>,
|
||||
Renderer::Theme: iced_native::svg::StyleSheet
|
||||
Renderer::Theme: iced_native::svg::StyleSheet,
|
||||
{
|
||||
type State = NavBarState;
|
||||
type Event = NavBarEvent;
|
||||
|
|
@ -146,11 +146,13 @@ where
|
|||
.height(Length::Units(50))
|
||||
.align_items(Alignment::Center),
|
||||
)
|
||||
.style(if *section == state.selected_section && state.section_active {
|
||||
theme::Button::Primary.into()
|
||||
} else {
|
||||
theme::Button::Text.into()
|
||||
})
|
||||
.style(
|
||||
if *section == state.selected_section && state.section_active {
|
||||
theme::Button::Primary.into()
|
||||
} else {
|
||||
theme::Button::Text.into()
|
||||
},
|
||||
)
|
||||
.on_press(NavBarEvent::SectionSelected(section.clone()))
|
||||
.into(),
|
||||
);
|
||||
|
|
@ -159,17 +161,15 @@ where
|
|||
pages.push(
|
||||
button(row![text(&page.title).size(16).width(Length::Fill)])
|
||||
.padding(10)
|
||||
.style(
|
||||
if let Some(selected_page) = &state.selected_page {
|
||||
if state.page_active && page == selected_page {
|
||||
theme::Button::Primary.into()
|
||||
} else {
|
||||
theme::Button::Text.into()
|
||||
}
|
||||
.style(if let Some(selected_page) = &state.selected_page {
|
||||
if state.page_active && page == selected_page {
|
||||
theme::Button::Primary.into()
|
||||
} else {
|
||||
theme::Button::Text.into()
|
||||
}
|
||||
)
|
||||
} else {
|
||||
theme::Button::Text.into()
|
||||
})
|
||||
.on_press(NavBarEvent::PageSelected(section.clone(), page.clone()))
|
||||
.into(),
|
||||
);
|
||||
|
|
@ -180,13 +180,13 @@ where
|
|||
let nav_bar: Element<Self::Event, Renderer> =
|
||||
container(if self.condensed && state.selected_page.is_some() {
|
||||
row![container(scrollable!(column(pages)
|
||||
.spacing(10)
|
||||
.padding(10)
|
||||
.max_width(200)
|
||||
.width(Length::Units(200))
|
||||
.height(Length::Shrink)))
|
||||
.height(Length::Fill)
|
||||
.style(theme::Container::Custom(nav_bar_pages_style))]
|
||||
.spacing(10)
|
||||
.padding(10)
|
||||
.max_width(200)
|
||||
.width(Length::Units(200))
|
||||
.height(Length::Shrink)))
|
||||
.height(Length::Fill)
|
||||
.style(theme::Container::Custom(nav_bar_pages_style))]
|
||||
} else if !state.section_active || self.condensed && state.selected_page.is_none() {
|
||||
row![scrollable!(column(sections)
|
||||
.spacing(10)
|
||||
|
|
@ -222,8 +222,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, Message: 'a, Renderer> From<NavBar<'a, Message>>
|
||||
for Element<'a, Message, Renderer>
|
||||
impl<'a, Message: 'a, Renderer> From<NavBar<'a, Message>> for Element<'a, Message, Renderer>
|
||||
where
|
||||
Renderer: iced_native::text::Renderer + iced_native::svg::Renderer + 'a,
|
||||
<Renderer as iced_native::Renderer>::Theme:
|
||||
|
|
@ -232,7 +231,7 @@ where
|
|||
<<Renderer as iced_native::Renderer>::Theme as container::StyleSheet>::Style:
|
||||
From<theme::Container>,
|
||||
<<Renderer as iced_native::Renderer>::Theme as text::StyleSheet>::Style: From<theme::Text>,
|
||||
Renderer::Theme: iced_native::svg::StyleSheet
|
||||
Renderer::Theme: iced_native::svg::StyleSheet,
|
||||
{
|
||||
fn from(nav_bar: NavBar<'a, Message>) -> Self {
|
||||
iced_lazy::component(nav_bar)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue