一大波更新

master
yutent 2023-08-17 20:51:59 +08:00
parent a53302eb62
commit e78c60aca9
30 changed files with 299 additions and 5 deletions

5
Readme.md Normal file
View File

@ -0,0 +1,5 @@
<div align="center">
<img src="./preview/image.png">
</div>

View File

@ -10,6 +10,7 @@ gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk, GLib, GdkPixbuf from gi.repository import Gtk, Gdk, GLib, GdkPixbuf
from window import SonistWindow from window import SonistWindow
# from mpd.asyncio import MPDClient # from mpd.asyncio import MPDClient
from mpd.base import MPDClient from mpd.base import MPDClient
@ -20,7 +21,7 @@ class Application(Gtk.Application):
def __init__(self): def __init__(self):
Gtk.Application.__init__(self, application_id = app_id) Gtk.Application.__init__(self, application_id = app_id)
self.window = SonistWindow() self.add_window(SonistWindow())
self.mpc = MPDClient() self.mpc = MPDClient()
self.mpc.timeout = 10 self.mpc.timeout = 10
@ -29,6 +30,8 @@ class Application(Gtk.Application):
def do_activate(self): def do_activate(self):
print('hello mpc') print('hello mpc')
self.set_app_menu(None)
self.set_menubar(None)
# self.window.show_all() # self.window.show_all()

BIN
preview/image.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

58
ui/image.py Normal file
View File

@ -0,0 +1,58 @@
#!/usr/bin/env python3
import gi, cairo, math
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk, GdkPixbuf
class ScaleImage(Gtk.Image):
def __init__(self, filepath):
Gtk.Image.__init__(self)
self.origin = GdkPixbuf.Pixbuf.new_from_file(filepath)
self.pixbuf = self.origin
self.width = self.origin.get_width()
self.height = self.origin.get_height()
self.set_from_pixbuf(self.origin)
def resize(self, width, height):
self.width = width
self.height = height
self.pixbuf = self.origin.scale_simple(width, height, GdkPixbuf.InterpType.BILINEAR)
self.set_from_pixbuf(self.pixbuf)
def set_radius(self, radius = 0):
w = self.width
h = self.height
surface = cairo.ImageSurface(cairo.Format.ARGB32, w, h)
ctx = cairo.Context(surface)
Gdk.cairo_set_source_pixbuf(ctx, self.pixbuf, 0, 0)
# 左上角 圆角
ctx.arc(radius, radius, radius, -math.pi, -math.pi / 2.)
ctx.line_to(w - radius, 0)
# 右上角 圆角
ctx.arc(w - radius, radius, radius, -math.pi / 2., 0)
ctx.line_to(w, -radius)
# 右下角 圆角
ctx.arc(w - radius, h - radius, radius, 0, math.pi / 2.)
ctx.line_to(radius, h)
# 左下角 圆角
ctx.arc(radius, h - radius, radius, math.pi / 2., math.pi)
ctx.close_path()
ctx.clip()
ctx.paint()
pixbuf = Gdk.pixbuf_get_from_surface(surface, 0, 0, w, h)
self.set_from_pixbuf(pixbuf)

32
ui/image_button.py Normal file
View File

@ -0,0 +1,32 @@
#!/usr/bin/env python3
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from .image import ScaleImage
class ImageButton(Gtk.Button):
def __init__(self, filepath, width = 26, height = 26):
Gtk.Button.__init__(self)
self.set_name('ImageButton')
self.set_size_request(width, height)
image = ScaleImage(filepath)
image.resize(width, height)
self.set_image(image)
css_provider = Gtk.CssProvider()
style = f"""
#ImageButton {{
border: 0;
background-color: transparent;
outline: none;
}}
"""
css_provider.load_from_data(style.encode('UTF-8'))
context = self.get_style_context()
context.add_provider(css_provider, Gtk.STYLE_PROVIDER_PRIORITY_USER)

38
ui/slider.py Normal file
View File

@ -0,0 +1,38 @@
#!/usr/bin/env python3
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
class Slider(Gtk.Scale):
def __init__(self, width = 256, height = 5):
Gtk.Scale.__init__(self)
self.set_name('Slider')
self.set_range(0, 100)
self.set_size_request(width, height)
self.set_draw_value(False)
css_provider = Gtk.CssProvider()
style = f"""
#Slider {{
outline: none;
}}
#Slider trough {{
background-color: rgba(129, 161, 193, 0.35);
outline: none;
}}
#Slider trough highlight {{
background-color: rgba(163, 190, 140, 0.75);
}}
#Slider slider {{
background-color: rgba(163, 190, 140, 0.75);
outline: none;
}}
"""
css_provider.load_from_data(style.encode('UTF-8'))
context = self.get_style_context()
context.add_provider(css_provider, Gtk.STYLE_PROVIDER_PRIORITY_USER)

23
ui/text.py Normal file
View File

@ -0,0 +1,23 @@
#!/usr/bin/env python3
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
class TextBox(Gtk.EventBox):
def __init__(self, width, height):
Gtk.EventBox.__init__(self)
self.set_size_request(width, height)
self.label = Gtk.Label()
align = Gtk.Alignment(xalign=0.5, yalign=0.5)
self.add(self.label)
self.add(align)
def set_text(self, string):
self.label.set_text('孙晓 - 丹歌惊鸿')

BIN
usr/share/sonist/album.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
usr/share/sonist/all.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

BIN
usr/share/sonist/all_a.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
usr/share/sonist/avatar.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

BIN
usr/share/sonist/disk.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

BIN
usr/share/sonist/mute.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
usr/share/sonist/mute_a.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
usr/share/sonist/next.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

BIN
usr/share/sonist/next_a.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
usr/share/sonist/pause.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
usr/share/sonist/play.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
usr/share/sonist/play_a.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

BIN
usr/share/sonist/prev.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
usr/share/sonist/prev_a.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

BIN
usr/share/sonist/rand.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
usr/share/sonist/rand_a.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
usr/share/sonist/single.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

BIN
usr/share/sonist/volume.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

36
utils.py Normal file
View File

@ -0,0 +1,36 @@
#!/usr/bin/env python3
import gi
from gi.repository import Gdk, GLib, GdkPixbuf
from PIL import Image, ImageFilter
def pixbuf_to_pil(pixbuf):
data = pixbuf.get_pixels()
w = pixbuf.get_width()
h = pixbuf.get_height()
stride = pixbuf.get_rowstride()
mode = "RGBA" if pixbuf.get_has_alpha() else "RGB"
img = Image.frombytes(mode, (w, h), data, "raw", mode, stride)
return img
def pil_to_pixbuf(img):
data = []
for p in img.getdata():
data.extend(p)
data = bytes(data)
alpha = img.mode == 'RGBA'
w, h = img.size
rowstride = w * 4
return GdkPixbuf.Pixbuf.new_from_bytes(GLib.Bytes.new(data), GdkPixbuf.Colorspace.RGB, alpha, 8, w, h, rowstride)
def blur_image(pixbuf):
# 加载图片并确认该图片为RGBA模式保证透明度
img = pixbuf_to_pil(pixbuf).convert('RGBA')
mask = Image.new('RGBA', img.size, (32, 32, 32,160))
img = img.filter(ImageFilter.GaussianBlur(radius = 16))
img.alpha_composite(mask)
return pil_to_pixbuf(img)

107
window.py
View File

@ -7,14 +7,113 @@ gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk, GLib, GdkPixbuf from gi.repository import Gtk, Gdk, GLib, GdkPixbuf
from utils import blur_image
from ui.image import ScaleImage
from ui.slider import Slider
from ui.image_button import ImageButton
from ui.text import TextBox
class SonistWindow(Gtk.Window): class SonistWindow(Gtk.Window):
def __init__(self): def __init__(self):
Gtk.Window.__init__(self) Gtk.Window.__init__(self)
self.set_default_size(480, 320) self.set_name('SonistWindow')
self.set_default_size(320, 384)
self.set_wmclass('Sonist', 'Sonist')
button = Gtk.Button() self.set_opacity(0.9)
self.add(button) # self.set_keep_above(True)
self.show_all() # album_img = './usr/share/sonist/album.png'
album_img = './usr/share/sonist/avatar.jpg'
self.connect("destroy", self.all_quit)
self.set_background_image(album_img)
layout = Gtk.Layout()
# 唱片
disk = ScaleImage('./usr/share/sonist/disk.png')
album = ScaleImage(album_img)
disk.resize(192, 192)
album.resize(128, 128)
album.set_radius(64)
box = Gtk.Fixed()
box.put(disk, 0, 0)
box.put(album, 32, 32)
layout.put(box, 64, 32)
# title
title_box = TextBox(256, 20)
title_box.set_text('孙晓 - 丹歌惊鸿')
layout.put(title_box, 32, 244)
# 播放进度
slider = Slider()
layout.put(slider, 32, 270)
# 控制条
ctrl_box = Gtk.Box(spacing = 6)
all = ImageButton('./usr/share/sonist/all.png')
# rand = ImageButton('./usr/share/sonist/rand.png')
prev = ImageButton('./usr/share/sonist/prev.png')
pause = ImageButton('./usr/share/sonist/pause.png', 48, 48)
next = ImageButton('./usr/share/sonist/next.png')
volume = ImageButton('./usr/share/sonist/volume.png')
ctrl_box.pack_start(all, True, True, 0)
# ctrl_box.pack_start(rand, True, True, 0)
ctrl_box.pack_start(prev, True, True, 0)
ctrl_box.pack_start(pause, True, True, 0)
ctrl_box.pack_start(next, True, True, 0)
ctrl_box.pack_start(volume, True, True, 0)
layout.put(ctrl_box, 48, 300)
self.add(layout)
self.show_all()
def set_background_image(self, filepath):
pixbuf = GdkPixbuf.Pixbuf.new_from_file(filepath)
pixbuf = blur_image(pixbuf)
pixbuf.savev(f"/tmp/sonist_album_cache", 'png', [], [])
css = f"""
#SonistWindow {{
background-image: url('/tmp/sonist_album_cache');
background-size: 100% 100%;
background-position: center;
}}
"""
# 加载CSS样式
css_provider = Gtk.CssProvider()
css_provider.load_from_data(css.encode('UTF-8'))
context = Gtk.StyleContext()
screen = Gdk.Screen.get_default()
context.add_provider_for_screen(screen, css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
def all_quit(self, win):
print('朕要休息了~~~')
Gtk.main_quit()