-
-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Implement bottom panel * Remove thread sleep * Remove unused iced features * RustFmt * Remove unwrap from the main method * Add bottom panel image * Update readme with bottom panel example * Handle result * Handle panel run result
- Loading branch information
1 parent
32888f0
commit 80e9861
Showing
6 changed files
with
217 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
[package] | ||
name = "bottom_panel" | ||
authors.workspace = true | ||
edition.workspace = true | ||
version.workspace = true | ||
license.workspace = true | ||
repository.workspace = true | ||
description.workspace = true | ||
keywords.workspace = true | ||
readme.workspace = true | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[dependencies] | ||
iced = { version = "0.12.1", features = ["image", "svg"]} | ||
iced_runtime.workspace = true | ||
iced_layershell.workspace = true | ||
gio = "0.20.0" | ||
regex = "1.10.5" | ||
xdg = "2.5.2" | ||
tracing = "0.1.40" |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
use std::path::PathBuf; | ||
use std::str::FromStr; | ||
|
||
use gio::{AppLaunchContext, DesktopAppInfo}; | ||
|
||
use crate::Message; | ||
use gio::prelude::*; | ||
use iced::widget::{button, image, row, svg}; | ||
use iced::{theme, Element, Length}; | ||
|
||
static DEFAULT_ICON: &[u8] = include_bytes!("../misc/text-plain.svg"); | ||
|
||
#[derive(Debug, Clone)] | ||
pub struct App { | ||
app_info: DesktopAppInfo, | ||
icon: Option<PathBuf>, | ||
} | ||
|
||
impl App { | ||
pub fn launch(&self) { | ||
self.app_info.launch(&[], AppLaunchContext::NONE).unwrap() | ||
} | ||
|
||
fn icon(&self) -> Element<Message> { | ||
match &self.icon { | ||
Some(path) => { | ||
if path | ||
.as_os_str() | ||
.to_str() | ||
.is_some_and(|pathname| pathname.ends_with("png")) | ||
{ | ||
image(image::Handle::from_path(path)) | ||
.width(Length::Fixed(80.)) | ||
.height(Length::Fixed(80.)) | ||
.into() | ||
} else { | ||
svg(svg::Handle::from_path(path)) | ||
.width(Length::Fixed(40.)) | ||
.height(Length::Fixed(40.)) | ||
.into() | ||
} | ||
} | ||
None => svg(svg::Handle::from_memory(DEFAULT_ICON)) | ||
.width(Length::Fixed(40.)) | ||
.height(Length::Fixed(40.)) | ||
.into(), | ||
} | ||
} | ||
|
||
pub fn view(&self, index: usize, selected: bool) -> Element<Message> { | ||
button(row![self.icon(),].spacing(10)) | ||
.on_press(Message::Launch(index)) | ||
.width(Length::Fill) | ||
.height(Length::Fill) | ||
.style(if selected { | ||
theme::Button::Primary | ||
} else { | ||
theme::Button::Secondary | ||
}) | ||
.into() | ||
} | ||
} | ||
|
||
static ICONS_SIZE: &[&str] = &["256x256", "256x256"]; | ||
|
||
static THEMES_LIST: &[&str] = &["yaru"]; | ||
|
||
fn get_icon_path_from_xdgicon(iconname: &str) -> Option<PathBuf> { | ||
let scalable_icon_path = | ||
xdg::BaseDirectories::with_prefix("icons/hicolor/scalable/apps").unwrap(); | ||
if let Some(iconpath) = scalable_icon_path.find_data_file(format!("{iconname}.svg")) { | ||
return Some(iconpath); | ||
} | ||
for prefix in ICONS_SIZE { | ||
let iconpath = | ||
xdg::BaseDirectories::with_prefix(&format!("icons/hicolor/{prefix}/apps")).unwrap(); | ||
if let Some(iconpath) = iconpath.find_data_file(format!("{iconname}.png")) { | ||
return Some(iconpath); | ||
} | ||
} | ||
let pixmappath = xdg::BaseDirectories::with_prefix("pixmaps").unwrap(); | ||
if let Some(iconpath) = pixmappath.find_data_file(format!("{iconname}.svg")) { | ||
return Some(iconpath); | ||
} | ||
if let Some(iconpath) = pixmappath.find_data_file(format!("{iconname}.png")) { | ||
return Some(iconpath); | ||
} | ||
for themes in THEMES_LIST { | ||
let iconpath = | ||
xdg::BaseDirectories::with_prefix(&format!("icons/{themes}/apps/48")).unwrap(); | ||
if let Some(iconpath) = iconpath.find_data_file(format!("{iconname}.svg")) { | ||
return Some(iconpath); | ||
} | ||
let iconpath = | ||
xdg::BaseDirectories::with_prefix(&format!("icons/{themes}/apps/64")).unwrap(); | ||
if let Some(iconpath) = iconpath.find_data_file(format!("{iconname}.svg")) { | ||
return Some(iconpath); | ||
} | ||
} | ||
None | ||
} | ||
|
||
fn get_icon_path(iconname: &str) -> Option<PathBuf> { | ||
if iconname.contains('/') { | ||
PathBuf::from_str(iconname).ok() | ||
} else { | ||
get_icon_path_from_xdgicon(iconname) | ||
} | ||
} | ||
pub fn all_apps() -> Vec<App> { | ||
gio::AppInfo::all() | ||
.iter() | ||
.filter(|app| app.should_show() && app.downcast_ref::<DesktopAppInfo>().is_some()) | ||
.map(|app| app.clone().downcast::<DesktopAppInfo>().unwrap()) | ||
.take(10) | ||
.map(|app| App { | ||
app_info: app.clone(), | ||
icon: match &app.icon() { | ||
None => None, | ||
Some(icon) => { | ||
let iconname = gio::prelude::IconExt::to_string(icon).unwrap(); | ||
get_icon_path(iconname.as_str()) | ||
} | ||
}, | ||
}) | ||
.collect() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
mod applications; | ||
use applications::{all_apps, App}; | ||
use iced::widget::row; | ||
use iced::{Command, Element, Theme}; | ||
|
||
use iced_layershell::reexport::{Anchor, Layer}; | ||
use iced_layershell::settings::{LayerShellSettings, Settings}; | ||
use iced_layershell::Application; | ||
|
||
fn main() -> Result<(), iced_layershell::Error> { | ||
Panel::run(Settings { | ||
layer_settings: LayerShellSettings { | ||
size: Some((600, 50)), | ||
anchor: Anchor::Bottom, | ||
layer: Layer::Overlay, | ||
margin: (0, 0, 10, 0), | ||
..Default::default() | ||
}, | ||
..Default::default() | ||
}) | ||
} | ||
|
||
struct Panel { | ||
apps: Vec<App>, | ||
} | ||
|
||
#[derive(Debug, Clone)] | ||
enum Message { | ||
Launch(usize), | ||
} | ||
|
||
impl Application for Panel { | ||
type Executor = iced::executor::Default; | ||
type Message = Message; | ||
type Theme = Theme; | ||
type Flags = (); | ||
|
||
fn new(_flags: Self::Flags) -> (Self, Command<Self::Message>) { | ||
(Self { apps: all_apps() }, Command::none()) | ||
} | ||
fn namespace(&self) -> String { | ||
String::from("bottom panel") | ||
} | ||
|
||
fn update(&mut self, message: Self::Message) -> Command<Self::Message> { | ||
match message { | ||
Message::Launch(index) => { | ||
self.apps[index].launch(); | ||
Command::none() | ||
} | ||
} | ||
} | ||
|
||
fn view(&self) -> Element<Message> { | ||
let bottom_vec: Vec<Element<Message>> = self | ||
.apps | ||
.iter() | ||
.enumerate() | ||
.map(|(index, app)| app.view(index, false)) | ||
.collect(); | ||
|
||
row(bottom_vec).into() | ||
} | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.