Merge branch 'issue-85-gtk4' into 'main'

Draft: Port UI to GTK 4

See merge request coderkun/mcg!4
This commit is contained in:
coderkun 2023-01-16 23:47:28 +00:00
commit 9942863b97
23 changed files with 1675 additions and 2206 deletions

View file

@ -1,8 +1,20 @@
.bg-texture { #content_stack {
box-shadow:inset 4px 4px 10px rgba(0,0,0,0.3); box-shadow:inset 4px 4px 10px rgba(0,0,0,0.3);
background-image:url('noise-texture.png'); background-image:url('noise-texture.png');
} }
#port_spinner {
background:none;
margin-top:-13px;
}
#port_spinner text {
padding-left: 0;
}
#server_stack_sidebar {
background-color:alpha(@theme_bg_color, 1);
}
.no-bg { .no-bg {
background:none; background:none;
} }
@ -18,13 +30,13 @@
font-weight:bold; font-weight:bold;
} }
revealer.sidebar > * { #cover_info_revealer {
background-color:alpha(@theme_bg_color, 0.8); background-color:alpha(@theme_bg_color, 0.8);
box-shadow:0 0 10px @theme_bg_color; box-shadow:0 0 10px @theme_bg_color;
margin-left:20px margin-left:20px;
} }
revealer.sidebar scale mark indicator { #cover_info_revealer scale mark indicator {
margin-right:5px; margin-right:5px;
} }
@ -32,24 +44,6 @@ actionbar {
background-color:@theme_unfocused_bg_color; background-color:@theme_unfocused_bg_color;
} }
/* Icon View in regular mode */ gridview child {
iconview.view:selected, padding: 10px;
iconview.view:selected:focus {
background-color:@theme_selected_bg_color;
}
iconview.view:hover {
-gtk-icon-effect:highlight;
}
/* Icon View in selection mode */
iconview.view.selection {
-gtk-icon-effect:dim;
}
iconview.view.selection:selected,
iconview.view.selection:selected:focus {
background-color:@theme_selected_bg_color;
-gtk-icon-effect:highlight;
}
iconview.view.selection:hover {
-gtk-icon-effect:none;
} }

View file

@ -1,8 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.2 -->
<interface> <interface>
<requires lib="gtk+" version="3.10"/> <requires lib="gtk+" version="4.8"/>
<template class="McgAlbumHeaderbar" parent="GtkHeaderBar"> <requires lib="adw" version="1.2" />
<template class="McgAlbumHeaderbar" parent="AdwBin">
<child>
<object class="GtkHeaderBar">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can-focus">False</property> <property name="can-focus">False</property>
<child type="title"> <child type="title">
@ -21,11 +23,13 @@
<attribute name="scale" value="1"/> <attribute name="scale" value="1"/>
</attributes> </attributes>
</object> </object>
<!--
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
<property name="fill">True</property> <property name="fill">True</property>
<property name="position">0</property> <property name="position">0</property>
</packing> </packing>
-->
</child> </child>
<child> <child>
<object class="GtkLabel" id="standalone_artist"> <object class="GtkLabel" id="standalone_artist">
@ -34,11 +38,13 @@
<property name="label" translatable="yes">Artist</property> <property name="label" translatable="yes">Artist</property>
<property name="selectable">True</property> <property name="selectable">True</property>
</object> </object>
<!--
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
<property name="fill">True</property> <property name="fill">True</property>
<property name="position">1</property> <property name="position">1</property>
</packing> </packing>
-->
</child> </child>
</object> </object>
</child> </child>
@ -57,5 +63,7 @@
</child> </child>
</object> </object>
</child> </child>
</template> </object>
</child>
</template>
</interface> </interface>

View file

@ -1,182 +1,86 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.2 -->
<interface> <interface>
<requires lib="gtk+" version="3.12"/> <requires lib="gtk+" version="4.8"/>
<object class="GtkAdjustment" id="server-port-adjustment"> <requires lib="adw" version="1.2" />
<property name="lower">1024</property> <object class="GtkAdjustment" id="server-port-adjustment">
<property name="upper">9999</property> <property name="lower">1024</property>
<property name="value">6600</property> <property name="upper">9999</property>
<property name="step-increment">1</property> <property name="value">6600</property>
<property name="page-increment">100</property> <property name="step-increment">1</property>
</object> <property name="page-increment">100</property>
<template class="McgConnectionPanel" parent="GtkBox"> </object>
<property name="visible">True</property> <object class="GtkBox" id="toolbar">
<property name="can-focus">False</property> <property name="orientation">horizontal</property>
<property name="orientation">vertical</property> <property name="spacing">6</property>
<child> </object>
<object class="GtkBox"> <template class="McgConnectionPanel" parent="AdwBin">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child> <child>
<!-- n-columns=3 n-rows=6 --> <object class="AdwStatusPage">
<object class="GtkGrid"> <property name="title">Connect to MPD</property>
<property name="width-request">500</property>
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="column-spacing">5</property>
<property name="row-homogeneous">True</property>
<property name="column-homogeneous">True</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child> <child>
<object class="GtkTreeView" id="zeroconf_list"> <object class="GtkBox">
<property name="visible">True</property> <property name="hexpand">false</property>
<property name="can-focus">True</property> <property name="halign">center</property>
<signal name="focus-out-event" handler="on_zeroconf_list_outfocused" swapped="no"/> <child>
<child internal-child="selection"> <object class="GtkListBox" id="zeroconf_list">
<object class="GtkTreeSelection"> <property name="hexpand">true</property>
<signal name="changed" handler="on_service_selected" swapped="no"/> <child type="placeholder">
</object> <object class="GtkLabel">
</child> <property name="label" translatable="true">No service found</property>
</object> </object>
<packing> </child>
<property name="expand">True</property> </object>
<property name="fill">True</property> </child>
<property name="position">0</property> <child>
</packing> <object class="GtkListBox">
<property name="hexpand">true</property>
<property name="selection-mode">none</property>
<style>
<class name="boxed-list"/>
</style>
<child>
<object class="AdwEntryRow" id="host_row">
<property name="title" translatable="true">Host</property>
<property name="show-apply-button">true</property>
<signal name="apply" handler="on_host_entry_apply"/>
</object>
</child>
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<style>
<class name="header"/>
</style>
<child>
<object class="GtkLabel">
<property name="label" translatable="true">Port</property>
<property name="halign">start</property>
<property name="hexpand">false</property>
<style>
<class name="subtitle"/>
</style>
</object>
</child>
<child>
<object class="GtkSpinButton" id="port_spinner">
<property name="name">port_spinner</property>
<property name="value">6600</property>
<property name="adjustment">server-port-adjustment</property>
<signal name="value-changed" handler="on_port_spinner_value_changed"/>
</object>
</child>
</object>
</child>
<child>
<object class="AdwPasswordEntryRow" id="password_row">
<property name="title" translatable="true">Password</property>
<property name="show-apply-button">true</property>
</object>
</child>
</object>
</child>
</object>
</child> </child>
<child> </object>
<object class="GtkSeparator">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-start">5</property>
<property name="orientation">vertical</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack-type">end</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">0</property>
<property name="height">6</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="host_entry">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="text">localhost</property>
<property name="placeholder-text" translatable="yes">Enter hostname or IP address</property>
<signal name="focus-out-event" handler="on_host_entry_outfocused" swapped="no"/>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">1</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="password_entry">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="visibility">False</property>
<property name="placeholder-text" translatable="yes">Enter password or leave blank</property>
<property name="input-purpose">password</property>
<signal name="focus-out-event" handler="on_password_entry_outfocused" swapped="no"/>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">5</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="port_spinner">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="text">6600</property>
<property name="input-purpose">number</property>
<property name="adjustment">server-port-adjustment</property>
<property name="value">6600</property>
<signal name="value-changed" handler="on_port_spinner_value_changed" swapped="no"/>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">3</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Host:</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Port:</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">2</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Password:</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">4</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child> </child>
</object> </template>
<packing>
<property name="expand">True</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
</template>
</interface> </interface>

View file

@ -1,199 +1,198 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.2 -->
<interface> <interface>
<requires lib="gtk+" version="3.22"/> <requires lib="gtk+" version="4.8"/>
<template class="McgCoverPanel" parent="GtkOverlay"> <requires lib="adw" version="1.2" />
<property name="visible">True</property> <object class="GtkBox" id="toolbar">
<property name="can-focus">False</property> <property name="orientation">horizontal</property>
<child>
<object class="GtkStack" id="cover_stack">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkSpinner" id="cover_spinner">
<property name="visible">True</property>
<property name="can-focus">False</property>
</object>
<packing>
<property name="name">cover-spinner</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="cover_scroll">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="kinetic-scrolling">False</property>
<property name="overlay-scrolling">False</property>
<signal name="size-allocate" handler="on_cover_size_allocate" swapped="no"/>
<child>
<object class="GtkViewport">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkEventBox" id="cover_box">
<property name="visible">True</property>
<property name="can-focus">False</property>
<signal name="button-press-event" handler="on_cover_box_pressed" swapped="no"/>
<child>
<object class="GtkImage" id="cover_image">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon_size">0</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="name">cover-scroll</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="index">-1</property>
</packing>
</child>
<child type="overlay">
<object class="GtkRevealer" id="info_revealer">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">end</property> <property name="halign">end</property>
<property name="transition-type">slide-right</property> <property name="spacing">6</property>
<child> <child>
<object class="GtkScrolledWindow" id="cover_info_scroll"> <object class="GtkButton" id="fullscreen_button">
<property name="visible">True</property> <property name="receives-default">True</property>
<property name="can-focus">True</property> <property name="tooltip-text" translatable="yes">Show the cover in fullscreen mode</property>
<property name="halign">start</property> <property name="action-name">win.toggle-fullscreen</property>
<property name="vscrollbar-policy">never</property>
<property name="max-content-width">200</property>
<property name="propagate-natural-width">True</property>
<child>
<object class="GtkViewport">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="shadow-type">none</property>
<child> <child>
<object class="GtkBox"> <object class="GtkImage">
<property name="visible">True</property> <property name="icon-name">view-fullscreen-symbolic</property>
<property name="can-focus">False</property> </object>
<property name="halign">start</property>
<property name="margin-start">5</property>
<property name="margin-end">5</property>
<property name="margin-top">5</property>
<property name="margin-bottom">5</property>
<property name="orientation">vertical</property>
<child>
<!-- n-columns=3 n-rows=3 -->
<object class="GtkGrid">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-start">5</property>
<property name="margin-bottom">5</property>
<property name="row-spacing">5</property>
<property name="column-homogeneous">True</property>
<child>
<object class="GtkLabel" id="album_title_label">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="label">Album</property>
<property name="wrap">True</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="album_date_label">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="label">Date</property>
<property name="wrap">True</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="album_artist_label">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="label">Artist</property>
<property name="wrap">True</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">2</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<style>
<class name="cover-labels"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">10</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkScale" id="songs_scale">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="orientation">vertical</property>
<property name="restrict-to-fill-level">False</property>
<property name="digits">0</property>
<property name="draw-value">False</property>
<signal name="button-press-event" handler="on_songs_start_change" swapped="no"/>
<signal name="button-release-event" handler="on_songs_change" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="pack-type">end</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child> </child>
</object> </object>
</child>
</object>
</child> </child>
<style> </object>
<class name="sidebar"/> <template class="McgCoverPanel" parent="GtkOverlay">
<class name="background"/> <child>
</style> <object class="GtkStack" id="cover_stack">
</object> <child>
</child> <object class="GtkSpinner" id="cover_spinner">
</template> </object>
</child>
<child>
<object class="GtkImage" id="cover_default">
<property name="icon-name">image-x-generic-symbolic</property>
</object>
</child>
<child>
<object class="GtkScrolledWindow" id="cover_scroll">
<property name="kinetic-scrolling">False</property>
<property name="overlay-scrolling">False</property>
<property name="hexpand">true</property>
<property name="halign">fill</property>
<property name="vexpand">true</property>
<property name="valign">fill</property>
<child>
<object class="GtkViewport" id="cover_box">
<property name="hexpand">true</property>
<property name="halign">fill</property>
<property name="vexpand">true</property>
<property name="valign">fill</property>
<child>
<object class="GtkImage" id="cover_image">
<property name="hexpand">true</property>
<property name="halign">fill</property>
<property name="vexpand">true</property>
<property name="valign">fill</property>
<property name="icon-name">image-x-generic-symbolic</property>
<property name="icon-size">large</property>
<!--
<signal name="button-press-event" handler="on_cover_box_pressed" swapped="no"/>
-->
</object>
</child>
</object>
</child>
</object>
<!--
<packing>
<property name="name">cover-scroll</property>
<property name="position">1</property>
</packing>
-->
</child>
</object>
<!--
<packing>
<property name="index">-1</property>
</packing>
-->
</child>
<child type="overlay">
<object class="GtkRevealer" id="info_revealer">
<property name="halign">end</property>
<property name="transition-type">slide-right</property>
<property name="name">cover_info_revealer</property>
<style>
<!--
<class name="sidebar"/>
-->
<class name="background"/>
</style>
<child>
<object class="GtkScrolledWindow" id="cover_info_scroll">
<property name="halign">start</property>
<property name="vscrollbar-policy">never</property>
<property name="max-content-width">200</property>
<property name="propagate-natural-width">True</property>
<property name="name">cover_info_scroll</property>
<child>
<object class="GtkViewport">
<!--
<property name="shadow-type">none</property>
-->
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="halign">start</property>
<property name="valign">fill</property>
<property name="vexpand">true</property>
<property name="margin-start">5</property>
<property name="margin-end">5</property>
<property name="margin-top">5</property>
<property name="margin-bottom">5</property>
<child>
<object class="GtkGrid">
<property name="margin-start">5</property>
<property name="margin-bottom">5</property>
<property name="row-spacing">5</property>
<property name="column-homogeneous">True</property>
<style>
<class name="cover-labels"/>
</style>
<child>
<object class="GtkLabel" id="album_title_label">
<property name="halign">start</property>
<property name="label">Album</property>
<property name="wrap">True</property>
<property name="xalign">0</property>
<layout>
<property name="column">0</property>
<property name="row">0</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel" id="album_date_label">
<property name="halign">start</property>
<property name="label">Date</property>
<property name="wrap">True</property>
<property name="xalign">0</property>
<layout>
<property name="column">0</property>
<property name="row">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel" id="album_artist_label">
<property name="halign">start</property>
<property name="label">Artist</property>
<property name="wrap">True</property>
<property name="xalign">0</property>
<layout>
<property name="column">0</property>
<property name="row">2</property>
</layout>
</object>
</child>
</object>
<!--
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">10</property>
<property name="position">0</property>
</packing>
-->
</child>
<child>
<object class="GtkScale" id="songs_scale">
<property name="orientation">vertical</property>
<property name="valign">fill</property>
<property name="vexpand">true</property>
<property name="restrict-to-fill-level">False</property>
<property name="digits">0</property>
<property name="draw-value">False</property>
<!--
<signal name="button-press-event" handler="on_songs_start_change" swapped="no"/>
<signal name="button-release-event" handler="on_songs_change" swapped="no"/>
-->
</object>
<!--
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="pack-type">end</property>
<property name="position">1</property>
</packing>
-->
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</template>
</interface> </interface>

View file

@ -1,33 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.2 -->
<interface>
<requires lib="gtk+" version="3.10"/>
<template class="McgCoverToolbar" parent="GtkButtonBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="spacing">6</property>
<property name="layout-style">end</property>
<child>
<object class="GtkButton" id="fullscreen_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="tooltip-text" translatable="yes">Show the cover in fullscreen mode</property>
<property name="action-name">win.toggle-fullscreen</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">view-fullscreen-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
<property name="non-homogeneous">True</property>
</packing>
</child>
</template>
</interface>

View file

@ -1,11 +1,278 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.2 -->
<interface> <interface>
<requires lib="gtk+" version="3.16"/> <requires lib="gtk+" version="4.8"/>
<template class="McgLibraryPanel" parent="GtkStack"> <requires lib="adw" version="1.2" />
<property name="visible">True</property> <object class="GtkAdjustment" id="grid_adjustment">
<property name="can-focus">False</property> <property name="lower">100</property>
<property name="transition-type">slide-left-right</property> <property name="upper">1000</property>
<property name="value">150</property>
<property name="step-increment">1</property>
<property name="page-increment">10</property>
</object>
<object class="GtkPopover" id="toolbar_popover">
<property name="can-focus">False</property>
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="halign">end</property>
<child>
<object class="GtkScale" id="grid_scale">
<property name="width-request">350</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="adjustment">grid_adjustment</property>
<property name="restrict-to-fill-level">False</property>
<property name="fill-level">-1</property>
<property name="round-digits">0</property>
<property name="digits">0</property>
<property name="has-origin">False</property>
<!--
<signal name="button-release-event" handler="on_grid_scale_changed" swapped="no"/>
-->
<signal name="change-value" handler="on_grid_scale_change" swapped="no"/>
</object>
<!--
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
-->
</child>
<child>
<object class="GtkButton" id="library-toolbar-update">
<property name="label">gtk-refresh</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<!--
<property name="relief">none</property>
<property name="use-stock">True</property>
-->
<signal name="clicked" handler="on_update_clicked" swapped="no"/>
</object>
<!--
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
-->
</child>
<child>
<object class="GtkBox" id="library-toolbar-sort">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkSeparator">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
</object>
<!--
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
-->
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Sort</property>
</object>
<!--
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
-->
</child>
<child>
<object class="GtkCheckButton" id="sort_artist">
<property name="label" translatable="yes">sort by artist</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<!--
<property name="draw-indicator">True</property>
-->
<property name="group">sort_year</property>
<signal name="toggled" handler="on_sort_toggled" swapped="no"/>
</object>
<!--
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
-->
</child>
<child>
<object class="GtkCheckButton" id="sort_title">
<property name="label" translatable="yes">sort by title</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<!--
<property name="draw-indicator">True</property>
-->
<property name="group">sort_year</property>
<signal name="toggled" handler="on_sort_toggled" swapped="no"/>
</object>
<!--
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
-->
</child>
<child>
<object class="GtkCheckButton" id="sort_year">
<property name="label" translatable="yes">sort by year</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="active">True</property>
<!--
<property name="draw-indicator">True</property>
-->
<signal name="toggled" handler="on_sort_toggled" swapped="no"/>
</object>
<!--
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
-->
</child>
<child>
<object class="GtkCheckButton" id="toolbar_sort_order_button">
<property name="label">gtk-sort-descending</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<!--
<property name="use-stock">True</property>
<property name="draw-indicator">True</property>
-->
<property name="active">True</property>
<signal name="toggled" handler="on_sort_order_toggled" swapped="no"/>
</object>
<!--
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">5</property>
</packing>
-->
</child>
</object>
<!--
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
-->
</child>
</object>
</child>
</object>
<object class="GtkBox" id="toolbar">
<property name="orientation">horizontal</property>
<property name="halign">end</property>
<property name="spacing">6</property>
<child>
<object class="GtkToggleButton" id="toolbar_search_bar">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="tooltip-text" translatable="yes">Search the library</property>
<signal name="toggled" handler="on_search_toggled" swapped="no"/>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">system-search-symbolic</property>
</object>
</child>
<!--
<accelerator key="f" signal="activate" modifiers="GDK_CONTROL_MASK"/>
-->
</object>
<!--
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
<property name="non-homogeneous">True</property>
</packing>
-->
</child>
<child>
<object class="GtkToggleButton" id="select_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="tooltip-text" translatable="yes">Select multiple albums</property>
<signal name="toggled" handler="on_select_toggled" swapped="no"/>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">object-select-symbolic</property>
</object>
</child>
</object>
<!--
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
<property name="non-homogeneous">True</property>
</packing>
-->
</child>
<child>
<object class="GtkMenuButton">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="tooltip-text" translatable="yes">Settings and actions</property>
<property name="popover">toolbar_popover</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">open-menu-symbolic</property>
</object>
</child>
</object>
<!--
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
<property name="non-homogeneous">True</property>
</packing>
-->
</child>
</object>
<template class="McgLibraryPanel" parent="AdwBin">
<child>
<object class="GtkStack">
<property name="transition-type">slide-left-right</property>
<child> <child>
<object class="GtkBox" id="panel_normal"> <object class="GtkBox" id="panel_normal">
<property name="visible">True</property> <property name="visible">True</property>
@ -13,27 +280,31 @@
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="GtkSearchBar" id="filter_bar"> <object class="GtkSearchBar" id="filter_bar">
<property name="visible">True</property> <!--
<property name="app-paintable">True</property> <property name="app-paintable">True</property>
<property name="can-focus">False</property> -->
<signal name="notify" handler="on_filter_bar_notify" swapped="no"/> <signal name="notify" handler="on_filter_bar_notify" swapped="no"/>
<child> <child>
<object class="GtkSearchEntry" id="filter_entry"> <object class="GtkSearchEntry" id="filter_entry">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can-focus">True</property> <property name="can-focus">True</property>
<!--
<property name="primary-icon-name">edit-find-symbolic</property> <property name="primary-icon-name">edit-find-symbolic</property>
<property name="primary-icon-activatable">False</property> <property name="primary-icon-activatable">False</property>
<property name="primary-icon-sensitive">False</property> <property name="primary-icon-sensitive">False</property>
-->
<property name="placeholder-text" translatable="yes">search library</property> <property name="placeholder-text" translatable="yes">search library</property>
<signal name="search-changed" handler="on_filter_entry_changed" swapped="no"/> <signal name="search-changed" handler="on_filter_entry_changed" swapped="no"/>
</object> </object>
</child> </child>
</object> </object>
<!--
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
<property name="fill">True</property> <property name="fill">True</property>
<property name="position">0</property> <property name="position">0</property>
</packing> </packing>
-->
</child> </child>
<child> <child>
<placeholder/> <placeholder/>
@ -62,15 +333,16 @@
<property name="spacing">10</property> <property name="spacing">10</property>
<child> <child>
<object class="GtkImage" id="progress_image"> <object class="GtkImage" id="progress_image">
<property name="visible">True</property> <property name="icon-size">large</property>
<property name="can-focus">False</property> <property name="icon-name">image-x-generic-symbolic</property>
<property name="icon_size">6</property>
</object> </object>
<!--
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
<property name="fill">True</property> <property name="fill">True</property>
<property name="position">0</property> <property name="position">0</property>
</packing> </packing>
-->
</child> </child>
<child> <child>
<object class="GtkProgressBar" id="progress_bar"> <object class="GtkProgressBar" id="progress_bar">
@ -80,87 +352,135 @@
<property name="pulse-step">0</property> <property name="pulse-step">0</property>
<property name="show-text">True</property> <property name="show-text">True</property>
</object> </object>
<!--
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
<property name="fill">True</property> <property name="fill">True</property>
<property name="position">1</property> <property name="position">1</property>
</packing> </packing>
-->
</child> </child>
</object> </object>
<!--
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
<property name="fill">True</property> <property name="fill">True</property>
<property name="position">1</property> <property name="position">1</property>
</packing> </packing>
-->
</child> </child>
<child> <child>
<placeholder/> <placeholder/>
</child> </child>
</object> </object>
<!--
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
<property name="fill">True</property> <property name="fill">True</property>
<property name="position">1</property> <property name="position">1</property>
</packing> </packing>
-->
</child> </child>
<child> <child>
<placeholder/> <placeholder/>
</child> </child>
</object> </object>
<!--
<packing> <packing>
<property name="name">page1</property> <property name="name">page1</property>
<property name="title">page1</property> <property name="title">page1</property>
</packing> </packing>
-->
</child> </child>
<child> <child>
<object class="GtkScrolledWindow" id="scroll"> <object class="GtkScrolledWindow" id="scroll">
<property name="visible">True</property> <property name="vexpand">true</property>
<property name="can-focus">True</property>
<child> <child>
<object class="GtkIconView" id="library_grid"> <object class="GtkGridView" id="library_grid">
<property name="visible">True</property> <property name="orientation">vertical</property>
<property name="can-focus">True</property> <!--
<property name="margin">0</property> <signal name="activate" handler="on_library_grid_clicked" swapped="no"/>
<property name="item-orientation">horizontal</property> <signal name="selection-changed" handler="on_library_grid_selection_changed" swapped="no"/>
<property name="row-spacing">0</property> <signal name="size-allocate" handler="on_resize" swapped="no"/>
<property name="column-spacing">0</property> -->
<property name="tooltip-column">1</property> <style>
<property name="item-padding">0</property> <class name="no-bg"/>
<property name="activate-on-single-click">True</property> </style>
<signal name="item-activated" handler="on_library_grid_clicked" swapped="no"/> <property name="factory">
<signal name="selection-changed" handler="on_library_grid_selection_changed" swapped="no"/> <object class="GtkBuilderListItemFactory">
<signal name="size-allocate" handler="on_resize" swapped="no"/> <property name="bytes">
<style> <![CDATA[
<class name="no-bg"/> <?xml version="1.0" encoding="UTF-8"?>
</style> <interface>
</object> <template class="GtkListItem">
<property name="child">
<object class="GtkBox">
<property name="orientation">vertical</property>
<!--
<child>
<object class="GtkLabel">
<property name="hexpand">false</property>
<binding name="label">
<lookup name="title" type="GridItem">
<lookup name="item">GtkListItem</lookup>
</lookup>
</binding>
</object>
</child>
-->
<child>
<object class="GtkPicture">
<property name="content-fit">contain</property>
<property name="can-shrink">false</property>
<binding name="tooltip-markup">
<lookup name="tooltip" type="GridItem">
<lookup name="item">GtkListItem</lookup>
</lookup>
</binding>
<binding name="paintable">
<lookup name="cover" type="GridItem">
<lookup name="item">GtkListItem</lookup>
</lookup>
</binding>
</object>
</child>
</object>
</property>
</template>
</interface>
]]>
</property>
</object>
</property>
</object>
</child> </child>
<style> <style>
<class name="no-bg"/> <class name="no-bg"/>
</style> </style>
</object> </object>
<!--
<packing> <packing>
<property name="name">page0</property> <property name="name">page0</property>
<property name="title">page0</property> <property name="title">page0</property>
<property name="position">1</property> <property name="position">1</property>
</packing> </packing>
-->
</child> </child>
</object> </object>
<!--
<packing> <packing>
<property name="expand">True</property> <property name="expand">True</property>
<property name="fill">True</property> <property name="fill">True</property>
<property name="position">2</property> <property name="position">2</property>
</packing> </packing>
-->
</child> </child>
<child> <child>
<object class="GtkRevealer" id="actionbar_revealer"> <object class="GtkRevealer" id="actionbar_revealer">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="transition-type">none</property> <property name="transition-type">none</property>
<property name="reveal-child">false</property>
<child> <child>
<object class="GtkActionBar" id="library-actionbar"> <object class="GtkActionBar" id="library-actionbar">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child> <child>
<object class="GtkButton"> <object class="GtkButton">
<property name="label" translatable="yes">cancel</property> <property name="label" translatable="yes">cancel</property>
@ -169,10 +489,12 @@
<property name="receives-default">True</property> <property name="receives-default">True</property>
<signal name="clicked" handler="on_selection_cancel_clicked" swapped="no"/> <signal name="clicked" handler="on_selection_cancel_clicked" swapped="no"/>
</object> </object>
<!--
<packing> <packing>
<property name="pack-type">end</property> <property name="pack-type">end</property>
<property name="position">1</property> <property name="position">1</property>
</packing> </packing>
-->
</child> </child>
<child> <child>
<object class="GtkButton"> <object class="GtkButton">
@ -182,25 +504,31 @@
<property name="receives-default">True</property> <property name="receives-default">True</property>
<signal name="clicked" handler="on_selection_add_clicked" swapped="no"/> <signal name="clicked" handler="on_selection_add_clicked" swapped="no"/>
</object> </object>
<!--
<packing> <packing>
<property name="pack-type">end</property> <property name="pack-type">end</property>
<property name="position">0</property> <property name="position">0</property>
</packing> </packing>
-->
</child> </child>
</object> </object>
</child> </child>
</object> </object>
<!--
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
<property name="fill">True</property> <property name="fill">True</property>
<property name="position">3</property> <property name="position">3</property>
</packing> </packing>
-->
</child> </child>
</object> </object>
<!--
<packing> <packing>
<property name="name">page0</property> <property name="name">page0</property>
<property name="title">page0</property> <property name="title">page0</property>
</packing> </packing>
-->
</child> </child>
<child> <child>
<object class="GtkBox" id="panel_standalone"> <object class="GtkBox" id="panel_standalone">
@ -217,9 +545,11 @@
<property name="visible">True</property> <property name="visible">True</property>
<property name="can-focus">False</property> <property name="can-focus">False</property>
</object> </object>
<!--
<packing> <packing>
<property name="name">standalone-spinne</property> <property name="name">standalone-spinne</property>
</packing> </packing>
-->
</child> </child>
<child> <child>
<object class="GtkScrolledWindow" id="standalone_scroll"> <object class="GtkScrolledWindow" id="standalone_scroll">
@ -227,7 +557,9 @@
<property name="can-focus">True</property> <property name="can-focus">True</property>
<property name="kinetic-scrolling">False</property> <property name="kinetic-scrolling">False</property>
<property name="overlay-scrolling">False</property> <property name="overlay-scrolling">False</property>
<!--
<signal name="size-allocate" handler="on_standalone_scroll_size_allocate" swapped="no"/> <signal name="size-allocate" handler="on_standalone_scroll_size_allocate" swapped="no"/>
-->
<child> <child>
<object class="GtkViewport"> <object class="GtkViewport">
<property name="visible">True</property> <property name="visible">True</property>
@ -237,23 +569,29 @@
<property name="visible">True</property> <property name="visible">True</property>
<property name="can-focus">False</property> <property name="can-focus">False</property>
<property name="icon-name">gtk-missing-image</property> <property name="icon-name">gtk-missing-image</property>
<!--
<property name="icon_size">6</property> <property name="icon_size">6</property>
-->
</object> </object>
</child> </child>
</object> </object>
</child> </child>
</object> </object>
<!--
<packing> <packing>
<property name="name">standalone-scroll</property> <property name="name">standalone-scroll</property>
<property name="position">1</property> <property name="position">1</property>
</packing> </packing>
-->
</child> </child>
</object> </object>
<!--
<packing> <packing>
<property name="expand">True</property> <property name="expand">True</property>
<property name="fill">True</property> <property name="fill">True</property>
<property name="position">0</property> <property name="position">0</property>
</packing> </packing>
-->
</child> </child>
<child> <child>
<object class="GtkActionBar" id="library-standalone-actionbar"> <object class="GtkActionBar" id="library-standalone-actionbar">
@ -267,10 +605,12 @@
<property name="receives-default">True</property> <property name="receives-default">True</property>
<signal name="clicked" handler="on_standalone_queue_clicked" swapped="no"/> <signal name="clicked" handler="on_standalone_queue_clicked" swapped="no"/>
</object> </object>
<!--
<packing> <packing>
<property name="pack-type">end</property> <property name="pack-type">end</property>
<property name="position">1</property> <property name="position">1</property>
</packing> </packing>
-->
</child> </child>
<child> <child>
<object class="GtkButton"> <object class="GtkButton">
@ -280,24 +620,32 @@
<property name="receives-default">True</property> <property name="receives-default">True</property>
<signal name="clicked" handler="on_standalone_play_clicked" swapped="no"/> <signal name="clicked" handler="on_standalone_play_clicked" swapped="no"/>
</object> </object>
<!--
<packing> <packing>
<property name="pack-type">end</property> <property name="pack-type">end</property>
<property name="position">0</property> <property name="position">0</property>
</packing> </packing>
-->
</child> </child>
</object> </object>
<!--
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
<property name="fill">True</property> <property name="fill">True</property>
<property name="position">1</property> <property name="position">1</property>
</packing> </packing>
-->
</child> </child>
</object> </object>
<!--
<packing> <packing>
<property name="name">page1</property> <property name="name">page1</property>
<property name="title">page1</property> <property name="title">page1</property>
<property name="position">1</property> <property name="position">1</property>
</packing> </packing>
-->
</child> </child>
</template> </object>
</child>
</template>
</interface> </interface>

View file

@ -1,232 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.2 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkAdjustment" id="grid_adjustment">
<property name="lower">100</property>
<property name="upper">1000</property>
<property name="value">150</property>
<property name="step-increment">1</property>
<property name="page-increment">10</property>
</object>
<object class="GtkPopover" id="toolbar_popover">
<property name="can-focus">False</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkScale" id="grid_scale">
<property name="width-request">350</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="adjustment">grid_adjustment</property>
<property name="restrict-to-fill-level">False</property>
<property name="fill-level">-1</property>
<property name="round-digits">0</property>
<property name="digits">0</property>
<property name="has-origin">False</property>
<signal name="button-release-event" handler="on_grid_scale_changed" swapped="no"/>
<signal name="change-value" handler="on_grid_scale_change" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="library-toolbar-update">
<property name="label">gtk-refresh</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="relief">none</property>
<property name="use-stock">True</property>
<signal name="clicked" handler="on_update_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkBox" id="library-toolbar-sort">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkSeparator">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Sort</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="sort_artist">
<property name="label" translatable="yes">sort by artist</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="draw-indicator">True</property>
<property name="group">sort_year</property>
<signal name="toggled" handler="on_sort_toggled" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="sort_title">
<property name="label" translatable="yes">sort by title</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="draw-indicator">True</property>
<property name="group">sort_year</property>
<signal name="toggled" handler="on_sort_toggled" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="sort_year">
<property name="label" translatable="yes">sort by year</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="active">True</property>
<property name="draw-indicator">True</property>
<signal name="toggled" handler="on_sort_toggled" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="toolbar_sort_order_button">
<property name="label">gtk-sort-descending</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="use-stock">True</property>
<property name="active">True</property>
<property name="draw-indicator">True</property>
<signal name="toggled" handler="on_sort_order_toggled" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">5</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
</object>
<template class="McgLibraryToolbar" parent="GtkButtonBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="spacing">6</property>
<property name="layout-style">end</property>
<child>
<object class="GtkToggleButton" id="toolbar_search_bar">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="tooltip-text" translatable="yes">Search the library</property>
<signal name="toggled" handler="on_search_toggled" swapped="no"/>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">system-search-symbolic</property>
</object>
</child>
<accelerator key="f" signal="activate" modifiers="GDK_CONTROL_MASK"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
<property name="non-homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkToggleButton" id="select_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="tooltip-text" translatable="yes">Select multiple albums</property>
<signal name="toggled" handler="on_select_toggled" swapped="no"/>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">object-select-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
<property name="non-homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkMenuButton">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="tooltip-text" translatable="yes">Settings and actions</property>
<property name="popover">toolbar_popover</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">open-menu-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
<property name="non-homogeneous">True</property>
</packing>
</child>
</template>
</interface>

View file

@ -1,194 +1,204 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.2 -->
<interface> <interface>
<requires lib="gtk+" version="3.16"/> <requires lib="gtk+" version="4.8"/>
<template class="McgPlaylistPanel" parent="GtkStack"> <requires lib="adw" version="1.2" />
<property name="visible">True</property> <object class="GtkBox" id="toolbar">
<property name="can-focus">False</property> <property name="orientation">horizontal</property>
<property name="transition-type">slide-left-right</property> <property name="halign">end</property>
<child> <property name="spacing">6</property>
<object class="GtkBox" id="panel_normal">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child> <child>
<object class="GtkScrolledWindow"> <object class="GtkToggleButton" id="select_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<child>
<object class="GtkIconView" id="playlist_grid">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can-focus">True</property> <property name="can-focus">True</property>
<property name="margin">0</property> <property name="receives-default">True</property>
<property name="item-orientation">horizontal</property> <property name="tooltip-text" translatable="yes">Select multiple albums</property>
<property name="row-spacing">0</property> <!--
<property name="column-spacing">0</property> <signal name="toggled" handler="on_select_toggled" swapped="no"/>
<property name="tooltip-column">1</property> -->
<property name="item-padding">0</property> <child>
<property name="activate-on-single-click">True</property> <object class="GtkImage">
<signal name="item-activated" handler="on_playlist_grid_clicked" swapped="no"/> <property name="icon-name">object-select-symbolic</property>
<signal name="selection-changed" handler="on_playlist_grid_selection_changed" swapped="no"/> </object>
<style> </child>
<class name="no-bg"/> </object>
</style>
</object>
</child>
<style>
<class name="no-bg"/>
</style>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkRevealer" id="actionbar_revealer"> <object class="GtkButton" id="playlist_clear_button">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="transition-type">slide-up</property>
<child>
<object class="GtkActionBar" id="actionbar">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkButton">
<property name="label" translatable="yes">cancel</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<signal name="clicked" handler="on_selection_cancel_clicked" swapped="no"/>
</object>
<packing>
<property name="pack-type">end</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton">
<property name="label" translatable="yes">remove</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<signal name="clicked" handler="on_selection_remove_clicked" swapped="no"/>
</object>
<packing>
<property name="pack-type">end</property>
<property name="position">0</property>
</packing>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack-type">end</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="name">page2</property>
<property name="title">page2</property>
</packing>
</child>
<child>
<object class="GtkBox" id="panel_standalone">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkStack" id="standalone_stack">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkSpinner" id="standalone_spinner">
<property name="visible">True</property>
<property name="can-focus">False</property>
</object>
<packing>
<property name="name">standalone-spinne</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="standalone_scroll">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can-focus">True</property> <property name="can-focus">True</property>
<property name="kinetic-scrolling">False</property> <property name="receives-default">True</property>
<property name="overlay-scrolling">False</property> <property name="tooltip-text" translatable="yes">Clear the playlist</property>
<signal name="size-allocate" handler="on_standalone_scroll_size_allocate" swapped="no"/> <!--
<signal name="clicked" handler="on_clear_clicked" swapped="no"/>
-->
<child> <child>
<object class="GtkViewport"> <object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkImage" id="standalone_image">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can-focus">False</property> <property name="can-focus">False</property>
<property name="icon-name">gtk-missing-image</property> <property name="icon-name">edit-clear</property>
<property name="icon_size">6</property> </object>
</object>
</child>
</object>
</child> </child>
</object> </object>
<packing>
<property name="name">standalone-scroll</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
</object>
<template class="McgPlaylistPanel" parent="AdwBin">
<child> <child>
<object class="GtkActionBar" id="actionbar_standalone"> <object class="GtkStack">
<property name="visible">True</property> <property name="transition-type">slide-left-right</property>
<property name="can-focus">False</property> <child>
<child> <object class="GtkBox" id="panel_normal">
<object class="GtkButton"> <property name="orientation">vertical</property>
<property name="label" translatable="yes">remove</property> <child>
<property name="visible">True</property> <object class="GtkScrolledWindow">
<property name="can-focus">True</property> <property name="vexpand">true</property>
<property name="receives-default">True</property> <child>
<signal name="clicked" handler="on_standalone_remove_clicked" swapped="no"/> <object class="GtkGridView" id="playlist_grid">
</object> <property name="orientation">vertical</property>
<packing> <!--
<property name="pack-type">end</property> <property name="item-padding">0</property>
<property name="position">1</property> -->
</packing> <property name="single-click-activate">true</property>
</child> <signal name="activate" handler="on_playlist_grid_clicked"/>
<child> <!--
<object class="GtkButton"> <signal name="selection-changed" handler="on_playlist_grid_selection_changed" swapped="no"/>
<property name="label" translatable="yes">play</property> -->
<property name="visible">True</property> <style>
<property name="can-focus">True</property> <class name="no-bg"/>
<property name="receives-default">True</property> </style>
<signal name="clicked" handler="on_standalone_play_clicked" swapped="no"/> <property name="factory">
</object> <object class="GtkBuilderListItemFactory">
<packing> <property name="bytes">
<property name="pack-type">end</property> <![CDATA[
<property name="position">0</property> <?xml version="1.0" encoding="UTF-8"?>
</packing> <interface>
</child> <template class="GtkListItem">
</object> <property name="activatable">true</property>
<packing> <property name="child">
<property name="expand">False</property> <object class="GtkBox">
<property name="fill">True</property> <property name="orientation">vertical</property>
<property name="position">1</property> <child>
</packing> <object class="GtkPicture">
<property name="content-fit">contain</property>
<property name="can-shrink">false</property>
<binding name="tooltip-markup">
<lookup name="tooltip" type="GridItem">
<lookup name="item">GtkListItem</lookup>
</lookup>
</binding>
<binding name="paintable">
<lookup name="cover" type="GridItem">
<lookup name="item">GtkListItem</lookup>
</lookup>
</binding>
</object>
</child>
</object>
</property>
</template>
</interface>
]]>
</property>
</object>
</property>
</object>
</child>
<style>
<class name="no-bg"/>
</style>
</object>
</child>
<child>
<object class="GtkRevealer" id="actionbar_revealer">
<property name="transition-type">slide-up</property>
<child>
<object class="GtkActionBar" id="actionbar">
<child>
<object class="GtkButton">
<property name="label" translatable="yes">cancel</property>
<property name="receives-default">True</property>
<!--
<signal name="clicked" handler="on_selection_cancel_clicked" swapped="no"/>
-->
</object>
</child>
<child>
<object class="GtkButton">
<property name="label" translatable="yes">remove</property>
<property name="receives-default">True</property>
<!--
<signal name="clicked" handler="on_selection_remove_clicked" swapped="no"/>
-->
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox" id="panel_standalone">
<property name="orientation">vertical</property>
<child>
<object class="GtkStack" id="standalone_stack">
<child>
<object class="GtkSpinner" id="standalone_spinner">
<property name="visible">True</property>
<property name="can-focus">False</property>
</object>
</child>
<child>
<object class="GtkScrolledWindow" id="standalone_scroll">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="kinetic-scrolling">False</property>
<property name="overlay-scrolling">False</property>
<!--
<signal name="size-allocate" handler="on_standalone_scroll_size_allocate" swapped="no"/>
-->
<child>
<object class="GtkViewport">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkImage" id="standalone_image">
<property name="icon-name">gtk-missing-image</property>
<!--
<property name="icon_size">6</property>
-->
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkActionBar" id="actionbar_standalone">
<child>
<object class="GtkButton">
<property name="label" translatable="yes">remove</property>
<property name="receives-default">True</property>
<!--
<signal name="clicked" handler="on_standalone_remove_clicked" swapped="no"/>
-->
</object>
</child>
<child>
<object class="GtkButton">
<property name="label" translatable="yes">play</property>
<property name="receives-default">True</property>
<!--
<signal name="clicked" handler="on_standalone_play_clicked" swapped="no"/>
-->
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child> </child>
</object> </template>
<packing>
<property name="name">page1</property>
<property name="title">page1</property>
<property name="position">1</property>
</packing>
</child>
</template>
</interface> </interface>

View file

@ -1,55 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.2 -->
<interface>
<requires lib="gtk+" version="3.10"/>
<template class="McgPlaylistToolbar" parent="GtkButtonBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="spacing">6</property>
<property name="layout-style">end</property>
<child>
<object class="GtkToggleButton" id="select_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="tooltip-text" translatable="yes">Select multiple albums</property>
<signal name="toggled" handler="on_select_toggled" swapped="no"/>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">object-select-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
<property name="non-homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkButton" id="playlist_clear_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="tooltip-text" translatable="yes">Clear the playlist</property>
<signal name="clicked" handler="on_clear_clicked" swapped="no"/>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">edit-clear</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
<property name="non-homogeneous">True</property>
</packing>
</child>
</template>
</interface>

View file

@ -1,547 +1,326 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.2 -->
<interface> <interface>
<requires lib="gtk+" version="3.16"/> <requires lib="gtk+" version="4.8"/>
<template class="McgServerPanel" parent="GtkBox"> <requires lib="adw" version="1.2" />
<property name="visible">True</property> <object class="GtkBox" id="toolbar">
<property name="can-focus">False</property> <property name="orientation">horizontal</property>
<child> <property name="halign">end</property>
<object class="GtkStackSidebar">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="stack">stack</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkStack" id="stack">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child> <child>
<object class="GtkBox"> <object class="GtkToggleButton" id="sidebar_switcher">
<property name="visible">True</property> <property name="icon-name">sidebar-show-symbolic</property>
<property name="can-focus">False</property> <property name="active">true</property>
<child type="center"> <property name="visible" bind-source="server_flap" bind-property="folded" bind-flags="sync-create"/>
<object class="GtkBox"> </object>
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child type="center">
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-start">5</property>
<property name="margin-end">5</property>
<property name="margin-top">5</property>
<property name="margin-bottom">5</property>
<property name="orientation">vertical</property>
<property name="spacing">10</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">dialog-information-symbolic</property>
<property name="icon_size">6</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<!-- n-columns=3 n-rows=4 -->
<object class="GtkGrid">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="row-spacing">2</property>
<property name="column-spacing">5</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="valign">start</property>
<property name="label" translatable="yes">File:</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="valign">start</property>
<property name="label" translatable="yes">Audio:</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="valign">start</property>
<property name="label" translatable="yes">Bitrate:</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">2</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="valign">start</property>
<property name="label" translatable="yes">Error:</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">3</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="status_bitrate">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">&lt;i&gt;none&lt;/i&gt;</property>
<property name="use-markup">True</property>
<property name="wrap">True</property>
<property name="selectable">True</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="status_audio">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">&lt;i&gt;none&lt;/i&gt;</property>
<property name="use-markup">True</property>
<property name="wrap">True</property>
<property name="selectable">True</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="status_file">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">&lt;i&gt;none&lt;/i&gt;</property>
<property name="use-markup">True</property>
<property name="wrap">True</property>
<property name="selectable">True</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="status_error">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">&lt;i&gt;none&lt;/i&gt;</property>
<property name="use-markup">True</property>
<property name="wrap">True</property>
<property name="selectable">True</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">3</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="name">page0</property>
<property name="title" translatable="yes">Status</property>
</packing>
</child> </child>
</object>
<template class="McgServerPanel" parent="AdwBin">
<child> <child>
<object class="GtkBox"> <object class="AdwFlap" id="server_flap">
<property name="visible">True</property> <property name="flap-position">end</property>
<property name="can-focus">False</property> <property name="reveal-flap" bind-source="sidebar_switcher" bind-property="active" bind-flags="sync-create|bidirectional" />
<child type="center"> <property name="flap">
<object class="GtkBox"> <object class="GtkStackSidebar">
<property name="visible">True</property> <property name="stack">stack</property>
<property name="can-focus">False</property> <property name="name">server_stack_sidebar</property>
<property name="orientation">vertical</property> </object>
<child type="center"> </property>
<object class="GtkBox"> <property name="separator">
<property name="visible">True</property> <object class="GtkSeparator"/>
<property name="can-focus">False</property> </property>
<property name="orientation">vertical</property> <property name="content">
<property name="spacing">10</property> <object class="GtkStack" id="stack">
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">starred-symbolic</property>
<property name="icon_size">6</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<!-- n-columns=3 n-rows=7 -->
<object class="GtkGrid">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="row-spacing">2</property>
<property name="column-spacing">5</property>
<child> <child>
<object class="GtkLabel" id="stats_artists"> <object class="GtkStackPage">
<property name="visible">True</property> <property name="name">status</property>
<property name="can-focus">False</property> <property name="title">Status</property>
<property name="halign">end</property> <property name="child">
<property name="justify">right</property> <object class="AdwStatusPage">
<property name="selectable">True</property> <property name="icon-name">dialog-information-symbolic</property>
</object> <child>
<packing> <object class="GtkGrid">
<property name="left-attach">0</property> <property name="row-spacing">2</property>
<property name="top-attach">0</property> <property name="column-spacing">5</property>
</packing> <property name="hexpand">false</property>
<property name="halign">center</property>
<child>
<object class="GtkLabel">
<property name="halign">start</property>
<property name="valign">start</property>
<property name="label" translatable="yes">File:</property>
<layout>
<property name="column">0</property>
<property name="row">0</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="halign">start</property>
<property name="valign">start</property>
<property name="label" translatable="yes">Audio:</property>
<layout>
<property name="column">0</property>
<property name="row">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="halign">start</property>
<property name="valign">start</property>
<property name="label" translatable="yes">Bitrate:</property>
<layout>
<property name="column">0</property>
<property name="row">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="halign">start</property>
<property name="valign">start</property>
<property name="label" translatable="yes">Error:</property>
<layout>
<property name="column">0</property>
<property name="row">3</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel" id="status_file">
<property name="halign">start</property>
<property name="label" translatable="yes">&lt;i&gt;none&lt;/i&gt;</property>
<property name="use-markup">True</property>
<property name="wrap">True</property>
<property name="selectable">True</property>
<property name="xalign">0</property>
<layout>
<property name="column">1</property>
<property name="row">0</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel" id="status_audio">
<property name="halign">start</property>
<property name="label" translatable="yes">&lt;i&gt;none&lt;/i&gt;</property>
<property name="use-markup">True</property>
<property name="wrap">True</property>
<property name="selectable">True</property>
<property name="xalign">0</property>
<layout>
<property name="column">1</property>
<property name="row">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel" id="status_bitrate">
<property name="halign">start</property>
<property name="label" translatable="yes">&lt;i&gt;none&lt;/i&gt;</property>
<property name="use-markup">True</property>
<property name="wrap">True</property>
<property name="selectable">True</property>
<property name="xalign">0</property>
<layout>
<property name="column">1</property>
<property name="row">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel" id="status_error">
<property name="halign">start</property>
<property name="label" translatable="yes">&lt;i&gt;none&lt;/i&gt;</property>
<property name="use-markup">True</property>
<property name="wrap">True</property>
<property name="selectable">True</property>
<property name="xalign">0</property>
<layout>
<property name="column">1</property>
<property name="row">3</property>
</layout>
</object>
</child>
</object>
</child>
</object>
</property>
</object>
</child> </child>
<child> <child>
<object class="GtkLabel" id="stats_albums"> <object class="GtkStackPage">
<property name="visible">True</property> <property name="name">stats</property>
<property name="can-focus">False</property> <property name="title">Statistics</property>
<property name="halign">end</property> <property name="child">
<property name="justify">right</property> <object class="AdwStatusPage">
</object> <property name="icon-name">starred-symbolic</property>
<packing> <child>
<property name="left-attach">0</property> <object class="GtkGrid">
<property name="top-attach">1</property> <property name="row-spacing">2</property>
</packing> <property name="column-spacing">5</property>
<property name="column-homogeneous">true</property>
<property name="hexpand">false</property>
<property name="halign">center</property>
<child>
<object class="GtkLabel" id="stats_artists">
<property name="halign">end</property>
<property name="justify">right</property>
<layout>
<property name="column">0</property>
<property name="row">0</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="halign">start</property>
<property name="label" translatable="yes">Artists</property>
<layout>
<property name="column">1</property>
<property name="row">0</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel" id="stats_albums">
<property name="halign">end</property>
<property name="justify">right</property>
<layout>
<property name="column">0</property>
<property name="row">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="halign">start</property>
<property name="label" translatable="yes">Albums</property>
<layout>
<property name="column">1</property>
<property name="row">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel" id="stats_songs">
<property name="halign">end</property>
<property name="justify">right</property>
<layout>
<property name="column">0</property>
<property name="row">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="halign">start</property>
<property name="label" translatable="yes">Songs</property>
<layout>
<property name="column">1</property>
<property name="row">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel" id="stats_dbplaytime">
<property name="halign">end</property>
<property name="justify">right</property>
<layout>
<property name="column">0</property>
<property name="row">3</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="halign">start</property>
<property name="label" translatable="yes">Seconds</property>
<layout>
<property name="column">1</property>
<property name="row">3</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<layout>
<property name="column">0</property>
<property name="row">4</property>
<property name="column-span">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel" id="stats_playtime">
<property name="halign">end</property>
<property name="justify">right</property>
<layout>
<property name="column">0</property>
<property name="row">5</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="halign">start</property>
<property name="label" translatable="yes">Seconds played</property>
<layout>
<property name="column">1</property>
<property name="row">5</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel" id="stats_uptime">
<property name="halign">end</property>
<property name="justify">right</property>
<layout>
<property name="column">0</property>
<property name="row">6</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="halign">start</property>
<property name="label" translatable="yes">Seconds running</property>
<layout>
<property name="column">1</property>
<property name="row">6</property>
</layout>
</object>
</child>
</object>
</child>
</object>
</property>
</object>
</child> </child>
<child> <child>
<object class="GtkLabel" id="stats_songs"> <object class="GtkStackPage">
<property name="visible">True</property> <property name="name">devices</property>
<property name="can-focus">False</property> <property name="title">Audio Devices</property>
<property name="halign">end</property> <property name="child">
<property name="justify">right</property> <object class="AdwStatusPage">
</object> <property name="icon-name">audio-speakers-symbolic</property>
<packing> <child>
<property name="left-attach">0</property> <object class="GtkListBox" id="output_devices">
<property name="top-attach">2</property> <property name="hexpand">false</property>
</packing> <property name="halign">center</property>
<property name="selection-mode">none</property>
<style>
<class name="no-bg"/>
</style>
</object>
</child>
</object>
</property>
</object>
</child> </child>
<child> </object>
<object class="GtkLabel"> </property>
<property name="visible">True</property> </object>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Albums</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Songs</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">2</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Artists</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="stats_dbplaytime">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">end</property>
<property name="justify">right</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">3</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Seconds</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">3</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="stats_uptime">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">end</property>
<property name="justify">right</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">6</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="stats_playtime">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">end</property>
<property name="justify">right</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">5</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">4</property>
<property name="width">2</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Seconds played</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">5</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Seconds running</property>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">6</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="name">page1</property>
<property name="title" translatable="yes">Statistics</property>
<property name="position">1</property>
</packing>
</child> </child>
<child> </template>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child type="center">
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child type="center">
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">10</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">audio-speakers-symbolic</property>
<property name="icon_size">6</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkListBox" id="output_devices">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="selection-mode">none</property>
<style>
<class name="no-bg"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="name">page2</property>
<property name="title" translatable="yes">Audio Devices</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</template>
</interface> </interface>

View file

@ -1,14 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.2 -->
<interface>
<requires lib="gtk+" version="3.10"/>
<template class="McgServerToolbar" parent="GtkButtonBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<property name="layout-style">start</property>
<child>
<placeholder/>
</child>
</template>
</interface>

View file

@ -1,229 +1,74 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.2 -->
<interface> <interface>
<requires lib="gtk+" version="3.20"/> <requires lib="gtk+" version="4.8" />
<template class="McgAppWindow" parent="GtkApplicationWindow"> <requires lib="adw" version="1.2" />
<property name="can-focus">False</property> <template class="McgAppWindow" parent="AdwApplicationWindow">
<property name="icon-name">xyz.suruatoel.mcg</property> <property name="content">
<signal name="size-allocate" handler="on_resize" swapped="no"/> <object class="GtkBox">
<signal name="window-state-event" handler="on_state" swapped="no"/>
<child>
<object class="GtkOverlay">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkStack" id="content_stack">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="transition-duration">100</property>
<property name="transition-type">crossfade</property>
<child>
<object class="GtkStack" id="panel_stack">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="name">page0</property>
<property name="title">page0</property>
</packing>
</child>
</object>
<packing>
<property name="index">-1</property>
</packing>
</child>
<child type="overlay">
<object class="GtkRevealer" id="info_revealer">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="valign">start</property>
<child>
<object class="GtkInfoBar" id="info_bar">
<property name="can-focus">False</property>
<property name="valign">start</property>
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<property name="baseline-position">top</property> <child>
<property name="show-close-button">True</property> <object class="AdwHeaderBar" id="headerbar">
<signal name="close" handler="on_info_bar_close" swapped="no"/> <property name="centering-policy">strict</property>
<signal name="response" handler="on_info_bar_response" swapped="no"/> <property name="show_end_title_buttons">true</property>
<child internal-child="action_area"> <property name="title-widget">
<object class="GtkButtonBox"> <object class="AdwViewSwitcherTitle" id="headerbar_panel_switcher">
<property name="can-focus">False</property> <property name="title">CoverGrid</property>
</object> <property name="stack">panel_stack</property>
<packing> </object>
<property name="expand">False</property> </property>
<property name="fill">False</property> <child>
<property name="position">0</property> <object class="GtkSwitch" id="headerbar_button_connect">
</packing> <signal name="state-set" handler="on_headerbar_connection_state_set" swapped="no"/>
</object>
</child>
<child>
<object class="GtkToggleButton" id="headerbar_button_playpause">
<property name="tooltip-text" translatable="yes">Switch between play and pause</property>
<signal name="toggled" handler="on_headerbar_playpause_toggled" swapped="no"/>
<child>
<object class="GtkImage">
<property name="can-focus">False</property>
<property name="icon-name">media-playback-start</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkVolumeButton" id="headerbar_button_volume">
<signal name="value-changed" handler="on_headerbar_volume_changed" swapped="no"/>
</object>
</child>
<child type="end">
<object class="GtkStack" id="toolbar_stack">
</object>
</child>
</object>
</child> </child>
<child internal-child="content_area"> <child>
<object class="GtkBox"> <object class="AdwToastOverlay" id="info_toast">
<property name="can-focus">False</property> <child>
<child> <object class="GtkStack" id="content_stack">
<object class="GtkLabel" id="info_label"> <property name="name">content_stack</property>
<property name="visible">True</property> <property name="vexpand">true</property>
<property name="can-focus">False</property> <child>
</object> <object class="AdwViewStack" id="panel_stack">
<packing> <property name="vexpand">true</property>
<property name="expand">False</property> <signal name="notify::visible-child" handler="on_stack_switched" swapped="no"/>
<property name="fill">True</property> </object>
<property name="position">0</property> </child>
</packing> </object>
</child> </child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child> </child>
</object> <child>
</child> <object class="AdwViewSwitcherBar">
</object> <property name="stack">panel_stack</property>
</child> <binding name="reveal">
</object> <lookup name="title-visible">headerbar_panel_switcher</lookup>
</child> </binding>
<child type="titlebar"> </object>
<object class="GtkHeaderBar" id="headerbar"> </child>
<property name="name">headerbar</property> </object>
<property name="visible">True</property> </property>
<property name="can-focus">False</property> </template>
<property name="show-close-button">True</property>
<child type="title">
<object class="GtkStack" id="headerbar_title_stack">
<property name="name">headerbar-connection</property>
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="transition-duration">100</property>
<property name="transition-type">crossfade</property>
<child>
<object class="GtkLabel" id="headerbar_connection_label">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Connect to MPD</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
<packing>
<property name="name">page1</property>
<property name="title">page1</property>
</packing>
</child>
<child>
<object class="GtkStackSwitcher" id="headerbar_panel_switcher">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="stack">panel_stack</property>
</object>
<packing>
<property name="name">page0</property>
<property name="title">page0</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="position">4</property>
</packing>
</child>
<child>
<object class="GtkSwitch" id="headerbar_button_connect">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="tooltip-text" translatable="yes">Connect or disconnect</property>
<signal name="notify::active" handler="on_headerbar_connection_active_notify" swapped="no"/>
<signal name="state-set" handler="on_headerbar_connection_state_set" swapped="no"/>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkSeparator">
<property name="visible">True</property>
<property name="can-focus">False</property>
</object>
<packing>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkToggleButton" id="headerbar_button_playpause">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="tooltip-text" translatable="yes">Switch between play and pause</property>
<signal name="toggled" handler="on_headerbar_playpause_toggled" swapped="no"/>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">media-playback-start</property>
</object>
</child>
</object>
<packing>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkVolumeButton" id="headerbar_button_volume">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="focus-on-click">False</property>
<property name="receives-default">True</property>
<property name="tooltip-text" translatable="yes">Adjust the volume</property>
<property name="relief">none</property>
<property name="orientation">vertical</property>
<signal name="button-press-event" handler="on_headerbar_volume_press" swapped="no"/>
<signal name="button-release-event" handler="on_headerbar_volume_release" swapped="no"/>
<signal name="value-changed" handler="on_headerbar_volume_changed" swapped="no"/>
<child internal-child="plus_button">
<object class="GtkButton">
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="relief">none</property>
</object>
</child>
<child internal-child="minus_button">
<object class="GtkButton">
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="relief">none</property>
</object>
</child>
</object>
<packing>
<property name="position">4</property>
</packing>
</child>
<child>
<object class="GtkStack" id="toolbar_stack">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="pack-type">end</property>
<property name="position">4</property>
</packing>
</child>
</object>
</child>
<style>
<class name="bg-texture"/>
</style>
</template>
</interface> </interface>

View file

@ -4,18 +4,16 @@
<file>gtk.css</file> <file>gtk.css</file>
<file>noise-texture.png</file> <file>noise-texture.png</file>
<file>ui/window.ui</file> <file>ui/window.ui</file>
<!--
<file>ui/gtk.menu.ui</file> <file>ui/gtk.menu.ui</file>
<file>ui/info-dialog.ui</file> <file>ui/info-dialog.ui</file>
<file>ui/shortcuts-dialog.ui</file> <file>ui/shortcuts-dialog.ui</file>
-->
<file>ui/connection-panel.ui</file> <file>ui/connection-panel.ui</file>
<file>ui/album-headerbar.ui</file> <file>ui/album-headerbar.ui</file>
<file>ui/server-toolbar.ui</file>
<file>ui/server-panel.ui</file> <file>ui/server-panel.ui</file>
<file>ui/cover-toolbar.ui</file>
<file>ui/cover-panel.ui</file> <file>ui/cover-panel.ui</file>
<file>ui/playlist-toolbar.ui</file>
<file>ui/playlist-panel.ui</file> <file>ui/playlist-panel.ui</file>
<file>ui/library-toolbar.ui</file>
<file>ui/library-panel.ui</file> <file>ui/library-panel.ui</file>
</gresource> </gresource>
</gresources> </gresources>

View file

@ -2,15 +2,16 @@
import gi import gi
gi.require_version('Gtk', '3.0') gi.require_version('Gtk', '4.0')
gi.require_version('Adw', '1')
from gi.repository import Gtk, GObject from gi.repository import Gtk, GObject, Adw
@Gtk.Template(resource_path='/xyz/suruatoel/mcg/ui/album-headerbar.ui') @Gtk.Template(resource_path='/xyz/suruatoel/mcg/ui/album-headerbar.ui')
class AlbumHeaderbar(Gtk.HeaderBar): class AlbumHeaderbar(Adw.Bin):
__gtype_name__ = 'McgAlbumHeaderbar' __gtype_name__ = 'McgAlbumHeaderbar'
__gsignals__ = { __gsignals__ = {
'close': (GObject.SIGNAL_RUN_FIRST, None, ()) 'close': (GObject.SIGNAL_RUN_FIRST, None, ())

View file

@ -5,11 +5,12 @@ import logging
import urllib import urllib
import gi import gi
gi.require_version('Gtk', '3.0') gi.require_version('Gtk', '4.0')
from gi.repository import Gio, Gtk, Gdk, GLib gi.require_version('Adw', '1')
from gi.repository import Gio, Gtk, Gdk, GLib, Adw
from .window import Window from .window import Window
from .infodialog import InfoDialog #from .infodialog import InfoDialog
@ -38,6 +39,7 @@ class Application(Gtk.Application):
self._load_css() self._load_css()
self._setup_actions() self._setup_actions()
self._load_appmenu() self._load_appmenu()
self._setup_adw()
def do_activate(self): def do_activate(self):
@ -48,10 +50,12 @@ class Application(Gtk.Application):
def on_menu_info(self, action, value): def on_menu_info(self, action, value):
if not self._info_dialog: # FIXME Info dialog
self._info_dialog = InfoDialog() #if not self._info_dialog:
self._info_dialog.run() # self._info_dialog = InfoDialog()
self._info_dialog.hide() #self._info_dialog.run()
#self._info_dialog.hide()
pass
def on_menu_quit(self, action, value): def on_menu_quit(self, action, value):
@ -70,15 +74,15 @@ class Application(Gtk.Application):
def _set_default_settings(self): def _set_default_settings(self):
settings = Gtk.Settings.get_default() style_manager = Adw.StyleManager.get_default()
settings.set_property('gtk-application-prefer-dark-theme', True) style_manager.set_color_scheme(Adw.ColorScheme.PREFER_DARK)
def _load_css(self): def _load_css(self):
styleProvider = Gtk.CssProvider() styleProvider = Gtk.CssProvider()
styleProvider.load_from_resource(self._get_resource_path('gtk.css')) styleProvider.load_from_resource(self._get_resource_path('gtk.css'))
Gtk.StyleContext.add_provider_for_screen( Gtk.StyleContext.add_provider_for_display(
Gdk.Screen.get_default(), Gdk.Display.get_default(),
styleProvider, styleProvider,
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
) )
@ -95,10 +99,23 @@ class Application(Gtk.Application):
def _load_appmenu(self): def _load_appmenu(self):
builder = Gtk.Builder() builder = Gtk.Builder()
builder.set_translation_domain(Application.DOMAIN) # FIXME Handle menu
builder.add_from_resource(self._get_resource_path('ui/gtk.menu.ui')) #builder.set_translation_domain(Application.DOMAIN)
self.set_app_menu(builder.get_object('app-menu')) #builder.add_from_resource(self._get_resource_path('ui/gtk.menu.ui'))
#self.set_app_menu(builder.get_object('app-menu'))
def _get_resource_path(self, path): def _get_resource_path(self, path):
return "/{}/{}".format(Application.ID.replace('.', '/'), path) return "/{}/{}".format(Application.ID.replace('.', '/'), path)
def _setup_adw(self):
Adw.HeaderBar()
Adw.ViewSwitcherTitle()
Adw.ViewSwitcherBar()
Adw.ViewStackPage()
Adw.ToastOverlay()
Adw.StatusPage()
Adw.Flap()
Adw.EntryRow()
Adw.PasswordEntryRow()

View file

@ -2,9 +2,11 @@
import gi import gi
gi.require_version('Gtk', '3.0') gi.require_version('Gtk', '4.0')
gi.require_version('Adw', '1')
import locale
from gi.repository import Gtk, GObject from gi.repository import Gtk, Gio, GObject, Adw
from mcg.zeroconf import ZeroconfProvider from mcg.zeroconf import ZeroconfProvider
@ -12,56 +14,58 @@ from mcg.zeroconf import ZeroconfProvider
@Gtk.Template(resource_path='/xyz/suruatoel/mcg/ui/connection-panel.ui') @Gtk.Template(resource_path='/xyz/suruatoel/mcg/ui/connection-panel.ui')
class ConnectionPanel(Gtk.Box): class ConnectionPanel(Adw.Bin):
__gtype_name__ = 'McgConnectionPanel' __gtype_name__ = 'McgConnectionPanel'
__gsignals__ = { __gsignals__ = {
'connection-changed': (GObject.SIGNAL_RUN_FIRST, None, (str, int, str)) 'connection-changed': (GObject.SIGNAL_RUN_FIRST, None, (str, int, str))
} }
# Widgets # Widgets
toolbar = Gtk.Template.Child()
zeroconf_list = Gtk.Template.Child() zeroconf_list = Gtk.Template.Child()
host_entry = Gtk.Template.Child() host_row = Gtk.Template.Child()
port_spinner = Gtk.Template.Child() port_spinner = Gtk.Template.Child()
password_entry = Gtk.Template.Child() password_row = Gtk.Template.Child()
def __init__(self): def __init__(self, **kwargs):
super().__init__() super().__init__(**kwargs)
self._services = Gtk.ListStore(str, str, int)
self._profile = None
# Zeroconf
self.zeroconf_list.set_model(self._services)
renderer = Gtk.CellRendererText()
column = Gtk.TreeViewColumn("Zeroconf", renderer, text=0)
self.zeroconf_list.append_column(column)
# Zeroconf provider # Zeroconf provider
self._zeroconf_provider = ZeroconfProvider() self._zeroconf_provider = ZeroconfProvider()
self._zeroconf_provider.connect_signal(ZeroconfProvider.SIGNAL_SERVICE_NEW, self.on_new_service) self._zeroconf_provider.connect_signal(ZeroconfProvider.SIGNAL_SERVICE_NEW, self.on_new_service)
def get_toolbar(self):
return self.toolbar
def set_selected(self, selected):
pass
def on_new_service(self, service): def on_new_service(self, service):
name, host, port = service name, host, port = service
self._services.append([name, host, port])
row_button = Gtk.Button()
row_button.set_label(locale.gettext("use"))
row_button.connect("clicked", self.on_service_selected, host, port)
row = Adw.ActionRow()
row.set_title(name)
row.set_subtitle("{} ({})".format(host, port))
row.add_suffix(row_button)
self.zeroconf_list.insert(row, -1)
def on_service_selected(self, widget, host, port):
self.set_host(host)
self.set_port(port)
@Gtk.Template.Callback() @Gtk.Template.Callback()
def on_service_selected(self, selection): def on_host_entry_apply(self, widget):
model, treeiter = selection.get_selected()
if treeiter != None:
service = model[treeiter]
self.set_host(service[1])
self.set_port(service[2])
@Gtk.Template.Callback()
def on_zeroconf_list_outfocused(self, widget, event):
self.zeroconf_list.get_selection().unselect_all()
@Gtk.Template.Callback()
def on_host_entry_outfocused(self, widget, event):
self._call_back() self._call_back()
@ -70,17 +74,12 @@ class ConnectionPanel(Gtk.Box):
self._call_back() self._call_back()
@Gtk.Template.Callback()
def on_password_entry_outfocused(self, widget, event):
self._call_back()
def set_host(self, host): def set_host(self, host):
self.host_entry.set_text(host) self.host_row.set_text(host)
def get_host(self): def get_host(self):
return self.host_entry.get_text() return self.host_row.get_text()
def set_port(self, port): def set_port(self, port):
@ -94,11 +93,11 @@ class ConnectionPanel(Gtk.Box):
def set_password(self, password): def set_password(self, password):
if password is None: if password is None:
password = "" password = ""
self.password_entry.set_text(password) self.password_row.set_text(password)
def get_password(self): def get_password(self):
if self.password_entry.get_text() == "": if self.password_row.get_text() == "":
return None return None
else: else:
return self.password_entry.get_text() return self.password_entry.get_text()

View file

@ -2,7 +2,7 @@
import gi import gi
gi.require_version('Gtk', '3.0') gi.require_version('Gtk', '4.0')
import logging import logging
import math import math
@ -13,27 +13,6 @@ from mcg.utils import Utils
@Gtk.Template(resource_path='/xyz/suruatoel/mcg/ui/cover-toolbar.ui')
class CoverToolbar(Gtk.ButtonBox):
__gtype_name__ = 'McgCoverToolbar'
__gsignals__ = {
'fullscreen': (GObject.SIGNAL_RUN_FIRST, None, ())
}
# Widgets
fullscreen_button = Gtk.Template.Child()
def __init__(self):
super().__init__()
def set_fullscreen_sensitive(self, sensitive):
self.fullscreen_button.set_sensitive(sensitive)
@Gtk.Template(resource_path='/xyz/suruatoel/mcg/ui/cover-panel.ui') @Gtk.Template(resource_path='/xyz/suruatoel/mcg/ui/cover-panel.ui')
class CoverPanel(Gtk.Overlay): class CoverPanel(Gtk.Overlay):
__gtype_name__ = 'McgCoverPanel' __gtype_name__ = 'McgCoverPanel'
@ -44,9 +23,13 @@ class CoverPanel(Gtk.Overlay):
} }
# Widgets # Widgets
# Toolbar
toolbar = Gtk.Template.Child()
fullscreen_button = Gtk.Template.Child()
# Cover # Cover
cover_stack = Gtk.Template.Child() cover_stack = Gtk.Template.Child()
cover_spinner = Gtk.Template.Child() cover_spinner = Gtk.Template.Child()
cover_default = Gtk.Template.Child()
cover_scroll = Gtk.Template.Child() cover_scroll = Gtk.Template.Child()
cover_box = Gtk.Template.Child() cover_box = Gtk.Template.Child()
cover_image = Gtk.Template.Child() cover_image = Gtk.Template.Child()
@ -61,22 +44,20 @@ class CoverPanel(Gtk.Overlay):
def __init__(self): def __init__(self, **kwargs):
super().__init__() super().__init__(**kwargs)
self._current_album = None self._current_album = None
self._current_cover_album = None self._current_cover_album = None
self._cover_pixbuf = None self._cover_pixbuf = None
self._timer = None self._timer = None
self._properties = {} self._properties = {}
self._icon_theme = Gtk.IconTheme.get_default() self._icon_theme = Gtk.IconTheme.get_for_display(Gdk.Display.get_default())
self._fullscreened = False self._fullscreened = False
self._is_selected = False
self._current_size = None self._current_size = None
self._cover_pixbuf = self._get_default_image() #self._cover_pixbuf = self._get_default_image()
# Widgets # Widgets
self._toolbar = CoverToolbar()
self.cover_stack.set_visible_child(self.cover_scroll) self.cover_stack.set_visible_child(self.cover_scroll)
# Initial actions # Initial actions
@ -84,33 +65,34 @@ class CoverPanel(Gtk.Overlay):
def get_toolbar(self): def get_toolbar(self):
return self._toolbar return self.toolbar
def set_selected(self, selected): def set_selected(self, selected):
self._is_selected = selected pass
@Gtk.Template.Callback() # FIXME on_cover_box_pressed()
def on_cover_box_pressed(self, widget, event): #@Gtk.Template.Callback()
if self._current_album and event.type == Gdk.EventType._2BUTTON_PRESS: #def on_cover_box_pressed(self, widget, event):
self.emit('toggle-fullscreen') # if self._current_album and event.type == Gdk.EventType._2BUTTON_PRESS:
# self.emit('toggle-fullscreen')
@Gtk.Template.Callback() def set_width(self, width):
def on_cover_size_allocate(self, widget, allocation):
GObject.idle_add(self._resize_image) GObject.idle_add(self._resize_image)
self.cover_info_scroll.set_max_content_width(allocation.width // 2) self.cover_info_scroll.set_max_content_width(width // 2)
@Gtk.Template.Callback() # FIXME on_songs_start_change()
def on_songs_start_change(self, widget, event): #@Gtk.Template.Callback()
if self._timer: #def on_songs_start_change(self, widget, event):
GObject.source_remove(self._timer) # if self._timer:
self._timer = None # GObject.source_remove(self._timer)
# self._timer = None
@Gtk.Template.Callback() #@Gtk.Template.Callback()
def on_songs_change(self, widget, event): def on_songs_change(self, widget, event):
value = int(self.songs_scale.get_value()) value = int(self.songs_scale.get_value())
time = self._current_album.get_length() time = self._current_album.get_length()
@ -144,7 +126,7 @@ class CoverPanel(Gtk.Overlay):
# Set current album # Set current album
self._current_album = album self._current_album = album
self._enable_tracklist() self._enable_tracklist()
self._toolbar.set_fullscreen_sensitive(self._current_album is not None) self.fullscreen_button.set_sensitive(self._current_album is not None)
def set_play(self, pos, time): def set_play(self, pos, time):
@ -186,10 +168,11 @@ class CoverPanel(Gtk.Overlay):
self._cover_pixbuf = Utils.load_pixbuf(data) self._cover_pixbuf = Utils.load_pixbuf(data)
except Exception as e: except Exception as e:
self._logger.exception("Failed to set albumart") self._logger.exception("Failed to set albumart")
self._cover_pixbuf = self._get_default_image() self._cover_pixbuf = None
else: else:
# Reset image # Reset image
self._cover_pixbuf = self._get_default_image() self._cover_pixbuf = self._get_default_image()
self._cover_pixbuf = None
self._current_size = None self._current_size = None
self._current_cover_album = album self._current_cover_album = album
# Show image # Show image
@ -236,8 +219,11 @@ class CoverPanel(Gtk.Overlay):
def _show_image(self): def _show_image(self):
self._resize_image() if self._cover_pixbuf:
self.cover_stack.set_visible_child(self.cover_scroll) self._resize_image()
self.cover_stack.set_visible_child(self.cover_scroll)
else:
self.cover_stack.set_visible_child(self.cover_default)
self.cover_spinner.stop() self.cover_spinner.stop()
@ -245,12 +231,15 @@ class CoverPanel(Gtk.Overlay):
"""Diese Methode skaliert das geladene Bild aus dem Pixelpuffer """Diese Methode skaliert das geladene Bild aus dem Pixelpuffer
auf die Größe des Fensters unter Beibehalt der Seitenverhältnisse auf die Größe des Fensters unter Beibehalt der Seitenverhältnisse
""" """
# Get size # FIXME Get size
size = self.cover_scroll.get_allocation() size_width = self.cover_stack.get_size(Gtk.Orientation.HORIZONTAL)
size_height = self.cover_stack.get_size(Gtk.Orientation.HORIZONTAL)
# Abort if size is the same # Abort if size is the same
if self._current_size and size.width == self._current_size.width and size.height == self._current_size.height: if self._current_size:
return current_width, current_height = self._current_size
self._current_size = size if size_width == current_width and size_height == current_height:
return
self._current_size = (size_width, size_height,)
# Get pixelbuffer # Get pixelbuffer
pixbuf = self._cover_pixbuf pixbuf = self._cover_pixbuf
@ -259,8 +248,8 @@ class CoverPanel(Gtk.Overlay):
return return
# Skalierungswert für Breite und Höhe ermitteln # Skalierungswert für Breite und Höhe ermitteln
ratioW = float(size.width) / float(pixbuf.get_width()) ratioW = float(size_width) / float(pixbuf.get_width())
ratioH = float(size.height) / float(pixbuf.get_height()) ratioH = float(size_height) / float(pixbuf.get_height())
# Kleineren beider Skalierungswerte nehmen, nicht Hochskalieren # Kleineren beider Skalierungswerte nehmen, nicht Hochskalieren
ratio = min(ratioW, ratioH) ratio = min(ratioW, ratioH)
ratio = min(ratio, 1) ratio = min(ratio, 1)
@ -269,15 +258,7 @@ class CoverPanel(Gtk.Overlay):
height = int(math.floor(pixbuf.get_height()*ratio)) height = int(math.floor(pixbuf.get_height()*ratio))
if width <= 0 or height <= 0: if width <= 0 or height <= 0:
return return
# Pixelpuffer auf Oberfläche zeichnen # FIXME Pixelpuffer auf Oberfläche zeichnen
self.cover_image.set_allocation(self.cover_scroll.get_allocation()) #self.cover_image.set_allocation(self.cover_scroll.get_allocation())
self.cover_image.set_from_pixbuf(pixbuf.scale_simple(width, height, GdkPixbuf.InterpType.HYPER)) self.cover_image.set_from_pixbuf(pixbuf.scale_simple(width, height, GdkPixbuf.InterpType.HYPER))
self.cover_image.show() self.cover_image.show()
def _get_default_image(self):
return self._icon_theme.load_icon(
Utils.STOCK_ICON_DEFAULT,
512,
Gtk.IconLookupFlags.FORCE_SVG & Gtk.IconLookupFlags.FORCE_SIZE
)

View file

@ -2,120 +2,26 @@
import gi import gi
gi.require_version('Gtk', '3.0') gi.require_version('Gtk', '4.0')
gi.require_version('Adw', '1')
import locale import locale
import logging import logging
import math import math
import threading import threading
from gi.repository import Gtk, GObject, GdkPixbuf from gi.repository import Gtk, Gdk, GObject, GdkPixbuf, Gio, Adw
from mcg import client from mcg import client
from mcg.albumheaderbar import AlbumHeaderbar from mcg.albumheaderbar import AlbumHeaderbar
from mcg.utils import SortOrder from mcg.utils import SortOrder
from mcg.utils import Utils from mcg.utils import Utils
from mcg.utils import GridItem
@Gtk.Template(resource_path='/xyz/suruatoel/mcg/ui/library-toolbar.ui')
class LibraryToolbar(Gtk.ButtonBox):
__gtype_name__ = 'McgLibraryToolbar'
__gsignals__ = {
'select': (GObject.SIGNAL_RUN_FIRST, None, (bool,)),
'toggle-search': (GObject.SIGNAL_RUN_FIRST, None, (bool,)),
'update': (GObject.SIGNAL_RUN_FIRST, None, ()),
'start-scale': (GObject.SIGNAL_RUN_FIRST, None, (int,)),
'end-scale': (GObject.SIGNAL_RUN_FIRST, None, (int,)),
'sort': (GObject.SIGNAL_RUN_FIRST, None, (int,)),
'sort-type': (GObject.SIGNAL_RUN_FIRST, None, (Gtk.SortType,))
}
# Widgets
select_button = Gtk.Template.Child()
toolbar_search_bar = Gtk.Template.Child()
toolbar_popover = Gtk.Template.Child()
toolbar_sort_order_button = Gtk.Template.Child()
sort_artist = Gtk.Template.Child()
sort_title = Gtk.Template.Child()
sort_year = Gtk.Template.Child()
grid_scale = Gtk.Template.Child()
def __init__(self, item_size):
super().__init__()
# Toolbar menu
self.grid_scale.set_value(item_size)
self._toolbar_sort_buttons = {
SortOrder.ARTIST: self.sort_artist,
SortOrder.TITLE: self.sort_title,
SortOrder.YEAR: self.sort_year
}
@Gtk.Template.Callback()
def on_select_toggled(self, widget):
self.emit('select', widget.get_active())
@Gtk.Template.Callback()
def on_search_toggled(self, widget):
self.emit('toggle-search', widget.get_active())
@Gtk.Template.Callback()
def on_update_clicked(self, widget):
self.emit('update')
@Gtk.Template.Callback()
def on_grid_scale_change(self, widget, scroll, value):
self.emit('start-scale', value)
@Gtk.Template.Callback()
def on_grid_scale_changed(self, widget, event):
self.emit('end-scale', self.grid_scale.get_value())
self.toolbar_popover.popdown()
@Gtk.Template.Callback()
def on_sort_toggled(self, widget):
if widget.get_active():
sort = [key for key, value in self._toolbar_sort_buttons.items() if value is widget][0]
self.emit('sort', sort)
@Gtk.Template.Callback()
def on_sort_order_toggled(self, button):
if button.get_active():
sort_type = Gtk.SortType.DESCENDING
else:
sort_type = Gtk.SortType.ASCENDING
self.emit('sort-type', sort_type)
def get_grid_scale(self):
return self.grid_scale
def is_search_active(self):
return self.toolbar_search_bar.get_active()
def set_search_active(self, active):
self.toolbar_search_bar.set_active(active)
def exit_selection(self):
self.select_button.set_active(False)
@Gtk.Template(resource_path='/xyz/suruatoel/mcg/ui/library-panel.ui') @Gtk.Template(resource_path='/xyz/suruatoel/mcg/ui/library-panel.ui')
class LibraryPanel(Gtk.Stack): class LibraryPanel(Adw.Bin):
__gtype_name__ = 'McgLibraryPanel' __gtype_name__ = 'McgLibraryPanel'
__gsignals__ = { __gsignals__ = {
'open-standalone': (GObject.SIGNAL_RUN_FIRST, None, ()), 'open-standalone': (GObject.SIGNAL_RUN_FIRST, None, ()),
@ -127,13 +33,31 @@ class LibraryPanel(Gtk.Stack):
'item-size-changed': (GObject.SIGNAL_RUN_FIRST, None, (int,)), 'item-size-changed': (GObject.SIGNAL_RUN_FIRST, None, (int,)),
'sort-order-changed': (GObject.SIGNAL_RUN_FIRST, None, (int,)), 'sort-order-changed': (GObject.SIGNAL_RUN_FIRST, None, (int,)),
'sort-type-changed': (GObject.SIGNAL_RUN_FIRST, None, (Gtk.SortType,)), 'sort-type-changed': (GObject.SIGNAL_RUN_FIRST, None, (Gtk.SortType,)),
'albumart': (GObject.SIGNAL_RUN_FIRST, None, (str,)) 'albumart': (GObject.SIGNAL_RUN_FIRST, None, (str,)),
'select': (GObject.SIGNAL_RUN_FIRST, None, (bool,)),
'toggle-search': (GObject.SIGNAL_RUN_FIRST, None, (bool,)),
'update': (GObject.SIGNAL_RUN_FIRST, None, ()),
'start-scale': (GObject.SIGNAL_RUN_FIRST, None, (int,)),
'end-scale': (GObject.SIGNAL_RUN_FIRST, None, (int,)),
'sort': (GObject.SIGNAL_RUN_FIRST, None, (int,)),
'sort-type': (GObject.SIGNAL_RUN_FIRST, None, (Gtk.SortType,))
} }
# Widgets # Widgets
panel_standalone = Gtk.Template.Child() panel_standalone = Gtk.Template.Child()
actionbar_revealer = Gtk.Template.Child() actionbar_revealer = Gtk.Template.Child()
# Toolbar
toolbar = Gtk.Template.Child()
select_button = Gtk.Template.Child()
toolbar_search_bar = Gtk.Template.Child()
toolbar_popover = Gtk.Template.Child()
toolbar_sort_order_button = Gtk.Template.Child()
sort_artist = Gtk.Template.Child()
sort_title = Gtk.Template.Child()
sort_year = Gtk.Template.Child()
grid_scale = Gtk.Template.Child()
# Filter/search bar # Filter/search bar
filter_bar = Gtk.Template.Child() filter_bar = Gtk.Template.Child()
filter_entry = Gtk.Template.Child() filter_entry = Gtk.Template.Child()
@ -152,8 +76,8 @@ class LibraryPanel(Gtk.Stack):
standalone_image = Gtk.Template.Child() standalone_image = Gtk.Template.Child()
def __init__(self, client): def __init__(self, client, **kwargs):
super().__init__() super().__init__(**kwargs)
self._logger = logging.getLogger(__name__) self._logger = logging.getLogger(__name__)
self._client = client self._client = client
self._buttons = {} self._buttons = {}
@ -167,37 +91,37 @@ class LibraryPanel(Gtk.Stack):
self._old_ranges = {} self._old_ranges = {}
self._library_lock = threading.Lock() self._library_lock = threading.Lock()
self._library_stop = threading.Event() self._library_stop = threading.Event()
self._icon_theme = Gtk.IconTheme.get_default() self._icon_theme = Gtk.IconTheme.get_for_display(Gdk.Display.get_default())
self._standalone_pixbuf = None self._standalone_pixbuf = None
self._selected_albums = [] self._selected_albums = []
self._allocation = (0, 0) self._allocation = (0, 0)
self._is_selected = False self._is_selected = False
# Widgets # Widgets
self._toolbar = LibraryToolbar(self._item_size) # FIXME Toolbar signals
self._toolbar.connect('select', self.on_toolbar_select) #self._toolbar.connect('select', self.on_toolbar_select)
self._toolbar.connect('toggle-search', self.on_toolbar_toggle_search) #self._toolbar.connect('toggle-search', self.on_toolbar_toggle_search)
self._toolbar.connect('update', self.on_toolbar_update) #self._toolbar.connect('update', self.on_toolbar_update)
self._toolbar.connect('start-scale', self.on_toolbar_scale) #self._toolbar.connect('start-scale', self.on_toolbar_scale)
self._toolbar.connect('end-scale', self.on_toolbar_scaled) #self._toolbar.connect('end-scale', self.on_toolbar_scaled)
self._toolbar.connect('sort', self.on_toolbar_sort) #self._toolbar.connect('sort', self.on_toolbar_sort)
self._toolbar.connect('sort-type', self.on_toolbar_sort_type) #self._toolbar.connect('sort-type', self.on_toolbar_sort_type)
# Header bar # Header bar
self._headerbar_standalone = AlbumHeaderbar() self._headerbar_standalone = AlbumHeaderbar()
self._headerbar_standalone.connect('close', self.on_standalone_close_clicked) self._headerbar_standalone.connect('close', self.on_standalone_close_clicked)
# Progress Bar
self.progress_image.set_from_pixbuf(self._get_default_image())
# Library Grid: Model # Library Grid: Model
self._library_grid_model = Gtk.ListStore(GdkPixbuf.Pixbuf, str, str) self._library_grid_model = Gio.ListStore()
self._library_grid_model.set_sort_func(2, self.compare_albums, self._sort_order) self._library_grid_selection = Gtk.MultiSelection.new(self._library_grid_model)
self._library_grid_model.set_sort_column_id(2, self._sort_type) self._library_grid_filter = self._library_grid_selection
self._library_grid_filter = self._library_grid_model.filter_new()
self._library_grid_filter.set_visible_func(self.on_filter_visible)
# Library Grid # Library Grid
self.library_grid.set_model(self._library_grid_filter) self.library_grid.set_model(self._library_grid_filter)
self.library_grid.set_pixbuf_column(0) # Toolbar menu
self.library_grid.set_text_column(-1) self.grid_scale.set_value(self._item_size)
self.library_grid.set_tooltip_column(1) self._toolbar_sort_buttons = {
SortOrder.ARTIST: self.sort_artist,
SortOrder.TITLE: self.sort_title,
SortOrder.YEAR: self.sort_year
}
def get_headerbar_standalone(self): def get_headerbar_standalone(self):
@ -205,30 +129,75 @@ class LibraryPanel(Gtk.Stack):
def get_toolbar(self): def get_toolbar(self):
return self._toolbar return self.toolbar
def set_selected(self, selected): def set_selected(self, selected):
self._is_selected = selected self._is_selected = selected
@Gtk.Template.Callback() #@Gtk.Template.Callback()
def on_select_toggled(self, widget):
self.emit('select', widget.get_active())
#@Gtk.Template.Callback()
def on_search_toggled(self, widget):
self.emit('toggle-search', widget.get_active())
#@Gtk.Template.Callback()
def on_update_clicked(self, widget):
self.emit('update')
# FXME on_grid_scale_changed
#@Gtk.Template.Callback()
def on_grid_scale_change(self, widget, scroll, value):
self.emit('start-scale', value)
# FXME on_grid_scale_changed
#@Gtk.Template.Callback()
def on_grid_scale_changed(self, widget, event):
self.emit('end-scale', self.grid_scale.get_value())
self.toolbar_popover.popdown()
#@Gtk.Template.Callback()
def on_sort_toggled(self, widget):
if widget.get_active():
sort = [key for key, value in self._toolbar_sort_buttons.items() if value is widget][0]
self.emit('sort', sort)
#@Gtk.Template.Callback()
def on_sort_order_toggled(self, button):
if button.get_active():
sort_type = Gtk.SortType.DESCENDING
else:
sort_type = Gtk.SortType.ASCENDING
self.emit('sort-type', sort_type)
# FIXME on_resize()
#@Gtk.Template.Callback()
def on_resize(self, widget, event): def on_resize(self, widget, event):
new_allocation = (widget.get_allocation().width, widget.get_allocation().height) new_allocation = (widget.get_allocation().width, widget.get_allocation().height)
if new_allocation == self._allocation: if new_allocation == self._allocation:
return return
self._allocation = new_allocation self._allocation = new_allocation
self._toolbar.get_grid_scale().clear_marks() self.grid_scale.clear_marks()
width = widget.get_allocation().width width = widget.get_allocation().width
lower = int(self._toolbar.get_grid_scale().get_adjustment().get_lower()) lower = int(self.grid_scale.get_adjustment().get_lower())
upper = int(self._toolbar.get_grid_scale().get_adjustment().get_upper()) upper = int(self.grid_scale.get_adjustment().get_upper())
countMin = max(int(width / upper), 1) countMin = max(int(width / upper), 1)
countMax = max(int(width / lower), 1) countMax = max(int(width / lower), 1)
for index in range(countMin, countMax): for index in range(countMin, countMax):
pixel = int(width / index) pixel = int(width / index)
pixel = pixel - (2 * int(pixel / 100)) pixel = pixel - (2 * int(pixel / 100))
self._toolbar.get_grid_scale().add_mark( self.grid_scale.add_mark(
pixel, pixel,
Gtk.PositionType.BOTTOM, Gtk.PositionType.BOTTOM,
None None
@ -256,17 +225,17 @@ class LibraryPanel(Gtk.Stack):
def on_toolbar_scale(self, widget, value): def on_toolbar_scale(self, widget, value):
size = math.floor(value) size = math.floor(value)
range = self._toolbar.get_grid_scale().get_adjustment() range = self.grid_scale.get_adjustment()
if size < range.get_lower() or size > range.get_upper(): if size < range.get_lower() or size > range.get_upper():
return return
self._item_size = size self._item_size = size
GObject.idle_add(self.library_grid.set_item_padding, size / 100) #GObject.idle_add(self.library_grid.set_item_padding, size / 100)
GObject.idle_add(self._set_widget_grid_size, self.library_grid, size, True) GObject.idle_add(self._set_widget_grid_size, self.library_grid, size, True)
def on_toolbar_scaled(self, widget, value): def on_toolbar_scaled(self, widget, value):
size = round(value) size = round(value)
range = self._toolbar.get_grid_scale().get_adjustment() range = self.grid_scale.get_adjustment()
if size < range.get_lower() or size > range.get_upper(): if size < range.get_lower() or size > range.get_upper():
return False return False
self.emit('item-size-changed', size) self.emit('item-size-changed', size)
@ -280,23 +249,24 @@ class LibraryPanel(Gtk.Stack):
def on_toolbar_sort_type(self, widget, sort_type): def on_toolbar_sort_type(self, widget, sort_type):
self._sort_type = sort_type self._sort_type = sort_type
self._library_grid_model.set_sort_column_id(2, sort_type) #self._library_grid_model.set_sort_column_id(2, sort_type)
self.emit('sort-type-changed', sort_type) self.emit('sort-type-changed', sort_type)
@Gtk.Template.Callback() #@Gtk.Template.Callback()
def on_filter_bar_notify(self, widget, value): def on_filter_bar_notify(self, widget, value):
if self._toolbar.is_search_active() is not self.filter_bar.get_search_mode(): if self.toolbar_search_bar.get_active() is not self.filter_bar.get_search_mode():
self._toolbar.set_search_active(self.filter_bar.get_search_mode()) self.toolbar_search_bar.set_active(self.filter_bar.get_search_mode())
@Gtk.Template.Callback() #@Gtk.Template.Callback()
def on_filter_entry_changed(self, widget): def on_filter_entry_changed(self, widget):
self._filter_string = self.filter_entry.get_text() self._filter_string = self.filter_entry.get_text()
GObject.idle_add(self._library_grid_filter.refilter) GObject.idle_add(self._library_grid_filter.refilter)
@Gtk.Template.Callback() # FIXME on_library_grid_clicked()
#@Gtk.Template.Callback()
def on_library_grid_clicked(self, widget, path): def on_library_grid_clicked(self, widget, path):
# Get selected album # Get selected album
path = self._library_grid_filter.convert_path_to_child_path(path) path = self._library_grid_filter.convert_path_to_child_path(path)
@ -319,7 +289,8 @@ class LibraryPanel(Gtk.Stack):
self.standalone_spinner.start() self.standalone_spinner.start()
@Gtk.Template.Callback() # FIXME on_library_grid_selection_changed()
#@Gtk.Template.Callback()
def on_library_grid_selection_changed(self, widget): def on_library_grid_selection_changed(self, widget):
self._selected_albums = [] self._selected_albums = []
for path in widget.get_selected_items(): for path in widget.get_selected_items():
@ -337,30 +308,31 @@ class LibraryPanel(Gtk.Stack):
return album.filter(self._filter_string) return album.filter(self._filter_string)
@Gtk.Template.Callback() #@Gtk.Template.Callback()
def on_selection_cancel_clicked(self, widget): def on_selection_cancel_clicked(self, widget):
self._toolbar.exit_selection() self.select_button.set_active(False)
@Gtk.Template.Callback() #@Gtk.Template.Callback()
def on_selection_add_clicked(self, widget): def on_selection_add_clicked(self, widget):
ids = [album.get_id() for album in self._selected_albums] ids = [album.get_id() for album in self._selected_albums]
self.emit('queue-multiple', ids) self.emit('queue-multiple', ids)
self._toolbar.exit_selection() self.select_button.set_active(False)
@Gtk.Template.Callback() # FIXME on_standalone_scroll_size_allocate()
#@Gtk.Template.Callback()
def on_standalone_scroll_size_allocate(self, widget, allocation): def on_standalone_scroll_size_allocate(self, widget, allocation):
self._resize_standalone_image() self._resize_standalone_image()
@Gtk.Template.Callback() #@Gtk.Template.Callback()
def on_standalone_play_clicked(self, widget): def on_standalone_play_clicked(self, widget):
self.emit('play', self._selected_albums[0].get_id()) self.emit('play', self._selected_albums[0].get_id())
self._close_standalone() self._close_standalone()
@Gtk.Template.Callback() #@Gtk.Template.Callback()
def on_standalone_queue_clicked(self, widget): def on_standalone_queue_clicked(self, widget):
self.emit('queue', self._selected_albums[0].get_id()) self.emit('queue', self._selected_albums[0].get_id())
self._close_standalone() self._close_standalone()
@ -377,7 +349,7 @@ class LibraryPanel(Gtk.Stack):
def set_item_size(self, item_size): def set_item_size(self, item_size):
if self._item_size != item_size: if self._item_size != item_size:
self._item_size = item_size self._item_size = item_size
self._toolbar.get_grid_scale().set_value(item_size) self.grid_scale.set_value(item_size)
self._redraw() self._redraw()
@ -464,6 +436,7 @@ class LibraryPanel(Gtk.Stack):
def _set_albums(self, host, albums, size): def _set_albums(self, host, albums, size):
"""
if not self._is_selected and albums != self._albums: if not self._is_selected and albums != self._albums:
GObject.idle_add( GObject.idle_add(
self.get_parent().child_set_property, self.get_parent().child_set_property,
@ -471,15 +444,16 @@ class LibraryPanel(Gtk.Stack):
'needs-attention', 'needs-attention',
True True
) )
"""
self._library_lock.acquire() self._library_lock.acquire()
self._library_stop.clear() self._library_stop.clear()
self._albums = albums self._albums = albums
GObject.idle_add(self.stack.set_visible_child, self.progress_box) GObject.idle_add(self.stack.set_visible_child, self.progress_box)
GObject.idle_add(self.progress_bar.set_fraction, 0.0) GObject.idle_add(self.progress_bar.set_fraction, 0.0)
GObject.idle_add(self.library_grid.set_item_padding, size / 100) #GObject.idle_add(self.library_grid.set_item_padding, size / 100)
self.library_grid.set_model(None) self.library_grid.set_model(None)
self.library_grid.freeze_child_notify() #self.library_grid.freeze_child_notify()
self._library_grid_model.clear() self._library_grid_model.remove_all()
i = 0 i = 0
n = len(albums) n = len(albums)
@ -496,23 +470,17 @@ class LibraryPanel(Gtk.Stack):
except Exception as e: except Exception as e:
self._logger.exception("Failed to load albumart") self._logger.exception("Failed to load albumart")
if pixbuf is None: if pixbuf is None:
pixbuf = self._icon_theme.load_icon( pixbuf = self._icon_theme.lookup_icon(
Utils.STOCK_ICON_DEFAULT, Utils.STOCK_ICON_DEFAULT,
None,
self._item_size, self._item_size,
Gtk.IconLookupFlags.FORCE_SVG & Gtk.IconLookupFlags.FORCE_SIZE self._item_size,
Gtk.TextDirection.LTR,
Gtk.IconLookupFlags.FORCE_SYMBOLIC
) )
if pixbuf is not None: if pixbuf is not None:
self._grid_pixbufs[album.get_id()] = pixbuf self._grid_pixbufs[album.get_id()] = pixbuf
self._library_grid_model.append([ self._library_grid_model.append(GridItem(album, pixbuf))
pixbuf,
GObject.markup_escape_text("\n".join([
album.get_title(),
', '.join(album.get_dates()),
Utils.create_artists_label(album),
Utils.create_length_label(album)
])),
album_id
])
i += 1 i += 1
GObject.idle_add(self.progress_bar.set_fraction, i/n) GObject.idle_add(self.progress_bar.set_fraction, i/n)
@ -522,8 +490,8 @@ class LibraryPanel(Gtk.Stack):
return return
self.library_grid.set_model(self._library_grid_filter) self.library_grid.set_model(self._library_grid_filter)
self.library_grid.thaw_child_notify() #self.library_grid.thaw_child_notify()
self.library_grid.set_item_width(-1) #self.library_grid.set_item_width(-1)
self._library_lock.release() self._library_lock.release()
self.stack.set_visible_child(self.scroll) self.stack.set_visible_child(self.scroll)
@ -632,12 +600,11 @@ class LibraryPanel(Gtk.Stack):
def _get_default_image(self): def _get_default_image(self):
return self._icon_theme.load_icon( return self._icon_theme.lookup_icon(
Utils.STOCK_ICON_DEFAULT, Utils.STOCK_ICON_DEFAULT,
None,
512, 512,
Gtk.IconLookupFlags.FORCE_SVG & Gtk.IconLookupFlags.FORCE_SIZE 512,
Gtk.TextDirection.LTR,
Gtk.IconLookupFlags.FORCE_SYMBOLIC
) )

View file

@ -1,6 +1,4 @@
import sys import sys
import gi
gi.require_version('Gtk', '3.0')
from .application import Application from .application import Application

View file

@ -2,56 +2,24 @@
import gi import gi
gi.require_version('Gtk', '3.0') gi.require_version('Gtk', '4.0')
gi.require_version('Adw', '1')
import logging import logging
import math import math
import threading import threading
from gi.repository import Gtk, GObject, GdkPixbuf from gi.repository import Gtk, Gdk, Gio, GObject, GdkPixbuf, Adw
from mcg import client from mcg import client
from mcg.albumheaderbar import AlbumHeaderbar from mcg.albumheaderbar import AlbumHeaderbar
from mcg.utils import Utils from mcg.utils import Utils
from mcg.utils import GridItem
@Gtk.Template(resource_path='/xyz/suruatoel/mcg/ui/playlist-toolbar.ui')
class PlaylistToolbar(Gtk.ButtonBox):
__gtype_name__ = 'McgPlaylistToolbar'
__gsignals__ = {
'select': (GObject.SIGNAL_RUN_FIRST, None, (bool,)),
'clear-playlist': (GObject.SIGNAL_RUN_FIRST, None, ())
}
# Widgets
playlist_clear_button = Gtk.Template.Child()
select_button = Gtk.Template.Child()
def __init__(self):
super().__init__()
@Gtk.Template.Callback()
def on_select_toggled(self, widget):
self.emit('select', widget.get_active())
@Gtk.Template.Callback()
def on_clear_clicked(self, widget):
if widget is self.playlist_clear_button:
self.emit('clear-playlist')
def exit_selection(self):
self.select_button.set_active(False)
@Gtk.Template(resource_path='/xyz/suruatoel/mcg/ui/playlist-panel.ui') @Gtk.Template(resource_path='/xyz/suruatoel/mcg/ui/playlist-panel.ui')
class PlaylistPanel(Gtk.Stack): class PlaylistPanel(Adw.Bin):
__gtype_name__ = 'McgPlaylistPanel' __gtype_name__ = 'McgPlaylistPanel'
__gsignals__ = { __gsignals__ = {
'open-standalone': (GObject.SIGNAL_RUN_FIRST, None, ()), 'open-standalone': (GObject.SIGNAL_RUN_FIRST, None, ()),
@ -60,13 +28,20 @@ class PlaylistPanel(Gtk.Stack):
'remove-album': (GObject.SIGNAL_RUN_FIRST, None, (GObject.TYPE_PYOBJECT,)), 'remove-album': (GObject.SIGNAL_RUN_FIRST, None, (GObject.TYPE_PYOBJECT,)),
'remove-multiple-albums': (GObject.SIGNAL_RUN_FIRST, None, (GObject.TYPE_PYOBJECT,)), 'remove-multiple-albums': (GObject.SIGNAL_RUN_FIRST, None, (GObject.TYPE_PYOBJECT,)),
'play': (GObject.SIGNAL_RUN_FIRST, None, (GObject.TYPE_PYOBJECT,)), 'play': (GObject.SIGNAL_RUN_FIRST, None, (GObject.TYPE_PYOBJECT,)),
'albumart': (GObject.SIGNAL_RUN_FIRST, None, (str,)) 'albumart': (GObject.SIGNAL_RUN_FIRST, None, (str,)),
'select': (GObject.SIGNAL_RUN_FIRST, None, (bool,)),
'clear-playlist': (GObject.SIGNAL_RUN_FIRST, None, ())
} }
# Widgets # Widgets
panel_standalone = Gtk.Template.Child() panel_standalone = Gtk.Template.Child()
actionbar_revealer = Gtk.Template.Child() actionbar_revealer = Gtk.Template.Child()
# Toolbar
toolbar = Gtk.Template.Child()
playlist_clear_button = Gtk.Template.Child()
select_button = Gtk.Template.Child()
# Playlist Grid # Playlist Grid
playlist_grid = Gtk.Template.Child() playlist_grid = Gtk.Template.Child()
# Action bar (normal) # Action bar (normal)
@ -79,8 +54,8 @@ class PlaylistPanel(Gtk.Stack):
standalone_image = Gtk.Template.Child() standalone_image = Gtk.Template.Child()
def __init__(self, client): def __init__(self, client, **kwargs):
GObject.GObject.__init__(self) super().__init__(**kwargs)
self._client = client self._client = client
self._host = None self._host = None
self._item_size = 150 self._item_size = 150
@ -88,25 +63,23 @@ class PlaylistPanel(Gtk.Stack):
self._playlist_albums = None self._playlist_albums = None
self._playlist_lock = threading.Lock() self._playlist_lock = threading.Lock()
self._playlist_stop = threading.Event() self._playlist_stop = threading.Event()
self._icon_theme = Gtk.IconTheme.get_default() self._icon_theme = Gtk.IconTheme.get_for_display(Gdk.Display.get_default())
self._standalone_pixbuf = None self._standalone_pixbuf = None
self._selected_albums = [] self._selected_albums = []
self._is_selected = False self._is_selected = False
# Widgets # Widgets
self._toolbar = PlaylistToolbar() # FIXME Toolbar signals
self._toolbar.connect('select', self.on_toolbar_select) #self._toolbar.connect('select', self.on_toolbar_select)
self._toolbar.connect('clear-playlist', self.on_toolbar_clear) #self._toolbar.connect('clear-playlist', self.on_toolbar_clear)
# Header bar # Header bar
self._headerbar_standalone = AlbumHeaderbar() self._headerbar_standalone = AlbumHeaderbar()
self._headerbar_standalone.connect('close', self.on_headerbar_close_clicked) self._headerbar_standalone.connect('close', self.on_headerbar_close_clicked)
# Playlist Grid: Model # Playlist Grid: Model
self._playlist_grid_model = Gtk.ListStore(GdkPixbuf.Pixbuf, str, str) self._playlist_grid_model = Gio.ListStore()
self._playlist_grid_selection = Gtk.MultiSelection.new(self._playlist_grid_model)
# Playlist Grid # Playlist Grid
self.playlist_grid.set_model(self._playlist_grid_model) self.playlist_grid.set_model(self._playlist_grid_selection)
self.playlist_grid.set_pixbuf_column(0)
self.playlist_grid.set_text_column(-1)
self.playlist_grid.set_tooltip_column(1)
def get_headerbar_standalone(self): def get_headerbar_standalone(self):
@ -114,7 +87,7 @@ class PlaylistPanel(Gtk.Stack):
def get_toolbar(self): def get_toolbar(self):
return self._toolbar return self.toolbar
def set_selected(self, selected): def set_selected(self, selected):
@ -136,16 +109,30 @@ class PlaylistPanel(Gtk.Stack):
self.emit('clear-playlist') self.emit('clear-playlist')
@Gtk.Template.Callback() # FIXME on_select_toggled()
def on_playlist_grid_clicked(self, widget, path): #@Gtk.Template.Callback()
# Get selected album def on_select_toggled(self, widget):
iter = self._playlist_grid_model.get_iter(path) self.emit('select', widget.get_active())
hash = self._playlist_grid_model.get_value(iter, 2)
album = self._playlist_albums[hash]
self._selected_albums = [album]
self.emit('albumart', hash)
# Show standalone album
# FIXME on_clear_clicked()
#@Gtk.Template.Callback()
def on_clear_clicked(self, widget):
if widget is self.playlist_clear_button:
self.emit('clear-playlist')
@Gtk.Template.Callback()
def on_playlist_grid_clicked(self, widget, position):
# Get selected album
item = self._playlist_grid_model.get_item(position)
album = item.get_album()
id = album.get_id()
self._selected_albums = [album]
self.emit('albumart', id)
# FIXME Show standalone album
return
if widget.get_selection_mode() == Gtk.SelectionMode.SINGLE: if widget.get_selection_mode() == Gtk.SelectionMode.SINGLE:
# Set labels # Set labels
self._headerbar_standalone.set_album(album) self._headerbar_standalone.set_album(album)
@ -158,7 +145,8 @@ class PlaylistPanel(Gtk.Stack):
self.standalone_spinner.start() self.standalone_spinner.start()
@Gtk.Template.Callback() # FIXME on_playlist_grid_selection_changed()
#@Gtk.Template.Callback()
def on_playlist_grid_selection_changed(self, widget): def on_playlist_grid_selection_changed(self, widget):
self._selected_albums = [] self._selected_albums = []
for path in widget.get_selected_items(): for path in widget.get_selected_items():
@ -167,18 +155,19 @@ class PlaylistPanel(Gtk.Stack):
self._selected_albums.append(self._playlist_albums[hash]) self._selected_albums.append(self._playlist_albums[hash])
@Gtk.Template.Callback() #@Gtk.Template.Callback()
def on_selection_cancel_clicked(self, widget): def on_selection_cancel_clicked(self, widget):
self._toolbar.exit_selection() self.select_button.set_active(False)
@Gtk.Template.Callback() #@Gtk.Template.Callback()
def on_selection_remove_clicked(self, widget): def on_selection_remove_clicked(self, widget):
self.emit('remove-multiple-albums', self._selected_albums) self.emit('remove-multiple-albums', self._selected_albums)
self._toolbar.exit_selection() self.select_button.set_active(False)
@Gtk.Template.Callback() # FIXME on_standalone_scroll_size_allocate()
#@Gtk.Template.Callback()
def on_standalone_scroll_size_allocate(self, widget, allocation): def on_standalone_scroll_size_allocate(self, widget, allocation):
self._resize_standalone_image() self._resize_standalone_image()
@ -187,13 +176,13 @@ class PlaylistPanel(Gtk.Stack):
self._close_standalone() self._close_standalone()
@Gtk.Template.Callback() #@Gtk.Template.Callback()
def on_standalone_remove_clicked(self, widget): def on_standalone_remove_clicked(self, widget):
self.emit('remove-album', self._selected_albums[0]) self.emit('remove-album', self._selected_albums[0])
self._close_standalone() self._close_standalone()
@Gtk.Template.Callback() #@Gtk.Template.Callback()
def on_standalone_play_clicked(self, widget): def on_standalone_play_clicked(self, widget):
self.emit('play', self._selected_albums[0]) self.emit('play', self._selected_albums[0])
self._close_standalone() self._close_standalone()
@ -235,6 +224,7 @@ class PlaylistPanel(Gtk.Stack):
def _set_playlist(self, host, playlist, size): def _set_playlist(self, host, playlist, size):
"""
if not self._is_selected and self._playlist != playlist: if not self._is_selected and self._playlist != playlist:
GObject.idle_add( GObject.idle_add(
self.get_parent().child_set_property, self.get_parent().child_set_property,
@ -242,16 +232,16 @@ class PlaylistPanel(Gtk.Stack):
'needs-attention', 'needs-attention',
True True
) )
"""
self._playlist_lock.acquire() self._playlist_lock.acquire()
self._playlist_stop.clear() self._playlist_stop.clear()
self._playlist = playlist self._playlist = playlist
self._playlist_albums = {} self._playlist_albums = {}
for album in playlist: for album in playlist:
self._playlist_albums[album.get_id()] = album self._playlist_albums[album.get_id()] = album
self.playlist_grid.set_model(None) self._playlist_grid_model.remove_all()
self.playlist_grid.freeze_child_notify() # FIXME Set item padding dynamically?
self._playlist_grid_model.clear() #GObject.idle_add(self.playlist_grid.set_item_padding, size / 100)
GObject.idle_add(self.playlist_grid.set_item_padding, size / 100)
cache = client.MCGCache(host, size) cache = client.MCGCache(host, size)
for album in playlist: for album in playlist:
@ -265,31 +255,22 @@ class PlaylistPanel(Gtk.Stack):
except Exception: except Exception:
self._logger.exception("Failed to load albumart") self._logger.exception("Failed to load albumart")
if pixbuf is None: if pixbuf is None:
pixbuf = self._icon_theme.load_icon( pixbuf = self._icon_theme.lookup_icon(
Utils.STOCK_ICON_DEFAULT, Utils.STOCK_ICON_DEFAULT,
None,
self._item_size, self._item_size,
Gtk.IconLookupFlags.FORCE_SVG & Gtk.IconLookupFlags.FORCE_SIZE self._item_size,
Gtk.TextDirection.LTR,
Gtk.IconLookupFlags.FORCE_SYMBOLIC
) )
if pixbuf is not None: if pixbuf is not None:
self._playlist_grid_model.append([ self._playlist_grid_model.append(GridItem(album, pixbuf))
pixbuf,
GObject.markup_escape_text("\n".join([
album.get_title(),
', '.join(album.get_dates()),
Utils.create_artists_label(album),
Utils.create_length_label(album)
])),
album.get_id()
])
if self._playlist_stop.is_set(): if self._playlist_stop.is_set():
self._playlist_lock.release() self._playlist_lock.release()
return return
self.playlist_grid.set_model(self._playlist_grid_model) self.playlist_grid.set_model(self._playlist_grid_selection)
self.playlist_grid.thaw_child_notify()
# TODO why set_columns()?
#self.playlist_grid.set_columns(len(playlist))
self._playlist_lock.release() self._playlist_lock.release()
@ -342,12 +323,11 @@ class PlaylistPanel(Gtk.Stack):
def _get_default_image(self): def _get_default_image(self):
return self._icon_theme.load_icon( return self._icon_theme.lookup_icon(
Utils.STOCK_ICON_DEFAULT, Utils.STOCK_ICON_DEFAULT,
None,
512, 512,
Gtk.IconLookupFlags.FORCE_SVG & Gtk.IconLookupFlags.FORCE_SIZE 512,
Gtk.TextDirection.LTR,
Gtk.IconLookupFlags.FORCE_SYMBOLIC
) )

View file

@ -2,32 +2,23 @@
import gi import gi
gi.require_version('Gtk', '3.0') gi.require_version('Gtk', '4.0')
gi.require_version('Adw', '1')
from gi.repository import Gtk, GObject from gi.repository import Gtk, Adw, GObject
@Gtk.Template(resource_path='/xyz/suruatoel/mcg/ui/server-toolbar.ui')
class ServerToolbar(Gtk.ButtonBox):
__gtype_name__ = 'McgServerToolbar'
def __init__(self):
super().__init__()
@Gtk.Template(resource_path='/xyz/suruatoel/mcg/ui/server-panel.ui') @Gtk.Template(resource_path='/xyz/suruatoel/mcg/ui/server-panel.ui')
class ServerPanel(Gtk.Box): class ServerPanel(Adw.Bin):
__gtype_name__ = 'McgServerPanel' __gtype_name__ = 'McgServerPanel'
__gsignals__ = { __gsignals__ = {
'change-output-device': (GObject.SIGNAL_RUN_FIRST, None, (GObject.TYPE_PYOBJECT,bool,)), 'change-output-device': (GObject.SIGNAL_RUN_FIRST, None, (GObject.TYPE_PYOBJECT,bool,)),
} }
# Widgets # Widgets
toolbar = Gtk.Template.Child()
# Status widgets # Status widgets
status_file = Gtk.Template.Child() status_file = Gtk.Template.Child()
status_audio = Gtk.Template.Child() status_audio = Gtk.Template.Child()
@ -44,14 +35,13 @@ class ServerPanel(Gtk.Box):
output_devices = Gtk.Template.Child() output_devices = Gtk.Template.Child()
def __init__(self): def __init__(self, **kwargs):
super().__init__() super().__init__(**kwargs)
self._none_label = "" self._none_label = ""
self._output_buttons = {} self._output_buttons = {}
self._is_selected = False self._is_selected = False
# Widgets # Widgets
self._toolbar = ServerToolbar()
self._none_label = self.status_file.get_label() self._none_label = self.status_file.get_label()
@ -60,7 +50,7 @@ class ServerPanel(Gtk.Box):
def get_toolbar(self): def get_toolbar(self):
return self._toolbar return self.toolbar
def on_output_device_toggled(self, widget, device): def on_output_device_toggled(self, widget, device):
@ -115,13 +105,12 @@ class ServerPanel(Gtk.Box):
self._output_buttons[device.get_id()].set_active(device.is_enabled()) self._output_buttons[device.get_id()].set_active(device.is_enabled())
self._output_buttons[device.get_id()].thaw_notify() self._output_buttons[device.get_id()].thaw_notify()
else: else:
button = Gtk.CheckButton(device.get_name()) button = Gtk.CheckButton.new_with_label(device.get_name())
if device.is_enabled(): if device.is_enabled():
button.set_active(True) button.set_active(True)
handler = button.connect('toggled', self.on_output_device_toggled, device) handler = button.connect('toggled', self.on_output_device_toggled, device)
self.output_devices.insert(button, -1) self.output_devices.insert(button, -1)
self._output_buttons[device.get_id()] = button self._output_buttons[device.get_id()] = button
self.output_devices.show_all()
# Remove devices # Remove devices
for id in self._output_buttons.keys(): for id in self._output_buttons.keys():

View file

@ -2,13 +2,13 @@
import gi import gi
gi.require_version('Gtk', '3.0') gi.require_version('Gtk', '4.0')
import hashlib import hashlib
import locale import locale
import os import os
import urllib import urllib
from gi.repository import GdkPixbuf from gi.repository import Gdk, GdkPixbuf, GObject
@ -86,3 +86,29 @@ class SortOrder:
ARTIST = 0 ARTIST = 0
TITLE = 1 TITLE = 1
YEAR = 2 YEAR = 2
class GridItem(GObject.GObject):
__gtype_name__ = "GridItem"
tooltip = GObject.Property(type=str, default=None)
cover = GObject.Property(type=Gdk.Paintable, default=None)
def __init__(self, album, cover):
super().__init__()
self._album = album
if cover:
self.cover = Gdk.Texture.new_for_pixbuf(cover)
self.tooltip = GObject.markup_escape_text("\n".join([
album.get_title(),
', '.join(album.get_dates()),
Utils.create_artists_label(album),
Utils.create_length_label(album)
]))
def get_album(self):
return self._album

View file

@ -2,7 +2,8 @@
import gi import gi
gi.require_version('Gtk', '3.0') gi.require_version('Gtk', '4.0')
gi.require_version('Adw', '1')
try: try:
import keyring import keyring
use_keyring = True use_keyring = True
@ -11,10 +12,10 @@ except:
import locale import locale
import logging import logging
from gi.repository import Gtk, Gdk, GObject, GLib, Gio from gi.repository import Gtk, Adw, Gdk, GObject, GLib, Gio
from . import client from . import client
from .shortcutsdialog import ShortcutsDialog #from .shortcutsdialog import ShortcutsDialog
from .connectionpanel import ConnectionPanel from .connectionpanel import ConnectionPanel
from .serverpanel import ServerPanel from .serverpanel import ServerPanel
from .coverpanel import CoverPanel from .coverpanel import CoverPanel
@ -43,7 +44,7 @@ class WindowState(GObject.Object):
@Gtk.Template(resource_path='/xyz/suruatoel/mcg/ui/window.ui') @Gtk.Template(resource_path='/xyz/suruatoel/mcg/ui/window.ui')
class Window(Gtk.ApplicationWindow): class Window(Adw.ApplicationWindow):
__gtype_name__ = 'McgAppWindow' __gtype_name__ = 'McgAppWindow'
SETTING_HOST = 'host' SETTING_HOST = 'host'
SETTING_PORT = 'port' SETTING_PORT = 'port'
@ -63,31 +64,30 @@ class Window(Gtk.ApplicationWindow):
toolbar_stack = Gtk.Template.Child() toolbar_stack = Gtk.Template.Child()
# Headerbar # Headerbar
headerbar = Gtk.Template.Child() headerbar = Gtk.Template.Child()
headerbar_title_stack = Gtk.Template.Child() #headerbar_title_stack = Gtk.Template.Child()
headerbar_panel_switcher = Gtk.Template.Child() headerbar_panel_switcher = Gtk.Template.Child()
headerbar_connection_label = Gtk.Template.Child() #headerbar_connection_label = Gtk.Template.Child()
headerbar_button_connect = Gtk.Template.Child() headerbar_button_connect = Gtk.Template.Child()
headerbar_button_playpause = Gtk.Template.Child() headerbar_button_playpause = Gtk.Template.Child()
headerbar_button_volume = Gtk.Template.Child() headerbar_button_volume = Gtk.Template.Child()
# Infobar # Infobar
info_revealer = Gtk.Template.Child() info_toast = Gtk.Template.Child()
info_bar = Gtk.Template.Child()
info_label = Gtk.Template.Child()
def __init__(self, app, title, settings): def __init__(self, app, title, settings, **kwargs):
super().__init__() super().__init__(**kwargs)
self.set_application(app) self.set_application(app)
self.set_title(title) self.set_title(title)
self._settings = settings self._settings = settings
self._panels = [] self._panels = []
self._mcg = client.Client() self._mcg = client.Client()
self._state = WindowState() self._state = WindowState()
self._changing_volume = False
self._setting_volume = False self._setting_volume = False
self._headerbar_connection_button_active = True
self._headerbar_playpause_button_active = True
# Help/Shortcuts dialog # FIXME Help/Shortcuts dialog
self.set_help_overlay(ShortcutsDialog()) #self.set_help_overlay(ShortcutsDialog())
# Login screen # Login screen
self._connection_panel = ConnectionPanel() self._connection_panel = ConnectionPanel()
@ -99,28 +99,28 @@ class Window(Gtk.ApplicationWindow):
self._panels.append(self._cover_panel) self._panels.append(self._cover_panel)
# Playlist panel # Playlist panel
self._playlist_panel = PlaylistPanel(self._mcg) self._playlist_panel = PlaylistPanel(self._mcg)
self._playlist_panel.connect('open-standalone', self.on_panel_open_standalone) #self._playlist_panel.connect('open-standalone', self.on_panel_open_standalone)
self._playlist_panel.connect('close-standalone', self.on_panel_close_standalone) #self._playlist_panel.connect('close-standalone', self.on_panel_close_standalone)
self._panels.append(self._playlist_panel) self._panels.append(self._playlist_panel)
# Library panel # Library panel
self._library_panel = LibraryPanel(self._mcg) self._library_panel = LibraryPanel(self._mcg)
self._library_panel.connect('open-standalone', self.on_panel_open_standalone) #self._library_panel.connect('open-standalone', self.on_panel_open_standalone)
self._library_panel.connect('close-standalone', self.on_panel_close_standalone) #self._library_panel.connect('close-standalone', self.on_panel_close_standalone)
self._panels.append(self._library_panel) self._panels.append(self._library_panel)
# Stack # Stack
self.content_stack.add(self._connection_panel) self.content_stack.add_child(self._connection_panel)
self.panel_stack.add_titled(self._server_panel, 'server-panel', locale.gettext("Server")) self.panel_stack.add_titled(self._server_panel, 'server-panel', locale.gettext("Server"))
self.panel_stack.add_titled(self._cover_panel, 'cover-panel', locale.gettext("Cover")) self.panel_stack.add_titled_with_icon(self._cover_panel, 'cover-panel', locale.gettext("Cover"), "image-x-generic-symbolic")
self.panel_stack.add_titled(self._playlist_panel, 'playlist-panel', locale.gettext("Playlist")) self.panel_stack.add_titled(self._playlist_panel, 'playlist-panel', locale.gettext("Playlist"))
self.panel_stack.add_titled(self._library_panel, 'library-panel', locale.gettext("Library")) self.panel_stack.add_titled(self._library_panel, 'library-panel', locale.gettext("Library"))
# Header # Header
self._playlist_panel.get_headerbar_standalone().connect('close', self.on_panel_close_standalone) #self._playlist_panel.get_headerbar_standalone().connect('close', self.on_panel_close_standalone)
self._library_panel.get_headerbar_standalone().connect('close', self.on_panel_close_standalone) #self._library_panel.get_headerbar_standalone().connect('close', self.on_panel_close_standalone)
# Toolbar stack # Toolbar stack
self.toolbar_stack.add(self._server_panel.get_toolbar()) self.toolbar_stack.add_child(self._server_panel.get_toolbar())
self.toolbar_stack.add(self._cover_panel.get_toolbar()) self.toolbar_stack.add_child(self._cover_panel.get_toolbar())
self.toolbar_stack.add(self._playlist_panel.get_toolbar()) self.toolbar_stack.add_child(self._playlist_panel.get_toolbar())
self.toolbar_stack.add(self._library_panel.get_toolbar()) self.toolbar_stack.add_child(self._library_panel.get_toolbar())
# Properties # Properties
self._set_headerbar_sensitive(False, False) self._set_headerbar_sensitive(False, False)
@ -134,6 +134,9 @@ class Window(Gtk.ApplicationWindow):
self._library_panel.set_sort_type(self._settings.get_boolean(Window.SETTING_SORT_TYPE)) self._library_panel.set_sort_type(self._settings.get_boolean(Window.SETTING_SORT_TYPE))
# Signals # Signals
self.connect("notify::default-width", self.on_resize)
self.connect("notify::maximized", self.on_maximized)
self.connect("notify::fullscreened", self.on_fullscreened)
self._connection_panel.connect('connection-changed', self.on_connection_panel_connection_changed) self._connection_panel.connect('connection-changed', self.on_connection_panel_connection_changed)
self.panel_stack.connect('notify::visible-child', self.on_stack_switched) self.panel_stack.connect('notify::visible-child', self.on_stack_switched)
self._server_panel.connect('change-output-device', self.on_server_panel_output_device_changed) self._server_panel.connect('change-output-device', self.on_server_panel_output_device_changed)
@ -176,7 +179,6 @@ class Window(Gtk.ApplicationWindow):
self.set_default_size(self._state.width, self._state.height) self.set_default_size(self._state.width, self._state.height)
if self._state.get_property(WindowState.IS_MAXIMIZED): if self._state.get_property(WindowState.IS_MAXIMIZED):
self.maximize() self.maximize()
self.show_all()
self.content_stack.set_visible_child(self._connection_panel) self.content_stack.set_visible_child(self._connection_panel)
if self._settings.get_boolean(Window.SETTING_CONNECTED): if self._settings.get_boolean(Window.SETTING_CONNECTED):
self._connect() self._connect()
@ -228,7 +230,7 @@ class Window(Gtk.ApplicationWindow):
def on_menu_toggle_fullscreen(self, action, value): def on_menu_toggle_fullscreen(self, action, value):
self.panel_stack.set_visible_child(self._cover_panel) self.panel_stack.set_visible_child(self.cover_panel_page)
if not self._state.get_property(WindowState.IS_FULLSCREENED): if not self._state.get_property(WindowState.IS_FULLSCREENED):
self.fullscreen() self.fullscreen()
else: else:
@ -236,52 +238,36 @@ class Window(Gtk.ApplicationWindow):
def on_menu_search_library(self, action, value): def on_menu_search_library(self, action, value):
self.panel_stack.set_visible_child(self._library_panel) self.panel_stack.set_visible_child(self.library_panel_page)
self._library_panel.show_search() self._library_panel.show_search()
# Window callbacks # Window callbacks
@Gtk.Template.Callback()
def on_resize(self, widget, event): def on_resize(self, widget, event):
if not self._state.get_property(WindowState.IS_MAXIMIZED): width = self.get_size(Gtk.Orientation.HORIZONTAL)
size = self.get_size() height = self.get_size(Gtk.Orientation.VERTICAL)
self._state.set_property(WindowState.WIDTH, size.width) if width > 0:
self._state.set_property(WindowState.HEIGHT, size.height) self._cover_panel.set_width(width)
if not self._state.get_property(WindowState.IS_MAXIMIZED):
self._state.set_property(WindowState.WIDTH, width)
self._state.set_property(WindowState.HEIGHT, height)
@Gtk.Template.Callback() def on_maximized(self, widget, maximized):
def on_state(self, widget, state): self._state.set_property(WindowState.IS_MAXIMIZED, maximized is True)
self._state.set_property(WindowState.IS_MAXIMIZED, (state.new_window_state & Gdk.WindowState.MAXIMIZED > 0))
self._fullscreen((state.new_window_state & Gdk.WindowState.FULLSCREEN > 0))
def on_fullscreened(self, widget, fullscreened):
self._fullscreen(fullscreened is True)
# HeaderBar callbacks # HeaderBar callbacks
@Gtk.Template.Callback()
def on_headerbar_connection_active_notify(self, widget, status):
self._connect()
@Gtk.Template.Callback() @Gtk.Template.Callback()
def on_headerbar_connection_state_set(self, widget, state): def on_headerbar_connection_state_set(self, widget, state):
return True if self._headerbar_connection_button_active:
self._connect()
@Gtk.Template.Callback()
def on_headerbar_volume_press(self, widget, active):
self._changing_volume = active
@Gtk.Template.Callback()
def on_headerbar_volume_release(self, widget, active):
self._changing_volume = active
@Gtk.Template.Callback()
def on_headerbar_playpause_toggled(self, widget):
self._mcg.playpause()
self._mcg.get_status()
@Gtk.Template.Callback() @Gtk.Template.Callback()
@ -290,17 +276,11 @@ class Window(Gtk.ApplicationWindow):
self._mcg.set_volume(int(value*100)) self._mcg.set_volume(int(value*100))
# Infobar callback
@Gtk.Template.Callback() @Gtk.Template.Callback()
def on_info_bar_close(self, *args): def on_headerbar_playpause_toggled(self, widget):
self.info_revealer.set_reveal_child(False) if self._headerbar_playpause_button_active:
self._mcg.playpause()
self._mcg.get_status()
@Gtk.Template.Callback()
def on_info_bar_response(self, widget, response):
self.info_revealer.set_reveal_child(False)
# Panel callbacks # Panel callbacks
@ -311,12 +291,12 @@ class Window(Gtk.ApplicationWindow):
self._set_menu_visible_panel() self._set_menu_visible_panel()
for panel in self._panels: for panel in self._panels:
panel.set_selected(panel == self.panel_stack.get_visible_child()) panel.set_selected(panel == self.panel_stack.get_visible_child())
GObject.idle_add( #GObject.idle_add(
self.panel_stack.child_set_property, # self.panel_stack.child_set_property,
self.panel_stack.get_visible_child(), # self.panel_stack.get_visible_child(),
'needs-attention', # 'needs-attention',
False # False
) #)
def on_panel_open_standalone(self, panel): def on_panel_open_standalone(self, panel):
self.set_titlebar(panel.get_headerbar_standalone()) self.set_titlebar(panel.get_headerbar_standalone())
@ -450,9 +430,7 @@ class Window(Gtk.ApplicationWindow):
# Status # Status
self._server_panel.set_status(file, audio, bitrate, error) self._server_panel.set_status(file, audio, bitrate, error)
# Error # Error
if error is None: if error:
self.info_revealer.set_reveal_child(False)
else:
self._show_error(error) self._show_error(error)
@ -487,6 +465,8 @@ class Window(Gtk.ApplicationWindow):
def on_mcg_custom(self, name): def on_mcg_custom(self, name):
pass
"""
if name == Window._CUSTOM_STARTUP_COMPLETE: if name == Window._CUSTOM_STARTUP_COMPLETE:
for panel in self._panels: for panel in self._panels:
GObject.idle_add( GObject.idle_add(
@ -495,6 +475,7 @@ class Window(Gtk.ApplicationWindow):
'needs-attention', 'needs-attention',
False False
) )
"""
def on_mcg_error(self, error): def on_mcg_error(self, error):
@ -593,58 +574,39 @@ class Window(Gtk.ApplicationWindow):
def _set_play(self): def _set_play(self):
self.headerbar_button_playpause.handler_block_by_func( self._headerbar_playpause_button_active = False
self.on_headerbar_playpause_toggled
)
self.headerbar_button_playpause.set_active(True) self.headerbar_button_playpause.set_active(True)
self.headerbar_button_playpause.handler_unblock_by_func( self._headerbar_playpause_button_active = True
self.on_headerbar_playpause_toggled
)
def _set_pause(self): def _set_pause(self):
self.headerbar_button_playpause.handler_block_by_func( self._headerbar_playpause_button_active = False
self.on_headerbar_playpause_toggled
)
self.headerbar_button_playpause.set_active(False) self.headerbar_button_playpause.set_active(False)
self.headerbar_button_playpause.handler_unblock_by_func( self._headerbar_playpause_button_active = True
self.on_headerbar_playpause_toggled
)
def _set_volume(self, volume): def _set_volume(self, volume):
if volume >= 0: if volume >= 0:
self.headerbar_button_volume.set_visible(True) self.headerbar_button_volume.set_visible(True)
if not self._changing_volume: self._setting_volume = True
self._setting_volume = True self.headerbar_button_volume.set_value(volume / 100)
self.headerbar_button_volume.set_value(volume / 100) self._setting_volume = False
self._setting_volume = False
else: else:
self.headerbar_button_volume.set_visible(False) self.headerbar_button_volume.set_visible(False)
def _headerbar_connected(self): def _headerbar_connected(self):
self.headerbar_button_connect.handler_block_by_func( self._headerbar_connection_button_active = False
self.on_headerbar_connection_active_notify
)
self.headerbar_button_connect.set_active(True) self.headerbar_button_connect.set_active(True)
self.headerbar_button_connect.set_state(True) self.headerbar_button_connect.set_state(True)
self.headerbar_button_connect.handler_unblock_by_func( self._headerbar_connection_button_active = True
self.on_headerbar_connection_active_notify
)
self.headerbar_title_stack.set_visible_child(self.headerbar_panel_switcher)
def _headerbar_disconnected(self): def _headerbar_disconnected(self):
self.headerbar_button_connect.handler_block_by_func( self._headerbar_connection_button_active = False
self.on_headerbar_connection_active_notify
)
self.headerbar_button_connect.set_active(False) self.headerbar_button_connect.set_active(False)
self.headerbar_button_connect.set_state(False) self.headerbar_button_connect.set_state(False)
self.headerbar_button_connect.handler_unblock_by_func( self._headerbar_connection_button_active = True
self.on_headerbar_connection_active_notify
)
self.headerbar_title_stack.set_visible_child(self.headerbar_connection_label)
def _set_headerbar_sensitive(self, sensitive, connecting): def _set_headerbar_sensitive(self, sensitive, connecting):
@ -655,6 +617,4 @@ class Window(Gtk.ApplicationWindow):
def _show_error(self, message): def _show_error(self, message):
self.info_bar.set_message_type(Gtk.MessageType.ERROR) self.info_toast.add_toast(Adw.Toast.new(message))
self.info_label.set_text(message)
self.info_revealer.set_reveal_child(True)