Compare commits

..
18 changed files with 1136 additions and 605 deletions

View file

@ -30,10 +30,6 @@
font-weight:bold; font-weight:bold;
} }
window.fullscreen #cover_box {
background: black;
}
#cover_info_revealer { #cover_info_revealer {
background-color:alpha(@theme_bg_color, 0.8); background-color:alpha(@theme_bg_color, 0.8);
box-shadow:0 0 10px @theme_bg_color; box-shadow:0 0 10px @theme_bg_color;
@ -49,12 +45,5 @@ actionbar {
} }
gridview child { gridview child {
padding: 1px; padding: 10px;
}
gridview.selection child {
opacity: 0.5;
}
gridview.selection child:hover,
gridview.selection child:selected {
opacity: 1;
} }

View file

@ -41,7 +41,6 @@
<property name="valign">fill</property> <property name="valign">fill</property>
<child> <child>
<object class="GtkViewport" id="cover_box"> <object class="GtkViewport" id="cover_box">
<property name="name">cover_box</property>
<property name="hexpand">true</property> <property name="hexpand">true</property>
<property name="halign">fill</property> <property name="halign">fill</property>
<property name="vexpand">true</property> <property name="vexpand">true</property>
@ -54,13 +53,27 @@
<property name="valign">fill</property> <property name="valign">fill</property>
<property name="icon-name">image-x-generic-symbolic</property> <property name="icon-name">image-x-generic-symbolic</property>
<property name="icon-size">large</property> <property name="icon-size">large</property>
<!--
<signal name="button-press-event" handler="on_cover_box_pressed" swapped="no"/>
-->
</object> </object>
</child> </child>
</object> </object>
</child> </child>
</object> </object>
<!--
<packing>
<property name="name">cover-scroll</property>
<property name="position">1</property>
</packing>
-->
</child> </child>
</object> </object>
<!--
<packing>
<property name="index">-1</property>
</packing>
-->
</child> </child>
<child type="overlay"> <child type="overlay">
<object class="GtkRevealer" id="info_revealer"> <object class="GtkRevealer" id="info_revealer">
@ -68,6 +81,9 @@
<property name="transition-type">slide-right</property> <property name="transition-type">slide-right</property>
<property name="name">cover_info_revealer</property> <property name="name">cover_info_revealer</property>
<style> <style>
<!--
<class name="sidebar"/>
-->
<class name="background"/> <class name="background"/>
</style> </style>
<child> <child>
@ -79,6 +95,9 @@
<property name="name">cover_info_scroll</property> <property name="name">cover_info_scroll</property>
<child> <child>
<object class="GtkViewport"> <object class="GtkViewport">
<!--
<property name="shadow-type">none</property>
-->
<child> <child>
<object class="GtkBox"> <object class="GtkBox">
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
@ -135,6 +154,14 @@
</object> </object>
</child> </child>
</object> </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>
<child> <child>
<object class="GtkScale" id="songs_scale"> <object class="GtkScale" id="songs_scale">
@ -144,7 +171,19 @@
<property name="restrict-to-fill-level">False</property> <property name="restrict-to-fill-level">False</property>
<property name="digits">0</property> <property name="digits">0</property>
<property name="draw-value">False</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> </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> </child>
</object> </object>
</child> </child>

46
data/ui/info-dialog.ui Normal file
View file

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.2 -->
<interface>
<requires lib="gtk+" version="3.10"/>
<template class="McgInfoDialog" parent="GtkAboutDialog">
<property name="can-focus">False</property>
<property name="resizable">False</property>
<property name="modal">True</property>
<property name="window-position">center</property>
<property name="type-hint">dialog</property>
<property name="gravity">center</property>
<property name="program-name">CoverGrid</property>
<property name="version">3.1</property>
<property name="comments" translatable="yes">CoverGrid is a client for the Music Player Daemon, focusing on albums instead of single tracks.</property>
<property name="website">http://www.suruatoel.xyz/codes/mcg</property>
<property name="logo-icon-name">xyz.suruatoel.mcg</property>
<property name="license-type">gpl-3-0</property>
<child internal-child="vbox">
<object class="GtkBox">
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child internal-child="action_area">
<object class="GtkButtonBox">
<property name="can-focus">False</property>
<property name="layout-style">end</property>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
</child>
</template>
</interface>

View file

@ -26,67 +26,166 @@
<property name="round-digits">0</property> <property name="round-digits">0</property>
<property name="digits">0</property> <property name="digits">0</property>
<property name="has-origin">False</property> <property name="has-origin">False</property>
<signal name="value-changed" handler="on_grid_scale_changed" swapped="no"/> <!--
<signal name="button-release-event" handler="on_grid_scale_changed" swapped="no"/>
-->
<signal name="change-value" handler="on_grid_scale_change" swapped="no"/>
</object> </object>
<!--
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
-->
</child> </child>
<child> <child>
<object class="GtkButton" id="library-toolbar-update"> <object class="GtkButton" id="library-toolbar-update">
<property name="label" translatable="yes">update library</property> <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"/> <signal name="clicked" handler="on_update_clicked" swapped="no"/>
</object> </object>
<!--
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
-->
</child> </child>
<child> <child>
<object class="GtkBox" id="library-toolbar-sort"> <object class="GtkBox" id="library-toolbar-sort">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="GtkSeparator"> <object class="GtkSeparator">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
</object> </object>
<!--
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
-->
</child> </child>
<child> <child>
<object class="GtkLabel"> <object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Sort</property> <property name="label" translatable="yes">Sort</property>
</object> </object>
<!--
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
-->
</child> </child>
<child> <child>
<object class="GtkCheckButton" id="sort_artist"> <object class="GtkCheckButton" id="sort_artist">
<property name="label" translatable="yes">sort by artist</property> <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="receives-default">False</property>
<!--
<property name="draw-indicator">True</property>
-->
<property name="group">sort_year</property> <property name="group">sort_year</property>
<signal name="toggled" handler="on_sort_toggled" swapped="no"/> <signal name="toggled" handler="on_sort_toggled" swapped="no"/>
</object> </object>
<!--
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
-->
</child> </child>
<child> <child>
<object class="GtkCheckButton" id="sort_title"> <object class="GtkCheckButton" id="sort_title">
<property name="label" translatable="yes">sort by title</property> <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="receives-default">False</property>
<!--
<property name="draw-indicator">True</property>
-->
<property name="group">sort_year</property> <property name="group">sort_year</property>
<signal name="toggled" handler="on_sort_toggled" swapped="no"/> <signal name="toggled" handler="on_sort_toggled" swapped="no"/>
</object> </object>
<!--
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
-->
</child> </child>
<child> <child>
<object class="GtkCheckButton" id="sort_year"> <object class="GtkCheckButton" id="sort_year">
<property name="label" translatable="yes">sort by year</property> <property name="label" translatable="yes">sort by year</property>
<property name="receives-default">False</property>
<property name="active">True</property>
<signal name="toggled" handler="on_sort_toggled" swapped="no"/>
</object>
</child>
<child>
<object class="GtkCheckButton" id="toolbar_sort_order_button">
<property name="label">sort library descending</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="can-focus">True</property> <property name="can-focus">True</property>
<property name="receives-default">False</property> <property name="receives-default">False</property>
<property name="active">True</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"/> <signal name="toggled" handler="on_sort_order_toggled" swapped="no"/>
</object> </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> </child>
</object> </object>
</child> </child>
</object> </object>
</child>
</object>
<object class="GtkBox" id="toolbar"> <object class="GtkBox" id="toolbar">
<property name="orientation">horizontal</property> <property name="orientation">horizontal</property>
@ -94,10 +193,15 @@
<property name="spacing">6</property> <property name="spacing">6</property>
<child> <child>
<object class="GtkToggleButton" id="toolbar_search_bar"> <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="receives-default">True</property>
<property name="tooltip-text" translatable="yes">Search the library</property> <property name="tooltip-text" translatable="yes">Search the library</property>
<signal name="toggled" handler="on_search_toggled" swapped="no"/>
<child> <child>
<object class="GtkImage"> <object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">system-search-symbolic</property> <property name="icon-name">system-search-symbolic</property>
</object> </object>
</child> </child>
@ -105,6 +209,14 @@
<accelerator key="f" signal="activate" modifiers="GDK_CONTROL_MASK"/> <accelerator key="f" signal="activate" modifiers="GDK_CONTROL_MASK"/>
--> -->
</object> </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>
<child> <child>
<object class="GtkToggleButton" id="select_button"> <object class="GtkToggleButton" id="select_button">
@ -115,10 +227,20 @@
<signal name="toggled" handler="on_select_toggled" swapped="no"/> <signal name="toggled" handler="on_select_toggled" swapped="no"/>
<child> <child>
<object class="GtkImage"> <object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">object-select-symbolic</property> <property name="icon-name">object-select-symbolic</property>
</object> </object>
</child> </child>
</object> </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>
<child> <child>
<object class="GtkMenuButton"> <object class="GtkMenuButton">
@ -135,38 +257,77 @@
</object> </object>
</child> </child>
</object> </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> </child>
</object>
</object>
<template class="McgLibraryPanel" parent="AdwBin"> <template class="McgLibraryPanel" parent="AdwBin">
<child> <child>
<object class="GtkStack" id="library_stack"> <object class="GtkStack">
<property name="transition-type">slide-left-right</property> <property name="transition-type">slide-left-right</property>
<child> <child>
<object class="GtkBox" id="panel_normal"> <object class="GtkBox" id="panel_normal">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="GtkSearchBar" id="filter_bar"> <object class="GtkSearchBar" id="filter_bar">
<property name="search-mode-enabled" bind-source="toolbar_search_bar" bind-property="active" bind-flags="sync-create"/> <!--
<property name="app-paintable">True</property>
-->
<signal name="notify" handler="on_filter_bar_notify" swapped="no"/>
<child> <child>
<object class="GtkSearchEntry" id="filter_entry"> <object class="GtkSearchEntry" id="filter_entry">
<property name="visible">True</property>
<property name="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> <property name="placeholder-text" translatable="yes">search library</property>
<signal name="search-changed" handler="on_filter_entry_changed" swapped="no"/> <signal name="search-changed" handler="on_filter_entry_changed" swapped="no"/>
</object> </object>
</child> </child>
</object> </object>
<!--
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
-->
</child>
<child>
<placeholder/>
</child> </child>
<child> <child>
<object class="GtkStack" id="stack"> <object class="GtkStack" id="stack">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="transition-type">crossfade</property> <property name="transition-type">crossfade</property>
<child> <child>
<object class="GtkBox" id="progress_box"> <object class="GtkBox" id="progress_box">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child type="center"> <child type="center">
<object class="GtkBox"> <object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child type="center"> <child type="center">
<object class="GtkBox"> <object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">center</property> <property name="halign">center</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<property name="spacing">10</property> <property name="spacing">10</property>
@ -175,6 +336,13 @@
<property name="icon-size">large</property> <property name="icon-size">large</property>
<property name="icon-name">image-x-generic-symbolic</property> <property name="icon-name">image-x-generic-symbolic</property>
</object> </object>
<!--
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
-->
</child> </child>
<child> <child>
<object class="GtkProgressBar" id="progress_bar"> <object class="GtkProgressBar" id="progress_bar">
@ -184,12 +352,45 @@
<property name="pulse-step">0</property> <property name="pulse-step">0</property>
<property name="show-text">True</property> <property name="show-text">True</property>
</object> </object>
<!--
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
-->
</child> </child>
</object> </object>
<!--
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
-->
</child>
<child>
<placeholder/>
</child> </child>
</object> </object>
<!--
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
-->
</child>
<child>
<placeholder/>
</child> </child>
</object> </object>
<!--
<packing>
<property name="name">page1</property>
<property name="title">page1</property>
</packing>
-->
</child> </child>
<child> <child>
<object class="GtkScrolledWindow" id="scroll"> <object class="GtkScrolledWindow" id="scroll">
@ -197,8 +398,11 @@
<child> <child>
<object class="GtkGridView" id="library_grid"> <object class="GtkGridView" id="library_grid">
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<property name="single_click_activate">true</property> <!--
<signal name="activate" handler="on_library_grid_clicked"/> <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> <style>
<class name="no-bg"/> <class name="no-bg"/>
</style> </style>
@ -209,10 +413,21 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<interface> <interface>
<template class="GtkListItem"> <template class="GtkListItem">
<property name="activatable">true</property>
<property name="child"> <property name="child">
<object class="GtkBox"> <object class="GtkBox">
<property name="orientation">vertical</property> <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> <child>
<object class="GtkPicture"> <object class="GtkPicture">
<property name="content-fit">contain</property> <property name="content-fit">contain</property>
@ -243,46 +458,98 @@
<class name="no-bg"/> <class name="no-bg"/>
</style> </style>
</object> </object>
<!--
<packing>
<property name="name">page0</property>
<property name="title">page0</property>
<property name="position">1</property>
</packing>
-->
</child> </child>
</object> </object>
<!--
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
-->
</child> </child>
<child> <child>
<object class="GtkRevealer" id="actionbar_revealer"> <object class="GtkRevealer" id="actionbar_revealer">
<property name="transition-type">slide-up</property> <property name="transition-type">none</property>
<property name="reveal-child">false</property>
<child>
<object class="GtkActionBar" id="library-actionbar">
<child> <child>
<object class="GtkActionBar" id="actionbar">
<child type="end">
<object class="GtkButton"> <object class="GtkButton">
<property name="label" translatable="yes">cancel</property> <property name="label" translatable="yes">cancel</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property> <property name="receives-default">True</property>
<signal name="clicked" handler="on_selection_cancel_clicked" swapped="no"/> <signal name="clicked" handler="on_selection_cancel_clicked" swapped="no"/>
</object> </object>
<!--
<packing>
<property name="pack-type">end</property>
<property name="position">1</property>
</packing>
-->
</child> </child>
<child type="end"> <child>
<object class="GtkButton"> <object class="GtkButton">
<property name="label" translatable="yes">queue</property> <property name="label" translatable="yes">queue</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property> <property name="receives-default">True</property>
<signal name="clicked" handler="on_selection_add_clicked" swapped="no"/> <signal name="clicked" handler="on_selection_add_clicked" swapped="no"/>
</object> </object>
<!--
<packing>
<property name="pack-type">end</property>
<property name="position">0</property>
</packing>
-->
</child> </child>
</object> </object>
</child> </child>
</object> </object>
<!--
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
-->
</child> </child>
</object> </object>
<!--
<packing>
<property name="name">page0</property>
<property name="title">page0</property>
</packing>
-->
</child> </child>
<child> <child>
<object class="GtkBox" id="panel_standalone"> <object class="GtkBox" id="panel_standalone">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="GtkStack" id="standalone_stack"> <object class="GtkStack" id="standalone_stack">
<property name="vexpand">true</property> <property name="visible">True</property>
<property name="can-focus">False</property>
<property name="transition-type">crossfade</property> <property name="transition-type">crossfade</property>
<child> <child>
<object class="GtkSpinner" id="standalone_spinner"> <object class="GtkSpinner" id="standalone_spinner">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can-focus">False</property> <property name="can-focus">False</property>
</object> </object>
<!--
<packing>
<property name="name">standalone-spinne</property>
</packing>
-->
</child> </child>
<child> <child>
<object class="GtkScrolledWindow" id="standalone_scroll"> <object class="GtkScrolledWindow" id="standalone_scroll">
@ -290,41 +557,93 @@
<property name="can-focus">True</property> <property name="can-focus">True</property>
<property name="kinetic-scrolling">False</property> <property name="kinetic-scrolling">False</property>
<property name="overlay-scrolling">False</property> <property name="overlay-scrolling">False</property>
<!--
<signal name="size-allocate" handler="on_standalone_scroll_size_allocate" swapped="no"/>
-->
<child> <child>
<object class="GtkViewport"> <object class="GtkViewport">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can-focus">False</property> <property name="can-focus">False</property>
<child> <child>
<object class="GtkImage" id="standalone_image"> <object class="GtkImage" id="standalone_image">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">gtk-missing-image</property> <property name="icon-name">gtk-missing-image</property>
<property name="icon-size">large</property> <!--
<property name="icon_size">6</property>
-->
</object> </object>
</child> </child>
</object> </object>
</child> </child>
</object> </object>
<!--
<packing>
<property name="name">standalone-scroll</property>
<property name="position">1</property>
</packing>
-->
</child> </child>
</object> </object>
<!--
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
-->
</child> </child>
<child> <child>
<object class="GtkActionBar" id="actionbar_standalone"> <object class="GtkActionBar" id="library-standalone-actionbar">
<child type="end"> <property name="visible">True</property>
<object class="GtkButton"> <property name="can-focus">False</property>
<property name="label" translatable="yes">play</property> <child>
<property name="receives-default">True</property>
<signal name="clicked" handler="on_standalone_play_clicked" swapped="no"/>
</object>
</child>
<child type="end">
<object class="GtkButton"> <object class="GtkButton">
<property name="label" translatable="yes">queue</property> <property name="label" translatable="yes">queue</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property> <property name="receives-default">True</property>
<signal name="clicked" handler="on_standalone_queue_clicked" swapped="no"/> <signal name="clicked" handler="on_standalone_queue_clicked" swapped="no"/>
</object> </object>
<!--
<packing>
<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> </child>
</object> </object>
<!--
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
-->
</child> </child>
</object> </object>
<!--
<packing>
<property name="name">page1</property>
<property name="title">page1</property>
<property name="position">1</property>
</packing>
-->
</child> </child>
</object> </object>
</child> </child>

View file

@ -12,7 +12,9 @@
<property name="can-focus">True</property> <property name="can-focus">True</property>
<property name="receives-default">True</property> <property name="receives-default">True</property>
<property name="tooltip-text" translatable="yes">Select multiple albums</property> <property name="tooltip-text" translatable="yes">Select multiple albums</property>
<!--
<signal name="toggled" handler="on_select_toggled" swapped="no"/> <signal name="toggled" handler="on_select_toggled" swapped="no"/>
-->
<child> <child>
<object class="GtkImage"> <object class="GtkImage">
<property name="icon-name">object-select-symbolic</property> <property name="icon-name">object-select-symbolic</property>
@ -26,7 +28,9 @@
<property name="can-focus">True</property> <property name="can-focus">True</property>
<property name="receives-default">True</property> <property name="receives-default">True</property>
<property name="tooltip-text" translatable="yes">Clear the playlist</property> <property name="tooltip-text" translatable="yes">Clear the playlist</property>
<!--
<signal name="clicked" handler="on_clear_clicked" swapped="no"/> <signal name="clicked" handler="on_clear_clicked" swapped="no"/>
-->
<child> <child>
<object class="GtkImage"> <object class="GtkImage">
<property name="visible">True</property> <property name="visible">True</property>
@ -39,7 +43,7 @@
</object> </object>
<template class="McgPlaylistPanel" parent="AdwBin"> <template class="McgPlaylistPanel" parent="AdwBin">
<child> <child>
<object class="GtkStack" id="playlist_stack"> <object class="GtkStack">
<property name="transition-type">slide-left-right</property> <property name="transition-type">slide-left-right</property>
<child> <child>
<object class="GtkBox" id="panel_normal"> <object class="GtkBox" id="panel_normal">
@ -50,8 +54,14 @@
<child> <child>
<object class="GtkGridView" id="playlist_grid"> <object class="GtkGridView" id="playlist_grid">
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<!--
<property name="item-padding">0</property>
-->
<property name="single-click-activate">true</property> <property name="single-click-activate">true</property>
<signal name="activate" handler="on_playlist_grid_clicked"/> <signal name="activate" handler="on_playlist_grid_clicked"/>
<!--
<signal name="selection-changed" handler="on_playlist_grid_selection_changed" swapped="no"/>
-->
<style> <style>
<class name="no-bg"/> <class name="no-bg"/>
</style> </style>
@ -102,18 +112,22 @@
<property name="transition-type">slide-up</property> <property name="transition-type">slide-up</property>
<child> <child>
<object class="GtkActionBar" id="actionbar"> <object class="GtkActionBar" id="actionbar">
<child type="end"> <child>
<object class="GtkButton"> <object class="GtkButton">
<property name="label" translatable="yes">cancel</property> <property name="label" translatable="yes">cancel</property>
<property name="receives-default">True</property> <property name="receives-default">True</property>
<!--
<signal name="clicked" handler="on_selection_cancel_clicked" swapped="no"/> <signal name="clicked" handler="on_selection_cancel_clicked" swapped="no"/>
-->
</object> </object>
</child> </child>
<child type="end"> <child>
<object class="GtkButton"> <object class="GtkButton">
<property name="label" translatable="yes">remove</property> <property name="label" translatable="yes">remove</property>
<property name="receives-default">True</property> <property name="receives-default">True</property>
<!--
<signal name="clicked" handler="on_selection_remove_clicked" swapped="no"/> <signal name="clicked" handler="on_selection_remove_clicked" swapped="no"/>
-->
</object> </object>
</child> </child>
</object> </object>
@ -127,7 +141,6 @@
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="GtkStack" id="standalone_stack"> <object class="GtkStack" id="standalone_stack">
<property name="vexpand">true</property>
<child> <child>
<object class="GtkSpinner" id="standalone_spinner"> <object class="GtkSpinner" id="standalone_spinner">
<property name="visible">True</property> <property name="visible">True</property>
@ -140,6 +153,9 @@
<property name="can-focus">True</property> <property name="can-focus">True</property>
<property name="kinetic-scrolling">False</property> <property name="kinetic-scrolling">False</property>
<property name="overlay-scrolling">False</property> <property name="overlay-scrolling">False</property>
<!--
<signal name="size-allocate" handler="on_standalone_scroll_size_allocate" swapped="no"/>
-->
<child> <child>
<object class="GtkViewport"> <object class="GtkViewport">
<property name="visible">True</property> <property name="visible">True</property>
@ -147,7 +163,9 @@
<child> <child>
<object class="GtkImage" id="standalone_image"> <object class="GtkImage" id="standalone_image">
<property name="icon-name">gtk-missing-image</property> <property name="icon-name">gtk-missing-image</property>
<property name="icon-size">large</property> <!--
<property name="icon_size">6</property>
-->
</object> </object>
</child> </child>
</object> </object>
@ -158,18 +176,22 @@
</child> </child>
<child> <child>
<object class="GtkActionBar" id="actionbar_standalone"> <object class="GtkActionBar" id="actionbar_standalone">
<child type="end"> <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>
<child type="end">
<object class="GtkButton"> <object class="GtkButton">
<property name="label" translatable="yes">remove</property> <property name="label" translatable="yes">remove</property>
<property name="receives-default">True</property> <property name="receives-default">True</property>
<!--
<signal name="clicked" handler="on_standalone_remove_clicked" swapped="no"/> <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> </object>
</child> </child>
</object> </object>

View file

@ -1,10 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.2 --> <!-- Generated with glade 3.38.2 -->
<interface> <interface>
<requires lib="gtk+" version="4.8"/> <requires lib="gtk+" version="3.18"/>
<requires lib="adw" version="1.2" />
<template class="McgShortcutsDialog" parent="GtkShortcutsWindow"> <template class="McgShortcutsDialog" parent="GtkShortcutsWindow">
<property name="modal">1</property> <property name="modal">True</property>
<child> <child>
<object class="GtkShortcutsSection"> <object class="GtkShortcutsSection">
<property name="visible">1</property> <property name="visible">1</property>
@ -12,45 +11,53 @@
<property name="max-height">10</property> <property name="max-height">10</property>
<child> <child>
<object class="GtkShortcutsGroup"> <object class="GtkShortcutsGroup">
<property name="visible">1</property>
<property name="title" translatable="yes">General</property> <property name="title" translatable="yes">General</property>
<child> <child>
<object class="GtkShortcutsShortcut"> <object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;primary&gt;KP_1</property> <property name="accelerator">&lt;primary&gt;KP_1</property>
<property name="title" translatable="yes">Switch to the Connection panel</property> <property name="title" translatable="yes">Switch to the Connection panel</property>
</object> </object>
</child> </child>
<child> <child>
<object class="GtkShortcutsShortcut"> <object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;primary&gt;KP_2</property> <property name="accelerator">&lt;primary&gt;KP_2</property>
<property name="title" translatable="yes">Switch to the Cover panel</property> <property name="title" translatable="yes">Switch to the Cover panel</property>
</object> </object>
</child> </child>
<child> <child>
<object class="GtkShortcutsShortcut"> <object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;primary&gt;KP_3</property> <property name="accelerator">&lt;primary&gt;KP_3</property>
<property name="title" translatable="yes">Switch to the Playlist panel</property> <property name="title" translatable="yes">Switch to the Playlist panel</property>
</object> </object>
</child> </child>
<child> <child>
<object class="GtkShortcutsShortcut"> <object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;primary&gt;KP_4</property> <property name="accelerator">&lt;primary&gt;KP_4</property>
<property name="title" translatable="yes">Switch to the Library panel</property> <property name="title" translatable="yes">Switch to the Library panel</property>
</object> </object>
</child> </child>
<child> <child>
<object class="GtkShortcutsShortcut"> <object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;primary&gt;k</property> <property name="accelerator">&lt;primary&gt;k</property>
<property name="title" translatable="yes">Show the keyboard shortcuts</property> <property name="title" translatable="yes">Show the keyboard shortcuts</property>
</object> </object>
</child> </child>
<child> <child>
<object class="GtkShortcutsShortcut"> <object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;primary&gt;i</property> <property name="accelerator">&lt;primary&gt;i</property>
<property name="title" translatable="yes">Open the info dialog</property> <property name="title" translatable="yes">Open the info dialog</property>
</object> </object>
</child> </child>
<child> <child>
<object class="GtkShortcutsShortcut"> <object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;primary&gt;q</property> <property name="accelerator">&lt;primary&gt;q</property>
<property name="title" translatable="yes">Quit the application</property> <property name="title" translatable="yes">Quit the application</property>
</object> </object>
@ -59,21 +66,25 @@
</child> </child>
<child> <child>
<object class="GtkShortcutsGroup"> <object class="GtkShortcutsGroup">
<property name="visible">1</property>
<property name="title" translatable="yes">Player</property> <property name="title" translatable="yes">Player</property>
<child> <child>
<object class="GtkShortcutsShortcut"> <object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;primary&gt;c</property> <property name="accelerator">&lt;primary&gt;c</property>
<property name="title" translatable="yes">Connect or disconnect</property> <property name="title" translatable="yes">Connect or disconnect</property>
</object> </object>
</child> </child>
<child> <child>
<object class="GtkShortcutsShortcut"> <object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;primary&gt;p</property> <property name="accelerator">&lt;primary&gt;p</property>
<property name="title" translatable="yes">Switch between play and pause</property> <property name="title" translatable="yes">Switch between play and pause</property>
</object> </object>
</child> </child>
<child> <child>
<object class="GtkShortcutsShortcut"> <object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;primary&gt;r</property> <property name="accelerator">&lt;primary&gt;r</property>
<property name="title" translatable="yes">Clear the playlist</property> <property name="title" translatable="yes">Clear the playlist</property>
</object> </object>
@ -82,9 +93,11 @@
</child> </child>
<child> <child>
<object class="GtkShortcutsGroup"> <object class="GtkShortcutsGroup">
<property name="visible">1</property>
<property name="title" translatable="yes">Cover Panel</property> <property name="title" translatable="yes">Cover Panel</property>
<child> <child>
<object class="GtkShortcutsShortcut"> <object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">F11</property> <property name="accelerator">F11</property>
<property name="title" translatable="yes">Show the cover in fullscreen mode</property> <property name="title" translatable="yes">Show the cover in fullscreen mode</property>
</object> </object>
@ -93,9 +106,11 @@
</child> </child>
<child> <child>
<object class="GtkShortcutsGroup"> <object class="GtkShortcutsGroup">
<property name="visible">1</property>
<property name="title" translatable="yes">Library Panel</property> <property name="title" translatable="yes">Library Panel</property>
<child> <child>
<object class="GtkShortcutsShortcut"> <object class="GtkShortcutsShortcut">
<property name="visible">1</property>
<property name="accelerator">&lt;primary&gt;f</property> <property name="accelerator">&lt;primary&gt;f</property>
<property name="title" translatable="yes">Search the library</property> <property name="title" translatable="yes">Search the library</property>
</object> </object>

View file

@ -4,8 +4,9 @@
<requires lib="adw" version="1.2" /> <requires lib="adw" version="1.2" />
<template class="McgAppWindow" parent="AdwApplicationWindow"> <template class="McgAppWindow" parent="AdwApplicationWindow">
<property name="content"> <property name="content">
<object class="AdwToolbarView" id="toolbar_view"> <object class="GtkBox">
<child type="top"> <property name="orientation">vertical</property>
<child>
<object class="AdwHeaderBar" id="headerbar"> <object class="AdwHeaderBar" id="headerbar">
<property name="centering-policy">strict</property> <property name="centering-policy">strict</property>
<property name="show_end_title_buttons">true</property> <property name="show_end_title_buttons">true</property>
@ -43,9 +44,6 @@
</child> </child>
</object> </object>
</child> </child>
<property name="content">
<object class="GtkBox" id="content_box">
<property name="orientation">vertical</property>
<child> <child>
<object class="AdwToastOverlay" id="info_toast"> <object class="AdwToastOverlay" id="info_toast">
<child> <child>
@ -72,7 +70,5 @@
</child> </child>
</object> </object>
</property> </property>
</object>
</property>
</template> </template>
</interface> </interface>

View file

@ -6,8 +6,9 @@
<file>ui/window.ui</file> <file>ui/window.ui</file>
<!-- <!--
<file>ui/gtk.menu.ui</file> <file>ui/gtk.menu.ui</file>
--> <file>ui/info-dialog.ui</file>
<file>ui/shortcuts-dialog.ui</file> <file>ui/shortcuts-dialog.ui</file>
-->
<file>ui/connection-panel.ui</file> <file>ui/connection-panel.ui</file>
<file>ui/album-headerbar.ui</file> <file>ui/album-headerbar.ui</file>
<file>ui/server-panel.ui</file> <file>ui/server-panel.ui</file>

View file

@ -26,9 +26,7 @@ class Application(Gtk.Application):
self._window = None self._window = None
self._info_dialog = None self._info_dialog = None
self._verbosity = logging.WARNING self._verbosity = logging.WARNING
self.set_accels_for_action('window.close', ['<primary>q']) #self.create_action('quit', self.quit, ['<primary>q'])
self.set_accels_for_action('win.show-help-overlay', ['<primary>k'])
self.set_accels_for_action('app.info', ['<primary>i'])
#self.create_action('about', self.on_about_action) #self.create_action('about', self.on_about_action)
#self.create_action('preferences', self.on_preferences_action) #self.create_action('preferences', self.on_preferences_action)
@ -52,15 +50,12 @@ class Application(Gtk.Application):
def on_menu_info(self, action, value): def on_menu_info(self, action, value):
self._info_dialog = Adw.AboutDialog() # FIXME Info dialog
self._info_dialog.set_application_icon("xyz.suruatoel.mcg") #if not self._info_dialog:
self._info_dialog.set_application_name("CoverGrid") # self._info_dialog = InfoDialog()
self._info_dialog.set_version("3.1") #self._info_dialog.run()
self._info_dialog.set_comments("CoverGrid is a client for the Music Player Daemon, focusing on albums instead of single tracks.") #self._info_dialog.hide()
self._info_dialog.set_website("https://www.suruatoel.xyz/codes/mcg") pass
self._info_dialog.set_license_type(Gtk.License.GPL_3_0)
self._info_dialog.set_issue_url("https://git.suruatoel.xyz/coderkun/mcg")
self._info_dialog.present()
def on_menu_quit(self, action, value): def on_menu_quit(self, action, value):
@ -116,7 +111,6 @@ class Application(Gtk.Application):
def _setup_adw(self): def _setup_adw(self):
Adw.HeaderBar() Adw.HeaderBar()
Adw.ToolbarView()
Adw.ViewSwitcherTitle() Adw.ViewSwitcherTitle()
Adw.ViewSwitcherBar() Adw.ViewSwitcherBar()
Adw.ViewStackPage() Adw.ViewStackPage()

View file

@ -616,8 +616,9 @@ class Client(Base):
def _queue_album(self, album): def _queue_album(self, album):
track_ids = [] track_ids = []
if album in self._albums:
self._logger.info("add album %s", album) self._logger.info("add album %s", album)
for track in album.get_tracks(): for track in self._albums[album].get_tracks():
self._logger.info("addid: %r", track.get_file()) self._logger.info("addid: %r", track.get_file())
track_id = None track_id = None
track_id_response = self._parse_dict(self._call('addid', track.get_file())) track_id_response = self._parse_dict(self._call('addid', track.get_file()))
@ -1092,7 +1093,7 @@ class MCGAlbum:
return True return True
def compare(album1, album2, criterion=None, reverse=False): def compare(album1, album2, criterion=None):
if criterion == None: if criterion == None:
criterion = SortOrder.TITLE criterion = SortOrder.TITLE
if criterion == SortOrder.ARTIST: if criterion == SortOrder.ARTIST:
@ -1102,22 +1103,20 @@ class MCGAlbum:
elif criterion == SortOrder.YEAR: elif criterion == SortOrder.YEAR:
value_function = "get_date" value_function = "get_date"
reverseMultiplier = -1 if reverse else 1
value1 = getattr(album1, value_function)() value1 = getattr(album1, value_function)()
value2 = getattr(album2, value_function)() value2 = getattr(album2, value_function)()
if value1 is None and value2 is None: if value1 is None and value2 is None:
return 0 return 0
elif value1 is None: elif value1 is None:
return -1 * reverseMultiplier return -1
elif value2 is None: elif value2 is None:
return 1 * reverseMultiplier return 1
if value1 < value2: if value1 < value2:
return -1 * reverseMultiplier return -1
elif value1 == value2: elif value1 == value2:
return 0 return 0
else: else:
return 1 * reverseMultiplier return 1

View file

@ -63,17 +63,6 @@ class CoverPanel(Gtk.Overlay):
# Initial actions # Initial actions
GObject.idle_add(self._enable_tracklist) GObject.idle_add(self._enable_tracklist)
# Click handler for image
clickController = Gtk.GestureClick()
clickController.connect('pressed', self.on_cover_box_pressed)
self.cover_box.add_controller(clickController)
# Button controller for songs scale
buttonController = Gtk.GestureClick()
buttonController.connect('pressed', self.on_songs_scale_pressed)
buttonController.connect('unpaired-release', self.on_songs_scale_released)
self.songs_scale.add_controller(buttonController)
def get_toolbar(self): def get_toolbar(self):
return self.toolbar return self.toolbar
@ -83,9 +72,11 @@ class CoverPanel(Gtk.Overlay):
pass pass
def on_cover_box_pressed(self, widget, npress, x, y): # FIXME on_cover_box_pressed()
if self._current_album and npress == 2: #@Gtk.Template.Callback()
self.emit('toggle-fullscreen') #def on_cover_box_pressed(self, widget, event):
# if self._current_album and event.type == Gdk.EventType._2BUTTON_PRESS:
# self.emit('toggle-fullscreen')
def set_width(self, width): def set_width(self, width):
@ -93,12 +84,16 @@ class CoverPanel(Gtk.Overlay):
self.cover_info_scroll.set_max_content_width(width // 2) self.cover_info_scroll.set_max_content_width(width // 2)
def on_songs_scale_pressed(self, widget, npress, x, y): # FIXME on_songs_start_change()
if self._timer: #@Gtk.Template.Callback()
GObject.source_remove(self._timer) #def on_songs_start_change(self, widget, event):
self._timer = None # if self._timer:
# GObject.source_remove(self._timer)
# self._timer = None
def on_songs_scale_released(self, widget, x, y, npress, sequence):
#@Gtk.Template.Callback()
def on_songs_change(self, widget, event):
value = int(self.songs_scale.get_value()) value = int(self.songs_scale.get_value())
time = self._current_album.get_length() time = self._current_album.get_length()
tracks = self._current_album.get_tracks() tracks = self._current_album.get_tracks()
@ -155,12 +150,13 @@ class CoverPanel(Gtk.Overlay):
def set_fullscreen(self, active): def set_fullscreen(self, active):
if active: if active:
self.info_revealer.set_reveal_child(False) self.info_revealer.set_reveal_child(False)
self.cover_box.override_background_color(Gtk.StateFlags.NORMAL, Gdk.RGBA(0, 0, 0, 1))
GObject.idle_add(self._resize_image) GObject.idle_add(self._resize_image)
self._fullscreened = True self._fullscreened = True
else: else:
self._fullscreened = False self._fullscreened = False
if self._current_album:
self.info_revealer.set_reveal_child(True) self.info_revealer.set_reveal_child(True)
self.cover_box.override_background_color(Gtk.StateFlags.NORMAL, Gdk.RGBA(0, 0, 0, 0))
GObject.idle_add(self._resize_image) GObject.idle_add(self._resize_image)
@ -175,6 +171,7 @@ class CoverPanel(Gtk.Overlay):
self._cover_pixbuf = None self._cover_pixbuf = None
else: else:
# Reset image # Reset image
self._cover_pixbuf = self._get_default_image()
self._cover_pixbuf = None self._cover_pixbuf = None
self._current_size = None self._current_size = None
self._current_cover_album = album self._current_cover_album = album
@ -208,7 +205,6 @@ class CoverPanel(Gtk.Overlay):
def _enable_tracklist(self): def _enable_tracklist(self):
if self._current_album: if self._current_album:
# enable # enable
if not self._fullscreened:
self.info_revealer.set_reveal_child(True) self.info_revealer.set_reveal_child(True)
else: else:
# disable # disable
@ -235,7 +231,7 @@ class CoverPanel(Gtk.Overlay):
"""Diese Methode skaliert das geladene Bild aus dem Pixelpuffer """Diese Methode skaliert das geladene Bild aus dem Pixelpuffer
auf die Größe des Fensters unter Beibehalt der Seitenverhältnisse auf die Größe des Fensters unter Beibehalt der Seitenverhältnisse
""" """
# Get size # FIXME Get size
size_width = self.cover_stack.get_size(Gtk.Orientation.HORIZONTAL) size_width = self.cover_stack.get_size(Gtk.Orientation.HORIZONTAL)
size_height = self.cover_stack.get_size(Gtk.Orientation.HORIZONTAL) size_height = self.cover_stack.get_size(Gtk.Orientation.HORIZONTAL)
# Abort if size is the same # Abort if size is the same
@ -262,5 +258,7 @@ class CoverPanel(Gtk.Overlay):
height = int(math.floor(pixbuf.get_height()*ratio)) height = int(math.floor(pixbuf.get_height()*ratio))
if width <= 0 or height <= 0: if width <= 0 or height <= 0:
return return
# 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.set_from_pixbuf(pixbuf.scale_simple(width, height, GdkPixbuf.InterpType.HYPER))
self.cover_image.show() self.cover_image.show()

15
src/infodialog.py Normal file
View file

@ -0,0 +1,15 @@
#!/usr/bin/env python3
import gi
gi.require_version('Gtk', '3.0')
import logging
from gi.repository import Gtk, GdkPixbuf
@Gtk.Template(resource_path='/xyz/suruatoel/mcg/ui/info-dialog.ui')
class InfoDialog(Gtk.AboutDialog):
__gtype_name__ = 'McgInfoDialog'

View file

@ -16,7 +16,6 @@ from mcg.albumheaderbar import AlbumHeaderbar
from mcg.utils import SortOrder from mcg.utils import SortOrder
from mcg.utils import Utils from mcg.utils import Utils
from mcg.utils import GridItem from mcg.utils import GridItem
from mcg.utils import SearchFilter
@ -33,14 +32,20 @@ class LibraryPanel(Adw.Bin):
'queue-multiple': (GObject.SIGNAL_RUN_FIRST, None, (GObject.TYPE_PYOBJECT,)), 'queue-multiple': (GObject.SIGNAL_RUN_FIRST, None, (GObject.TYPE_PYOBJECT,)),
'item-size-changed': (GObject.SIGNAL_RUN_FIRST, None, (int,)), 'item-size-changed': (GObject.SIGNAL_RUN_FIRST, None, (int,)),
'sort-order-changed': (GObject.SIGNAL_RUN_FIRST, None, (int,)), 'sort-order-changed': (GObject.SIGNAL_RUN_FIRST, None, (int,)),
'sort-type-changed': (GObject.SIGNAL_RUN_FIRST, None, (bool,)), 'sort-type-changed': (GObject.SIGNAL_RUN_FIRST, None, (Gtk.SortType,)),
'albumart': (GObject.SIGNAL_RUN_FIRST, None, (str,)), 'albumart': (GObject.SIGNAL_RUN_FIRST, None, (str,)),
'select': (GObject.SIGNAL_RUN_FIRST, None, (bool,)),
'toggle-search': (GObject.SIGNAL_RUN_FIRST, None, (bool,)),
'update': (GObject.SIGNAL_RUN_FIRST, None, ()),
'start-scale': (GObject.SIGNAL_RUN_FIRST, None, (int,)),
'end-scale': (GObject.SIGNAL_RUN_FIRST, None, (int,)),
'sort': (GObject.SIGNAL_RUN_FIRST, None, (int,)),
'sort-type': (GObject.SIGNAL_RUN_FIRST, None, (Gtk.SortType,))
} }
# Widgets # Widgets
library_stack = Gtk.Template.Child()
panel_normal = Gtk.Template.Child()
panel_standalone = Gtk.Template.Child() panel_standalone = Gtk.Template.Child()
actionbar_revealer = Gtk.Template.Child() actionbar_revealer = Gtk.Template.Child()
# Toolbar # Toolbar
@ -64,9 +69,6 @@ class LibraryPanel(Adw.Bin):
scroll = Gtk.Template.Child() scroll = Gtk.Template.Child()
# Library Grid # Library Grid
library_grid = Gtk.Template.Child() library_grid = Gtk.Template.Child()
# Action bar (normal)
actionbar = Gtk.Template.Child()
actionbar_standalone = Gtk.Template.Child()
# Standalone Image # Standalone Image
standalone_stack = Gtk.Template.Child() standalone_stack = Gtk.Template.Child()
standalone_spinner = Gtk.Template.Child() standalone_spinner = Gtk.Template.Child()
@ -81,31 +83,38 @@ class LibraryPanel(Adw.Bin):
self._buttons = {} self._buttons = {}
self._albums = None self._albums = None
self._host = "localhost" self._host = "localhost"
self._filter_string = ""
self._item_size = 150 self._item_size = 150
self._sort_order = SortOrder.YEAR self._sort_order = SortOrder.YEAR
self._sort_type = Gtk.SortType.DESCENDING self._sort_type = Gtk.SortType.DESCENDING
self._grid_pixbufs = {} self._grid_pixbufs = {}
self._grid_width = 0
self._old_ranges = {} self._old_ranges = {}
self._library_lock = threading.Lock() self._library_lock = threading.Lock()
self._library_stop = threading.Event() self._library_stop = threading.Event()
self._icon_theme = Gtk.IconTheme.get_for_display(Gdk.Display.get_default()) self._icon_theme = Gtk.IconTheme.get_for_display(Gdk.Display.get_default())
self._standalone_pixbuf = None self._standalone_pixbuf = None
self._selected_albums = [] self._selected_albums = []
self._allocation = (0, 0)
self._is_selected = False self._is_selected = False
# Widgets # Widgets
# 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 # Header bar
self._headerbar_standalone = AlbumHeaderbar() self._headerbar_standalone = AlbumHeaderbar()
self._headerbar_standalone.connect('close', self.on_standalone_close_clicked) self._headerbar_standalone.connect('close', self.on_standalone_close_clicked)
# Library Grid: Model # Library Grid: Model
self._library_grid_model = Gio.ListStore() self._library_grid_model = Gio.ListStore()
self._library_grid_filter = Gtk.FilterListModel() self._library_grid_selection = Gtk.MultiSelection.new(self._library_grid_model)
self._library_grid_filter.set_model(self._library_grid_model) self._library_grid_filter = self._library_grid_selection
self._library_grid_selection_multi = Gtk.MultiSelection.new(self._library_grid_filter)
self._library_grid_selection_single = Gtk.SingleSelection.new(self._library_grid_filter)
# Library Grid # Library Grid
self.library_grid.set_model(self._library_grid_selection_single) self.library_grid.set_model(self._library_grid_filter)
# Toolbar menu # Toolbar menu
self.grid_scale.set_value(self._item_size) self.grid_scale.set_value(self._item_size)
self._toolbar_sort_buttons = { self._toolbar_sort_buttons = {
@ -114,11 +123,6 @@ class LibraryPanel(Adw.Bin):
SortOrder.YEAR: self.sort_year SortOrder.YEAR: self.sort_year
} }
# Button controller for grid scale
buttonController = Gtk.GestureClick()
buttonController.connect('unpaired-release', self.on_grid_scale_released)
self.grid_scale.add_controller(buttonController)
def get_headerbar_standalone(self): def get_headerbar_standalone(self):
return self._headerbar_standalone return self._headerbar_standalone
@ -132,84 +136,148 @@ class LibraryPanel(Adw.Bin):
self._is_selected = selected self._is_selected = selected
@Gtk.Template.Callback() #@Gtk.Template.Callback()
def on_select_toggled(self, widget): def on_select_toggled(self, widget):
if self.select_button.get_active(): self.emit('select', widget.get_active())
self.actionbar_revealer.set_reveal_child(True)
self.library_grid.set_model(self._library_grid_selection_multi)
self.library_grid.set_single_click_activate(False)
self.library_grid.get_style_context().add_class(Utils.CSS_SELECTION)
else:
self.actionbar_revealer.set_reveal_child(False)
self.library_grid.set_model(self._library_grid_selection_single)
self.library_grid.set_single_click_activate(True)
self.library_grid.get_style_context().remove_class(Utils.CSS_SELECTION)
@Gtk.Template.Callback() #@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): def on_update_clicked(self, widget):
self.emit('update') self.emit('update')
def on_grid_scale_released(self, widget, x, y, npress, sequence): # FXME on_grid_scale_changed
size = math.floor(self.grid_scale.get_value()) #@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.grid_scale.clear_marks()
width = widget.get_allocation().width
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.grid_scale.add_mark(
pixel,
Gtk.PositionType.BOTTOM,
None
)
def on_toolbar_toggle_search(self, widget, active):
self.filter_bar.set_search_mode(active)
def on_toolbar_select(self, widget, active):
if active:
self.actionbar_revealer.set_reveal_child(True)
self.library_grid.set_selection_mode(Gtk.SelectionMode.MULTIPLE)
self.library_grid.get_style_context().add_class(Utils.CSS_SELECTION)
else:
self.actionbar_revealer.set_reveal_child(False)
self.library_grid.set_selection_mode(Gtk.SelectionMode.SINGLE)
self.library_grid.get_style_context().remove_class(Utils.CSS_SELECTION)
def on_toolbar_update(self, widget):
self.emit('update')
def on_toolbar_scale(self, widget, value):
size = math.floor(value)
range = self.grid_scale.get_adjustment() range = self.grid_scale.get_adjustment()
if size < range.get_lower() or size > range.get_upper(): if size < range.get_lower() or size > range.get_upper():
return return
self._item_size = size self._item_size = size
#GObject.idle_add(self.library_grid.set_item_padding, size / 100)
GObject.idle_add(self._set_widget_grid_size, self.library_grid, size, True)
def on_toolbar_scaled(self, widget, value):
size = round(value)
range = self.grid_scale.get_adjustment()
if size < range.get_lower() or size > range.get_upper():
return False
self.emit('item-size-changed', size) self.emit('item-size-changed', size)
self._redraw() self._redraw()
GObject.idle_add(self.toolbar_popover.popdown) return False
@Gtk.Template.Callback() def on_toolbar_sort(self, widget, sort):
def on_grid_scale_changed(self, widget): self._change_sort(sort)
size = math.floor(self.grid_scale.get_value())
range = widget.get_adjustment()
if size < range.get_lower() or size > range.get_upper():
return
self._set_widget_grid_size(self.library_grid, size, True)
@Gtk.Template.Callback() def on_toolbar_sort_type(self, widget, sort_type):
def on_sort_toggled(self, widget): self._sort_type = sort_type
if widget.get_active(): #self._library_grid_model.set_sort_column_id(2, sort_type)
self._sort_order = [key for key, value in self._toolbar_sort_buttons.items() if value is widget][0] self.emit('sort-type-changed', sort_type)
self._sort_grid_model()
self.emit('sort-order-changed', self._sort_order)
@Gtk.Template.Callback() #@Gtk.Template.Callback()
def on_sort_order_toggled(self, button): def on_filter_bar_notify(self, widget, value):
if button.get_active(): if self.toolbar_search_bar.get_active() is not self.filter_bar.get_search_mode():
self._sort_type = Gtk.SortType.DESCENDING self.toolbar_search_bar.set_active(self.filter_bar.get_search_mode())
else:
self._sort_type = Gtk.SortType.ASCENDING
self._sort_grid_model()
self.emit('sort-type-changed', button.get_active())
def set_size(self, width, height): #@Gtk.Template.Callback()
self._set_marks()
self._resize_standalone_image()
@Gtk.Template.Callback()
def on_filter_entry_changed(self, widget): def on_filter_entry_changed(self, widget):
self._library_grid_filter.set_filter(SearchFilter(self.filter_entry.get_text())) self._filter_string = self.filter_entry.get_text()
GObject.idle_add(self._library_grid_filter.refilter)
@Gtk.Template.Callback() # FIXME on_library_grid_clicked()
def on_library_grid_clicked(self, widget, position): #@Gtk.Template.Callback()
def on_library_grid_clicked(self, widget, path):
# Get selected album # Get selected album
item = self._library_grid_filter.get_item(position) path = self._library_grid_filter.convert_path_to_child_path(path)
album = item.get_album() iter = self._library_grid_model.get_iter(path)
id = album.get_id() id = self._library_grid_model.get_value(iter, 2)
album = self._albums[id]
self._selected_albums = [album] self._selected_albums = [album]
self.emit('albumart', id) self.emit('albumart', id)
# Show standalone album # Show standalone album
if widget.get_model() == self._library_grid_selection_single: if widget.get_selection_mode() == Gtk.SelectionMode.SINGLE:
# Set labels # Set labels
self._headerbar_standalone.set_album(album) self._headerbar_standalone.set_album(album)
@ -221,24 +289,50 @@ class LibraryPanel(Adw.Bin):
self.standalone_spinner.start() self.standalone_spinner.start()
@Gtk.Template.Callback() # FIXME on_library_grid_selection_changed()
#@Gtk.Template.Callback()
def on_library_grid_selection_changed(self, widget):
self._selected_albums = []
for path in widget.get_selected_items():
path = self._library_grid_filter.convert_path_to_child_path(path)
iter = self._library_grid_model.get_iter(path)
id = self._library_grid_model.get_value(iter, 2)
self._selected_albums.insert(0, self._albums[id])
def on_filter_visible(self, model, iter, data):
id = model.get_value(iter, 2)
if not id in self._albums.keys():
return
album = self._albums[id]
return album.filter(self._filter_string)
#@Gtk.Template.Callback()
def on_selection_cancel_clicked(self, widget): def on_selection_cancel_clicked(self, widget):
self.select_button.set_active(False) self.select_button.set_active(False)
@Gtk.Template.Callback() #@Gtk.Template.Callback()
def on_selection_add_clicked(self, widget): def on_selection_add_clicked(self, widget):
self.emit('queue-multiple', self._get_selected_albums()) ids = [album.get_id() for album in self._selected_albums]
self.emit('queue-multiple', ids)
self.select_button.set_active(False) 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()
def on_standalone_play_clicked(self, widget): def on_standalone_play_clicked(self, widget):
self.emit('play', self._selected_albums[0].get_id()) self.emit('play', self._selected_albums[0].get_id())
self._close_standalone() self._close_standalone()
@Gtk.Template.Callback() #@Gtk.Template.Callback()
def on_standalone_queue_clicked(self, widget): def on_standalone_queue_clicked(self, widget):
self.emit('queue', self._selected_albums[0].get_id()) self.emit('queue', self._selected_albums[0].get_id())
self._close_standalone() self._close_standalone()
@ -264,21 +358,29 @@ class LibraryPanel(Adw.Bin):
def set_sort_order(self, sort): def set_sort_order(self, sort):
if self._sort_order != sort:
button = self._toolbar_sort_buttons[sort] button = self._toolbar_sort_buttons[sort]
if button: if button and not button.get_active():
self._sort_order = [key for key, value in self._toolbar_sort_buttons.items() if value is button][0]
if not button.get_active():
button.set_active(True) button.set_active(True)
self._sort_grid_model() self._sort_order = sort
self._library_grid_model.set_sort_func(2, self.compare_albums, self._sort_order)
def get_sort_order(self):
return self._sort_order
def set_sort_type(self, sort_type): def set_sort_type(self, sort_type):
sort_type_gtk = Gtk.SortType.DESCENDING if sort_type else Gtk.SortType.ASCENDING if self._sort_type != sort_type:
if sort_type:
if sort_type_gtk != self._sort_type: sort_type_gtk = Gtk.SortType.DESCENDING
self.toolbar_sort_order_button.set_active(True)
else:
sort_type_gtk = Gtk.SortType.ASCENDING
self.toolbar_sort_order_button.set_active(False)
if self._sort_type != sort_type_gtk:
self._sort_type = sort_type_gtk self._sort_type = sort_type_gtk
self.toolbar_sort_order_button.set_active(sort_type) self._library_grid_model.set_sort_column_id(2, sort_type)
self._sort_grid_model()
def get_sort_type(self): def get_sort_type(self):
@ -314,18 +416,25 @@ class LibraryPanel(Adw.Bin):
GObject.idle_add(self._show_image) GObject.idle_add(self._show_image)
def _sort_grid_model(self): def compare_albums(self, model, row1, row2, criterion):
GObject.idle_add(self._library_grid_model.sort, self._grid_model_compare_func, self._sort_order, self._sort_type) id1 = model.get_value(row1, 2)
id2 = model.get_value(row2, 2)
if not id1 or not id2:
def _grid_model_compare_func(self, item1, item2, criterion, order): return
return client.MCGAlbum.compare(item1.get_album(), item2.get_album(), criterion, (order == Gtk.SortType.DESCENDING)) return client.MCGAlbum.compare(self._albums[id1], self._albums[id2], criterion)
def stop_threads(self): def stop_threads(self):
self._library_stop.set() self._library_stop.set()
def _change_sort(self, sort):
self._sort_order = sort
self._library_grid_model.set_sort_func(2, self.compare_albums, sort)
self.emit('sort-order-changed', sort)
def _set_albums(self, host, albums, size): def _set_albums(self, host, albums, size):
""" """
if not self._is_selected and albums != self._albums: if not self._is_selected and albums != self._albums:
@ -337,13 +446,14 @@ class LibraryPanel(Adw.Bin):
) )
""" """
self._library_lock.acquire() self._library_lock.acquire()
self._library_stop.clear()
self._albums = albums self._albums = albums
stack_transition_type = self.stack.get_transition_type()
GObject.idle_add(self.stack.set_transition_type, Gtk.StackTransitionType.NONE)
GObject.idle_add(self.stack.set_visible_child, self.progress_box) GObject.idle_add(self.stack.set_visible_child, self.progress_box)
GObject.idle_add(self.progress_bar.set_fraction, 0.0) GObject.idle_add(self.progress_bar.set_fraction, 0.0)
GObject.idle_add(self.stack.set_transition_type, stack_transition_type) #GObject.idle_add(self.library_grid.set_item_padding, size / 100)
GObject.idle_add(self._library_grid_model.remove_all) self.library_grid.set_model(None)
#self.library_grid.freeze_child_notify()
self._library_grid_model.remove_all()
i = 0 i = 0
n = len(albums) n = len(albums)
@ -358,7 +468,7 @@ class LibraryPanel(Adw.Bin):
# Exception is handled by client # Exception is handled by client
pass pass
except Exception as e: except Exception as e:
self._logger.exception("Failed to load albumart", e) self._logger.exception("Failed to load albumart")
if pixbuf is None: if pixbuf is None:
pixbuf = self._icon_theme.lookup_icon( pixbuf = self._icon_theme.lookup_icon(
Utils.STOCK_ICON_DEFAULT, Utils.STOCK_ICON_DEFAULT,
@ -370,15 +480,20 @@ class LibraryPanel(Adw.Bin):
) )
if pixbuf is not None: if pixbuf is not None:
self._grid_pixbufs[album.get_id()] = pixbuf self._grid_pixbufs[album.get_id()] = pixbuf
GObject.idle_add(self._library_grid_model.append, GridItem(album, pixbuf)) self._library_grid_model.append(GridItem(album, pixbuf))
i += 1 i += 1
GObject.idle_add(self.progress_bar.set_fraction, i/n) GObject.idle_add(self.progress_bar.set_fraction, i/n)
GObject.idle_add(self.progress_bar.set_text, locale.gettext("Loading images")) GObject.idle_add(self.progress_bar.set_text, locale.gettext("Loading images"))
if self._library_stop.is_set():
self._library_lock.release() self._library_lock.release()
GObject.idle_add(self.stack.set_visible_child, self.scroll) return
self._sort_grid_model()
self.library_grid.set_model(self._library_grid_filter)
#self.library_grid.thaw_child_notify()
#self.library_grid.set_item_width(-1)
self._library_lock.release()
self.stack.set_visible_child(self.scroll)
def _set_widget_grid_size(self, grid_widget, size, vertical): def _set_widget_grid_size(self, grid_widget, size, vertical):
@ -389,31 +504,50 @@ class LibraryPanel(Adw.Bin):
def _set_widget_grid_size_thread(self, grid_widget, size, vertical): def _set_widget_grid_size_thread(self, grid_widget, size, vertical):
self._library_lock.acquire() self._library_lock.acquire()
self._library_stop.clear() self._library_stop.clear()
if size == self._item_size: grid_filter = grid_widget.get_model()
grid_model = grid_filter.get_model()
# get old_range
grid_widget_id = id(grid_widget)
if grid_widget_id not in self._old_ranges or self._old_ranges[grid_widget_id] is None:
self._old_ranges[grid_widget_id] = range(0, len(grid_filter))
old_range = self._old_ranges[grid_widget_id]
old_start = len(old_range) > 0 and old_range[0] or 0
old_end = len(old_range) > 0 and old_range[len(old_range)-1] + 1 or 0
# calculate visible range
w = (grid_widget.get_allocation().width // size) + (vertical and 0 or 1)
h = (grid_widget.get_allocation().height // size) + (vertical and 1 or 0)
c = w * h
vis_range = grid_widget.get_visible_range()
if vis_range is None:
self._library_lock.release() self._library_lock.release()
return return
for i in range(self._library_grid_model.get_n_items()): (vis_start,), (vis_end,) = vis_range
grid_item = self._library_grid_model.get_item(i) vis_end = min(vis_start + c, len(grid_filter))
album_id = grid_item.get_album().get_id() vis_range = range(vis_start, vis_end)
# set pixbuf
cur_start = min(old_start, vis_start)
cur_end = max(old_end, vis_end)
cur_range = range(cur_start, cur_end)
for index in cur_range:
iter = grid_filter.convert_iter_to_child_iter(grid_filter[index].iter)
if index in vis_range:
album_id = grid_model.get_value(iter, 2)
pixbuf = self._grid_pixbufs[album_id] pixbuf = self._grid_pixbufs[album_id]
if pixbuf is not None:
pixbuf = pixbuf.scale_simple(size, size, GdkPixbuf.InterpType.NEAREST) pixbuf = pixbuf.scale_simple(size, size, GdkPixbuf.InterpType.NEAREST)
else: else:
pixbuf = self._icon_theme.lookup_icon( pixbuf = GdkPixbuf.Pixbuf.new(GdkPixbuf.Colorspace.RGB, False, 8, 1, 1)
Utils.STOCK_ICON_DEFAULT, grid_model.set_value(iter, 0, pixbuf)
None,
size,
size,
Gtk.TextDirection.LTR,
Gtk.IconLookupFlags.FORCE_SYMBOLIC
)
GObject.idle_add(grid_item.set_cover, pixbuf)
if self._library_stop.is_set(): if self._library_stop.is_set():
self._library_lock.release() self._library_lock.release()
return return
self._old_ranges[grid_widget_id] = vis_range
grid_widget.set_item_width(size)
self._library_lock.release() self._library_lock.release()
@ -428,34 +562,13 @@ class LibraryPanel(Adw.Bin):
self.set_albums(self._host, self._albums) self.set_albums(self._host, self._albums)
def _set_marks(self):
width = self.scroll.get_width()
if width == self._grid_width:
return
self._grid_width = width
self.grid_scale.clear_marks()
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.grid_scale.add_mark(
pixel,
Gtk.PositionType.BOTTOM,
None
)
def _open_standalone(self): def _open_standalone(self):
self.library_stack.set_visible_child(self.panel_standalone) self.set_visible_child(self.panel_standalone)
self.emit('open-standalone') self.emit('open-standalone')
def _close_standalone(self): def _close_standalone(self):
self.library_stack.set_visible_child(self.panel_normal) self.set_visible_child(self.get_children()[0])
self.emit('close-standalone') self.emit('close-standalone')
@ -463,19 +576,15 @@ class LibraryPanel(Adw.Bin):
"""Diese Methode skaliert das geladene Bild aus dem Pixelpuffer """Diese Methode skaliert das geladene Bild aus dem Pixelpuffer
auf die Größe des Fensters unter Beibehalt der Seitenverhältnisse auf die Größe des Fensters unter Beibehalt der Seitenverhältnisse
""" """
# Get size
size_width = self.standalone_stack.get_width()
size_height = self.standalone_stack.get_height()
# Get pixelbuffer
pixbuf = self._standalone_pixbuf pixbuf = self._standalone_pixbuf
size = self.standalone_scroll.get_allocation()
# Check pixelbuffer # Check pixelbuffer
if pixbuf is None: if pixbuf is None:
return return
# Skalierungswert für Breite und Höhe ermitteln # Skalierungswert für Breite und Höhe ermitteln
ratioW = float(size_width) / float(pixbuf.get_width()) ratioW = float(size.width) / float(pixbuf.get_width())
ratioH = float(size_height) / float(pixbuf.get_height()) ratioH = float(size.height) / float(pixbuf.get_height())
# Kleineren beider Skalierungswerte nehmen, nicht Hochskalieren # Kleineren beider Skalierungswerte nehmen, nicht Hochskalieren
ratio = min(ratioW, ratioH) ratio = min(ratioW, ratioH)
ratio = min(ratio, 1) ratio = min(ratio, 1)
@ -485,6 +594,7 @@ class LibraryPanel(Adw.Bin):
if width <= 0 or height <= 0: if width <= 0 or height <= 0:
return return
# Pixelpuffer auf Oberfläche zeichnen # Pixelpuffer auf Oberfläche zeichnen
self.standalone_image.set_allocation(self.standalone_scroll.get_allocation())
self.standalone_image.set_from_pixbuf(pixbuf.scale_simple(width, height, GdkPixbuf.InterpType.HYPER)) self.standalone_image.set_from_pixbuf(pixbuf.scale_simple(width, height, GdkPixbuf.InterpType.HYPER))
self.standalone_image.show() self.standalone_image.show()
@ -498,11 +608,3 @@ class LibraryPanel(Adw.Bin):
Gtk.TextDirection.LTR, Gtk.TextDirection.LTR,
Gtk.IconLookupFlags.FORCE_SYMBOLIC Gtk.IconLookupFlags.FORCE_SYMBOLIC
) )
def _get_selected_albums(self):
albums = []
for i in range(self.library_grid.get_model().get_n_items()):
if self.library_grid.get_model().is_selected(i):
albums.append(self.library_grid.get_model().get_item(i).get_album())
return albums

View file

@ -25,6 +25,7 @@ mcg_sources = [
'client.py', 'client.py',
'connectionpanel.py', 'connectionpanel.py',
'coverpanel.py', 'coverpanel.py',
'infodialog.py',
'librarypanel.py', 'librarypanel.py',
'playlistpanel.py', 'playlistpanel.py',
'serverpanel.py', 'serverpanel.py',

View file

@ -29,12 +29,13 @@ class PlaylistPanel(Adw.Bin):
'remove-multiple-albums': (GObject.SIGNAL_RUN_FIRST, None, (GObject.TYPE_PYOBJECT,)), 'remove-multiple-albums': (GObject.SIGNAL_RUN_FIRST, None, (GObject.TYPE_PYOBJECT,)),
'play': (GObject.SIGNAL_RUN_FIRST, None, (GObject.TYPE_PYOBJECT,)), 'play': (GObject.SIGNAL_RUN_FIRST, None, (GObject.TYPE_PYOBJECT,)),
'albumart': (GObject.SIGNAL_RUN_FIRST, None, (str,)), 'albumart': (GObject.SIGNAL_RUN_FIRST, None, (str,)),
'select': (GObject.SIGNAL_RUN_FIRST, None, (bool,)),
'clear-playlist': (GObject.SIGNAL_RUN_FIRST, None, ())
} }
# Widgets # Widgets
playlist_stack = Gtk.Template.Child()
panel_normal = Gtk.Template.Child()
panel_standalone = Gtk.Template.Child() panel_standalone = Gtk.Template.Child()
actionbar_revealer = Gtk.Template.Child() actionbar_revealer = Gtk.Template.Child()
# Toolbar # Toolbar
@ -68,15 +69,17 @@ class PlaylistPanel(Adw.Bin):
self._is_selected = False self._is_selected = False
# Widgets # Widgets
# FIXME Toolbar signals
#self._toolbar.connect('select', self.on_toolbar_select)
#self._toolbar.connect('clear-playlist', self.on_toolbar_clear)
# Header bar # Header bar
self._headerbar_standalone = AlbumHeaderbar() self._headerbar_standalone = AlbumHeaderbar()
self._headerbar_standalone.connect('close', self.on_headerbar_close_clicked) self._headerbar_standalone.connect('close', self.on_headerbar_close_clicked)
# Playlist Grid: Model # Playlist Grid: Model
self._playlist_grid_model = Gio.ListStore() self._playlist_grid_model = Gio.ListStore()
self._playlist_grid_selection_multi = Gtk.MultiSelection.new(self._playlist_grid_model) self._playlist_grid_selection = Gtk.MultiSelection.new(self._playlist_grid_model)
self._playlist_grid_selection_single = Gtk.SingleSelection.new(self._playlist_grid_model)
# Playlist Grid # Playlist Grid
self.playlist_grid.set_model(self._playlist_grid_selection_single) self.playlist_grid.set_model(self._playlist_grid_selection)
def get_headerbar_standalone(self): def get_headerbar_standalone(self):
@ -91,22 +94,31 @@ class PlaylistPanel(Adw.Bin):
self._is_selected = selected self._is_selected = selected
@Gtk.Template.Callback() def on_toolbar_select(self, widget, active):
def on_select_toggled(self, widget): if active:
if self.select_button.get_active():
self.actionbar_revealer.set_reveal_child(True) self.actionbar_revealer.set_reveal_child(True)
self.playlist_grid.set_model(self._playlist_grid_selection_multi) self.playlist_grid.set_selection_mode(Gtk.SelectionMode.MULTIPLE)
self.playlist_grid.set_single_click_activate(False)
self.playlist_grid.get_style_context().add_class(Utils.CSS_SELECTION) self.playlist_grid.get_style_context().add_class(Utils.CSS_SELECTION)
else: else:
self.actionbar_revealer.set_reveal_child(False) self.actionbar_revealer.set_reveal_child(False)
self.playlist_grid.set_model(self._playlist_grid_selection_single) self.playlist_grid.set_selection_mode(Gtk.SelectionMode.SINGLE)
self.playlist_grid.set_single_click_activate(True)
self.playlist_grid.get_style_context().remove_class(Utils.CSS_SELECTION) self.playlist_grid.get_style_context().remove_class(Utils.CSS_SELECTION)
@Gtk.Template.Callback() def on_toolbar_clear(self, widget):
self.emit('clear-playlist')
# FIXME on_select_toggled()
#@Gtk.Template.Callback()
def on_select_toggled(self, widget):
self.emit('select', widget.get_active())
# FIXME on_clear_clicked()
#@Gtk.Template.Callback()
def on_clear_clicked(self, widget): def on_clear_clicked(self, widget):
if widget is self.playlist_clear_button:
self.emit('clear-playlist') self.emit('clear-playlist')
@ -119,8 +131,9 @@ class PlaylistPanel(Adw.Bin):
self._selected_albums = [album] self._selected_albums = [album]
self.emit('albumart', id) self.emit('albumart', id)
# Show standalone album # FIXME Show standalone album
if widget.get_model() == self._playlist_grid_selection_single: return
if widget.get_selection_mode() == Gtk.SelectionMode.SINGLE:
# Set labels # Set labels
self._headerbar_standalone.set_album(album) self._headerbar_standalone.set_album(album)
@ -132,37 +145,49 @@ class PlaylistPanel(Adw.Bin):
self.standalone_spinner.start() self.standalone_spinner.start()
@Gtk.Template.Callback() # FIXME on_playlist_grid_selection_changed()
#@Gtk.Template.Callback()
def on_playlist_grid_selection_changed(self, widget):
self._selected_albums = []
for path in widget.get_selected_items():
iter = self._playlist_grid_model.get_iter(path)
hash = self._playlist_grid_model.get_value(iter, 2)
self._selected_albums.append(self._playlist_albums[hash])
#@Gtk.Template.Callback()
def on_selection_cancel_clicked(self, widget): def on_selection_cancel_clicked(self, widget):
self.select_button.set_active(False) self.select_button.set_active(False)
@Gtk.Template.Callback() #@Gtk.Template.Callback()
def on_selection_remove_clicked(self, widget): def on_selection_remove_clicked(self, widget):
self.emit('remove-multiple-albums', self._get_selected_albums()) self.emit('remove-multiple-albums', self._selected_albums)
self.select_button.set_active(False) self.select_button.set_active(False)
# FIXME on_standalone_scroll_size_allocate()
#@Gtk.Template.Callback()
def on_standalone_scroll_size_allocate(self, widget, allocation):
self._resize_standalone_image()
def on_headerbar_close_clicked(self, widget): def on_headerbar_close_clicked(self, widget):
self._close_standalone() self._close_standalone()
@Gtk.Template.Callback() #@Gtk.Template.Callback()
def on_standalone_remove_clicked(self, widget): def on_standalone_remove_clicked(self, widget):
self.emit('remove-album', self._get_selected_albums()[0]) self.emit('remove-album', self._selected_albums[0])
self._close_standalone() self._close_standalone()
@Gtk.Template.Callback() #@Gtk.Template.Callback()
def on_standalone_play_clicked(self, widget): def on_standalone_play_clicked(self, widget):
self.emit('play', self._get_selected_albums()[0]) self.emit('play', self._selected_albums[0])
self._close_standalone() self._close_standalone()
def set_size(self, width, height):
self._resize_standalone_image()
def set_item_size(self, item_size): def set_item_size(self, item_size):
if self._item_size != item_size: if self._item_size != item_size:
self._item_size = item_size self._item_size = item_size
@ -215,6 +240,8 @@ class PlaylistPanel(Adw.Bin):
for album in playlist: for album in playlist:
self._playlist_albums[album.get_id()] = album self._playlist_albums[album.get_id()] = album
self._playlist_grid_model.remove_all() 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) cache = client.MCGCache(host, size)
for album in playlist: for album in playlist:
@ -243,7 +270,7 @@ class PlaylistPanel(Adw.Bin):
self._playlist_lock.release() self._playlist_lock.release()
return return
self.playlist_grid.set_model(self._playlist_grid_selection_single) self.playlist_grid.set_model(self._playlist_grid_selection)
self._playlist_lock.release() self._playlist_lock.release()
@ -259,12 +286,12 @@ class PlaylistPanel(Adw.Bin):
def _open_standalone(self): def _open_standalone(self):
self.playlist_stack.set_visible_child(self.panel_standalone) self.set_visible_child(self.panel_standalone)
self.emit('open-standalone') self.emit('open-standalone')
def _close_standalone(self): def _close_standalone(self):
self.playlist_stack.set_visible_child(self.panel_normal) self.set_visible_child(self.get_children()[0])
self.emit('close-standalone') self.emit('close-standalone')
@ -272,19 +299,15 @@ class PlaylistPanel(Adw.Bin):
"""Diese Methode skaliert das geladene Bild aus dem Pixelpuffer """Diese Methode skaliert das geladene Bild aus dem Pixelpuffer
auf die Größe des Fensters unter Beibehalt der Seitenverhältnisse auf die Größe des Fensters unter Beibehalt der Seitenverhältnisse
""" """
# Get size
size_width = self.standalone_stack.get_width()
size_height = self.standalone_stack.get_height()
# Get pixelbuffer
pixbuf = self._standalone_pixbuf pixbuf = self._standalone_pixbuf
size = self.standalone_scroll.get_allocation()
# Check pixelbuffer # Check pixelbuffer
if pixbuf is None: if pixbuf is None:
return return
# Skalierungswert für Breite und Höhe ermitteln # Skalierungswert für Breite und Höhe ermitteln
ratioW = float(size_width) / float(pixbuf.get_width()) ratioW = float(size.width) / float(pixbuf.get_width())
ratioH = float(size_height) / float(pixbuf.get_height()) ratioH = float(size.height) / float(pixbuf.get_height())
# Kleineren beider Skalierungswerte nehmen, nicht Hochskalieren # Kleineren beider Skalierungswerte nehmen, nicht Hochskalieren
ratio = min(ratioW, ratioH) ratio = min(ratioW, ratioH)
ratio = min(ratio, 1) ratio = min(ratio, 1)
@ -294,6 +317,7 @@ class PlaylistPanel(Adw.Bin):
if width <= 0 or height <= 0: if width <= 0 or height <= 0:
return return
# Pixelpuffer auf Oberfläche zeichnen # Pixelpuffer auf Oberfläche zeichnen
self.standalone_image.set_allocation(self.standalone_scroll.get_allocation())
self.standalone_image.set_from_pixbuf(pixbuf.scale_simple(width, height, GdkPixbuf.InterpType.HYPER)) self.standalone_image.set_from_pixbuf(pixbuf.scale_simple(width, height, GdkPixbuf.InterpType.HYPER))
self.standalone_image.show() self.standalone_image.show()
@ -307,11 +331,3 @@ class PlaylistPanel(Adw.Bin):
Gtk.TextDirection.LTR, Gtk.TextDirection.LTR,
Gtk.IconLookupFlags.FORCE_SYMBOLIC Gtk.IconLookupFlags.FORCE_SYMBOLIC
) )
def _get_selected_albums(self):
albums = []
for i in range(self.playlist_grid.get_model().get_n_items()):
if self.playlist_grid.get_model().is_selected(i):
albums.append(self.playlist_grid.get_model().get_item(i).get_album())
return albums

View file

@ -2,8 +2,8 @@
import gi import gi
gi.require_version('Gtk', '4.0') gi.require_version('Gtk', '3.0')
gi.require_version('Adw', '1')
from gi.repository import Gtk from gi.repository import Gtk

View file

@ -8,7 +8,7 @@ import locale
import os import os
import urllib import urllib
from gi.repository import Gdk, GdkPixbuf, GObject, Gtk from gi.repository import Gdk, GdkPixbuf, GObject
@ -112,21 +112,3 @@ class GridItem(GObject.GObject):
def get_album(self): def get_album(self):
return self._album return self._album
def set_cover(self, cover):
self.cover = Gdk.Texture.new_for_pixbuf(cover)
class SearchFilter(Gtk.Filter):
def __init__(self, search_string):
super().__init__()
self._search_string = search_string
def do_match(self, grid_item):
return grid_item.get_album().filter(self._search_string)

View file

@ -9,14 +9,13 @@ try:
use_keyring = True use_keyring = True
except: except:
use_keyring = False use_keyring = False
use_keyring = False
import locale import locale
import logging import logging
from gi.repository import Gtk, Adw, Gdk, GObject, GLib, Gio from gi.repository import Gtk, Adw, Gdk, GObject, GLib, Gio
from . import client from . import client
from .shortcutsdialog import ShortcutsDialog #from .shortcutsdialog import ShortcutsDialog
from .connectionpanel import ConnectionPanel from .connectionpanel import ConnectionPanel
from .serverpanel import ServerPanel from .serverpanel import ServerPanel
from .coverpanel import CoverPanel from .coverpanel import CoverPanel
@ -60,7 +59,6 @@ class Window(Adw.ApplicationWindow):
_CUSTOM_STARTUP_COMPLETE = 'startup-complete' _CUSTOM_STARTUP_COMPLETE = 'startup-complete'
# Widgets # Widgets
toolbar_view = Gtk.Template.Child()
content_stack = Gtk.Template.Child() content_stack = Gtk.Template.Child()
panel_stack = Gtk.Template.Child() panel_stack = Gtk.Template.Child()
toolbar_stack = Gtk.Template.Child() toolbar_stack = Gtk.Template.Child()
@ -88,8 +86,8 @@ class Window(Adw.ApplicationWindow):
self._headerbar_connection_button_active = True self._headerbar_connection_button_active = True
self._headerbar_playpause_button_active = True self._headerbar_playpause_button_active = True
# Help/Shortcuts dialog # FIXME Help/Shortcuts dialog
self.set_help_overlay(ShortcutsDialog()) #self.set_help_overlay(ShortcutsDialog())
# Login screen # Login screen
self._connection_panel = ConnectionPanel() self._connection_panel = ConnectionPanel()
@ -101,20 +99,20 @@ class Window(Adw.ApplicationWindow):
self._panels.append(self._cover_panel) self._panels.append(self._cover_panel)
# Playlist panel # Playlist panel
self._playlist_panel = PlaylistPanel(self._mcg) self._playlist_panel = PlaylistPanel(self._mcg)
self._playlist_panel.connect('open-standalone', self.on_panel_open_standalone) #self._playlist_panel.connect('open-standalone', self.on_panel_open_standalone)
self._playlist_panel.connect('close-standalone', self.on_panel_close_standalone) #self._playlist_panel.connect('close-standalone', self.on_panel_close_standalone)
self._panels.append(self._playlist_panel) self._panels.append(self._playlist_panel)
# Library panel # Library panel
self._library_panel = LibraryPanel(self._mcg) self._library_panel = LibraryPanel(self._mcg)
self._library_panel.connect('open-standalone', self.on_panel_open_standalone) #self._library_panel.connect('open-standalone', self.on_panel_open_standalone)
self._library_panel.connect('close-standalone', self.on_panel_close_standalone) #self._library_panel.connect('close-standalone', self.on_panel_close_standalone)
self._panels.append(self._library_panel) self._panels.append(self._library_panel)
# Stack # Stack
self.content_stack.add_child(self._connection_panel) self.content_stack.add_child(self._connection_panel)
self.panel_stack.add_titled_with_icon(self._server_panel, 'server-panel', locale.gettext("Server"), "network-wired-symbolic") self.panel_stack.add_titled(self._server_panel, 'server-panel', locale.gettext("Server"))
self.panel_stack.add_titled_with_icon(self._cover_panel, 'cover-panel', locale.gettext("Cover"), "image-x-generic-symbolic") self.panel_stack.add_titled_with_icon(self._cover_panel, 'cover-panel', locale.gettext("Cover"), "image-x-generic-symbolic")
self.panel_stack.add_titled_with_icon(self._playlist_panel, 'playlist-panel', locale.gettext("Playlist"), "view-list-symbolic") self.panel_stack.add_titled(self._playlist_panel, 'playlist-panel', locale.gettext("Playlist"))
self.panel_stack.add_titled_with_icon(self._library_panel, 'library-panel', locale.gettext("Library"), "emblem-music-symbolic") self.panel_stack.add_titled(self._library_panel, 'library-panel', locale.gettext("Library"))
# Header # Header
#self._playlist_panel.get_headerbar_standalone().connect('close', self.on_panel_close_standalone) #self._playlist_panel.get_headerbar_standalone().connect('close', self.on_panel_close_standalone)
#self._library_panel.get_headerbar_standalone().connect('close', self.on_panel_close_standalone) #self._library_panel.get_headerbar_standalone().connect('close', self.on_panel_close_standalone)
@ -137,7 +135,6 @@ class Window(Adw.ApplicationWindow):
# Signals # Signals
self.connect("notify::default-width", self.on_resize) self.connect("notify::default-width", self.on_resize)
self.connect("notify::default-height", self.on_resize)
self.connect("notify::maximized", self.on_maximized) self.connect("notify::maximized", self.on_maximized)
self.connect("notify::fullscreened", self.on_fullscreened) self.connect("notify::fullscreened", self.on_fullscreened)
self._connection_panel.connect('connection-changed', self.on_connection_panel_connection_changed) self._connection_panel.connect('connection-changed', self.on_connection_panel_connection_changed)
@ -233,7 +230,7 @@ class Window(Adw.ApplicationWindow):
def on_menu_toggle_fullscreen(self, action, value): def on_menu_toggle_fullscreen(self, action, value):
self.panel_stack.set_visible_child(self._cover_panel) self.panel_stack.set_visible_child(self.cover_panel_page)
if not self._state.get_property(WindowState.IS_FULLSCREENED): if not self._state.get_property(WindowState.IS_FULLSCREENED):
self.fullscreen() self.fullscreen()
else: else:
@ -255,8 +252,6 @@ class Window(Adw.ApplicationWindow):
if not self._state.get_property(WindowState.IS_MAXIMIZED): if not self._state.get_property(WindowState.IS_MAXIMIZED):
self._state.set_property(WindowState.WIDTH, width) self._state.set_property(WindowState.WIDTH, width)
self._state.set_property(WindowState.HEIGHT, height) self._state.set_property(WindowState.HEIGHT, height)
GObject.idle_add(self._playlist_panel.set_size, width, height)
GObject.idle_add(self._library_panel.set_size, width, height)
def on_maximized(self, widget, maximized): def on_maximized(self, widget, maximized):
@ -264,7 +259,7 @@ class Window(Adw.ApplicationWindow):
def on_fullscreened(self, widget, fullscreened): def on_fullscreened(self, widget, fullscreened):
self._fullscreen(self.is_fullscreen()) self._fullscreen(fullscreened is True)
# HeaderBar callbacks # HeaderBar callbacks
@ -303,16 +298,12 @@ class Window(Adw.ApplicationWindow):
# False # False
#) #)
def on_panel_open_standalone(self, panel): def on_panel_open_standalone(self, panel):
self.toolbar_view.add_top_bar(panel.get_headerbar_standalone()) self.set_titlebar(panel.get_headerbar_standalone())
self.toolbar_view.remove(self.headerbar)
def on_panel_close_standalone(self, panel): def on_panel_close_standalone(self, headerbar):
self.toolbar_view.add_top_bar(self.headerbar) self.set_titlebar(self.headerbar)
self.toolbar_view.remove(panel.get_headerbar_standalone())
def on_connection_panel_connection_changed(self, widget, host, port, password): def on_connection_panel_connection_changed(self, widget, host, port, password):
self._settings.set_string(Window.SETTING_HOST, host) self._settings.set_string(Window.SETTING_HOST, host)
@ -386,11 +377,11 @@ class Window(Adw.ApplicationWindow):
def on_library_panel_sort_order_changed(self, widget, sort_order): def on_library_panel_sort_order_changed(self, widget, sort_order):
self._settings.set_enum(Window.SETTING_SORT_ORDER, sort_order) self._settings.set_enum(Window.SETTING_SORT_ORDER, self._library_panel.get_sort_order())
def on_library_panel_sort_type_changed(self, widget, sort_type): def on_library_panel_sort_type_changed(self, widget, sort_type):
self._settings.set_boolean(Window.SETTING_SORT_TYPE, sort_type) self._settings.set_boolean(Window.SETTING_SORT_TYPE, self._library_panel.get_sort_type())
def on_library_panel_albumart(self, widget, album): def on_library_panel_albumart(self, widget, album):
@ -553,11 +544,17 @@ class Window(Adw.ApplicationWindow):
if self._state.get_property(WindowState.IS_FULLSCREENED): if self._state.get_property(WindowState.IS_FULLSCREENED):
self.headerbar.hide() self.headerbar.hide()
self._cover_panel.set_fullscreen(True) self._cover_panel.set_fullscreen(True)
self.set_cursor(Gdk.Cursor.new_from_name("none", None)) # Hide cursor
self.get_window().set_cursor(
Gdk.Cursor.new_from_name(Gdk.Display.get_default(), "none")
)
else: else:
self.headerbar.show() self.headerbar.show()
self._cover_panel.set_fullscreen(False) self._cover_panel.set_fullscreen(False)
self.set_cursor(Gdk.Cursor.new_from_name("default", None)) # Reset cursor
self.get_window().set_cursor(
Gdk.Cursor.new_from_name(Gdk.Display.get_default(), "default")
)
def _save_visible_panel(self): def _save_visible_panel(self):