2022-07-17 11:46:05 +00:00
# window.py
#
2022-08-23 17:57:53 +00:00
# Change the look of Adwaita, with ease
# Copyright (C) 2022 Gradience Team
2022-07-17 11:46:05 +00:00
#
2022-08-23 17:57:53 +00:00
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
2022-07-17 11:46:05 +00:00
#
2022-08-23 17:57:53 +00:00
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
2022-07-17 11:46:05 +00:00
#
2022-08-23 17:57:53 +00:00
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
2022-08-23 17:38:09 +00:00
import os
2022-07-17 11:46:05 +00:00
2022-08-10 10:36:29 +00:00
from gi . repository import Gtk , Adw , Gio , Gdk
2022-08-23 17:38:09 +00:00
from svglib . svglib import svg2rlg
from reportlab . graphics import renderPM
from material_color_utilities_python import *
2022-08-19 19:14:05 +00:00
from . error import GradienceError
2022-08-02 12:08:12 +00:00
from . settings_schema import settings_schema
2022-08-19 19:14:05 +00:00
from . palette_shades import GradiencePaletteShades
from . option import GradienceOption
from . app_type_dialog import GradienceAppTypeDialog
from . custom_css_group import GradienceCustomCSSGroup
from . presets_manager_window import GradiencePresetWindow
2022-08-19 12:44:02 +00:00
from . plugins_list import GradiencePluginsList
2022-08-23 17:38:09 +00:00
from . modules . utils import buglog
from . constants import rootdir , app_id , build_type
2022-08-19 12:45:50 +00:00
2022-08-21 12:39:32 +00:00
2022-08-13 10:24:16 +00:00
@Gtk.Template ( resource_path = f " { rootdir } /ui/window.ui " )
2022-08-19 19:14:05 +00:00
class GradienceMainWindow ( Adw . ApplicationWindow ) :
__gtype_name__ = " GradienceMainWindow "
2022-07-17 11:46:05 +00:00
content = Gtk . Template . Child ( )
2022-08-10 15:05:47 +00:00
toast_overlay = Gtk . Template . Child ( )
2022-08-10 14:57:45 +00:00
content_monet = Gtk . Template . Child ( " content_monet " )
2022-08-10 15:20:19 +00:00
content_plugins = Gtk . Template . Child ( " content_plugins " )
2022-08-01 19:42:42 +00:00
save_preset_button = Gtk . Template . Child ( " save-preset-button " )
2022-08-10 10:36:29 +00:00
main_menu = Gtk . Template . Child ( " main-menu " )
2022-07-18 19:20:02 +00:00
errors_button = Gtk . Template . Child ( " errors-button " )
errors_list = Gtk . Template . Child ( " errors-list " )
2022-08-20 09:56:30 +00:00
monet_image_file = None
2022-07-17 11:46:05 +00:00
2022-08-01 09:31:36 +00:00
def __init__ ( self , * * kwargs ) :
super ( ) . __init__ ( * * kwargs )
2022-08-13 10:44:22 +00:00
# Set devel style
if build_type == " debug " :
self . get_style_context ( ) . add_class ( " devel " )
2022-08-10 14:57:45 +00:00
self . setup_monet_page ( )
2022-08-10 15:20:19 +00:00
self . setup_plugins_page ( )
2022-08-10 15:21:31 +00:00
self . setup_colors_page ( )
2022-08-10 15:51:43 +00:00
2022-08-15 18:33:41 +00:00
self . settings = Gio . Settings ( app_id )
2022-08-10 09:08:55 +00:00
self . settings . bind (
2022-08-17 21:35:59 +00:00
" window-width " ,
self ,
" default-width " ,
Gio . SettingsBindFlags . DEFAULT )
2022-08-10 09:08:55 +00:00
self . settings . bind (
2022-08-17 21:35:59 +00:00
" window-height " ,
self ,
" default-height " ,
Gio . SettingsBindFlags . DEFAULT )
2022-08-10 09:08:55 +00:00
self . settings . bind (
2022-08-17 21:35:59 +00:00
" window-maximized " ,
self ,
" maximized " ,
Gio . SettingsBindFlags . DEFAULT )
2022-08-10 09:08:55 +00:00
2022-08-10 09:14:26 +00:00
self . settings . bind (
2022-08-17 21:35:59 +00:00
" window-fullscreen " ,
self ,
" fullscreened " ,
Gio . SettingsBindFlags . DEFAULT )
2022-08-10 09:14:26 +00:00
2022-08-19 22:07:10 +00:00
self . connect ( " close-request " , self . __close_window )
2022-08-20 16:15:28 +00:00
self . style_manager = self . get_application ( ) . style_manager
2022-08-20 16:19:16 +00:00
self . first_apply = True
2022-08-20 11:29:33 +00:00
self . get_default_wallpaper ( )
2022-08-24 09:05:13 +00:00
# FIXME: This function works only when build using meson, because Flatpak
# can't access host's dconf with current config/impl
2022-08-20 11:29:33 +00:00
def get_default_wallpaper ( self ) :
background_settings = Gio . Settings ( " org.gnome.desktop.background " )
if self . style_manager . get_dark ( ) :
2022-08-23 17:57:53 +00:00
picture_uri = background_settings . get_string (
2022-08-20 11:37:45 +00:00
" picture-uri-dark " )
2022-08-20 11:29:33 +00:00
else :
2022-08-23 17:57:53 +00:00
picture_uri = background_settings . get_string (
" picture-uri " )
buglog ( picture_uri )
self . monet_image_file = Gio . File . new_for_uri ( picture_uri )
2022-08-20 11:29:33 +00:00
image_basename = self . monet_image_file . get_basename ( )
2022-08-23 17:57:53 +00:00
buglog ( image_basename )
2022-08-20 11:29:33 +00:00
self . monet_file_chooser_button . set_label ( image_basename )
self . monet_image_file = self . monet_image_file . get_path ( )
2022-08-23 17:57:53 +00:00
self . monet_file_chooser_button . set_tooltip_text ( self . monet_image_file )
buglog ( self . monet_image_file )
2022-08-24 09:05:13 +00:00
# self.on_apply_button() # Comment out for now, because it always shows
# that annoying toast on startup
2022-08-20 11:29:33 +00:00
2022-08-10 14:57:45 +00:00
def on_file_picker_button_clicked ( self , * args ) :
self . monet_file_chooser_dialog . show ( )
2022-08-19 22:07:10 +00:00
def __close_window ( self , widegt ) :
if self . get_application ( ) . is_dirty :
2022-08-23 17:38:09 +00:00
buglog ( " app is dirty " )
2022-08-19 22:07:10 +00:00
2022-08-10 14:57:45 +00:00
def on_monet_file_chooser_response ( self , widget , response ) :
if response == Gtk . ResponseType . ACCEPT :
2022-08-11 10:55:12 +00:00
self . monet_image_file = self . monet_file_chooser_dialog . get_file ( )
2022-08-11 09:49:04 +00:00
image_basename = self . monet_image_file . get_basename ( )
2022-08-10 14:57:45 +00:00
self . monet_file_chooser_button . set_label ( image_basename )
2022-08-24 09:05:13 +00:00
self . monet_file_chooser_button . set_tooltip_text (
2022-08-25 09:37:14 +00:00
image_basename )
2022-08-10 14:57:45 +00:00
self . monet_file_chooser_dialog . hide ( )
2022-08-11 13:46:00 +00:00
if response == Gtk . ResponseType . ACCEPT :
2022-08-20 09:33:25 +00:00
self . monet_image_file = self . monet_image_file . get_path ( )
2022-08-20 09:56:30 +00:00
self . on_apply_button ( )
2022-08-11 09:49:04 +00:00
2022-08-10 14:57:45 +00:00
def setup_monet_page ( self ) :
2022-08-11 09:17:00 +00:00
2022-08-11 10:44:22 +00:00
self . monet_pref_group = Adw . PreferencesGroup ( )
self . monet_pref_group . set_name ( " monet " )
self . monet_pref_group . set_title ( _ ( " Monet Engine " ) )
2022-08-11 10:55:12 +00:00
self . monet_pref_group . set_description (
2022-08-31 01:36:59 +00:00
_ ( " Monet is an engine that generates a Material Design 3 palette from an image ' s color. " ) )
2022-08-10 14:57:45 +00:00
2022-08-20 09:56:30 +00:00
self . apply_button = Gtk . Button ( )
self . apply_button . set_label ( _ ( " Apply " ) )
2022-08-24 14:02:31 +00:00
self . apply_button . set_valign ( Gtk . Align . CENTER )
2022-08-20 09:56:30 +00:00
self . apply_button . connect ( " clicked " , self . on_apply_button )
self . apply_button . set_css_classes ( " suggested-action " )
self . monet_pref_group . set_header_suffix ( self . apply_button )
2022-08-10 14:57:45 +00:00
self . monet_file_chooser_row = Adw . ActionRow ( )
self . monet_file_chooser_row . set_title ( _ ( " Background Image " ) )
2022-08-11 10:55:12 +00:00
2022-08-10 14:57:45 +00:00
self . monet_file_chooser_dialog = Gtk . FileChooserNative ( )
self . monet_file_chooser_dialog . set_transient_for ( self )
self . monet_file_chooser_button = Gtk . Button ( )
2022-08-25 09:39:48 +00:00
self . monet_file_chooser_button . set_valign ( Gtk . Align . CENTER )
2022-08-15 12:37:58 +00:00
#self.monet_file_chooser_button.set_label(_("Choose a file"))
2022-08-17 21:35:59 +00:00
# self.monet_file_chooser_button.set_icon_name("folder-pictures-symbolic")
2022-08-15 12:37:58 +00:00
child_button = Gtk . Box ( )
label = Gtk . Label ( )
label . set_label ( _ ( " Choose a file " ) )
child_button . append ( label )
icon = Gtk . Image ( )
icon . set_from_icon_name ( " folder-pictures-symbolic " )
child_button . append ( icon )
child_button . set_spacing ( 5 )
self . monet_file_chooser_button . set_child ( child_button )
2022-08-25 10:45:30 +00:00
# self.monet_file_chooser_button.set_margin_top(5)
# self.monet_file_chooser_button.set_margin_bottom(5)
2022-08-10 14:57:45 +00:00
2022-08-11 10:55:12 +00:00
self . monet_file_chooser_button . connect (
2022-08-11 16:39:52 +00:00
" clicked " , self . on_file_picker_button_clicked
)
2022-08-11 10:55:12 +00:00
self . monet_file_chooser_dialog . connect (
2022-08-11 16:39:52 +00:00
" response " , self . on_monet_file_chooser_response
)
2022-08-10 14:57:45 +00:00
self . monet_file_chooser_row . add_suffix ( self . monet_file_chooser_button )
2022-08-11 10:44:22 +00:00
self . monet_pref_group . add ( self . monet_file_chooser_row )
2022-08-10 14:57:45 +00:00
2022-08-19 19:14:05 +00:00
self . monet_palette_shades = GradiencePaletteShades (
2022-08-19 18:23:30 +00:00
" monet " , _ ( " Monet Palette " ) , 6
2022-08-11 16:39:52 +00:00
)
2022-08-17 21:35:59 +00:00
self . get_application (
) . pref_palette_shades [ " monet " ] = self . monet_palette_shades
2022-08-11 10:55:49 +00:00
self . monet_pref_group . add ( self . monet_palette_shades )
2022-08-10 14:57:45 +00:00
2022-08-11 09:49:04 +00:00
self . tone_row = Adw . ComboRow ( )
self . tone_row . set_title ( _ ( " Tone " ) )
2022-08-11 10:03:21 +00:00
2022-08-11 10:09:18 +00:00
store = Gtk . StringList ( )
2022-08-11 12:45:45 +00:00
store_values = [ ]
2022-08-11 14:17:35 +00:00
for i in range ( 20 , 80 , 5 ) :
2022-08-11 10:55:12 +00:00
store_values . append ( str ( i ) )
2022-08-11 10:09:18 +00:00
for v in store_values :
2022-08-11 10:09:42 +00:00
store . append ( v )
2022-08-11 10:10:26 +00:00
self . tone_row . set_model ( store )
2022-08-11 10:45:10 +00:00
self . monet_pref_group . add ( self . tone_row )
2022-08-11 12:55:00 +00:00
self . monet_theme_row = Adw . ComboRow ( )
self . monet_theme_row . set_title ( _ ( " Theme " ) )
store = Gtk . StringList ( )
2022-08-11 18:13:21 +00:00
store . append ( " Auto " )
2022-08-11 12:55:00 +00:00
store . append ( " Dark " )
store . append ( " Light " )
self . monet_theme_row . set_model ( store )
self . monet_pref_group . add ( self . monet_theme_row )
2022-08-11 10:45:10 +00:00
self . content_monet . add ( self . monet_pref_group )
2022-08-20 11:37:45 +00:00
2022-08-20 09:56:30 +00:00
def on_apply_button ( self , * _args ) :
if self . monet_image_file :
if self . monet_image_file . endswith ( " .svg " ) :
2022-08-20 11:37:22 +00:00
drawing = svg2rlg ( self . monet_image_file )
self . monet_image_file = os . path . join (
os . environ . get ( " XDG_RUNTIME_DIR " ) , " gradience_bg.png " )
renderPM . drawToFile ( drawing , self . monet_image_file , fmt = ' PNG ' )
2022-08-21 08:21:30 +00:00
if self . monet_image_file . endswith ( " .xml " ) :
2022-08-23 17:38:09 +00:00
buglog ( " XML WIP " )
2022-08-21 08:21:30 +00:00
2022-08-20 11:29:33 +00:00
try :
self . monet_img = Image . open ( self . monet_image_file )
except Exception :
self . toast_overlay . add_toast (
2022-08-20 16:19:41 +00:00
Adw . Toast ( title = _ ( " Unsupported background type " ) )
2022-08-20 11:29:33 +00:00
)
else :
basewidth = 64
wpercent = ( basewidth / float ( self . monet_img . size [ 0 ] ) )
hsize = int ( ( float ( self . monet_img . size [ 1 ] ) * float ( wpercent ) ) )
self . monet_img = self . monet_img . resize (
( basewidth , hsize ) , Image . Resampling . LANCZOS )
self . theme = themeFromImage ( self . monet_img )
self . tone = self . tone_row . get_selected_item ( )
self . monet_theme = self . monet_theme_row . get_selected_item ( )
self . get_application ( ) . update_theme_from_monet (
self . theme , self . tone , self . monet_theme
)
2022-08-20 16:19:16 +00:00
if not self . first_apply :
self . toast_overlay . add_toast (
2022-08-25 13:28:38 +00:00
Adw . Toast ( title = _ ( " Palette generated " ) )
2022-08-20 16:19:16 +00:00
)
2022-08-20 09:56:30 +00:00
else :
self . toast_overlay . add_toast (
Adw . Toast ( title = _ ( " Select a background first " ) )
)
2022-08-11 09:49:04 +00:00
2022-08-10 15:20:19 +00:00
def setup_plugins_page ( self ) :
2022-09-01 14:06:04 +00:00
self . plugins_list = GradiencePluginsList ( self )
2022-08-19 12:44:02 +00:00
self . plugins_group = self . plugins_list . to_group ( )
self . content_plugins . add ( self . plugins_group )
2022-08-19 18:54:44 +00:00
self . get_application ( ) . plugins_group = self . plugins_group
2022-08-19 12:45:50 +00:00
2022-08-19 19:14:05 +00:00
custom_css_group = GradienceCustomCSSGroup ( )
2022-08-10 15:20:19 +00:00
for app_type in settings_schema [ " custom_css_app_types " ] :
self . get_application ( ) . custom_css [ app_type ] = " "
custom_css_group . load_custom_css ( self . get_application ( ) . custom_css )
self . content_plugins . add ( custom_css_group )
self . get_application ( ) . custom_css_group = custom_css_group
2022-08-10 15:21:31 +00:00
def setup_colors_page ( self ) :
for group in settings_schema [ " groups " ] :
pref_group = Adw . PreferencesGroup ( )
pref_group . set_name ( group [ " name " ] )
pref_group . set_title ( group [ " title " ] )
pref_group . set_description ( group [ " description " ] )
for variable in group [ " variables " ] :
2022-08-19 19:14:05 +00:00
pref_variable = GradienceOption (
2022-08-11 16:39:52 +00:00
variable [ " name " ] ,
variable [ " title " ] ,
variable . get ( " explanation " ) ,
variable [ " adw_gtk3_support " ] ,
)
2022-08-10 15:21:31 +00:00
pref_group . add ( pref_variable )
2022-08-17 21:35:59 +00:00
self . get_application (
) . pref_variables [ variable [ " name " ] ] = pref_variable
2022-08-10 15:21:31 +00:00
self . content . add ( pref_group )
palette_pref_group = Adw . PreferencesGroup ( )
palette_pref_group . set_name ( " palette_colors " )
palette_pref_group . set_title ( _ ( " Palette Colors " ) )
2022-08-11 10:55:12 +00:00
palette_pref_group . set_description (
2022-08-17 21:35:59 +00:00
_ ( ' Named palette colors used by some applications. Default colors follow the <a href= " https://developer.gnome.org/hig/reference/palette.html " >GNOME Human Interface Guidelines</a>. ' ) )
2022-08-10 15:21:31 +00:00
for color in settings_schema [ " palette " ] :
2022-08-19 19:14:05 +00:00
palette_shades = GradiencePaletteShades (
2022-08-11 16:39:52 +00:00
color [ " prefix " ] , color [ " title " ] , color [ " n_shades " ]
)
2022-08-10 15:21:31 +00:00
palette_pref_group . add ( palette_shades )
2022-08-17 21:35:59 +00:00
self . get_application (
) . pref_palette_shades [ color [ " prefix " ] ] = palette_shades
2022-08-10 15:21:31 +00:00
self . content . add ( palette_pref_group )
2022-07-21 19:03:18 +00:00
def update_errors ( self , errors ) :
2022-07-18 19:20:02 +00:00
child = self . errors_list . get_row_at_index ( 0 )
while child is not None :
self . errors_list . remove ( child )
child = self . errors_list . get_row_at_index ( 0 )
2022-07-21 19:03:18 +00:00
self . errors_button . set_visible ( len ( errors ) > 0 )
for error in errors :
2022-08-11 16:39:52 +00:00
self . errors_list . append (
2022-08-19 19:14:05 +00:00
GradienceError (
2022-08-17 21:35:59 +00:00
error [ " error " ] ,
error [ " element " ] ,
error [ " line " ] ) )
2022-08-01 09:31:36 +00:00
2022-08-23 10:57:19 +00:00
@Gtk.Template.Callback ( )
def on_presets_button_clicked ( self , * args ) :
GradiencePresetWindow ( ) . present ( )