mirror of
https://github.com/PancakeTAS/lsfg-vk.git
synced 2025-10-30 07:01:10 +00:00
ui: create wrappers for ui
This commit is contained in:
parent
850c8476c8
commit
bb13eb4656
7 changed files with 268 additions and 495 deletions
519
ui/src/main.rs
519
ui/src/main.rs
|
|
@ -1,497 +1,26 @@
|
|||
use gtk::prelude::*;
|
||||
use gtk::{glib, CssProvider, Builder, Label};
|
||||
use libadwaita::ApplicationWindow;
|
||||
use libadwaita::prelude::AdwApplicationWindowExt;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
use adw;
|
||||
use gtk::{gio, prelude::*};
|
||||
|
||||
// Import modules
|
||||
mod config;
|
||||
mod app_state;
|
||||
mod utils;
|
||||
mod settings_window;
|
||||
|
||||
use config::load_config;
|
||||
use app_state::AppState;
|
||||
use utils::round_to_2_decimals;
|
||||
use config::OrderedGlobalConfig;
|
||||
|
||||
fn main() -> glib::ExitCode {
|
||||
let application = libadwaita::Application::builder()
|
||||
.application_id("com.cali666.lsfg-vk-ui")
|
||||
.build();
|
||||
|
||||
// Set the desktop file name for proper GNOME integration
|
||||
glib::set_application_name("LSFG-VK UI");
|
||||
glib::set_prgname(Some("lsfg-vk-ui"));
|
||||
|
||||
application.connect_startup(move |_app| {
|
||||
// Load CSS for sidebar background
|
||||
let provider = CssProvider::new();
|
||||
provider.load_from_data(&format!(
|
||||
".settings-icon-button {{
|
||||
font-size: 1.4rem;
|
||||
}}
|
||||
|
||||
.sidebar {{
|
||||
background-color: @theme_bg_color;
|
||||
}}
|
||||
|
||||
.sidebar-content {{
|
||||
background-color: shade(@theme_bg_color, {});
|
||||
color: @theme_fg_color;
|
||||
padding: 12px;
|
||||
}}\n
|
||||
.linked-button-box {{
|
||||
margin-top: 12px;
|
||||
margin-bottom: 12px;
|
||||
}}",
|
||||
0.95
|
||||
));
|
||||
gtk::style_context_add_provider_for_display(
|
||||
>k::gdk::Display::default().expect("Could not connect to a display."),
|
||||
&provider,
|
||||
gtk::STYLE_PROVIDER_PRIORITY_APPLICATION,
|
||||
);
|
||||
|
||||
// Set up icon theme for the application icon
|
||||
if let Some(display) = gtk::gdk::Display::default() {
|
||||
let icon_theme = gtk::IconTheme::for_display(&display);
|
||||
icon_theme.add_resource_path("/com/cali666/lsfg-vk-ui/icons");
|
||||
}
|
||||
});
|
||||
|
||||
application.connect_activate(move |app| {
|
||||
// Load initial configuration
|
||||
let initial_config = load_config().unwrap_or_else(|e| {
|
||||
eprintln!("Error loading config: {}", e);
|
||||
// Corrected Config initialization
|
||||
config::Config { version: 1, ordered_global: OrderedGlobalConfig { global: None }, game: Vec::new() }
|
||||
});
|
||||
|
||||
// Load UI from .ui file
|
||||
let ui_bytes = include_bytes!("../resources/ui.ui");
|
||||
let builder = Builder::from_string(std::str::from_utf8(ui_bytes).unwrap());
|
||||
|
||||
// Get main window and other widgets
|
||||
let main_window: ApplicationWindow = builder
|
||||
.object("main_window")
|
||||
.expect("Could not get main_window from builder");
|
||||
main_window.set_application(Some(app));
|
||||
|
||||
let settings_button: gtk::Button = builder
|
||||
.object("settings_button")
|
||||
.expect("Could not get settings_button from builder");
|
||||
|
||||
// Set application icon for proper dock integration
|
||||
main_window.set_icon_name(Some("com.cali666.lsfg-vk-ui"));
|
||||
|
||||
let sidebar_list_box: gtk::ListBox = builder
|
||||
.object("sidebar_list_box")
|
||||
.expect("Could not get sidebar_list_box from builder");
|
||||
let create_profile_button: gtk::Button = builder
|
||||
.object("create_profile_button")
|
||||
.expect("Could not get create_profile_button from builder");
|
||||
|
||||
let multiplier_dropdown: gtk::DropDown = builder
|
||||
.object("multiplier_dropdown")
|
||||
.expect("Could not get multiplier_dropdown from builder");
|
||||
let flow_scale_entry: gtk::Entry = builder
|
||||
.object("flow_scale_entry")
|
||||
.expect("Could not get flow_scale_entry from builder");
|
||||
let performance_mode_switch: gtk::Switch = builder
|
||||
.object("performance_mode_switch")
|
||||
.expect("Could not get performance_mode_switch from builder");
|
||||
let hdr_mode_switch: gtk::Switch = builder
|
||||
.object("hdr_mode_switch")
|
||||
.expect("Could not get hdr_mode_switch from builder");
|
||||
let experimental_present_mode_dropdown: gtk::DropDown = builder
|
||||
.object("experimental_present_mode_dropdown")
|
||||
.expect("Could not get experimental_present_mode_dropdown from builder");
|
||||
|
||||
let main_stack: gtk::Stack = builder
|
||||
.object("main_stack")
|
||||
.expect("Could not get main_stack from builder. Ensure it has id='main_stack' in ui.ui.");
|
||||
let main_stack_switcher: gtk::StackSwitcher = builder
|
||||
.object("main_stack_switcher")
|
||||
.expect("Could not get main_stack_switcher from builder. Ensure it has id='main_stack_switcher' in ui.ui.");
|
||||
|
||||
main_stack_switcher.set_stack(Some(&main_stack));
|
||||
|
||||
let main_settings_box: gtk::Box = builder
|
||||
.object("main_box")
|
||||
.expect("Could not get main_box from builder");
|
||||
|
||||
let save_button = gtk::Button::builder()
|
||||
.label("Save Changes")
|
||||
.halign(gtk::Align::End)
|
||||
.margin_end(12)
|
||||
.margin_bottom(12)
|
||||
.build();
|
||||
|
||||
main_settings_box.append(&save_button);
|
||||
|
||||
// Initialize application state (with None for handler IDs initially)
|
||||
let app_state = Rc::new(RefCell::new(AppState {
|
||||
config: initial_config,
|
||||
selected_profile_index: None,
|
||||
main_window: main_window.clone(),
|
||||
sidebar_list_box: sidebar_list_box.clone(),
|
||||
multiplier_dropdown: multiplier_dropdown.clone(),
|
||||
flow_scale_entry: flow_scale_entry.clone(),
|
||||
performance_mode_switch: performance_mode_switch.clone(),
|
||||
hdr_mode_switch: hdr_mode_switch.clone(),
|
||||
experimental_present_mode_dropdown: experimental_present_mode_dropdown.clone(),
|
||||
save_button: save_button.clone(),
|
||||
main_settings_box: main_settings_box.clone(),
|
||||
main_stack: main_stack.clone(),
|
||||
multiplier_dropdown_handler_id: None,
|
||||
flow_scale_entry_handler_id: None,
|
||||
performance_mode_switch_handler_id: None,
|
||||
hdr_mode_switch_handler_id: None,
|
||||
experimental_present_mode_dropdown_handler_id: None,
|
||||
}));
|
||||
|
||||
// --- Connect Signals ---
|
||||
|
||||
// Connect settings button
|
||||
let main_window_clone = main_window.clone();
|
||||
let app_state_clone_for_settings = app_state.clone(); // Clone for settings window
|
||||
settings_button.connect_clicked(move |_| {
|
||||
let settings_win = settings_window::create_settings_window(&main_window_clone, app_state_clone_for_settings.clone());
|
||||
settings_win.present();
|
||||
});
|
||||
|
||||
let app_state_clone = app_state.clone();
|
||||
sidebar_list_box.connect_row_activated(move |_list_box, row| {
|
||||
let index = row.index() as usize;
|
||||
let mut state = app_state_clone.borrow_mut();
|
||||
state.selected_profile_index = Some(index);
|
||||
drop(state);
|
||||
|
||||
let app_state_for_idle = app_state_clone.clone();
|
||||
glib::idle_add_local(move || {
|
||||
app_state_for_idle.borrow().update_main_window_from_profile();
|
||||
glib::ControlFlow::Break
|
||||
});
|
||||
});
|
||||
|
||||
let app_state_clone = app_state.clone();
|
||||
create_profile_button.connect_clicked(move |_| {
|
||||
let dialog = gtk::MessageDialog::new(
|
||||
Some(&app_state_clone.borrow().main_window),
|
||||
gtk::DialogFlags::MODAL,
|
||||
gtk::MessageType::Question,
|
||||
gtk::ButtonsType::None,
|
||||
"",
|
||||
);
|
||||
dialog.set_title(Some("New Profile"));
|
||||
dialog.set_secondary_text(Some("Enter or browse Application Name"));
|
||||
|
||||
let entry = gtk::Entry::builder()
|
||||
.placeholder_text("Application Name")
|
||||
.hexpand(true)
|
||||
.build();
|
||||
|
||||
let pick_process_button = gtk::Button::builder()
|
||||
.label("🖵")
|
||||
.tooltip_text("Pick a running Vulkan process")
|
||||
.css_classes(["flat", "square", "icon-button"])
|
||||
.build();
|
||||
|
||||
let entry_box = gtk::Box::builder()
|
||||
.orientation(gtk::Orientation::Horizontal)
|
||||
.spacing(6)
|
||||
.margin_top(12)
|
||||
.margin_bottom(12)
|
||||
.margin_start(12)
|
||||
.margin_end(12)
|
||||
.build();
|
||||
entry_box.append(&entry);
|
||||
entry_box.append(&pick_process_button);
|
||||
|
||||
dialog.content_area().append(&entry_box);
|
||||
|
||||
dialog.add_button("Cancel", gtk::ResponseType::Cancel);
|
||||
dialog.add_button("Create", gtk::ResponseType::Other(1));
|
||||
|
||||
dialog.set_default_response(gtk::ResponseType::Other(1));
|
||||
|
||||
// Allow pressing Enter in the entry to trigger the "Create" button
|
||||
let dialog_clone = dialog.clone();
|
||||
entry.connect_activate(move |_| {
|
||||
dialog_clone.response(gtk::ResponseType::Other(1));
|
||||
});
|
||||
|
||||
// --- Process Picker Button Logic ---
|
||||
let entry_clone_for_picker = entry.clone();
|
||||
let main_window_clone_for_picker = app_state_clone.borrow().main_window.clone();
|
||||
|
||||
pick_process_button.connect_clicked(move |_| {
|
||||
let process_picker_window = libadwaita::ApplicationWindow::builder()
|
||||
.title("Select Process")
|
||||
.transient_for(&main_window_clone_for_picker)
|
||||
.modal(true)
|
||||
.default_width(400)
|
||||
.default_height(600)
|
||||
.build();
|
||||
|
||||
let scrolled_window = gtk::ScrolledWindow::builder()
|
||||
.hscrollbar_policy(gtk::PolicyType::Never)
|
||||
.vscrollbar_policy(gtk::PolicyType::Automatic)
|
||||
.hexpand(true) // Make the scrolled window expand horizontally
|
||||
.vexpand(true) // Make the scrolled window expand vertically
|
||||
.margin_top(12)
|
||||
.margin_start(12)
|
||||
.margin_end(12)
|
||||
.build();
|
||||
|
||||
let process_list_box = gtk::ListBox::builder()
|
||||
.selection_mode(gtk::SelectionMode::Single)
|
||||
.build();
|
||||
scrolled_window.set_child(Some(&process_list_box));
|
||||
|
||||
let content_box = gtk::Box::builder()
|
||||
.orientation(gtk::Orientation::Vertical)
|
||||
.build();
|
||||
content_box.append(&scrolled_window); // Add scrolled window first to take up space
|
||||
|
||||
let close_button = gtk::Button::builder()
|
||||
.label("Close")
|
||||
.halign(gtk::Align::End)
|
||||
.margin_end(12)
|
||||
.margin_bottom(12)
|
||||
.build();
|
||||
content_box.append(&close_button); // Add close button at the bottom
|
||||
|
||||
process_picker_window.set_content(Some(&content_box));
|
||||
|
||||
// Populate the list with processes
|
||||
let processes = utils::get_vulkan_processes(); // Call the new function from utils.rs
|
||||
for proc_name in processes {
|
||||
let row = gtk::ListBoxRow::new();
|
||||
let label = gtk::Label::builder()
|
||||
.label(&proc_name)
|
||||
.halign(gtk::Align::Start)
|
||||
.margin_start(12)
|
||||
.margin_end(12)
|
||||
.margin_top(8)
|
||||
.margin_bottom(8)
|
||||
.build();
|
||||
row.set_child(Some(&label));
|
||||
process_list_box.append(&row);
|
||||
}
|
||||
|
||||
// Connect selection handler
|
||||
let entry_clone_for_select = entry_clone_for_picker.clone();
|
||||
let picker_window_clone = process_picker_window.clone();
|
||||
process_list_box.connect_row_activated(move |_list_box, row| {
|
||||
if let Some(label_widget) = row.child().and_then(|c| c.downcast::<gtk::Label>().ok()) {
|
||||
let process_name = label_widget.label().to_string();
|
||||
entry_clone_for_select.set_text(&process_name);
|
||||
picker_window_clone.close();
|
||||
}
|
||||
});
|
||||
|
||||
// Connect close button
|
||||
let picker_window_clone_for_close = process_picker_window.clone();
|
||||
close_button.connect_clicked(move |_| {
|
||||
picker_window_clone_for_close.close();
|
||||
});
|
||||
|
||||
process_picker_window.present();
|
||||
});
|
||||
// --- End Process Picker Button Logic ---
|
||||
|
||||
let app_state_clone_dialog = app_state_clone.clone();
|
||||
let entry_clone = entry.clone();
|
||||
dialog.connect_response(
|
||||
move |d: >k::MessageDialog, response: gtk::ResponseType| {
|
||||
if response == gtk::ResponseType::Other(1) {
|
||||
let game_name = entry_clone.text().to_string();
|
||||
if !game_name.is_empty() {
|
||||
let mut state = app_state_clone_dialog.borrow_mut();
|
||||
|
||||
if state.config.game.iter().any(|p| p.exe == game_name) {
|
||||
let error_dialog = gtk::MessageDialog::new(
|
||||
Some(d),
|
||||
gtk::DialogFlags::MODAL,
|
||||
gtk::MessageType::Error,
|
||||
gtk::ButtonsType::Ok,
|
||||
"A profile with this name already exists",
|
||||
);
|
||||
error_dialog.set_title(Some("Error"));
|
||||
error_dialog.connect_response(move |d, _| { d.close(); });
|
||||
error_dialog.present();
|
||||
return;
|
||||
}
|
||||
|
||||
let new_profile = config::GameProfile {
|
||||
exe: game_name,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
state.config.game.push(new_profile);
|
||||
state.selected_profile_index = Some(state.config.game.len() - 1);
|
||||
|
||||
state.save_current_config();
|
||||
|
||||
state.populate_sidebar_with_handlers(Some(app_state_clone_dialog.clone()));
|
||||
drop(state);
|
||||
|
||||
let app_state_for_idle = app_state_clone_dialog.clone();
|
||||
glib::idle_add_local(move || {
|
||||
app_state_for_idle.borrow().update_main_window_from_profile();
|
||||
glib::ControlFlow::Break
|
||||
});
|
||||
}
|
||||
}
|
||||
d.close();
|
||||
}
|
||||
);
|
||||
dialog.present();
|
||||
});
|
||||
|
||||
let app_state_clone_for_handler_mult = app_state.clone();
|
||||
let multiplier_handler_id = multiplier_dropdown.connect_selected_item_notify(move |dropdown| {
|
||||
let mut state = app_state_clone_for_handler_mult.borrow_mut();
|
||||
|
||||
if let Some(index) = state.selected_profile_index {
|
||||
if index < state.config.game.len() {
|
||||
if let Some(profile) = state.config.game.get_mut(index) {
|
||||
if let Some(item) = dropdown.selected_item() {
|
||||
if let Some(string_obj) = item.downcast_ref::<gtk::StringObject>() {
|
||||
let text = string_obj.string();
|
||||
profile.multiplier = match text.as_str() {
|
||||
"off" => 1,
|
||||
_ => text.parse().unwrap_or(1),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
app_state.borrow_mut().multiplier_dropdown_handler_id = Some(multiplier_handler_id);
|
||||
|
||||
let app_state_clone_for_handler_flow = app_state.clone();
|
||||
let flow_handler_id = flow_scale_entry.connect_changed(move |entry| {
|
||||
let mut state = app_state_clone_for_handler_flow.borrow_mut();
|
||||
if let Some(index) = state.selected_profile_index {
|
||||
if let Some(profile) = state.config.game.get_mut(index) {
|
||||
if let Ok(value) = entry.text().parse::<f32>() {
|
||||
profile.flow_scale = round_to_2_decimals(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
app_state.borrow_mut().flow_scale_entry_handler_id = Some(flow_handler_id);
|
||||
|
||||
let app_state_clone_for_handler_perf = app_state.clone();
|
||||
let perf_handler_id = performance_mode_switch.connect_state_set(move |_sw, active| {
|
||||
let mut state = app_state_clone_for_handler_perf.borrow_mut();
|
||||
if let Some(index) = state.selected_profile_index {
|
||||
if let Some(profile) = state.config.game.get_mut(index) {
|
||||
profile.performance_mode = active;
|
||||
}
|
||||
}
|
||||
drop(state);
|
||||
glib::Propagation::Proceed
|
||||
});
|
||||
app_state.borrow_mut().performance_mode_switch_handler_id = Some(perf_handler_id);
|
||||
|
||||
let app_state_clone_for_handler_hdr = app_state.clone();
|
||||
let hdr_handler_id = hdr_mode_switch.connect_state_set(move |_sw, active| {
|
||||
let mut state = app_state_clone_for_handler_hdr.borrow_mut();
|
||||
if let Some(index) = state.selected_profile_index {
|
||||
if let Some(profile) = state.config.game.get_mut(index) {
|
||||
profile.hdr_mode = active;
|
||||
}
|
||||
}
|
||||
drop(state);
|
||||
glib::Propagation::Proceed
|
||||
});
|
||||
app_state.borrow_mut().hdr_mode_switch_handler_id = Some(hdr_handler_id);
|
||||
|
||||
let app_state_clone_for_handler_exp = app_state.clone();
|
||||
let exp_handler_id = experimental_present_mode_dropdown.connect_selected_item_notify(move |dropdown| {
|
||||
let mut state = app_state_clone_for_handler_exp.borrow_mut();
|
||||
if let Some(index) = state.selected_profile_index {
|
||||
if let Some(profile) = state.config.game.get_mut(index) {
|
||||
let selected_text = dropdown.selected_item().and_then(|item| item.downcast_ref::<gtk::StringObject>().map(|s| s.string().to_string()));
|
||||
if let Some(text) = selected_text {
|
||||
profile.experimental_present_mode = text;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
app_state.borrow_mut().experimental_present_mode_dropdown_handler_id = Some(exp_handler_id);
|
||||
|
||||
let app_state_clone_save = app_state.clone();
|
||||
save_button.connect_clicked(move |_| {
|
||||
let state_ref = app_state_clone_save.borrow();
|
||||
if let Some(index) = state_ref.selected_profile_index {
|
||||
let multiplier_str = state_ref.multiplier_dropdown.selected_item().and_then(|item| item.downcast_ref::<gtk::StringObject>().map(|s| s.string().to_string()));
|
||||
let flow_scale_text = state_ref.flow_scale_entry.text().to_string();
|
||||
let performance_mode_active = state_ref.performance_mode_switch.is_active();
|
||||
let hdr_mode_active = state_ref.hdr_mode_switch.is_active();
|
||||
let exp_mode_str = state_ref.experimental_present_mode_dropdown.selected_item().and_then(|item| item.downcast_ref::<gtk::StringObject>().map(|s| s.string().to_string()));
|
||||
|
||||
drop(state_ref);
|
||||
|
||||
let mut state = app_state_clone_save.borrow_mut();
|
||||
if let Some(profile) = state.config.game.get_mut(index) {
|
||||
if let Some(text) = multiplier_str {
|
||||
profile.multiplier = if text == "off" { 1 } else { text.parse().unwrap_or(1) };
|
||||
}
|
||||
|
||||
if let Ok(value) = flow_scale_text.parse::<f32>() {
|
||||
profile.flow_scale = round_to_2_decimals(value);
|
||||
}
|
||||
|
||||
profile.performance_mode = performance_mode_active;
|
||||
profile.hdr_mode = hdr_mode_active;
|
||||
|
||||
if let Some(text) = exp_mode_str {
|
||||
profile.experimental_present_mode = text;
|
||||
}
|
||||
|
||||
state.save_current_config();
|
||||
|
||||
let feedback_label = Label::new(Some("Saved!"));
|
||||
feedback_label.set_halign(gtk::Align::End);
|
||||
feedback_label.set_margin_end(12);
|
||||
feedback_label.set_margin_bottom(12);
|
||||
|
||||
let main_settings_box_clone = state.main_settings_box.clone();
|
||||
|
||||
main_settings_box_clone.append(&feedback_label);
|
||||
|
||||
glib::timeout_add_local(std::time::Duration::new(2, 0), move || {
|
||||
main_settings_box_clone.remove(&feedback_label);
|
||||
glib::ControlFlow::Break
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let app_state_clone_initial = app_state.clone();
|
||||
glib::idle_add_local(move || {
|
||||
let mut state = app_state_clone_initial.borrow_mut();
|
||||
if state.config.game.first().is_some() {
|
||||
state.selected_profile_index = Some(0);
|
||||
}
|
||||
state.populate_sidebar_with_handlers(Some(app_state_clone_initial.clone()));
|
||||
drop(state);
|
||||
|
||||
if app_state_clone_initial.borrow().selected_profile_index.is_some() {
|
||||
app_state_clone_initial.borrow().update_main_window_from_profile();
|
||||
}
|
||||
glib::ControlFlow::Break
|
||||
});
|
||||
|
||||
main_window.present();
|
||||
});
|
||||
|
||||
application.run()
|
||||
pub mod wrapper {
|
||||
pub mod ui;
|
||||
pub mod pref;
|
||||
}
|
||||
|
||||
const APP_ID: &str = "gay.pancake.lsfg-vk.ConfigurationUi";
|
||||
|
||||
fn main() {
|
||||
gio::resources_register_include!("ui.gresource")
|
||||
.expect("Failed to register resources");
|
||||
|
||||
let app = adw::Application::builder()
|
||||
.application_id(APP_ID)
|
||||
.build();
|
||||
app.connect_activate(build_ui);
|
||||
app.run();
|
||||
}
|
||||
|
||||
fn build_ui(app: &adw::Application) {
|
||||
let window = wrapper::ui::Window::new(app);
|
||||
window.set_application(Some(app));
|
||||
window.present();
|
||||
}
|
||||
|
|
|
|||
49
ui/src/wrapper/pref.rs
Normal file
49
ui/src/wrapper/pref.rs
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
use gtk::glib;
|
||||
use gtk;
|
||||
use adw;
|
||||
|
||||
pub mod dropdown;
|
||||
pub mod entry;
|
||||
pub mod switch;
|
||||
|
||||
glib::wrapper! {
|
||||
pub struct PrefDropdown(ObjectSubclass<dropdown::PrefDropdown>)
|
||||
@extends
|
||||
adw::PreferencesRow, gtk::ListBoxRow, gtk::Widget,
|
||||
@implements
|
||||
gtk::Accessible, gtk::Actionable, gtk::Buildable, gtk::ConstraintTarget;
|
||||
}
|
||||
|
||||
glib::wrapper! {
|
||||
pub struct PrefSwitch(ObjectSubclass<switch::PrefSwitch>)
|
||||
@extends
|
||||
adw::PreferencesRow, gtk::ListBoxRow, gtk::Widget,
|
||||
@implements
|
||||
gtk::Accessible, gtk::Actionable, gtk::Buildable, gtk::ConstraintTarget;
|
||||
}
|
||||
|
||||
glib::wrapper! {
|
||||
pub struct PrefEntry(ObjectSubclass<entry::PrefEntry>)
|
||||
@extends
|
||||
adw::PreferencesRow, gtk::ListBoxRow, gtk::Widget,
|
||||
@implements
|
||||
gtk::Accessible, gtk::Actionable, gtk::Buildable, gtk::ConstraintTarget;
|
||||
}
|
||||
|
||||
impl PrefDropdown {
|
||||
pub fn new() -> Self {
|
||||
glib::Object::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl PrefSwitch {
|
||||
pub fn new() -> Self {
|
||||
glib::Object::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl PrefEntry {
|
||||
pub fn new() -> Self {
|
||||
glib::Object::new()
|
||||
}
|
||||
}
|
||||
44
ui/src/wrapper/pref/dropdown.rs
Normal file
44
ui/src/wrapper/pref/dropdown.rs
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
use std::cell::RefCell;
|
||||
|
||||
use gtk::glib;
|
||||
use gtk::subclass::prelude::*;
|
||||
use adw::subclass::prelude::*;
|
||||
use adw::prelude::*;
|
||||
|
||||
#[derive(gtk::CompositeTemplate, glib::Properties, Default)]
|
||||
#[properties(wrapper_type = super::PrefDropdown)]
|
||||
#[template(resource = "/gay/pancake/lsfg-vk/pref/dropdown.ui")]
|
||||
pub struct PrefDropdown {
|
||||
#[property(get, set)]
|
||||
opt_name: RefCell<String>,
|
||||
#[property(get, set)]
|
||||
default_selection: RefCell<u32>,
|
||||
#[property(get, set)]
|
||||
options: RefCell<gtk::StringList>,
|
||||
}
|
||||
|
||||
#[glib::object_subclass]
|
||||
impl ObjectSubclass for PrefDropdown {
|
||||
const NAME: &'static str = "LSPrefDropdown";
|
||||
type Type = super::PrefDropdown;
|
||||
type ParentType = adw::PreferencesRow;
|
||||
|
||||
fn class_init(klass: &mut Self::Class) {
|
||||
klass.bind_template();
|
||||
}
|
||||
|
||||
fn instance_init(obj: &glib::subclass::InitializingObject<Self>) {
|
||||
obj.init_template();
|
||||
}
|
||||
}
|
||||
|
||||
#[glib::derived_properties]
|
||||
impl ObjectImpl for PrefDropdown {
|
||||
fn constructed(&self) {
|
||||
self.parent_constructed();
|
||||
}
|
||||
}
|
||||
|
||||
impl WidgetImpl for PrefDropdown {}
|
||||
impl ListBoxRowImpl for PrefDropdown {}
|
||||
impl PreferencesRowImpl for PrefDropdown {}
|
||||
44
ui/src/wrapper/pref/entry.rs
Normal file
44
ui/src/wrapper/pref/entry.rs
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
use std::cell::RefCell;
|
||||
|
||||
use gtk::glib;
|
||||
use gtk::subclass::prelude::*;
|
||||
use adw::subclass::prelude::*;
|
||||
use adw::prelude::*;
|
||||
|
||||
#[derive(gtk::CompositeTemplate, glib::Properties, Default)]
|
||||
#[properties(wrapper_type = super::PrefEntry)]
|
||||
#[template(resource = "/gay/pancake/lsfg-vk/pref/entry.ui")]
|
||||
pub struct PrefEntry {
|
||||
#[property(get, set)]
|
||||
opt_name: RefCell<String>,
|
||||
#[property(get, set)]
|
||||
default_text: RefCell<String>,
|
||||
#[property(get, set)]
|
||||
tooltip_text: RefCell<String>
|
||||
}
|
||||
|
||||
#[glib::object_subclass]
|
||||
impl ObjectSubclass for PrefEntry {
|
||||
const NAME: &'static str = "LSPrefEntry";
|
||||
type Type = super::PrefEntry;
|
||||
type ParentType = adw::PreferencesRow;
|
||||
|
||||
fn class_init(klass: &mut Self::Class) {
|
||||
klass.bind_template();
|
||||
}
|
||||
|
||||
fn instance_init(obj: &glib::subclass::InitializingObject<Self>) {
|
||||
obj.init_template();
|
||||
}
|
||||
}
|
||||
|
||||
#[glib::derived_properties]
|
||||
impl ObjectImpl for PrefEntry {
|
||||
fn constructed(&self) {
|
||||
self.parent_constructed();
|
||||
}
|
||||
}
|
||||
|
||||
impl WidgetImpl for PrefEntry {}
|
||||
impl ListBoxRowImpl for PrefEntry {}
|
||||
impl PreferencesRowImpl for PrefEntry {}
|
||||
42
ui/src/wrapper/pref/switch.rs
Normal file
42
ui/src/wrapper/pref/switch.rs
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
use std::cell::RefCell;
|
||||
|
||||
use gtk::glib;
|
||||
use gtk::subclass::prelude::*;
|
||||
use adw::subclass::prelude::*;
|
||||
use adw::prelude::*;
|
||||
|
||||
#[derive(gtk::CompositeTemplate, glib::Properties, Default)]
|
||||
#[properties(wrapper_type = super::PrefSwitch)]
|
||||
#[template(resource = "/gay/pancake/lsfg-vk/pref/switch.ui")]
|
||||
pub struct PrefSwitch {
|
||||
#[property(get, set)]
|
||||
opt_name: RefCell<String>,
|
||||
#[property(get, set)]
|
||||
default_state: RefCell<bool>,
|
||||
}
|
||||
|
||||
#[glib::object_subclass]
|
||||
impl ObjectSubclass for PrefSwitch {
|
||||
const NAME: &'static str = "LSPrefSwitch";
|
||||
type Type = super::PrefSwitch;
|
||||
type ParentType = adw::PreferencesRow;
|
||||
|
||||
fn class_init(klass: &mut Self::Class) {
|
||||
klass.bind_template();
|
||||
}
|
||||
|
||||
fn instance_init(obj: &glib::subclass::InitializingObject<Self>) {
|
||||
obj.init_template();
|
||||
}
|
||||
}
|
||||
|
||||
#[glib::derived_properties]
|
||||
impl ObjectImpl for PrefSwitch {
|
||||
fn constructed(&self) {
|
||||
self.parent_constructed();
|
||||
}
|
||||
}
|
||||
|
||||
impl WidgetImpl for PrefSwitch {}
|
||||
impl ListBoxRowImpl for PrefSwitch {}
|
||||
impl PreferencesRowImpl for PrefSwitch {}
|
||||
29
ui/src/wrapper/ui.rs
Normal file
29
ui/src/wrapper/ui.rs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
use gtk::glib;
|
||||
use gtk;
|
||||
use adw;
|
||||
use gtk::glib::types::StaticTypeExt;
|
||||
|
||||
pub mod window;
|
||||
|
||||
glib::wrapper! {
|
||||
pub struct Window(ObjectSubclass<window::Window>)
|
||||
@extends
|
||||
adw::ApplicationWindow, adw::Window,
|
||||
gtk::ApplicationWindow, gtk::Window, gtk::Widget,
|
||||
@implements
|
||||
gtk::gio::ActionGroup, gtk::gio::ActionMap,
|
||||
gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget,
|
||||
gtk::Native, gtk::Root, gtk::ShortcutManager;
|
||||
}
|
||||
|
||||
impl Window {
|
||||
pub fn new(app: &adw::Application) -> Self {
|
||||
super::pref::PrefDropdown::ensure_type();
|
||||
super::pref::PrefSwitch::ensure_type();
|
||||
super::pref::PrefEntry::ensure_type();
|
||||
|
||||
glib::Object::builder()
|
||||
.property("application", app)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
36
ui/src/wrapper/ui/window.rs
Normal file
36
ui/src/wrapper/ui/window.rs
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
use gtk::subclass::prelude::*;
|
||||
use adw::subclass::prelude::*;
|
||||
use gtk::{glib, CompositeTemplate};
|
||||
|
||||
#[derive(CompositeTemplate, Default)]
|
||||
#[template(resource = "/gay/pancake/lsfg-vk/window.ui")]
|
||||
pub struct Window {
|
||||
|
||||
}
|
||||
|
||||
#[glib::object_subclass]
|
||||
impl ObjectSubclass for Window {
|
||||
const NAME: &'static str = "LSApplicationWindow";
|
||||
type Type = super::Window;
|
||||
type ParentType = adw::ApplicationWindow;
|
||||
|
||||
fn class_init(klass: &mut Self::Class) {
|
||||
klass.bind_template();
|
||||
}
|
||||
|
||||
fn instance_init(obj: &glib::subclass::InitializingObject<Self>) {
|
||||
obj.init_template();
|
||||
}
|
||||
}
|
||||
|
||||
impl ObjectImpl for Window {
|
||||
fn constructed(&self) {
|
||||
self.parent_constructed();
|
||||
}
|
||||
}
|
||||
|
||||
impl WidgetImpl for Window {}
|
||||
impl WindowImpl for Window {}
|
||||
impl ApplicationWindowImpl for Window {}
|
||||
impl AdwWindowImpl for Window {}
|
||||
impl AdwApplicationWindowImpl for Window {}
|
||||
Loading…
Add table
Reference in a new issue