Replace emoji icons with proper SVG icons loaded from GResources: - Add Weather Icons (Erik Flowers) for weather conditions - Add music note icon for media player widget - Add tomato icon for pomodoro timer - Create GResource manifest and build.rs for compilation - Update providers to use resource paths for icons - Image::from_resource() loads icons from compiled bundle This ensures icons display consistently regardless of user's installed icon theme. Weather icons are OFL licensed. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
139 lines
5.0 KiB
Rust
139 lines
5.0 KiB
Rust
use crate::providers::LaunchItem;
|
|
use gtk4::prelude::*;
|
|
use gtk4::{Box as GtkBox, Image, Label, ListBoxRow, Orientation, Widget};
|
|
|
|
#[allow(dead_code)]
|
|
pub struct ResultRow {
|
|
row: ListBoxRow,
|
|
}
|
|
|
|
impl ResultRow {
|
|
pub fn new(item: &LaunchItem) -> ListBoxRow {
|
|
let row = ListBoxRow::builder()
|
|
.selectable(true)
|
|
.activatable(true)
|
|
.build();
|
|
|
|
row.add_css_class("owlry-result-row");
|
|
|
|
let hbox = GtkBox::builder()
|
|
.orientation(Orientation::Horizontal)
|
|
.spacing(12)
|
|
.margin_top(8)
|
|
.margin_bottom(8)
|
|
.margin_start(12)
|
|
.margin_end(12)
|
|
.build();
|
|
|
|
// Icon - handle GResource paths, file paths, icon names, and fallbacks
|
|
let icon_widget: Widget = if let Some(icon_path) = &item.icon {
|
|
let img = if icon_path.starts_with("/org/owlry/launcher/icons/") {
|
|
// GResource path - load from bundled resources
|
|
Image::from_resource(icon_path)
|
|
} else if icon_path.starts_with('/') {
|
|
// Absolute file path
|
|
Image::from_file(icon_path)
|
|
} else {
|
|
// Icon theme name
|
|
Image::from_icon_name(icon_path)
|
|
};
|
|
img.set_pixel_size(32);
|
|
img.add_css_class("owlry-result-icon");
|
|
img.upcast()
|
|
} else {
|
|
// Default icon based on provider type
|
|
let default_icon = match item.provider {
|
|
crate::providers::ProviderType::Application => "application-x-executable",
|
|
crate::providers::ProviderType::Bookmarks => "user-bookmarks",
|
|
crate::providers::ProviderType::Calculator => "accessories-calculator",
|
|
crate::providers::ProviderType::Clipboard => "edit-paste",
|
|
crate::providers::ProviderType::Command => "utilities-terminal",
|
|
crate::providers::ProviderType::Dmenu => "view-list-symbolic",
|
|
crate::providers::ProviderType::Emoji => "face-smile",
|
|
crate::providers::ProviderType::Files => "folder",
|
|
crate::providers::ProviderType::Scripts => "application-x-executable",
|
|
crate::providers::ProviderType::Ssh => "network-server",
|
|
crate::providers::ProviderType::System => "system-shutdown",
|
|
crate::providers::ProviderType::Uuctl => "system-run",
|
|
crate::providers::ProviderType::WebSearch => "web-browser",
|
|
// Widget providers now have icons set, but keep fallbacks
|
|
crate::providers::ProviderType::Weather => "weather-clear-symbolic",
|
|
crate::providers::ProviderType::MediaPlayer => "media-playback-start-symbolic",
|
|
crate::providers::ProviderType::Pomodoro => "alarm-symbolic",
|
|
};
|
|
let img = Image::from_icon_name(default_icon);
|
|
img.set_pixel_size(32);
|
|
img.add_css_class("owlry-result-icon");
|
|
img.upcast()
|
|
};
|
|
|
|
// Text container
|
|
let text_box = GtkBox::builder()
|
|
.orientation(Orientation::Vertical)
|
|
.hexpand(true)
|
|
.valign(gtk4::Align::Center)
|
|
.build();
|
|
|
|
// Name label
|
|
let name_label = Label::builder()
|
|
.label(&item.name)
|
|
.halign(gtk4::Align::Start)
|
|
.ellipsize(gtk4::pango::EllipsizeMode::End)
|
|
.build();
|
|
|
|
name_label.add_css_class("owlry-result-name");
|
|
|
|
// Description label
|
|
if let Some(desc) = &item.description {
|
|
let desc_label = Label::builder()
|
|
.label(desc)
|
|
.halign(gtk4::Align::Start)
|
|
.ellipsize(gtk4::pango::EllipsizeMode::End)
|
|
.build();
|
|
|
|
desc_label.add_css_class("owlry-result-description");
|
|
text_box.append(&name_label);
|
|
text_box.append(&desc_label);
|
|
} else {
|
|
text_box.append(&name_label);
|
|
}
|
|
|
|
// Tag badges (show first 3 tags)
|
|
if !item.tags.is_empty() {
|
|
let tags_box = GtkBox::builder()
|
|
.orientation(Orientation::Horizontal)
|
|
.spacing(4)
|
|
.halign(gtk4::Align::Start)
|
|
.build();
|
|
|
|
for tag in item.tags.iter().take(3) {
|
|
let tag_label = Label::builder()
|
|
.label(tag)
|
|
.build();
|
|
tag_label.add_css_class("owlry-tag-badge");
|
|
tags_box.append(&tag_label);
|
|
}
|
|
|
|
text_box.append(&tags_box);
|
|
}
|
|
|
|
// Provider badge
|
|
let badge = Label::builder()
|
|
.label(&item.provider.to_string())
|
|
.halign(gtk4::Align::End)
|
|
.valign(gtk4::Align::Center)
|
|
.build();
|
|
|
|
badge.add_css_class("owlry-result-badge");
|
|
badge.add_css_class(&format!("owlry-badge-{}", item.provider));
|
|
|
|
hbox.append(&icon_widget);
|
|
hbox.append(&text_box);
|
|
hbox.append(&badge);
|
|
|
|
row.set_child(Some(&hbox));
|
|
|
|
row
|
|
}
|
|
}
|