Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
T
tuneit
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Ximper Linux
tuneit
Commits
9dfbac49
Verified
Commit
9dfbac49
authored
Jan 29, 2026
by
Kirill Unitsaev
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
widgets/theme_chooser: improve style
parent
82236502
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
103 additions
and
59 deletions
+103
-59
ThemeChooserWidget.py
src/settings/setting/widgets/ThemeChooserWidget.py
+103
-59
No files found.
src/settings/setting/widgets/ThemeChooserWidget.py
View file @
9dfbac49
from
gi.repository
import
Gtk
,
Adw
,
GObject
,
Gdk
import
math
from
gi.repository
import
Gtk
,
Adw
,
Gdk
from
.BaseWidget
import
BaseWidget
...
...
@@ -98,7 +99,7 @@ class ThemeChooserWidget(BaseWidget):
# FlowBox for theme cards
self
.
flowbox
=
Gtk
.
FlowBox
(
homogeneous
=
True
,
selection_mode
=
Gtk
.
SelectionMode
.
SINGL
E
,
selection_mode
=
Gtk
.
SelectionMode
.
NON
E
,
min_children_per_line
=
2
,
max_children_per_line
=
2
,
row_spacing
=
12
,
...
...
@@ -107,14 +108,22 @@ class ThemeChooserWidget(BaseWidget):
content_box
.
append
(
self
.
flowbox
)
self
.
theme_cards
=
{}
self
.
handler_id
=
self
.
flowbox
.
connect
(
"child-activated"
,
self
.
_on_theme_selected
)
self
.
border_overlays
=
{}
self
.
flowbox
.
connect
(
"child-activated"
,
self
.
_on_theme_selected
)
# Subscribe to accent color changes
style_manager
=
Adw
.
StyleManager
.
get_default
()
style_manager
.
connect
(
"notify::accent-color-rgba"
,
self
.
_on_accent_color_changed
)
self
.
_build_cards
()
self
.
_update_reset_visibility
()
return
self
.
row
def
_create_theme_card
(
self
,
label
,
value
,
preview_path
=
None
):
"""Create a theme preview card."""
"""Create a theme preview card with selection border overlay."""
overlay
=
Gtk
.
Overlay
()
card
=
Gtk
.
Box
(
orientation
=
Gtk
.
Orientation
.
VERTICAL
,
spacing
=
8
,
...
...
@@ -134,10 +143,6 @@ class ThemeChooserWidget(BaseWidget):
# Generate color preview
preview
=
self
.
_create_color_preview
(
value
)
preview_frame
=
Gtk
.
Frame
()
preview_frame
.
set_child
(
preview
)
preview_frame
.
add_css_class
(
"theme-preview-frame"
)
card_inner
=
Gtk
.
Box
(
orientation
=
Gtk
.
Orientation
.
VERTICAL
,
spacing
=
6
,
...
...
@@ -146,7 +151,7 @@ class ThemeChooserWidget(BaseWidget):
margin_start
=
8
,
margin_end
=
8
,
)
card_inner
.
append
(
preview
_frame
)
card_inner
.
append
(
preview
)
# Label
name_label
=
Gtk
.
Label
(
...
...
@@ -157,7 +162,36 @@ class ThemeChooserWidget(BaseWidget):
card_inner
.
append
(
name_label
)
card
.
append
(
card_inner
)
return
card
overlay
.
set_child
(
card
)
# Selection border overlay
border_area
=
Gtk
.
DrawingArea
()
border_area
.
set_can_target
(
False
)
border_area
.
set_draw_func
(
self
.
_draw_selection_border
,
value
)
overlay
.
add_overlay
(
border_area
)
self
.
border_overlays
[
value
]
=
border_area
return
overlay
def
_draw_selection_border
(
self
,
area
,
cr
,
width
,
height
,
value
):
if
value
!=
self
.
setting
.
_get_backend_value
():
return
rgba
=
Adw
.
StyleManager
.
get_default
()
.
get_accent_color_rgba
()
r
,
w
=
12
,
3
cr
.
new_path
()
cr
.
arc
(
width
-
r
,
r
,
r
-
w
/
2
,
-
math
.
pi
/
2
,
0
)
cr
.
arc
(
width
-
r
,
height
-
r
,
r
-
w
/
2
,
0
,
math
.
pi
/
2
)
cr
.
arc
(
r
,
height
-
r
,
r
-
w
/
2
,
math
.
pi
/
2
,
math
.
pi
)
cr
.
arc
(
r
,
r
,
r
-
w
/
2
,
math
.
pi
,
3
*
math
.
pi
/
2
)
cr
.
close_path
()
cr
.
set_source_rgba
(
rgba
.
red
,
rgba
.
green
,
rgba
.
blue
,
1.0
)
cr
.
set_line_width
(
w
)
cr
.
stroke
()
def
_clear_flowbox
(
self
):
while
True
:
...
...
@@ -166,6 +200,7 @@ class ThemeChooserWidget(BaseWidget):
break
self
.
flowbox
.
remove
(
child
)
self
.
theme_cards
=
{}
self
.
border_overlays
=
{}
def
_build_cards
(
self
):
if
not
self
.
setting
.
map
:
...
...
@@ -174,7 +209,6 @@ class ThemeChooserWidget(BaseWidget):
self
.
flowbox
.
append
(
placeholder
)
return
current_value
=
self
.
setting
.
_get_backend_value
()
previews
=
self
.
setting
.
previews
or
{}
for
label
,
value
in
self
.
setting
.
map
.
items
():
...
...
@@ -185,10 +219,6 @@ class ThemeChooserWidget(BaseWidget):
self
.
flowbox
.
append
(
flowbox_child
)
self
.
theme_cards
[
value
]
=
flowbox_child
if
value
==
current_value
:
with
GObject
.
signal_handler_block
(
self
.
flowbox
,
self
.
handler_id
):
self
.
flowbox
.
select_child
(
flowbox_child
)
def
_create_color_preview
(
self
,
value
):
"""Create a colored preview box for the theme."""
preview
=
Gtk
.
Box
(
...
...
@@ -209,61 +239,68 @@ class ThemeChooserWidget(BaseWidget):
preview
.
append
(
drawing
)
return
preview
def
_rounded_rect
(
self
,
cr
,
x
,
y
,
w
,
h
,
r
):
"""Draw a rounded rectangle path."""
cr
.
new_path
()
cr
.
arc
(
x
+
w
-
r
,
y
+
r
,
r
,
-
math
.
pi
/
2
,
0
)
cr
.
arc
(
x
+
w
-
r
,
y
+
h
-
r
,
r
,
0
,
math
.
pi
/
2
)
cr
.
arc
(
x
+
r
,
y
+
h
-
r
,
r
,
math
.
pi
/
2
,
math
.
pi
)
cr
.
arc
(
x
+
r
,
y
+
r
,
r
,
math
.
pi
,
3
*
math
.
pi
/
2
)
cr
.
close_path
()
def
_draw_theme_preview
(
self
,
area
,
cr
,
width
,
height
,
colors
):
"""Draw a
simple theme
preview."""
bg_color
,
accent
_color
=
colors
"""Draw a
window mockup
preview."""
bg_color
,
headerbar
_color
=
colors
# Parse colors
bg_rgba
=
Gdk
.
RGBA
()
bg_rgba
.
parse
(
bg_color
)
accent_rgba
=
Gdk
.
RGBA
()
accent_rgba
.
parse
(
accent_color
)
bg
=
Gdk
.
RGBA
()
bg
.
parse
(
bg_color
)
hb
=
Gdk
.
RGBA
()
hb
.
parse
(
headerbar_color
)
# Draw background
cr
.
set_source_rgba
(
bg_rgba
.
red
,
bg_rgba
.
green
,
bg_rgba
.
blue
,
1.0
)
cr
.
rectangle
(
0
,
0
,
width
,
height
)
cr
.
fill
()
r
=
8
header_h
=
24
margin
=
4
# Draw sidebar
sidebar_width
=
28
cr
.
set_source_rgba
(
accent_rgba
.
red
,
accent_rgba
.
green
,
accent_rgba
.
blue
,
0.5
)
cr
.
rectangle
(
0
,
0
,
sidebar_width
,
height
)
# Window shadow
cr
.
set_source_rgba
(
0
,
0
,
0
,
0.15
)
self
.
_rounded_rect
(
cr
,
margin
+
2
,
margin
+
2
,
width
-
margin
*
2
,
height
-
margin
*
2
,
r
)
cr
.
fill
()
# Draw header bar simulation
cr
.
set_source_rgba
(
accent_rgba
.
red
,
accent_rgba
.
green
,
accent_rgba
.
blue
,
1.0
)
cr
.
rectangle
(
0
,
0
,
width
,
16
)
# Window background
cr
.
set_source_rgba
(
bg
.
red
,
bg
.
green
,
bg
.
blue
,
1.0
)
self
.
_rounded_rect
(
cr
,
margin
,
margin
,
width
-
margin
*
2
,
height
-
margin
*
2
,
r
)
cr
.
fill
()
# Draw window controls (circles)
cr
.
set_source_rgba
(
bg_rgba
.
red
,
bg_rgba
.
green
,
bg_rgba
.
blue
,
0.8
)
for
x
in
[
width
-
12
,
width
-
24
,
width
-
36
]:
cr
.
arc
(
x
,
8
,
4
,
0
,
2
*
3.14159
)
# Headerbar (top rounded corners only)
cr
.
new_path
()
cr
.
arc
(
margin
+
r
,
margin
+
r
,
r
,
math
.
pi
,
3
*
math
.
pi
/
2
)
cr
.
arc
(
width
-
margin
-
r
,
margin
+
r
,
r
,
-
math
.
pi
/
2
,
0
)
cr
.
line_to
(
width
-
margin
,
margin
+
header_h
)
cr
.
line_to
(
margin
,
margin
+
header_h
)
cr
.
close_path
()
cr
.
set_source_rgba
(
hb
.
red
,
hb
.
green
,
hb
.
blue
,
1.0
)
cr
.
fill
()
# Draw sidebar items
cr
.
set_source_rgba
(
bg_rgba
.
red
,
bg_rgba
.
green
,
bg_rgba
.
blue
,
0.6
)
for
y
in
[
26
,
40
,
54
,
68
]:
cr
.
rectangle
(
6
,
y
,
sidebar_width
-
12
,
8
)
# Window controls
ctrl_y
=
margin
+
header_h
/
2
cr
.
set_source_rgba
(
bg
.
red
,
bg
.
green
,
bg
.
blue
,
0.6
)
for
i
,
x
in
enumerate
([
width
-
margin
-
14
,
width
-
margin
-
26
,
width
-
margin
-
38
]):
cr
.
arc
(
x
,
ctrl_y
,
4
,
0
,
2
*
math
.
pi
)
cr
.
fill
()
# Draw content lines
content_start
=
sidebar_width
+
8
cr
.
set_source_rgba
(
accent_rgba
.
red
,
accent_rgba
.
green
,
accent_rgba
.
blue
,
0.6
)
for
y
in
[
28
,
46
,
64
]:
cr
.
rectangle
(
content_start
,
y
,
width
-
content_start
-
8
,
6
)
# Content area mockup
content_y
=
margin
+
header_h
+
10
content_x
=
margin
+
10
content_w
=
width
-
margin
*
2
-
20
cr
.
set_source_rgba
(
hb
.
red
,
hb
.
green
,
hb
.
blue
,
0.4
)
for
i
,
y
in
enumerate
([
content_y
,
content_y
+
14
,
content_y
+
28
]):
w
=
content_w
if
i
==
0
else
content_w
*
(
0.7
if
i
==
1
else
0.5
)
self
.
_rounded_rect
(
cr
,
content_x
,
y
,
w
,
8
,
2
)
cr
.
fill
()
def
update_display
(
self
):
current_value
=
self
.
setting
.
_get_backend_value
()
with
GObject
.
signal_handler_block
(
self
.
flowbox
,
self
.
handler_id
):
if
current_value
in
self
.
theme_cards
:
self
.
flowbox
.
select_child
(
self
.
theme_cards
[
current_value
])
self
.
_redraw_borders
()
self
.
_update_reset_visibility
()
def
on_map_updated
(
self
):
...
...
@@ -271,9 +308,19 @@ class ThemeChooserWidget(BaseWidget):
self
.
_build_cards
()
self
.
_update_reset_visibility
()
def
_redraw_borders
(
self
):
"""Redraw all border overlays to update selection state."""
for
border_area
in
self
.
border_overlays
.
values
():
border_area
.
queue_draw
()
def
_on_accent_color_changed
(
self
,
style_manager
,
pspec
):
"""Redraw borders when system accent color changes."""
self
.
_redraw_borders
()
def
_on_theme_selected
(
self
,
flowbox
,
child
):
value
=
child
.
value
self
.
setting
.
_set_backend_value
(
value
)
self
.
_redraw_borders
()
self
.
_update_reset_visibility
()
def
_on_reset_clicked
(
self
,
button
):
...
...
@@ -282,10 +329,7 @@ class ThemeChooserWidget(BaseWidget):
if
default_value
is
not
None
:
self
.
setting
.
_set_backend_value
(
default_value
)
if
default_value
in
self
.
theme_cards
:
with
GObject
.
signal_handler_block
(
self
.
flowbox
,
self
.
handler_id
):
self
.
flowbox
.
select_child
(
self
.
theme_cards
[
default_value
])
self
.
_redraw_borders
()
self
.
_update_reset_visibility
()
def
_update_reset_visibility
(
self
):
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment