Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
76677b0
util: utility function to set a button's bg color and fg color
deviantfero May 27, 2025
ac9738e
implement function to set uniform margins
deviantfero May 27, 2025
65edcc7
update launcher to use Gtk.Appliaction
deviantfero May 27, 2025
31ba967
replace widget initializer syntax, update color parsing
deviantfero May 27, 2025
9ca1554
replace deprecated color chooser dialog with ColorDialog
deviantfero Aug 17, 2025
0d08756
replace deprecated FileChooserDialog with FileDialog
deviantfero Aug 17, 2025
a6bf7b7
replace Gtk.Image() with new Gtk.Picture()
deviantfero Dec 10, 2025
631c9aa
rename window class, make sample not expand
deviantfero Dec 10, 2025
011e9f9
work on image size
deviantfero Dec 10, 2025
87a7557
correct typo
deviantfero Dec 10, 2025
da8b7aa
fix: make filepicker dialogs work in GTK4
deviantfero Jan 12, 2026
a71d515
fix: make keyword dialog a custom written window dialog for GTK4
deviantfero Feb 5, 2026
fd9ceff
feat: handle esc/enter like in original dialog
deviantfero Feb 6, 2026
8a54aee
feat: prefer images showing completely rather than covering surface
deviantfero Feb 6, 2026
7a34fe8
fix: use ComboBoxText() instead in color_grid and template_grid
deviantfero Mar 22, 2026
0729b22
fix: use Pixbuf list from the beggining, use new GTK4 dialog
deviantfero Mar 22, 2026
687598b
chore: prepend ui callback functions with _
deviantfero Mar 22, 2026
e33fb9d
fix: sample rendering constrained while allowing wallpaper expand
deviantfero Mar 23, 2026
f86bb36
fix: update keyword function calls to remove _ when inappropiate
deviantfero May 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
205 changes: 103 additions & 102 deletions wpgtk/gui/color_grid.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,13 @@
from ..data import themer
from . import util as gui_util

from .color_picker import ColorDialog
from gi import require_version

require_version("Gtk", "3.0")
from gi.repository import Gtk, Gdk, GdkPixbuf # noqa: E402
require_version("Gtk", "4.0")
from gi.repository import Gtk, Gdk, GLib # noqa: E402
from gi.repository.GdkPixbuf import Pixbuf # noqa: E402

# TODO: remove current_walls call, use simple list
# TODO: use simple text combo
# TODO: only update pixbuf if parent has same color scheme
current_walls = files.get_file_list()
PAD = 10
Expand All @@ -27,36 +26,36 @@ class ColorGrid(Gtk.Grid):
def __init__(self, parent):
Gtk.Grid.__init__(self)
self.parent = parent
self.set_border_width(PAD)
self.set_column_homogeneous(1)
gui_util.set_uniform_margins(self, PAD)
self.set_row_spacing(PAD)
self.set_column_spacing(PAD)

self.colorgrid = Gtk.Grid()
self.colorgrid.set_border_width(PAD)
self.colorgrid.set_column_homogeneous(1)
self.colorgrid.set_row_spacing(PAD)
self.colorgrid.set_column_spacing(PAD)
self.colorgrid.set_vexpand(False)

self.sat_add = Gtk.Button("+")
self.sat_add = Gtk.Button.new_with_label("+")
self.sat_add.set_sensitive(False)

self.sat_red = Gtk.Button("-")
self.sat_red = Gtk.Button.new_with_label("-")
self.sat_red.set_sensitive(False)

self.sat_add.connect("pressed", self.hls_change, "sat", "add")
self.sat_red.connect("pressed", self.hls_change, "sat", "red")
self.sat_lbl = Gtk.Label("Saturation:")
self.sat_add.connect("clicked", self._hls_change, "sat", "add")
self.sat_red.connect("clicked", self._hls_change, "sat", "red")
self.sat_lbl = Gtk.Label(label="Saturation:")

self.light_add = Gtk.Button("+")
self.light_add = Gtk.Button(label="+")
self.light_add.set_sensitive(False)

self.light_red = Gtk.Button("-")
self.light_red = Gtk.Button(label="-")
self.light_red.set_sensitive(False)

self.light_add.connect("pressed", self.hls_change, "light", "add")
self.light_red.connect("pressed", self.hls_change, "light", "red")
self.light_lbl = Gtk.Label("Brightness:")
self.light_add.connect("clicked", self._hls_change, "light", "add")
self.light_red.connect("clicked", self._hls_change, "light", "red")
self.light_lbl = Gtk.Label(label="Brightness:")

self.sat_light_grid = Gtk.Grid()
self.sat_light_grid.set_column_homogeneous(1)
Expand All @@ -74,59 +73,56 @@ def __init__(self, parent):
self.combo_grid.set_row_spacing(PAD)

self.color_list = ["000000"] * 16
self.button_list = [Gtk.Button("000000") for x in range(16)]
self.button_list = [Gtk.Button(label="000000") for x in range(16)]
self.selected_file = ""
for button in self.button_list:
button.connect("pressed", self.on_color_click)
button.connect("clicked", self._on_color_click)
button.set_sensitive(False)

cont = 0
for y in range(0, 8, 2):
for x in range(0, 4):
label = Gtk.Label(str(cont))
label = Gtk.Label(label=str(cont))
self.colorgrid.attach(label, x, y, 1, 1)
self.colorgrid.attach(self.button_list[cont], x, y + 1, 1, 1)
cont += 1

sample_name = os.path.join(SAMPLE_DIR, ".no_sample.sample.png")
self.sample = Gtk.Image()

pixbuf_sample = gui_util.get_sample_pixbuf(sample_name)
if pixbuf_sample is not None:
self.sample.set_from_pixbuf(self.pixbuf_sample)

self.shuffle_button = Gtk.Button("Shuffle colors")
self.shuffle_button.connect("pressed", self.on_shuffle_click)
self._sample_pixbuf = None
self.sample = Gtk.DrawingArea()
self.sample.set_content_height(50)
self.sample.set_hexpand(True)
self.sample.set_vexpand(False)
self.sample.set_valign(Gtk.Align.START)
self.sample.set_draw_func(gui_util.draw_sample, lambda: self._sample_pixbuf)
self._set_sample_file(sample_name)

self.shuffle_button = Gtk.Button(label="Shuffle colors")
self.shuffle_button.connect("clicked", self._on_shuffle_click)
self.shuffle_button.set_sensitive(False)

self.import_button = Gtk.Button("import")
self.import_button = Gtk.Button(label="Import")
self.import_button.set_sensitive(False)
self.import_button.connect("pressed", self.on_import_click)
self.import_button.connect("clicked", self._on_import_click)

self.ok_button = Gtk.Button("Save")
self.ok_button.connect("pressed", self.on_ok_click)
self.ok_button = Gtk.Button(label="Save")
self.ok_button.connect("clicked", self._on_ok_click)
self.ok_button.set_sensitive(False)

self.auto_button = Gtk.Button("Auto-adjust")
self.auto_button.connect("pressed", self.on_auto_click)
self.auto_button = Gtk.Button(label="Auto-adjust")
self.auto_button.connect("clicked", self._on_auto_click)
self.auto_button.set_sensitive(False)

self.reset_button = Gtk.Button("Reset")
self.reset_button = Gtk.Button(label="Reset")
self.reset_button.set_sensitive(False)
self.reset_button.connect("pressed", self.on_reset_click)

self.done_lbl = Gtk.Label("")
self.reset_button.connect("clicked", self._on_reset_click)

option_list = Gtk.ListStore(str)
for elem in list(files.get_file_list()):
option_list.append([elem])
self.done_lbl = Gtk.Label(label="")

self.option_combo = Gtk.ComboBox.new_with_model(option_list)
self.renderer_text = Gtk.CellRendererText()
self.option_combo.pack_start(self.renderer_text, True)
self.option_combo.add_attribute(self.renderer_text, "text", 0)
self.option_combo.set_entry_text_column(0)
self.option_combo.connect("changed", self.combo_box_change)
self.option_combo = Gtk.ComboBoxText()
for elem in files.get_file_list():
self.option_combo.append_text(elem)
self.option_combo.connect("changed", self._combo_box_change)

self.combo_grid.attach(self.option_combo, 0, 0, 3, 1)
self.combo_grid.attach(self.reset_button, 3, 0, 1, 1)
Expand All @@ -151,17 +147,24 @@ def __init__(self, parent):
self.attach(self.sat_light_grid, 0, 4, 1, 1)
self.attach(self.done_lbl, 0, 5, 1, 1)

def _set_sample_file(self, path):
try:
self._sample_pixbuf = Pixbuf.new_from_file(path)
except Exception:
self._sample_pixbuf = None
self.sample.queue_draw()

def render_buttons(self):
for x, button in enumerate(self.button_list):
gcolor = Gdk.color_parse(self.color_list[x])
if util.get_hls_val(self.color_list[x], "light") < 99:
fgcolor = Gdk.color_parse("#FFFFFF")
fgcolor = "#FFFFFF"
else:
fgcolor = Gdk.color_parse("#000000")
fgcolor = "#000000"
button.set_label(self.color_list[x])
button.set_sensitive(True)
button.modify_bg(Gtk.StateType.NORMAL, gcolor)
button.modify_fg(Gtk.StateType.NORMAL, fgcolor)
gui_util.set_widget_colors(
button, background=self.color_list[x], foreground=fgcolor
)

def render_theme(self):
sample_path = files.get_sample_path(self.selected_file)
Expand All @@ -172,15 +175,13 @@ def render_theme(self):
self.color_list = themer.set_fallback_theme(self.selected_file)
self.render_buttons()

pixbuf_sample = gui_util.get_sample_pixbuf(sample_path)
if pixbuf_sample is None:
if not os.path.isfile(sample_path):
sample.create_sample(self.color_list, sample_path)
pixbuf_sample = gui_util.get_sample_pixbuf(sample_path)

self.sample.set_from_pixbuf(pixbuf_sample)
self.parent.sample.set_from_pixbuf(pixbuf_sample)
self._set_sample_file(sample_path)
self.parent._set_sample_file(sample_path)

def hls_change(self, widget, *gparam):
def _hls_change(self, widget, *gparam):
if gparam[0] == "sat":
val = 0.05 if gparam[1] == "add" else -0.05
self.color_list = [
Expand All @@ -197,12 +198,9 @@ def hls_change(self, widget, *gparam):
def render_sample(self):
sample.create_sample(self.color_list)
sample_path = os.path.join(SAMPLE_DIR, ".tmp.sample.png")
self.pixbuf_sample = GdkPixbuf.Pixbuf.new_from_file_at_size(
sample_path, width=500, height=300
)
self.sample.set_from_pixbuf(self.pixbuf_sample)
self._set_sample_file(sample_path)

def on_ok_click(self, widget):
def _on_ok_click(self, widget):
color.write_colors(self.selected_file, self.color_list)
tmpfile = os.path.join(SAMPLE_DIR, ".tmp.sample.png")

Expand All @@ -214,80 +212,83 @@ def on_ok_click(self, widget):

self.done_lbl.set_text("Changes saved")
sample_path = files.get_sample_path(self.selected_file)
self.parent.pixbuf_sample = GdkPixbuf.Pixbuf.new_from_file_at_size(
sample_path, width=500, height=300
)
self.parent.sample.set_from_pixbuf(self.pixbuf_sample)
self.parent._set_sample_file(sample_path)

def on_auto_click(self, widget):
def _on_auto_click(self, widget):
self.color_list = color.auto_adjust(self.color_list)
self.render_buttons()
self.render_sample()

def on_reset_click(self, widget):
def _on_reset_click(self, widget):
themer.reset_theme(self.selected_file)
self.render_theme()

def on_import_click(self, widget):
fcd = Gtk.FileChooserDialog(
"Select a colorscheme",
self.parent,
Gtk.FileChooserAction.OPEN,
(
Gtk.STOCK_CANCEL,
Gtk.ResponseType.CANCEL,
Gtk.STOCK_OPEN,
Gtk.ResponseType.OK,
),
)
def _on_import_click(self, widget):
fcd = Gtk.FileDialog()

filter = Gtk.FileFilter()
filter.set_name("JSON colorscheme")
filter.add_mime_type("application/json")
fcd.add_filter(filter)
response = fcd.run()

if response == Gtk.ResponseType.OK:
self.color_list = color.get_color_list(fcd.get_filename(), True)
self.render_buttons()
self.render_sample()
fcd.destroy()
fcd.set_default_filter(filter)
fcd.set_title("Select a colorscheme")

fcd.open(parent=self.parent, callback=self._on_import_finish)

def _on_import_finish(self, dialog, result):
try:
filename = dialog.open_finish(result)

def on_shuffle_click(self, widget):
if filename:
self.color_list = color.get_color_list(filename, True)
self.render_buttons()
self.render_sample()
except GLib.Error as error:
print(f"Error opening file: {error.message}")

def _on_shuffle_click(self, widget):
self.color_list = color.shuffle_colors(self.color_list)
self.render_buttons()
self.render_sample()

def on_color_click(self, widget):
def _on_color_click(self, widget):
self.done_lbl.set_text("")
self.active_color_button = widget
gcolor = Gdk.RGBA()
gcolor.parse(widget.get_label())
dialog = ColorDialog(self.parent, self.selected_file, gcolor)
response = dialog.run()
dialog = Gtk.ColorDialog()
dialog.set_with_alpha(False)
dialog.set_title("Choose a Color")
dialog.choose_rgba(
parent=self.parent, initial_color=gcolor, callback=self._on_color_selected
)

if response == Gtk.ResponseType.OK:
r, g, b, _ = dialog.colorchooser.get_rgba()
def _on_color_selected(self, dialog, result):
rgba = dialog.choose_rgba_finish(result)

if rgba:
r, g, b, _ = rgba
rgb = list(map(lambda x: round(x * 100 * 2.55), [r, g, b]))
hex_color = pywal.util.rgb_to_hex(rgb)
widget.set_label(hex_color)
# widget.set_label(hex_color)

gcolor = Gdk.color_parse(hex_color)
if util.get_hls_val(hex_color, "light") < 100:
fgcolor = Gdk.color_parse("#FFFFFF")
fgcolor = "#FFFFFF"
else:
fgcolor = Gdk.color_parse("#000000")
fgcolor = "#000000"

widget.set_sensitive(True)
widget.modify_bg(Gtk.StateType.NORMAL, gcolor)
widget.modify_fg(Gtk.StateType.NORMAL, fgcolor)
self.active_color_button.set_sensitive(True)
self.active_color_button.set_label(hex_color)
gui_util.set_widget_colors(
self.active_color_button, background=hex_color, foreground=fgcolor
)

for i, c in enumerate(self.button_list):
if c.get_label() != self.color_list[i]:
self.color_list[i] = c.get_label()
self.render_sample()
dialog.destroy()

def combo_box_change(self, widget):
def _combo_box_change(self, widget):
self.done_lbl.set_text("")
x = self.option_combo.get_active()

Expand Down
Loading