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);
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 {
background:none;
}
@ -18,13 +30,13 @@
font-weight:bold;
}
revealer.sidebar > * {
#cover_info_revealer {
background-color:alpha(@theme_bg_color, 0.8);
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;
}
@ -32,24 +44,6 @@ actionbar {
background-color:@theme_unfocused_bg_color;
}
/* Icon View in regular mode */
iconview.view:selected,
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;
gridview child {
padding: 10px;
}

View file

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

View file

@ -1,182 +1,86 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.2 -->
<interface>
<requires lib="gtk+" version="3.12"/>
<object class="GtkAdjustment" id="server-port-adjustment">
<property name="lower">1024</property>
<property name="upper">9999</property>
<property name="value">6600</property>
<property name="step-increment">1</property>
<property name="page-increment">100</property>
</object>
<template class="McgConnectionPanel" parent="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<requires lib="gtk+" version="4.8"/>
<requires lib="adw" version="1.2" />
<object class="GtkAdjustment" id="server-port-adjustment">
<property name="lower">1024</property>
<property name="upper">9999</property>
<property name="value">6600</property>
<property name="step-increment">1</property>
<property name="page-increment">100</property>
</object>
<object class="GtkBox" id="toolbar">
<property name="orientation">horizontal</property>
<property name="spacing">6</property>
</object>
<template class="McgConnectionPanel" parent="AdwBin">
<child>
<!-- n-columns=3 n-rows=6 -->
<object class="GtkGrid">
<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>
<object class="AdwStatusPage">
<property name="title">Connect to MPD</property>
<child>
<object class="GtkTreeView" id="zeroconf_list">
<property name="visible">True</property>
<property name="can-focus">True</property>
<signal name="focus-out-event" handler="on_zeroconf_list_outfocused" swapped="no"/>
<child internal-child="selection">
<object class="GtkTreeSelection">
<signal name="changed" handler="on_service_selected" swapped="no"/>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
<object class="GtkBox">
<property name="hexpand">false</property>
<property name="halign">center</property>
<child>
<object class="GtkListBox" id="zeroconf_list">
<property name="hexpand">true</property>
<child type="placeholder">
<object class="GtkLabel">
<property name="label" translatable="true">No service found</property>
</object>
</child>
</object>
</child>
<child>
<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>
<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>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
</template>
</template>
</interface>

View file

@ -1,199 +1,198 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.2 -->
<interface>
<requires lib="gtk+" version="3.22"/>
<template class="McgCoverPanel" parent="GtkOverlay">
<property name="visible">True</property>
<property name="can-focus">False</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>
<requires lib="gtk+" version="4.8"/>
<requires lib="adw" version="1.2" />
<object class="GtkBox" id="toolbar">
<property name="orientation">horizontal</property>
<property name="halign">end</property>
<property name="transition-type">slide-right</property>
<property name="spacing">6</property>
<child>
<object class="GtkScrolledWindow" id="cover_info_scroll">
<property name="visible">True</property>
<property name="can-focus">True</property>
<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>
<child>
<object class="GtkViewport">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="shadow-type">none</property>
<object class="GtkButton" id="fullscreen_button">
<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="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<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>
<object class="GtkImage">
<property name="icon-name">view-fullscreen-symbolic</property>
</object>
</child>
</object>
</child>
</object>
</object>
</child>
<style>
<class name="sidebar"/>
<class name="background"/>
</style>
</object>
</child>
</template>
</object>
<template class="McgCoverPanel" parent="GtkOverlay">
<child>
<object class="GtkStack" id="cover_stack">
<child>
<object class="GtkSpinner" id="cover_spinner">
</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>

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"?>
<!-- Generated with glade 3.38.2 -->
<interface>
<requires lib="gtk+" version="3.16"/>
<template class="McgLibraryPanel" parent="GtkStack">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="transition-type">slide-left-right</property>
<requires lib="gtk+" version="4.8"/>
<requires lib="adw" version="1.2" />
<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="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>
<object class="GtkBox" id="panel_normal">
<property name="visible">True</property>
@ -13,27 +280,31 @@
<property name="orientation">vertical</property>
<child>
<object class="GtkSearchBar" id="filter_bar">
<property name="visible">True</property>
<!--
<property name="app-paintable">True</property>
<property name="can-focus">False</property>
-->
<signal name="notify" handler="on_filter_bar_notify" swapped="no"/>
<child>
<object class="GtkSearchEntry" id="filter_entry">
<property name="visible">True</property>
<property name="can-focus">True</property>
<!--
<property name="primary-icon-name">edit-find-symbolic</property>
<property name="primary-icon-activatable">False</property>
<property name="primary-icon-sensitive">False</property>
-->
<property name="placeholder-text" translatable="yes">search library</property>
<signal name="search-changed" handler="on_filter_entry_changed" swapped="no"/>
</object>
</child>
</object>
<!--
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
-->
</child>
<child>
<placeholder/>
@ -62,15 +333,16 @@
<property name="spacing">10</property>
<child>
<object class="GtkImage" id="progress_image">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon_size">6</property>
<property name="icon-size">large</property>
<property name="icon-name">image-x-generic-symbolic</property>
</object>
<!--
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
-->
</child>
<child>
<object class="GtkProgressBar" id="progress_bar">
@ -80,87 +352,135 @@
<property name="pulse-step">0</property>
<property name="show-text">True</property>
</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">page1</property>
</packing>
-->
</child>
<child>
<object class="GtkScrolledWindow" id="scroll">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="vexpand">true</property>
<child>
<object class="GtkIconView" id="library_grid">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="margin">0</property>
<property name="item-orientation">horizontal</property>
<property name="row-spacing">0</property>
<property name="column-spacing">0</property>
<property name="tooltip-column">1</property>
<property name="item-padding">0</property>
<property name="activate-on-single-click">True</property>
<signal name="item-activated" handler="on_library_grid_clicked" swapped="no"/>
<signal name="selection-changed" handler="on_library_grid_selection_changed" swapped="no"/>
<signal name="size-allocate" handler="on_resize" swapped="no"/>
<style>
<class name="no-bg"/>
</style>
</object>
<object class="GtkGridView" id="library_grid">
<property name="orientation">vertical</property>
<!--
<signal name="activate" handler="on_library_grid_clicked" swapped="no"/>
<signal name="selection-changed" handler="on_library_grid_selection_changed" swapped="no"/>
<signal name="size-allocate" handler="on_resize" swapped="no"/>
-->
<style>
<class name="no-bg"/>
</style>
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="bytes">
<![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<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>
<style>
<class name="no-bg"/>
</style>
</object>
<!--
<packing>
<property name="name">page0</property>
<property name="title">page0</property>
<property name="position">1</property>
</packing>
-->
</child>
</object>
<!--
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
-->
</child>
<child>
<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="reveal-child">false</property>
<child>
<object class="GtkActionBar" id="library-actionbar">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkButton">
<property name="label" translatable="yes">cancel</property>
@ -169,10 +489,12 @@
<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">
@ -182,25 +504,31 @@
<property name="receives-default">True</property>
<signal name="clicked" handler="on_selection_add_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="position">3</property>
</packing>
-->
</child>
</object>
<!--
<packing>
<property name="name">page0</property>
<property name="title">page0</property>
</packing>
-->
</child>
<child>
<object class="GtkBox" id="panel_standalone">
@ -217,9 +545,11 @@
<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">
@ -227,7 +557,9 @@
<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>
@ -237,23 +569,29 @@
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">gtk-missing-image</property>
<!--
<property name="icon_size">6</property>
-->
</object>
</child>
</object>
</child>
</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 class="GtkActionBar" id="library-standalone-actionbar">
@ -267,10 +605,12 @@
<property name="receives-default">True</property>
<signal name="clicked" handler="on_standalone_queue_clicked" swapped="no"/>
</object>
<!--
<packing>
<property name="pack-type">end</property>
<property name="position">1</property>
</packing>
-->
</child>
<child>
<object class="GtkButton">
@ -280,24 +620,32 @@
<property name="receives-default">True</property>
<signal name="clicked" handler="on_standalone_play_clicked" swapped="no"/>
</object>
<!--
<packing>
<property name="pack-type">end</property>
<property name="position">0</property>
</packing>
-->
</child>
</object>
<!--
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
-->
</child>
</object>
<!--
<packing>
<property name="name">page1</property>
<property name="title">page1</property>
<property name="position">1</property>
</packing>
-->
</child>
</template>
</object>
</child>
</template>
</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"?>
<!-- Generated with glade 3.38.2 -->
<interface>
<requires lib="gtk+" version="3.16"/>
<template class="McgPlaylistPanel" parent="GtkStack">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="transition-type">slide-left-right</property>
<child>
<object class="GtkBox" id="panel_normal">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<requires lib="gtk+" version="4.8"/>
<requires lib="adw" version="1.2" />
<object class="GtkBox" id="toolbar">
<property name="orientation">horizontal</property>
<property name="halign">end</property>
<property name="spacing">6</property>
<child>
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can-focus">True</property>
<child>
<object class="GtkIconView" id="playlist_grid">
<object class="GtkToggleButton" id="select_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="margin">0</property>
<property name="item-orientation">horizontal</property>
<property name="row-spacing">0</property>
<property name="column-spacing">0</property>
<property name="tooltip-column">1</property>
<property name="item-padding">0</property>
<property name="activate-on-single-click">True</property>
<signal name="item-activated" handler="on_playlist_grid_clicked" swapped="no"/>
<signal name="selection-changed" handler="on_playlist_grid_selection_changed" swapped="no"/>
<style>
<class name="no-bg"/>
</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>
<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="icon-name">object-select-symbolic</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkRevealer" id="actionbar_revealer">
<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">
<object class="GtkButton" id="playlist_clear_button">
<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"/>
<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="GtkViewport">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkImage" id="standalone_image">
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">gtk-missing-image</property>
<property name="icon_size">6</property>
</object>
</child>
</object>
<property name="icon-name">edit-clear</property>
</object>
</child>
</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>
</object>
</child>
</object>
<template class="McgPlaylistPanel" parent="AdwBin">
<child>
<object class="GtkActionBar" id="actionbar_standalone">
<property name="visible">True</property>
<property name="can-focus">False</property>
<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_standalone_remove_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">play</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<signal name="clicked" handler="on_standalone_play_clicked" swapped="no"/>
</object>
<packing>
<property name="pack-type">end</property>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
<object class="GtkStack">
<property name="transition-type">slide-left-right</property>
<child>
<object class="GtkBox" id="panel_normal">
<property name="orientation">vertical</property>
<child>
<object class="GtkScrolledWindow">
<property name="vexpand">true</property>
<child>
<object class="GtkGridView" id="playlist_grid">
<property name="orientation">vertical</property>
<!--
<property name="item-padding">0</property>
-->
<property name="single-click-activate">true</property>
<signal name="activate" handler="on_playlist_grid_clicked"/>
<!--
<signal name="selection-changed" handler="on_playlist_grid_selection_changed" swapped="no"/>
-->
<style>
<class name="no-bg"/>
</style>
<property name="factory">
<object class="GtkBuilderListItemFactory">
<property name="bytes">
<![CDATA[
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GtkListItem">
<property name="activatable">true</property>
<property name="child">
<object class="GtkBox">
<property name="orientation">vertical</property>
<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>
<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>
</object>
<packing>
<property name="name">page1</property>
<property name="title">page1</property>
<property name="position">1</property>
</packing>
</child>
</template>
</template>
</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"?>
<!-- Generated with glade 3.38.2 -->
<interface>
<requires lib="gtk+" version="3.16"/>
<template class="McgServerPanel" parent="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<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>
<requires lib="gtk+" version="4.8"/>
<requires lib="adw" version="1.2" />
<object class="GtkBox" id="toolbar">
<property name="orientation">horizontal</property>
<property name="halign">end</property>
<child>
<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="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>
<object class="GtkToggleButton" id="sidebar_switcher">
<property name="icon-name">sidebar-show-symbolic</property>
<property name="active">true</property>
<property name="visible" bind-source="server_flap" bind-property="folded" bind-flags="sync-create"/>
</object>
</child>
</object>
<template class="McgServerPanel" parent="AdwBin">
<child>
<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">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>
<object class="AdwFlap" id="server_flap">
<property name="flap-position">end</property>
<property name="reveal-flap" bind-source="sidebar_switcher" bind-property="active" bind-flags="sync-create|bidirectional" />
<property name="flap">
<object class="GtkStackSidebar">
<property name="stack">stack</property>
<property name="name">server_stack_sidebar</property>
</object>
</property>
<property name="separator">
<object class="GtkSeparator"/>
</property>
<property name="content">
<object class="GtkStack" id="stack">
<child>
<object class="GtkLabel" id="stats_artists">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">end</property>
<property name="justify">right</property>
<property name="selectable">True</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">0</property>
</packing>
<object class="GtkStackPage">
<property name="name">status</property>
<property name="title">Status</property>
<property name="child">
<object class="AdwStatusPage">
<property name="icon-name">dialog-information-symbolic</property>
<child>
<object class="GtkGrid">
<property name="row-spacing">2</property>
<property name="column-spacing">5</property>
<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>
<object class="GtkLabel" id="stats_albums">
<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">1</property>
</packing>
<object class="GtkStackPage">
<property name="name">stats</property>
<property name="title">Statistics</property>
<property name="child">
<object class="AdwStatusPage">
<property name="icon-name">starred-symbolic</property>
<child>
<object class="GtkGrid">
<property name="row-spacing">2</property>
<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>
<object class="GtkLabel" id="stats_songs">
<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">2</property>
</packing>
<object class="GtkStackPage">
<property name="name">devices</property>
<property name="title">Audio Devices</property>
<property name="child">
<object class="AdwStatusPage">
<property name="icon-name">audio-speakers-symbolic</property>
<child>
<object class="GtkListBox" id="output_devices">
<property name="hexpand">false</property>
<property name="halign">center</property>
<property name="selection-mode">none</property>
<style>
<class name="no-bg"/>
</style>
</object>
</child>
</object>
</property>
</object>
</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">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>
</object>
</property>
</object>
</child>
<child>
<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>
</template>
</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"?>
<!-- Generated with glade 3.38.2 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<template class="McgAppWindow" parent="GtkApplicationWindow">
<property name="can-focus">False</property>
<property name="icon-name">xyz.suruatoel.mcg</property>
<signal name="size-allocate" handler="on_resize" swapped="no"/>
<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>
<requires lib="gtk+" version="4.8" />
<requires lib="adw" version="1.2" />
<template class="McgAppWindow" parent="AdwApplicationWindow">
<property name="content">
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="baseline-position">top</property>
<property name="show-close-button">True</property>
<signal name="close" handler="on_info_bar_close" swapped="no"/>
<signal name="response" handler="on_info_bar_response" swapped="no"/>
<child internal-child="action_area">
<object class="GtkButtonBox">
<property name="can-focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
<child>
<object class="AdwHeaderBar" id="headerbar">
<property name="centering-policy">strict</property>
<property name="show_end_title_buttons">true</property>
<property name="title-widget">
<object class="AdwViewSwitcherTitle" id="headerbar_panel_switcher">
<property name="title">CoverGrid</property>
<property name="stack">panel_stack</property>
</object>
</property>
<child>
<object class="GtkSwitch" id="headerbar_button_connect">
<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 internal-child="content_area">
<object class="GtkBox">
<property name="can-focus">False</property>
<child>
<object class="GtkLabel" id="info_label">
<property name="visible">True</property>
<property name="can-focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
<child>
<object class="AdwToastOverlay" id="info_toast">
<child>
<object class="GtkStack" id="content_stack">
<property name="name">content_stack</property>
<property name="vexpand">true</property>
<child>
<object class="AdwViewStack" id="panel_stack">
<property name="vexpand">true</property>
<signal name="notify::visible-child" handler="on_stack_switched" swapped="no"/>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
<child type="titlebar">
<object class="GtkHeaderBar" id="headerbar">
<property name="name">headerbar</property>
<property name="visible">True</property>
<property name="can-focus">False</property>
<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>
<child>
<object class="AdwViewSwitcherBar">
<property name="stack">panel_stack</property>
<binding name="reveal">
<lookup name="title-visible">headerbar_panel_switcher</lookup>
</binding>
</object>
</child>
</object>
</property>
</template>
</interface>

View file

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

View file

@ -2,15 +2,16 @@
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')
class AlbumHeaderbar(Gtk.HeaderBar):
class AlbumHeaderbar(Adw.Bin):
__gtype_name__ = 'McgAlbumHeaderbar'
__gsignals__ = {
'close': (GObject.SIGNAL_RUN_FIRST, None, ())

View file

@ -5,11 +5,12 @@ import logging
import urllib
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gio, Gtk, Gdk, GLib
gi.require_version('Gtk', '4.0')
gi.require_version('Adw', '1')
from gi.repository import Gio, Gtk, Gdk, GLib, Adw
from .window import Window
from .infodialog import InfoDialog
#from .infodialog import InfoDialog
@ -38,6 +39,7 @@ class Application(Gtk.Application):
self._load_css()
self._setup_actions()
self._load_appmenu()
self._setup_adw()
def do_activate(self):
@ -48,10 +50,12 @@ class Application(Gtk.Application):
def on_menu_info(self, action, value):
if not self._info_dialog:
self._info_dialog = InfoDialog()
self._info_dialog.run()
self._info_dialog.hide()
# FIXME Info dialog
#if not self._info_dialog:
# self._info_dialog = InfoDialog()
#self._info_dialog.run()
#self._info_dialog.hide()
pass
def on_menu_quit(self, action, value):
@ -70,15 +74,15 @@ class Application(Gtk.Application):
def _set_default_settings(self):
settings = Gtk.Settings.get_default()
settings.set_property('gtk-application-prefer-dark-theme', True)
style_manager = Adw.StyleManager.get_default()
style_manager.set_color_scheme(Adw.ColorScheme.PREFER_DARK)
def _load_css(self):
styleProvider = Gtk.CssProvider()
styleProvider.load_from_resource(self._get_resource_path('gtk.css'))
Gtk.StyleContext.add_provider_for_screen(
Gdk.Screen.get_default(),
Gtk.StyleContext.add_provider_for_display(
Gdk.Display.get_default(),
styleProvider,
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
)
@ -95,10 +99,23 @@ class Application(Gtk.Application):
def _load_appmenu(self):
builder = Gtk.Builder()
builder.set_translation_domain(Application.DOMAIN)
builder.add_from_resource(self._get_resource_path('ui/gtk.menu.ui'))
self.set_app_menu(builder.get_object('app-menu'))
# FIXME Handle menu
#builder.set_translation_domain(Application.DOMAIN)
#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):
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
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
@ -12,56 +14,58 @@ from mcg.zeroconf import ZeroconfProvider
@Gtk.Template(resource_path='/xyz/suruatoel/mcg/ui/connection-panel.ui')
class ConnectionPanel(Gtk.Box):
class ConnectionPanel(Adw.Bin):
__gtype_name__ = 'McgConnectionPanel'
__gsignals__ = {
'connection-changed': (GObject.SIGNAL_RUN_FIRST, None, (str, int, str))
}
# Widgets
toolbar = Gtk.Template.Child()
zeroconf_list = Gtk.Template.Child()
host_entry = Gtk.Template.Child()
host_row = Gtk.Template.Child()
port_spinner = Gtk.Template.Child()
password_entry = Gtk.Template.Child()
password_row = Gtk.Template.Child()
def __init__(self):
super().__init__()
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)
def __init__(self, **kwargs):
super().__init__(**kwargs)
# Zeroconf provider
self._zeroconf_provider = ZeroconfProvider()
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):
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()
def on_service_selected(self, selection):
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):
def on_host_entry_apply(self, widget):
self._call_back()
@ -70,17 +74,12 @@ class ConnectionPanel(Gtk.Box):
self._call_back()
@Gtk.Template.Callback()
def on_password_entry_outfocused(self, widget, event):
self._call_back()
def set_host(self, host):
self.host_entry.set_text(host)
self.host_row.set_text(host)
def get_host(self):
return self.host_entry.get_text()
return self.host_row.get_text()
def set_port(self, port):
@ -94,11 +93,11 @@ class ConnectionPanel(Gtk.Box):
def set_password(self, password):
if password is None:
password = ""
self.password_entry.set_text(password)
self.password_row.set_text(password)
def get_password(self):
if self.password_entry.get_text() == "":
if self.password_row.get_text() == "":
return None
else:
return self.password_entry.get_text()

View file

@ -2,7 +2,7 @@
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('Gtk', '4.0')
import logging
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')
class CoverPanel(Gtk.Overlay):
__gtype_name__ = 'McgCoverPanel'
@ -44,9 +23,13 @@ class CoverPanel(Gtk.Overlay):
}
# Widgets
# Toolbar
toolbar = Gtk.Template.Child()
fullscreen_button = Gtk.Template.Child()
# Cover
cover_stack = Gtk.Template.Child()
cover_spinner = Gtk.Template.Child()
cover_default = Gtk.Template.Child()
cover_scroll = Gtk.Template.Child()
cover_box = Gtk.Template.Child()
cover_image = Gtk.Template.Child()
@ -61,22 +44,20 @@ class CoverPanel(Gtk.Overlay):
def __init__(self):
super().__init__()
def __init__(self, **kwargs):
super().__init__(**kwargs)
self._current_album = None
self._current_cover_album = None
self._cover_pixbuf = None
self._timer = None
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._is_selected = False
self._current_size = None
self._cover_pixbuf = self._get_default_image()
#self._cover_pixbuf = self._get_default_image()
# Widgets
self._toolbar = CoverToolbar()
self.cover_stack.set_visible_child(self.cover_scroll)
# Initial actions
@ -84,33 +65,34 @@ class CoverPanel(Gtk.Overlay):
def get_toolbar(self):
return self._toolbar
return self.toolbar
def set_selected(self, selected):
self._is_selected = selected
pass
@Gtk.Template.Callback()
def on_cover_box_pressed(self, widget, event):
if self._current_album and event.type == Gdk.EventType._2BUTTON_PRESS:
self.emit('toggle-fullscreen')
# FIXME on_cover_box_pressed()
#@Gtk.Template.Callback()
#def on_cover_box_pressed(self, widget, event):
# if self._current_album and event.type == Gdk.EventType._2BUTTON_PRESS:
# self.emit('toggle-fullscreen')
@Gtk.Template.Callback()
def on_cover_size_allocate(self, widget, allocation):
def set_width(self, width):
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()
def on_songs_start_change(self, widget, event):
if self._timer:
GObject.source_remove(self._timer)
self._timer = None
# FIXME on_songs_start_change()
#@Gtk.Template.Callback()
#def on_songs_start_change(self, widget, event):
# if self._timer:
# GObject.source_remove(self._timer)
# self._timer = None
@Gtk.Template.Callback()
#@Gtk.Template.Callback()
def on_songs_change(self, widget, event):
value = int(self.songs_scale.get_value())
time = self._current_album.get_length()
@ -144,7 +126,7 @@ class CoverPanel(Gtk.Overlay):
# Set current album
self._current_album = album
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):
@ -186,10 +168,11 @@ class CoverPanel(Gtk.Overlay):
self._cover_pixbuf = Utils.load_pixbuf(data)
except Exception as e:
self._logger.exception("Failed to set albumart")
self._cover_pixbuf = self._get_default_image()
self._cover_pixbuf = None
else:
# Reset image
self._cover_pixbuf = self._get_default_image()
self._cover_pixbuf = None
self._current_size = None
self._current_cover_album = album
# Show image
@ -236,8 +219,11 @@ class CoverPanel(Gtk.Overlay):
def _show_image(self):
self._resize_image()
self.cover_stack.set_visible_child(self.cover_scroll)
if self._cover_pixbuf:
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()
@ -245,12 +231,15 @@ class CoverPanel(Gtk.Overlay):
"""Diese Methode skaliert das geladene Bild aus dem Pixelpuffer
auf die Größe des Fensters unter Beibehalt der Seitenverhältnisse
"""
# Get size
size = self.cover_scroll.get_allocation()
# FIXME Get size
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
if self._current_size and size.width == self._current_size.width and size.height == self._current_size.height:
return
self._current_size = size
if self._current_size:
current_width, current_height = self._current_size
if size_width == current_width and size_height == current_height:
return
self._current_size = (size_width, size_height,)
# Get pixelbuffer
pixbuf = self._cover_pixbuf
@ -259,8 +248,8 @@ class CoverPanel(Gtk.Overlay):
return
# Skalierungswert für Breite und Höhe ermitteln
ratioW = float(size.width) / float(pixbuf.get_width())
ratioH = float(size.height) / float(pixbuf.get_height())
ratioW = float(size_width) / float(pixbuf.get_width())
ratioH = float(size_height) / float(pixbuf.get_height())
# Kleineren beider Skalierungswerte nehmen, nicht Hochskalieren
ratio = min(ratioW, ratioH)
ratio = min(ratio, 1)
@ -269,15 +258,7 @@ class CoverPanel(Gtk.Overlay):
height = int(math.floor(pixbuf.get_height()*ratio))
if width <= 0 or height <= 0:
return
# Pixelpuffer auf Oberfläche zeichnen
self.cover_image.set_allocation(self.cover_scroll.get_allocation())
# FIXME Pixelpuffer auf Oberfläche zeichnen
#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.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
gi.require_version('Gtk', '3.0')
gi.require_version('Gtk', '4.0')
gi.require_version('Adw', '1')
import locale
import logging
import math
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.albumheaderbar import AlbumHeaderbar
from mcg.utils import SortOrder
from mcg.utils import Utils
@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)
from mcg.utils import GridItem
@Gtk.Template(resource_path='/xyz/suruatoel/mcg/ui/library-panel.ui')
class LibraryPanel(Gtk.Stack):
class LibraryPanel(Adw.Bin):
__gtype_name__ = 'McgLibraryPanel'
__gsignals__ = {
'open-standalone': (GObject.SIGNAL_RUN_FIRST, None, ()),
@ -127,13 +33,31 @@ class LibraryPanel(Gtk.Stack):
'item-size-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,)),
'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
panel_standalone = 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_bar = Gtk.Template.Child()
filter_entry = Gtk.Template.Child()
@ -152,8 +76,8 @@ class LibraryPanel(Gtk.Stack):
standalone_image = Gtk.Template.Child()
def __init__(self, client):
super().__init__()
def __init__(self, client, **kwargs):
super().__init__(**kwargs)
self._logger = logging.getLogger(__name__)
self._client = client
self._buttons = {}
@ -167,37 +91,37 @@ class LibraryPanel(Gtk.Stack):
self._old_ranges = {}
self._library_lock = threading.Lock()
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._selected_albums = []
self._allocation = (0, 0)
self._is_selected = False
# Widgets
self._toolbar = LibraryToolbar(self._item_size)
self._toolbar.connect('select', self.on_toolbar_select)
self._toolbar.connect('toggle-search', self.on_toolbar_toggle_search)
self._toolbar.connect('update', self.on_toolbar_update)
self._toolbar.connect('start-scale', self.on_toolbar_scale)
self._toolbar.connect('end-scale', self.on_toolbar_scaled)
self._toolbar.connect('sort', self.on_toolbar_sort)
self._toolbar.connect('sort-type', self.on_toolbar_sort_type)
# FIXME Toolbar signals
#self._toolbar.connect('select', self.on_toolbar_select)
#self._toolbar.connect('toggle-search', self.on_toolbar_toggle_search)
#self._toolbar.connect('update', self.on_toolbar_update)
#self._toolbar.connect('start-scale', self.on_toolbar_scale)
#self._toolbar.connect('end-scale', self.on_toolbar_scaled)
#self._toolbar.connect('sort', self.on_toolbar_sort)
#self._toolbar.connect('sort-type', self.on_toolbar_sort_type)
# Header bar
self._headerbar_standalone = AlbumHeaderbar()
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
self._library_grid_model = Gtk.ListStore(GdkPixbuf.Pixbuf, str, str)
self._library_grid_model.set_sort_func(2, self.compare_albums, self._sort_order)
self._library_grid_model.set_sort_column_id(2, self._sort_type)
self._library_grid_filter = self._library_grid_model.filter_new()
self._library_grid_filter.set_visible_func(self.on_filter_visible)
self._library_grid_model = Gio.ListStore()
self._library_grid_selection = Gtk.MultiSelection.new(self._library_grid_model)
self._library_grid_filter = self._library_grid_selection
# Library Grid
self.library_grid.set_model(self._library_grid_filter)
self.library_grid.set_pixbuf_column(0)
self.library_grid.set_text_column(-1)
self.library_grid.set_tooltip_column(1)
# Toolbar menu
self.grid_scale.set_value(self._item_size)
self._toolbar_sort_buttons = {
SortOrder.ARTIST: self.sort_artist,
SortOrder.TITLE: self.sort_title,
SortOrder.YEAR: self.sort_year
}
def get_headerbar_standalone(self):
@ -205,30 +129,75 @@ class LibraryPanel(Gtk.Stack):
def get_toolbar(self):
return self._toolbar
return self.toolbar
def set_selected(self, 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):
new_allocation = (widget.get_allocation().width, widget.get_allocation().height)
if new_allocation == self._allocation:
return
self._allocation = new_allocation
self._toolbar.get_grid_scale().clear_marks()
self.grid_scale.clear_marks()
width = widget.get_allocation().width
lower = int(self._toolbar.get_grid_scale().get_adjustment().get_lower())
upper = int(self._toolbar.get_grid_scale().get_adjustment().get_upper())
lower = int(self.grid_scale.get_adjustment().get_lower())
upper = int(self.grid_scale.get_adjustment().get_upper())
countMin = max(int(width / upper), 1)
countMax = max(int(width / lower), 1)
for index in range(countMin, countMax):
pixel = int(width / index)
pixel = pixel - (2 * int(pixel / 100))
self._toolbar.get_grid_scale().add_mark(
self.grid_scale.add_mark(
pixel,
Gtk.PositionType.BOTTOM,
None
@ -256,17 +225,17 @@ class LibraryPanel(Gtk.Stack):
def on_toolbar_scale(self, widget, 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():
return
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)
def on_toolbar_scaled(self, widget, 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():
return False
self.emit('item-size-changed', size)
@ -280,23 +249,24 @@ class LibraryPanel(Gtk.Stack):
def on_toolbar_sort_type(self, widget, 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)
@Gtk.Template.Callback()
#@Gtk.Template.Callback()
def on_filter_bar_notify(self, widget, value):
if self._toolbar.is_search_active() is not self.filter_bar.get_search_mode():
self._toolbar.set_search_active(self.filter_bar.get_search_mode())
if self.toolbar_search_bar.get_active() is not 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):
self._filter_string = self.filter_entry.get_text()
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):
# Get selected album
path = self._library_grid_filter.convert_path_to_child_path(path)
@ -319,7 +289,8 @@ class LibraryPanel(Gtk.Stack):
self.standalone_spinner.start()
@Gtk.Template.Callback()
# FIXME on_library_grid_selection_changed()
#@Gtk.Template.Callback()
def on_library_grid_selection_changed(self, widget):
self._selected_albums = []
for path in widget.get_selected_items():
@ -337,30 +308,31 @@ class LibraryPanel(Gtk.Stack):
return album.filter(self._filter_string)
@Gtk.Template.Callback()
#@Gtk.Template.Callback()
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):
ids = [album.get_id() for album in self._selected_albums]
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):
self._resize_standalone_image()
@Gtk.Template.Callback()
#@Gtk.Template.Callback()
def on_standalone_play_clicked(self, widget):
self.emit('play', self._selected_albums[0].get_id())
self._close_standalone()
@Gtk.Template.Callback()
#@Gtk.Template.Callback()
def on_standalone_queue_clicked(self, widget):
self.emit('queue', self._selected_albums[0].get_id())
self._close_standalone()
@ -377,7 +349,7 @@ class LibraryPanel(Gtk.Stack):
def set_item_size(self, item_size):
if 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()
@ -464,6 +436,7 @@ class LibraryPanel(Gtk.Stack):
def _set_albums(self, host, albums, size):
"""
if not self._is_selected and albums != self._albums:
GObject.idle_add(
self.get_parent().child_set_property,
@ -471,15 +444,16 @@ class LibraryPanel(Gtk.Stack):
'needs-attention',
True
)
"""
self._library_lock.acquire()
self._library_stop.clear()
self._albums = albums
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.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.freeze_child_notify()
self._library_grid_model.clear()
#self.library_grid.freeze_child_notify()
self._library_grid_model.remove_all()
i = 0
n = len(albums)
@ -496,23 +470,17 @@ class LibraryPanel(Gtk.Stack):
except Exception as e:
self._logger.exception("Failed to load albumart")
if pixbuf is None:
pixbuf = self._icon_theme.load_icon(
pixbuf = self._icon_theme.lookup_icon(
Utils.STOCK_ICON_DEFAULT,
None,
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:
self._grid_pixbufs[album.get_id()] = pixbuf
self._library_grid_model.append([
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
])
self._library_grid_model.append(GridItem(album, pixbuf))
i += 1
GObject.idle_add(self.progress_bar.set_fraction, i/n)
@ -522,8 +490,8 @@ class LibraryPanel(Gtk.Stack):
return
self.library_grid.set_model(self._library_grid_filter)
self.library_grid.thaw_child_notify()
self.library_grid.set_item_width(-1)
#self.library_grid.thaw_child_notify()
#self.library_grid.set_item_width(-1)
self._library_lock.release()
self.stack.set_visible_child(self.scroll)
@ -632,12 +600,11 @@ class LibraryPanel(Gtk.Stack):
def _get_default_image(self):
return self._icon_theme.load_icon(
return self._icon_theme.lookup_icon(
Utils.STOCK_ICON_DEFAULT,
None,
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 gi
gi.require_version('Gtk', '3.0')
from .application import Application

View file

@ -2,56 +2,24 @@
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('Gtk', '4.0')
gi.require_version('Adw', '1')
import logging
import math
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.albumheaderbar import AlbumHeaderbar
from mcg.utils import Utils
@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)
from mcg.utils import GridItem
@Gtk.Template(resource_path='/xyz/suruatoel/mcg/ui/playlist-panel.ui')
class PlaylistPanel(Gtk.Stack):
class PlaylistPanel(Adw.Bin):
__gtype_name__ = 'McgPlaylistPanel'
__gsignals__ = {
'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-multiple-albums': (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
panel_standalone = 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 = Gtk.Template.Child()
# Action bar (normal)
@ -79,8 +54,8 @@ class PlaylistPanel(Gtk.Stack):
standalone_image = Gtk.Template.Child()
def __init__(self, client):
GObject.GObject.__init__(self)
def __init__(self, client, **kwargs):
super().__init__(**kwargs)
self._client = client
self._host = None
self._item_size = 150
@ -88,25 +63,23 @@ class PlaylistPanel(Gtk.Stack):
self._playlist_albums = None
self._playlist_lock = threading.Lock()
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._selected_albums = []
self._is_selected = False
# Widgets
self._toolbar = PlaylistToolbar()
self._toolbar.connect('select', self.on_toolbar_select)
self._toolbar.connect('clear-playlist', self.on_toolbar_clear)
# FIXME Toolbar signals
#self._toolbar.connect('select', self.on_toolbar_select)
#self._toolbar.connect('clear-playlist', self.on_toolbar_clear)
# Header bar
self._headerbar_standalone = AlbumHeaderbar()
self._headerbar_standalone.connect('close', self.on_headerbar_close_clicked)
# 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
self.playlist_grid.set_model(self._playlist_grid_model)
self.playlist_grid.set_pixbuf_column(0)
self.playlist_grid.set_text_column(-1)
self.playlist_grid.set_tooltip_column(1)
self.playlist_grid.set_model(self._playlist_grid_selection)
def get_headerbar_standalone(self):
@ -114,7 +87,7 @@ class PlaylistPanel(Gtk.Stack):
def get_toolbar(self):
return self._toolbar
return self.toolbar
def set_selected(self, selected):
@ -136,16 +109,30 @@ class PlaylistPanel(Gtk.Stack):
self.emit('clear-playlist')
@Gtk.Template.Callback()
def on_playlist_grid_clicked(self, widget, path):
# Get selected album
iter = self._playlist_grid_model.get_iter(path)
hash = self._playlist_grid_model.get_value(iter, 2)
album = self._playlist_albums[hash]
self._selected_albums = [album]
self.emit('albumart', hash)
# FIXME on_select_toggled()
#@Gtk.Template.Callback()
def on_select_toggled(self, widget):
self.emit('select', widget.get_active())
# 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:
# Set labels
self._headerbar_standalone.set_album(album)
@ -158,7 +145,8 @@ class PlaylistPanel(Gtk.Stack):
self.standalone_spinner.start()
@Gtk.Template.Callback()
# FIXME on_playlist_grid_selection_changed()
#@Gtk.Template.Callback()
def on_playlist_grid_selection_changed(self, widget):
self._selected_albums = []
for path in widget.get_selected_items():
@ -167,18 +155,19 @@ class PlaylistPanel(Gtk.Stack):
self._selected_albums.append(self._playlist_albums[hash])
@Gtk.Template.Callback()
#@Gtk.Template.Callback()
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):
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):
self._resize_standalone_image()
@ -187,13 +176,13 @@ class PlaylistPanel(Gtk.Stack):
self._close_standalone()
@Gtk.Template.Callback()
#@Gtk.Template.Callback()
def on_standalone_remove_clicked(self, widget):
self.emit('remove-album', self._selected_albums[0])
self._close_standalone()
@Gtk.Template.Callback()
#@Gtk.Template.Callback()
def on_standalone_play_clicked(self, widget):
self.emit('play', self._selected_albums[0])
self._close_standalone()
@ -235,6 +224,7 @@ class PlaylistPanel(Gtk.Stack):
def _set_playlist(self, host, playlist, size):
"""
if not self._is_selected and self._playlist != playlist:
GObject.idle_add(
self.get_parent().child_set_property,
@ -242,16 +232,16 @@ class PlaylistPanel(Gtk.Stack):
'needs-attention',
True
)
"""
self._playlist_lock.acquire()
self._playlist_stop.clear()
self._playlist = playlist
self._playlist_albums = {}
for album in playlist:
self._playlist_albums[album.get_id()] = album
self.playlist_grid.set_model(None)
self.playlist_grid.freeze_child_notify()
self._playlist_grid_model.clear()
GObject.idle_add(self.playlist_grid.set_item_padding, size / 100)
self._playlist_grid_model.remove_all()
# FIXME Set item padding dynamically?
#GObject.idle_add(self.playlist_grid.set_item_padding, size / 100)
cache = client.MCGCache(host, size)
for album in playlist:
@ -265,31 +255,22 @@ class PlaylistPanel(Gtk.Stack):
except Exception:
self._logger.exception("Failed to load albumart")
if pixbuf is None:
pixbuf = self._icon_theme.load_icon(
pixbuf = self._icon_theme.lookup_icon(
Utils.STOCK_ICON_DEFAULT,
None,
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:
self._playlist_grid_model.append([
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()
])
self._playlist_grid_model.append(GridItem(album, pixbuf))
if self._playlist_stop.is_set():
self._playlist_lock.release()
return
self.playlist_grid.set_model(self._playlist_grid_model)
self.playlist_grid.thaw_child_notify()
# TODO why set_columns()?
#self.playlist_grid.set_columns(len(playlist))
self.playlist_grid.set_model(self._playlist_grid_selection)
self._playlist_lock.release()
@ -342,12 +323,11 @@ class PlaylistPanel(Gtk.Stack):
def _get_default_image(self):
return self._icon_theme.load_icon(
return self._icon_theme.lookup_icon(
Utils.STOCK_ICON_DEFAULT,
None,
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
gi.require_version('Gtk', '3.0')
gi.require_version('Gtk', '4.0')
gi.require_version('Adw', '1')
from gi.repository import Gtk, GObject
@Gtk.Template(resource_path='/xyz/suruatoel/mcg/ui/server-toolbar.ui')
class ServerToolbar(Gtk.ButtonBox):
__gtype_name__ = 'McgServerToolbar'
def __init__(self):
super().__init__()
from gi.repository import Gtk, Adw, GObject
@Gtk.Template(resource_path='/xyz/suruatoel/mcg/ui/server-panel.ui')
class ServerPanel(Gtk.Box):
class ServerPanel(Adw.Bin):
__gtype_name__ = 'McgServerPanel'
__gsignals__ = {
'change-output-device': (GObject.SIGNAL_RUN_FIRST, None, (GObject.TYPE_PYOBJECT,bool,)),
}
# Widgets
toolbar = Gtk.Template.Child()
# Status widgets
status_file = Gtk.Template.Child()
status_audio = Gtk.Template.Child()
@ -44,14 +35,13 @@ class ServerPanel(Gtk.Box):
output_devices = Gtk.Template.Child()
def __init__(self):
super().__init__()
def __init__(self, **kwargs):
super().__init__(**kwargs)
self._none_label = ""
self._output_buttons = {}
self._is_selected = False
# Widgets
self._toolbar = ServerToolbar()
self._none_label = self.status_file.get_label()
@ -60,7 +50,7 @@ class ServerPanel(Gtk.Box):
def get_toolbar(self):
return self._toolbar
return self.toolbar
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()].thaw_notify()
else:
button = Gtk.CheckButton(device.get_name())
button = Gtk.CheckButton.new_with_label(device.get_name())
if device.is_enabled():
button.set_active(True)
handler = button.connect('toggled', self.on_output_device_toggled, device)
self.output_devices.insert(button, -1)
self._output_buttons[device.get_id()] = button
self.output_devices.show_all()
# Remove devices
for id in self._output_buttons.keys():

View file

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