Set up to allow styling and user styling in the future
This commit is contained in:
parent
beecf03025
commit
7c310b36e1
11
src/main.rs
11
src/main.rs
@ -18,6 +18,17 @@ fn main() {
|
||||
|
||||
// Create and show the GTK UI
|
||||
let ui = GtkLauncherUI::new(app, launcher);
|
||||
|
||||
// Apply built-in default styles
|
||||
if let Err(e) = ui.apply_default_css() {
|
||||
eprintln!("Warning: Could not apply default styles: {}", e);
|
||||
}
|
||||
|
||||
// Optionally apply user CSS overrides
|
||||
// if let Err(_) = ui.apply_css("waycast.css") {
|
||||
// // Silently ignore if user hasn't provided custom CSS
|
||||
// }
|
||||
|
||||
ui.show();
|
||||
});
|
||||
|
||||
|
111
src/ui/gtk/default.css
Normal file
111
src/ui/gtk/default.css
Normal file
@ -0,0 +1,111 @@
|
||||
/* Default CSS styles for Waycast launcher */
|
||||
/* Not too much so that colors follow system theme */
|
||||
|
||||
/* Main window */
|
||||
#launcher-window {
|
||||
/* background-color: rgba(0, 0, 0, 0.9);
|
||||
border-radius: 12px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1); */
|
||||
}
|
||||
|
||||
/* Main container */
|
||||
#main-container {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
/* Search input */
|
||||
#search-input {
|
||||
font-size: 16px;
|
||||
padding: 12px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 12px;
|
||||
/* border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
color: white; */
|
||||
}
|
||||
|
||||
#search-input:focus {
|
||||
/* background-color: rgba(255, 255, 255, 0.15);
|
||||
border-color: rgba(74, 144, 226, 0.6); */
|
||||
box-shadow: 0 0 0 2px rgba(74, 144, 226, 0.3);
|
||||
}
|
||||
|
||||
/* Results container */
|
||||
#results-container {
|
||||
border-radius: 8px;
|
||||
/* background-color: rgba(255, 255, 255, 0.05); */
|
||||
}
|
||||
|
||||
/* Results list */
|
||||
#results-list {
|
||||
/* background-color: transparent; */
|
||||
}
|
||||
|
||||
/* Individual list items */
|
||||
#list-item {
|
||||
padding: 8px 12px;
|
||||
border-radius: 6px;
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
#list-item:hover {
|
||||
/* background-color: rgba(255, 255, 255, 0.1); */
|
||||
}
|
||||
|
||||
#list-item:selected {
|
||||
/* background-color: rgba(74, 144, 226, 0.4); */
|
||||
}
|
||||
|
||||
/* Item icon */
|
||||
#item-icon {
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
/* Item text container */
|
||||
#item-text {
|
||||
/* Text styling handled by individual elements */
|
||||
}
|
||||
|
||||
/* Item title */
|
||||
#item-title {
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
/* color: white; */
|
||||
}
|
||||
|
||||
/* Item description */
|
||||
#item-description {
|
||||
font-size: 11px;
|
||||
/* color: rgba(255, 255, 255, 0.7); */
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
/* CSS Classes (alternative to IDs) */
|
||||
|
||||
.launcher-window {
|
||||
/* Alternative window styling */
|
||||
}
|
||||
|
||||
.launcher-search {
|
||||
/* Alternative search styling */
|
||||
}
|
||||
|
||||
.launcher-item {
|
||||
/* Alternative item styling */
|
||||
}
|
||||
|
||||
.launcher-item:hover {
|
||||
/* Alternative hover state */
|
||||
}
|
||||
|
||||
.launcher-title {
|
||||
/* Alternative title styling */
|
||||
}
|
||||
|
||||
.launcher-description {
|
||||
/* Alternative description styling */
|
||||
}
|
||||
|
||||
.launcher-icon {
|
||||
/* Alternative icon styling */
|
||||
}
|
@ -10,7 +10,7 @@ use gio::ListStore;
|
||||
use gtk::subclass::prelude::ObjectSubclassIsExt;
|
||||
use gtk4_layer_shell as layerShell;
|
||||
use layerShell::LayerShell;
|
||||
use std::path::PathBuf;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::rc::Rc;
|
||||
use std::cell::RefCell;
|
||||
use gio::prelude::ApplicationExt;
|
||||
@ -99,6 +99,8 @@ impl GtkLauncherUI {
|
||||
|
||||
let search_input = Entry::new();
|
||||
search_input.set_placeholder_text(Some("Search..."));
|
||||
search_input.set_widget_name("search-input");
|
||||
search_input.add_css_class("launcher-search");
|
||||
|
||||
let scrolled_window = ScrolledWindow::new();
|
||||
scrolled_window.set_min_content_height(300);
|
||||
@ -113,6 +115,8 @@ impl GtkLauncherUI {
|
||||
// Setup factory to create widgets
|
||||
factory.connect_setup(move |_, list_item| {
|
||||
let container = GtkBox::new(Orientation::Horizontal, 10);
|
||||
container.set_widget_name("list-item");
|
||||
container.add_css_class("launcher-item");
|
||||
list_item.set_child(Some(&container));
|
||||
});
|
||||
|
||||
@ -151,16 +155,22 @@ impl GtkLauncherUI {
|
||||
}
|
||||
}
|
||||
image.set_pixel_size(icon_size);
|
||||
image.set_widget_name("item-icon");
|
||||
image.add_css_class("launcher-icon");
|
||||
|
||||
// Create text container (vertical box for title + description)
|
||||
let text_box = GtkBox::new(Orientation::Vertical, 2);
|
||||
text_box.set_hexpand(true);
|
||||
text_box.set_valign(gtk::Align::Center);
|
||||
text_box.set_widget_name("item-text");
|
||||
text_box.add_css_class("launcher-text");
|
||||
|
||||
// Create title label
|
||||
let title_label = Label::new(Some(&item_obj.title()));
|
||||
title_label.set_xalign(0.0);
|
||||
title_label.set_ellipsize(gtk::pango::EllipsizeMode::End);
|
||||
title_label.set_widget_name("item-title");
|
||||
title_label.add_css_class("launcher-title");
|
||||
text_box.append(&title_label);
|
||||
|
||||
// Create description label if description exists
|
||||
@ -168,7 +178,8 @@ impl GtkLauncherUI {
|
||||
let desc_label = Label::new(Some(&description));
|
||||
desc_label.set_xalign(0.0);
|
||||
desc_label.set_ellipsize(gtk::pango::EllipsizeMode::Middle);
|
||||
desc_label.add_css_class("dim-label"); // Make it visually secondary
|
||||
desc_label.set_widget_name("item-description");
|
||||
desc_label.add_css_class("launcher-description");
|
||||
desc_label.set_opacity(0.7);
|
||||
text_box.append(&desc_label);
|
||||
}
|
||||
@ -181,11 +192,21 @@ impl GtkLauncherUI {
|
||||
let list_view = ListView::new(Some(selection.clone()), Some(factory));
|
||||
list_view.set_vexpand(true);
|
||||
list_view.set_can_focus(true);
|
||||
list_view.set_widget_name("results-list");
|
||||
list_view.add_css_class("launcher-list");
|
||||
|
||||
scrolled_window.set_child(Some(&list_view));
|
||||
scrolled_window.set_widget_name("results-container");
|
||||
scrolled_window.add_css_class("launcher-results-container");
|
||||
|
||||
main_box.append(&search_input);
|
||||
main_box.append(&scrolled_window);
|
||||
main_box.set_widget_name("main-container");
|
||||
main_box.add_css_class("launcher-main");
|
||||
|
||||
window.set_child(Some(&main_box));
|
||||
window.set_widget_name("launcher-window");
|
||||
window.add_css_class("launcher-window");
|
||||
|
||||
// Set up layer shell so the launcher can float
|
||||
window.init_layer_shell();
|
||||
@ -330,6 +351,57 @@ impl GtkLauncherUI {
|
||||
pub fn show(&self) {
|
||||
self.window.present();
|
||||
}
|
||||
|
||||
/// Apply default built-in CSS styles
|
||||
pub fn apply_default_css(&self) -> Result<(), String> {
|
||||
const DEFAULT_CSS: &str = include_str!("default.css");
|
||||
|
||||
let css_provider = gtk::CssProvider::new();
|
||||
css_provider.load_from_data(DEFAULT_CSS);
|
||||
|
||||
if let Some(display) = gtk::gdk::Display::default() {
|
||||
gtk::style_context_add_provider_for_display(
|
||||
&display,
|
||||
&css_provider,
|
||||
gtk::STYLE_PROVIDER_PRIORITY_APPLICATION,
|
||||
);
|
||||
Ok(())
|
||||
} else {
|
||||
Err("Could not get default display".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn apply_css<P: AsRef<Path>>(&self, css_path: P) -> Result<(), String> {
|
||||
let css_provider = gtk::CssProvider::new();
|
||||
|
||||
// Check if file exists first
|
||||
if !css_path.as_ref().exists() {
|
||||
return Err(format!("CSS file does not exist: {}", css_path.as_ref().display()));
|
||||
}
|
||||
|
||||
// Try to load the CSS file
|
||||
// Note: load_from_path doesn't return a Result, it panics on error
|
||||
// So we'll use a different approach with error handling
|
||||
use std::fs;
|
||||
match fs::read_to_string(css_path.as_ref()) {
|
||||
Ok(css_content) => {
|
||||
css_provider.load_from_data(&css_content);
|
||||
|
||||
// Apply the CSS to the display
|
||||
if let Some(display) = gtk::gdk::Display::default() {
|
||||
gtk::style_context_add_provider_for_display(
|
||||
&display,
|
||||
&css_provider,
|
||||
gtk::STYLE_PROVIDER_PRIORITY_APPLICATION,
|
||||
);
|
||||
Ok(())
|
||||
} else {
|
||||
Err("Could not get default display".to_string())
|
||||
}
|
||||
}
|
||||
Err(e) => Err(format!("Failed to read CSS file: {}", e))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn find_icon_file(
|
||||
|
Loading…
x
Reference in New Issue
Block a user