Commit f7ff00c4 authored by Bilal Elmoussaoui's avatar Bilal Elmoussaoui
Browse files

subclass application & window

parent 6c34856d
Pipeline #161713 passed with stage
in 6 minutes and 59 seconds
......@@ -3,7 +3,6 @@ data/org.gnome.design.Contrast.gschema.xml.in
data/org.gnome.design.Contrast.metainfo.xml.in.in
data/resources/ui/about_dialog.ui.in
data/resources/ui/shortcuts.ui
data/resources/ui/window.ui.in
src/contrast_level.rs
src/contrast_preview.rs
src/main.rs
......
......@@ -2,77 +2,111 @@ use super::config;
use super::window::Window;
use gio::prelude::*;
use glib::Receiver;
use glib::subclass;
use glib::subclass::prelude::*;
use glib::translate::*;
use glib::{Receiver, Sender};
use gtk::prelude::*;
use gtk::subclass::prelude::{ApplicationImpl, GtkApplicationImpl};
use gtk::SettingsExt;
use std::cell::RefCell;
use std::env;
use std::{cell::RefCell, rc::Rc};
pub enum Action {
ApplyStylesheet(String),
}
pub struct Application {
app: gtk::Application,
window: Window,
provider: gtk::CssProvider,
pub struct ApplicationPrivate {
sender: Sender<Action>,
receiver: RefCell<Option<Receiver<Action>>>,
window: RefCell<Option<Window>>,
provider: gtk::CssProvider,
}
impl Application {
pub fn new() -> Rc<Self> {
let app = gtk::Application::new(Some(config::APP_ID), gio::ApplicationFlags::FLAGS_NONE).unwrap();
impl ObjectSubclass for ApplicationPrivate {
const NAME: &'static str = "Application";
type ParentType = gtk::Application;
type Instance = subclass::simple::InstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
glib_object_subclass!();
fn new() -> Self {
let (sender, r) = glib::MainContext::channel(glib::PRIORITY_DEFAULT);
let receiver = RefCell::new(Some(r));
let window = Window::new(sender, &app);
let provider = gtk::CssProvider::new();
Self {
sender,
receiver,
window: RefCell::new(None),
provider,
}
}
}
impl ObjectImpl for ApplicationPrivate {
glib_object_impl!();
}
let application = Rc::new(Self { app, window, provider, receiver });
application.setup_gactions();
application.setup_signals();
application.setup_css();
application
// Implement Gtk.Application
impl GtkApplicationImpl for ApplicationPrivate {}
impl ApplicationImpl for ApplicationPrivate {
fn activate(&self, _app: &gio::Application) {
if let Some(ref window) = *self.window.borrow() {
window.present();
return;
}
// No window available -> we have to create one
let app = ObjectSubclass::get_instance(self).downcast::<Application>().unwrap();
let window = app.create_window();
window.present();
self.window.replace(Some(window));
info!("Created application window.");
// Setup action channel
let receiver = self.receiver.borrow_mut().take().unwrap();
receiver.attach(None, move |action| app.do_action(action));
}
}
fn setup_gactions(&self) {
// Quit
action!(
self.app,
"quit",
clone!(@strong self.app as app => move |_, _| {
app.quit();
})
);
// About
action!(
self.app,
"about",
clone!(@weak self.window as window => move |_, _| {
let builder = gtk::Builder::new_from_resource("/org/gnome/design/Contrast/about_dialog.ui");
get_widget!(builder, gtk::AboutDialog, about_dialog);
about_dialog.set_transient_for(Some(&window));
about_dialog.connect_response(|dialog, _| dialog.destroy());
about_dialog.show();
})
);
glib_wrapper! {
pub struct Application(
Object<subclass::simple::InstanceStruct<ApplicationPrivate>,
subclass::simple::ClassStruct<ApplicationPrivate>,
SwApplicationClass>)
@extends gio::Application, gtk::Application;
// Accels
self.app.set_accels_for_action("app.quit", &["<primary>q"]);
self.app.set_accels_for_action("win.show-help-overlay", &["<primary>question"]);
self.app.set_accels_for_action("window.reverse-colors", &["<primary>r"]);
match fn {
get_type => || ApplicationPrivate::get_type().to_glib(),
}
}
fn setup_signals(&self) {
self.app.connect_activate(clone!(@weak self.window as window => move |app| {
window.set_application(Some(app));
app.add_window(&window);
window.present();
}));
impl Application {
pub fn run() {
info!("{}Contrast ({})", config::NAME_PREFIX, config::APP_ID);
info!("Version: {} ({})", config::VERSION, config::PROFILE);
info!("Datadir: {}", config::PKGDATADIR);
// Create new GObject and downcast it into SwApplication
let app = glib::Object::new(Application::static_type(), &[("application-id", &Some(config::APP_ID)), ("flags", &gio::ApplicationFlags::empty())])
.unwrap()
.downcast::<Application>()
.unwrap();
app.setup_accels();
// Start running gtk::Application
let args: Vec<String> = env::args().collect();
ApplicationExtManual::run(&app, &args);
}
fn setup_css(&self) {
fn create_window(&self) -> Window {
let self_ = ApplicationPrivate::from_instance(self);
let window = Window::new(self_.sender.clone(), &self.clone());
// Load custom styling
if let Some(gtk_settings) = gtk::Settings::get_default() {
gtk_settings.set_property_gtk_theme_name(Some("Adwaita"));
}
......@@ -82,34 +116,32 @@ impl Application {
}
if let Some(screen) = gdk::Screen::get_default() {
gtk::StyleContext::add_provider_for_screen(&screen, &self.provider, 400);
gtk::StyleContext::add_provider_for_screen(&screen, &self_.provider, 400);
let p = gtk::CssProvider::new();
gtk::CssProvider::load_from_resource(&p, "/org/gnome/design/Contrast/style.css");
gtk::StyleContext::add_provider_for_screen(&screen, &p, 500);
}
window
}
fn setup_accels(&self) {
// Accels
self.set_accels_for_action("app.quit", &["<primary>q"]);
self.set_accels_for_action("win.show-help-overlay", &["<primary>question"]);
self.set_accels_for_action("window.reverse-colors", &["<primary>r"]);
}
fn do_action(&self, action: Action) -> glib::Continue {
let self_ = ApplicationPrivate::from_instance(self);
match action {
Action::ApplyStylesheet(text) => {
if let Err(err) = self.provider.load_from_data(text.as_bytes()) {
if let Err(err) = self_.provider.load_from_data(text.as_bytes()) {
error!("Stylesheet couldn't be updated {}", err);
}
}
};
glib::Continue(true)
}
pub fn run(&self, app: Rc<Self>) {
info!("{}Contrast ({})", config::NAME_PREFIX, config::APP_ID);
info!("Version: {} ({})", config::VERSION, config::PROFILE);
info!("Datadir: {}", config::PKGDATADIR);
let receiver = self.receiver.borrow_mut().take().unwrap();
receiver.attach(None, move |action| app.do_action(action));
let args: Vec<String> = env::args().collect();
self.app.run(&args);
}
}
......@@ -98,16 +98,15 @@ impl ColourPopover {
}
fn fill_palette(&self) {
let mut colours = vec![];
for colour in ADWAITA_COLORS.iter() {
let rgb = gdk::RGBA {
let colours = ADWAITA_COLORS
.iter()
.map(|colour| gdk::RGBA {
red: colour.0 / 255.0,
green: colour.1 / 255.0,
blue: colour.2 / 255.0,
alpha: 1.0,
};
colours.push(rgb);
}
})
.collect::<Vec<gdk::RGBA>>();
self.color_chooser.add_palette(gtk::Orientation::Vertical, 5, &colours);
}
}
......@@ -36,6 +36,5 @@ fn main() {
static_resources::init().expect("Failed to initialize the resource file.");
let app = Application::new();
app.run(app.clone());
Application::run();
}
use super::application::Action;
use super::application::{Action, Application};
use super::colour;
use super::colour_entry::ColourEntry;
use super::config::PROFILE;
use super::config::{APP_ID, PROFILE};
use super::contrast_level::ContrastLevelBar;
use super::contrast_preview::ContrastPreview;
use super::window_state::WindowState;
......@@ -64,13 +64,17 @@ impl ObjectImpl for WindowPrivate {
if PROFILE == "Devel" {
self_.get_style_context().add_class("devel");
}
self_.set_icon_name(Some(APP_ID));
// Keyboard Shortcuts
let builder = gtk::Builder::new_from_resource("/org/gnome/design/Contrast/shortcuts.ui");
get_widget!(builder, gtk::ShortcutsWindow, shortcuts_dialog);
self_.set_help_overlay(Some(&shortcuts_dialog));
let container = gtk::Box::new(gtk::Orientation::Vertical, 0);
container.get_style_context().add_class("main-container");
container.set_valign(gtk::Align::Center);
// Header Bar
let headerbar = libhandy::HeaderBar::new();
headerbar.set_show_close_button(true);
headerbar.set_title(Some(&gettext("Contrast")));
self_.set_titlebar(Some(&headerbar));
self.fg_entry.get_entry().get_style_context().add_class("fg-entry");
self.bg_entry.get_entry().get_style_context().add_class("bg-entry");
......@@ -86,12 +90,7 @@ impl ObjectImpl for WindowPrivate {
entries_container.pack_start(&reverse_btn, false, false, 6);
entries_container.pack_start(&self.fg_entry, false, false, 6);
entries_container.set_halign(gtk::Align::Center);
let headerbar = libhandy::HeaderBar::new();
headerbar.set_show_close_button(true);
headerbar.set_title(Some(&gettext("Contrast")));
headerbar.set_custom_title(Some(&entries_container));
self_.set_titlebar(Some(&headerbar));
let primary_menu = gio::Menu::new();
primary_menu.append(Some(&gettext("_Keyboard Shortcuts")), Some("win.show-help-overlay"));
......@@ -105,6 +104,11 @@ impl ObjectImpl for WindowPrivate {
primary_btn.set_popover(Some(&primary_popover));
headerbar.pack_end(&primary_btn);
// Main Container: Composed of ContrastPreview & ContrastLevelBar
let container = gtk::Box::new(gtk::Orientation::Vertical, 0);
container.get_style_context().add_class("main-container");
container.set_valign(gtk::Align::Center);
container.pack_start(&self.preview, true, true, 12);
container.pack_start(&self.levelbar.borrow().widget, true, true, 12);
......@@ -138,9 +142,10 @@ glib_wrapper! {
}
impl Window {
pub fn new(sender: glib::Sender<Action>, app: &gtk::Application) -> Self {
pub fn new(sender: glib::Sender<Action>, app: &Application) -> Self {
let window = glib::Object::new(Window::static_type(), &[("application", app)]).unwrap().downcast::<Window>().unwrap();
window.setup_signals(sender);
window.setup_actions(app);
window
}
......@@ -179,7 +184,6 @@ impl Window {
let bg_handle = self_.bg_entry.get_entry().connect_changed(on_entry_changed.clone());
let fg_handle = self_.fg_entry.get_entry().connect_changed(on_entry_changed);
let actions = gio::SimpleActionGroup::new();
action!(
actions,
......@@ -200,7 +204,31 @@ impl Window {
})
);
self.insert_action_group("window", Some(&actions));
self.colour_changed(self_.bg_entry.get_text(), self_.fg_entry.get_text());
}
fn setup_actions(&self, app: &Application) {
// Quit
action!(
self.get_application().unwrap(),
"quit",
clone!(@strong app => move |_, _| {
app.quit();
})
);
// About
action!(
self.get_application().unwrap(),
"about",
clone!(@strong self as window => move |_, _| {
let builder = gtk::Builder::new_from_resource("/org/gnome/design/Contrast/about_dialog.ui");
get_widget!(builder, gtk::AboutDialog, about_dialog);
about_dialog.set_transient_for(Some(&window));
about_dialog.connect_response(|dialog, _| dialog.destroy());
about_dialog.show();
})
);
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment