Simplify state management for main window

This commit is contained in:
Elias Projahn 2020-10-09 20:19:46 +02:00
parent c2d40fe56e
commit 0adbc889b2
2 changed files with 488 additions and 415 deletions

View file

@ -1,40 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.36.0 --> <!-- Generated with glade 3.38.1 -->
<interface> <interface>
<requires lib="gtk+" version="3.22" /> <requires lib="gtk+" version="3.22" />
<requires lib="libhandy" version="1.0" /> <requires lib="libhandy" version="1.0" />
<object class="HdyApplicationWindow" id="window"> <object class="HdyApplicationWindow" id="window">
<property name="can_focus">False</property> <property name="can-focus">False</property>
<property name="default_width">800</property> <property name="default-width">800</property>
<property name="default_height">566</property> <property name="default-height">566</property>
<child> <child>
<object class="HdyLeaflet" id="leaflet"> <object class="HdyLeaflet" id="leaflet">
<property name="visible">True</property> <property name="visible">True</property>
<property name="visible_child">sidebar_box</property> <property name="can-focus">False</property>
<property name="can_swipe_back">True</property> <property name="visible-child">sidebar_box</property>
<property name="can-swipe-back">True</property>
<child> <child>
<object class="GtkBox" id="sidebar_box"> <object class="GtkBox" id="sidebar_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="width-request">250</property> <property name="width-request">250</property>
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="hexpand">False</property> <property name="hexpand">False</property>
<property name="orientation">vertical</property>
<child> <child>
<object class="HdyHeaderBar" id="left_header"> <object class="HdyHeaderBar" id="left_header">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can-focus">False</property>
<property name="show_close_button">True</property> <property name="show-close-button">True</property>
<child> <child>
<object class="GtkMenuButton"> <object class="GtkMenuButton">
<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">True</property> <property name="receives-default">True</property>
<property name="menu_model">add_menu</property> <property name="menu-model">add_menu</property>
<child> <child>
<object class="GtkImage"> <object class="GtkImage">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can-focus">False</property>
<property name="icon_name">list-add-symbolic</property> <property name="icon-name">list-add-symbolic</property>
</object> </object>
</child> </child>
</object> </object>
@ -42,21 +43,21 @@
<child> <child>
<object class="GtkMenuButton"> <object class="GtkMenuButton">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="can-focus">True</property>
<property name="focus_on_click">False</property> <property name="focus-on-click">False</property>
<property name="receives_default">True</property> <property name="receives-default">True</property>
<property name="menu_model">add_menu</property> <property name="menu-model">add_menu</property>
<child> <child>
<object class="GtkImage"> <object class="GtkImage">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can-focus">False</property>
<property name="icon_name">open-menu-symbolic</property> <property name="icon-name">open-menu-symbolic</property>
</object> </object>
</child> </child>
</object> </object>
<packing> <packing>
<property name="pack_type">end</property> <property name="pack-type">end</property>
<property name="position">0</property> <property name="position">1</property>
</packing> </packing>
</child> </child>
</object> </object>
@ -69,21 +70,21 @@
<child> <child>
<object class="HdySearchBar"> <object class="HdySearchBar">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can-focus">False</property>
<property name="search-mode-enabled">True</property> <property name="search-mode-enabled">True</property>
<child> <child>
<object class="HdyClamp"> <object class="HdyClamp">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can-focus">False</property>
<property name="maximum-size">400</property> <property name="maximum-size">400</property>
<child> <child>
<object class="GtkSearchEntry" id="person_search_entry"> <object class="GtkSearchEntry" id="person_search_entry">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="can-focus">True</property>
<property name="primary_icon_name">edit-find-symbolic</property> <property name="primary-icon-name">edit-find-symbolic</property>
<property name="primary_icon_activatable">False</property> <property name="primary-icon-activatable">False</property>
<property name="primary_icon_sensitive">False</property> <property name="primary-icon-sensitive">False</property>
<property name="placeholder_text" translatable="yes">Search persons and ensembles …</property> <property name="placeholder-text" translatable="yes">Search persons and ensembles …</property>
</object> </object>
</child> </child>
</object> </object>
@ -96,28 +97,49 @@
</packing> </packing>
</child> </child>
<child> <child>
<object class="GtkScrolledWindow"> <object class="GtkStack" id="sidebar_stack">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="can-focus">False</property>
<property name="transition-type">crossfade</property>
<child> <child>
<object class="GtkViewport"> <object class="GtkSpinner">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can-focus">False</property>
<property name="shadow_type">none</property> <property name="active">True</property>
</object>
<packing>
<property name="name">loading</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can-focus">True</property>
<child> <child>
<object class="GtkListBox" id="person_list"> <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 type="placeholder"> <property name="shadow-type">none</property>
<object class="GtkLabel"> <child>
<object class="GtkListBox" id="person_list">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can-focus">False</property>
<property name="label" translatable="yes">No persons found.</property> <child type="placeholder">
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">No persons found.</property>
</object>
</child>
</object> </object>
</child> </child>
</object> </object>
</child> </child>
</object> </object>
<packing>
<property name="name">persons_list</property>
<property name="position">1</property>
</packing>
</child> </child>
</object> </object>
<packing> <packing>
@ -127,11 +149,14 @@
</packing> </packing>
</child> </child>
</object> </object>
<packing>
<property name="name">sidebar</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkSeparator"> <object class="GtkSeparator">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<style> <style>
<class name="sidebar" /> <class name="sidebar" />
@ -144,86 +169,21 @@
<child> <child>
<object class="GtkStack" id="stack"> <object class="GtkStack" id="stack">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can-focus">False</property>
<property name="transition_type">crossfade</property>
<property name="visible_child">empty_screen</property>
<property name="hexpand">True</property> <property name="hexpand">True</property>
<property name="transition-type">crossfade</property>
<child> <child>
<object class="GtkBox"> <object class="GtkBox" id="empty_screen">
<property name="visible">True</property> <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="HdyHeaderBar" id="header"> <object class="HdyHeaderBar" id="empty_header">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can-focus">False</property>
<property name="show_close_button">True</property> <property name="hexpand">True</property>
<property name="visible">True</property> <property name="title" translatable="yes">Musicus Editor</property>
<property name="can_focus">False</property> <property name="show-close-button">True</property>
<property name="show_close_button">True</property>
<child>
<object class="GtkRevealer">
<property name="reveal-child" bind-source="leaflet" bind-property="folded" bind-flags="sync-create" />
<property name="transition-duration" bind-source="leaflet" bind-property="mode-transition-duration" bind-flags="bidirectional|sync-create" />
<property name="transition-type">crossfade</property>
<property name="visible">True</property>
<child>
<object class="GtkButton" id="back_button">
<property name="action_name">win.back</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">go-previous-symbolic</property>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="pack_type">start</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkMenuButton" id="header_menu_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="focus_on_click">False</property>
<property name="receives_default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">view-more-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkToggleButton" id="search_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">edit-find-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="pack_type">end</property>
<property name="position">1</property>
</packing>
</child>
</object> </object>
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
@ -231,179 +191,10 @@
<property name="position">0</property> <property name="position">0</property>
</packing> </packing>
</child> </child>
<child>
<object class="HdySearchBar">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="search-mode-enabled" bind-source="search_button" bind-property="active" bind-flags="bidirectional|sync-create"></property>
<child>
<object class="HdyClamp">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="maximum-size">400</property>
<child>
<object class="GtkSearchEntry" id="search_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 works and recordings …</property>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can_focus">True</property>
<child>
<object class="GtkViewport">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="border_width">18</property>
<property name="orientation">vertical</property>
<property name="spacing">18</property>
<child>
<object class="GtkBox" id="work_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">12</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Works</property>
<attributes>
<attribute name="size" value="12288" />
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkFrame">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkListBox" id="work_list">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="recording_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">12</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Recordings</property>
<attributes>
<attribute name="size" value="12288" />
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkFrame">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkListBox" id="recording_list">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="height-request">200</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="name">person_screen</property>
</packing>
</child>
<child>
<object class="GtkBox" id="empty_screen">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<child>
<object class="HdyHeaderBar" id="empty_header">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="hexpand">true</property>
<property name="title" translatable="yes">Musicus Editor</property>
<property name="show_close_button">True</property>
</object>
</child>
<child> <child>
<object class="GtkBox"> <object class="GtkBox">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can-focus">False</property>
<property name="halign">center</property> <property name="halign">center</property>
<property name="valign">center</property> <property name="valign">center</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
@ -411,10 +202,10 @@
<child> <child>
<object class="GtkImage"> <object class="GtkImage">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can-focus">False</property>
<property name="opacity">0.5</property> <property name="opacity">0.5</property>
<property name="pixel_size">80</property> <property name="pixel-size">80</property>
<property name="icon_name">folder-music-symbolic</property> <property name="icon-name">folder-music-symbolic</property>
</object> </object>
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
@ -425,7 +216,7 @@
<child> <child>
<object class="GtkLabel"> <object class="GtkLabel">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can-focus">False</property>
<property name="opacity">0.5</property> <property name="opacity">0.5</property>
<property name="label" translatable="yes">Welcome to Musicus Editor!</property> <property name="label" translatable="yes">Welcome to Musicus Editor!</property>
<attributes> <attributes>
@ -441,12 +232,12 @@
<child> <child>
<object class="GtkLabel"> <object class="GtkLabel">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can-focus">False</property>
<property name="opacity">0.5</property> <property name="opacity">0.5</property>
<property name="label" translatable="yes">Get startet by selecting something from the sidebar or adding new things to your library using the button in the top left corner.</property> <property name="label" translatable="yes">Get startet by selecting something from the sidebar or adding new things to your library using the button in the top left corner.</property>
<property name="justify">center</property> <property name="justify">center</property>
<property name="wrap">True</property> <property name="wrap">True</property>
<property name="max_width_chars">40</property> <property name="max-width-chars">40</property>
</object> </object>
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
@ -466,7 +257,268 @@
<property name="name">empty_screen</property> <property name="name">empty_screen</property>
</packing> </packing>
</child> </child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="HdyHeaderBar" id="header">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="show-close-button">True</property>
<child>
<object class="GtkRevealer">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="transition-type">crossfade</property>
<property name="transition-duration" bind-source="leaflet" bind-property="mode-transition-duration" bind-flags="bidirectional|sync-create">0</property>
<property name="reveal-child" bind-source="leaflet" bind-property="folded" bind-flags="sync-create">False</property>
<child>
<object class="GtkButton" id="back_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="action-name">win.back</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">go-previous-symbolic</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkMenuButton" id="header_menu_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="focus-on-click">False</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">view-more-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="pack-type">end</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkToggleButton" id="search_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">edit-find-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="pack-type">end</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="HdySearchBar">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="search-mode-enabled" bind-source="search_button" bind-property="active" bind-flags="bidirectional|sync-create">False</property>
<child>
<object class="HdyClamp">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="maximum-size">400</property>
<child>
<object class="GtkSearchEntry" id="search_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 works and recordings …</property>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkStack" id="content_stack">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="transition-type">crossfade</property>
<child>
<object class="GtkSpinner">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="active">True</property>
</object>
<packing>
<property name="name">loading</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can-focus">True</property>
<child>
<object class="GtkViewport">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="shadow-type">none</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="border-width">18</property>
<property name="orientation">vertical</property>
<property name="spacing">18</property>
<child>
<object class="GtkBox" id="work_box">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">12</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Works</property>
<attributes>
<attribute name="size" value="12288" />
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkFrame">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label-xalign">0</property>
<property name="shadow-type">in</property>
<child>
<object class="GtkListBox" id="work_list">
<property name="visible">True</property>
<property name="can-focus">False</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="recording_box">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">12</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Recordings</property>
<attributes>
<attribute name="size" value="12288" />
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkFrame">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label-xalign">0</property>
<property name="shadow-type">in</property>
<child>
<object class="GtkListBox" id="recording_list">
<property name="height-request">200</property>
<property name="visible">True</property>
<property name="can-focus">False</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="name">content</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="name">person_screen</property>
<property name="position">1</property>
</packing>
</child>
</object> </object>
<packing>
<property name="name">content</property>
</packing>
</child> </child>
</object> </object>
</child> </child>

View file

@ -7,41 +7,50 @@ use gtk::prelude::*;
use gtk_macros::{action, get_widget}; use gtk_macros::{action, get_widget};
use libhandy::prelude::*; use libhandy::prelude::*;
use libhandy::HeaderBarExt; use libhandy::HeaderBarExt;
use std::cell::RefCell; use std::cell::Cell;
use std::convert::TryInto; use std::convert::TryInto;
use std::rc::Rc; use std::rc::Rc;
enum WindowState {
Loading,
Persons(Vec<Person>),
PersonLoading(Person),
Person(Vec<WorkDescription>, Vec<RecordingDescription>),
}
pub struct Window { pub struct Window {
window: libhandy::ApplicationWindow, window: libhandy::ApplicationWindow,
backend: Rc<Backend>, backend: Rc<Backend>,
leaflet: libhandy::Leaflet, leaflet: libhandy::Leaflet,
persons: RefCell<Vec<Person>>, sidebar_stack: gtk::Stack,
works: RefCell<Vec<WorkDescription>>,
recordings: RefCell<Vec<RecordingDescription>>,
sidebar_box: gtk::Box,
person_search_entry: gtk::SearchEntry, person_search_entry: gtk::SearchEntry,
person_list: gtk::ListBox, person_list: gtk::ListBox,
stack: gtk::Stack, stack: gtk::Stack,
header: libhandy::HeaderBar, header: libhandy::HeaderBar,
header_menu_button: gtk::MenuButton, header_menu_button: gtk::MenuButton,
content_stack: gtk::Stack,
work_box: gtk::Box, work_box: gtk::Box,
work_list: gtk::ListBox, work_list: gtk::ListBox,
recording_box: gtk::Box, recording_box: gtk::Box,
recording_list: gtk::ListBox, recording_list: gtk::ListBox,
person_list_row_activated_handler_id: Cell<Option<glib::SignalHandlerId>>,
} }
impl Window { impl Window {
pub fn new(app: &gtk::Application) -> Rc<Self> { pub fn new(app: &gtk::Application) -> Rc<Self> {
use WindowState::*;
let builder = gtk::Builder::from_resource("/de/johrpan/musicus_editor/ui/window.ui"); let builder = gtk::Builder::from_resource("/de/johrpan/musicus_editor/ui/window.ui");
get_widget!(builder, libhandy::ApplicationWindow, window); get_widget!(builder, libhandy::ApplicationWindow, window);
get_widget!(builder, libhandy::Leaflet, leaflet); get_widget!(builder, libhandy::Leaflet, leaflet);
get_widget!(builder, gtk::Box, sidebar_box);
get_widget!(builder, gtk::SearchEntry, person_search_entry); get_widget!(builder, gtk::SearchEntry, person_search_entry);
get_widget!(builder, gtk::Stack, sidebar_stack);
get_widget!(builder, gtk::ListBox, person_list); get_widget!(builder, gtk::ListBox, person_list);
get_widget!(builder, gtk::Stack, stack); get_widget!(builder, gtk::Stack, stack);
get_widget!(builder, libhandy::HeaderBar, header); get_widget!(builder, libhandy::HeaderBar, header);
get_widget!(builder, gtk::MenuButton, header_menu_button); get_widget!(builder, gtk::MenuButton, header_menu_button);
get_widget!(builder, gtk::Stack, content_stack);
get_widget!(builder, gtk::Box, work_box); get_widget!(builder, gtk::Box, work_box);
get_widget!(builder, gtk::ListBox, work_list); get_widget!(builder, gtk::ListBox, work_list);
get_widget!(builder, gtk::Box, recording_box); get_widget!(builder, gtk::Box, recording_box);
@ -53,49 +62,20 @@ impl Window {
window: window, window: window,
backend: Rc::new(backend), backend: Rc::new(backend),
leaflet: leaflet, leaflet: leaflet,
persons: RefCell::new(Vec::new()), sidebar_stack: sidebar_stack,
works: RefCell::new(Vec::new()),
recordings: RefCell::new(Vec::new()),
sidebar_box: sidebar_box,
person_list: person_list, person_list: person_list,
person_search_entry: person_search_entry, person_search_entry: person_search_entry,
stack: stack, stack: stack,
header: header, header: header,
header_menu_button: header_menu_button, header_menu_button: header_menu_button,
content_stack: content_stack,
work_box: work_box, work_box: work_box,
work_list: work_list, work_list: work_list,
recording_box: recording_box, recording_box: recording_box,
recording_list: recording_list, recording_list: recording_list,
person_list_row_activated_handler_id: Cell::new(None),
}); });
result
.person_list
.connect_row_activated(clone!(@strong result => move |_, row| {
let row = row.get_child().unwrap().downcast::<SelectorRow>().unwrap();
let index: usize = row.get_index().try_into().unwrap();
let person = result.persons.borrow()[index].clone();
result.show_person(person);
}));
result
.person_list
.set_filter_func(Some(Box::new(clone!(@strong result => move |row| {
let row = row.get_child().unwrap().downcast::<SelectorRow>().unwrap();
let index: usize = row.get_index().try_into().unwrap();
let search = result.person_search_entry.get_text().to_string().to_lowercase();
search.is_empty() || result.persons.borrow()[index]
.name_lf()
.to_lowercase()
.contains(&search)
}))));
result
.person_search_entry
.connect_search_changed(clone!(@strong result => move |_| {
result.person_list.invalidate_filter();
}));
action!( action!(
result.window, result.window,
"back", "back",
@ -109,10 +89,7 @@ impl Window {
"add-person", "add-person",
clone!(@strong result => move |_, _| { clone!(@strong result => move |_, _| {
PersonEditor::new(result.backend.clone(), &result.window, None, clone!(@strong result => move |_| { PersonEditor::new(result.backend.clone(), &result.window, None, clone!(@strong result => move |_| {
result.backend.get_persons(clone!(@strong result => move |persons| { result.clone().set_state(Loading);
result.persons.replace(persons);
result.show_persons();
}));
})).show(); })).show();
}) })
); );
@ -132,10 +109,7 @@ impl Window {
"add-work", "add-work",
clone!(@strong result => move |_, _| { clone!(@strong result => move |_, _| {
WorkEditor::new(result.backend.clone(), &result.window, None, clone!(@strong result => move |_| { WorkEditor::new(result.backend.clone(), &result.window, None, clone!(@strong result => move |_| {
result.backend.get_persons(clone!(@strong result => move |persons| { result.clone().set_state(Loading);
result.persons.replace(persons);
result.show_persons();
}));
})).show(); })).show();
}) })
); );
@ -161,11 +135,8 @@ impl Window {
clone!(@strong result => move |_, id| { clone!(@strong result => move |_, id| {
result.backend.get_person(id.unwrap().get().unwrap(), clone!(@strong result => move |person| { result.backend.get_person(id.unwrap().get().unwrap(), clone!(@strong result => move |person| {
let person = person.unwrap(); let person = person.unwrap();
PersonEditor::new(result.backend.clone(), &result.window, Some(person), clone!(@strong result => move |person| { PersonEditor::new(result.backend.clone(), &result.window, Some(person), clone!(@strong result => move |_| {
result.backend.get_persons(clone!(@strong result => move |persons| { result.clone().set_state(Loading);
result.persons.replace(persons);
result.show_persons();
}));
})).show(); })).show();
})); }));
}) })
@ -177,17 +148,19 @@ impl Window {
Some(glib::VariantTy::new("x").unwrap()), Some(glib::VariantTy::new("x").unwrap()),
clone!(@strong result => move |_, id| { clone!(@strong result => move |_, id| {
result.backend.delete_person(id.unwrap().get().unwrap(), clone!(@strong result => move |_| { result.backend.delete_person(id.unwrap().get().unwrap(), clone!(@strong result => move |_| {
result.back(); result.clone().set_state(Loading);
result.backend.get_persons(clone!(@strong result => move |persons| {
result.persons.replace(persons);
result.show_persons();
}));
})); }));
}) })
); );
result
.person_search_entry
.connect_search_changed(clone!(@strong result => move |_| {
result.person_list.invalidate_filter();
}));
result.window.set_application(Some(app)); result.window.set_application(Some(app));
result.show_persons(); result.clone().set_state(Loading);
result result
} }
@ -196,85 +169,133 @@ impl Window {
self.window.present(); self.window.present();
} }
fn show_persons(&self) { fn set_state(self: Rc<Self>, state: WindowState) {
for child in self.person_list.get_children() { use WindowState::*;
self.person_list.remove(&child);
}
for (index, person) in self.persons.borrow().iter().enumerate() { match state {
let label = gtk::Label::new(Some(&person.name_lf())); Loading => {
label.set_halign(gtk::Align::Start); self.backend
let row = SelectorRow::new(index.try_into().unwrap(), &label); .get_persons(clone!(@strong self as self_ => move |persons| {
row.show_all(); self_.clone().set_state(Persons(persons));
self.person_list.insert(&row, -1); }));
}
}
fn show_person(&self, person: Person) { self.sidebar_stack.set_visible_child_name("loading");
self.header.set_title(Some(&person.name_fl())); self.stack.set_visible_child_name("empty_screen");
let edit_menu_item = gio::MenuItem::new(Some("Edit person"), None); self.leaflet.set_visible_child_name("sidebar");
edit_menu_item.set_action_and_target_value( }
Some("win.edit-person"), Persons(persons) => {
Some(&glib::Variant::from(person.id)), for child in self.person_list.get_children() {
); self.person_list.remove(&child);
let delete_menu_item = gio::MenuItem::new(Some("Delete person"), None); }
delete_menu_item.set_action_and_target_value(
Some("win.delete-person"),
Some(&glib::Variant::from(person.id)),
);
let menu = gio::Menu::new();
menu.append_item(&edit_menu_item);
menu.append_item(&delete_menu_item);
self.header_menu_button.set_menu_model(Some(&menu)); for (index, person) in persons.iter().enumerate() {
let label = gtk::Label::new(Some(&person.name_lf()));
label.set_halign(gtk::Align::Start);
let row = SelectorRow::new(index.try_into().unwrap(), &label);
row.show_all();
self.person_list.insert(&row, -1);
}
// let result = self.clone(); match self.person_list_row_activated_handler_id.take() {
// self.backend.get_work_descriptions(person.id, |works| { Some(id) => self.person_list.disconnect(id),
// result.show_works(); None => (),
// result.show_recordings(); }
// result.stack.set_visible_child_name("person_screen");
// result.leaflet.set_visible_child(&result.stack);
// });
}
fn show_works(&self) { let handler_id = self.person_list.connect_row_activated(
for child in self.work_list.get_children() { clone!(@strong self as self_, @strong persons => move |_, row| {
self.work_list.remove(&child); let row = row.get_child().unwrap().downcast::<SelectorRow>().unwrap();
} let index: usize = row.get_index().try_into().unwrap();
let person = persons[index].clone();
self_.clone().set_state(PersonLoading(person));
}),
);
let works = self.works.borrow(); self.person_list_row_activated_handler_id
.set(Some(handler_id));
if works.is_empty() { self.person_list.set_filter_func(Some(Box::new(
self.work_box.hide(); clone!(@strong self as self_, @strong persons => move |row| {
} else { let row = row.get_child().unwrap().downcast::<SelectorRow>().unwrap();
self.work_box.show(); let index: usize = row.get_index().try_into().unwrap();
} let search = self_.person_search_entry.get_text().to_string().to_lowercase();
for (index, work) in works.iter().enumerate() { search.is_empty() || persons[index]
let label = gtk::Label::new(Some(&work.title)); .name_lf()
label.set_halign(gtk::Align::Start); .to_lowercase()
let row = SelectorRow::new(index.try_into().unwrap(), &label); .contains(&search)
row.show_all(); }),
self.work_list.insert(&row, -1); )));
}
}
fn show_recordings(&self) { self.sidebar_stack.set_visible_child_name("persons_list");
for child in self.recording_list.get_children() { self.stack.set_visible_child_name("empty_screen");
self.recording_list.remove(&child); self.leaflet.set_visible_child_name("sidebar");
} }
PersonLoading(person) => {
self.header.set_title(Some(&person.name_fl()));
let recordings = self.recordings.borrow(); let edit_menu_item = gio::MenuItem::new(Some("Edit person"), None);
edit_menu_item.set_action_and_target_value(
Some("win.edit-person"),
Some(&glib::Variant::from(person.id)),
);
if recordings.is_empty() { let delete_menu_item = gio::MenuItem::new(Some("Delete person"), None);
self.recording_box.hide(); delete_menu_item.set_action_and_target_value(
} else { Some("win.delete-person"),
self.recording_box.show(); Some(&glib::Variant::from(person.id)),
);
let menu = gio::Menu::new();
menu.append_item(&edit_menu_item);
menu.append_item(&delete_menu_item);
self.header_menu_button.set_menu_model(Some(&menu));
self.backend.get_work_descriptions(
person.id,
clone!(@strong self as self_ => move |works| {
self_.clone().set_state(Person(works, Vec::new()));
}),
);
self.content_stack.set_visible_child_name("loading");
self.stack.set_visible_child_name("person_screen");
self.leaflet.set_visible_child_name("content");
}
Person(works, recordings) => {
for child in self.work_list.get_children() {
self.work_list.remove(&child);
}
if works.is_empty() {
self.work_box.hide();
} else {
self.work_box.show();
}
for (index, work) in works.iter().enumerate() {
let label = gtk::Label::new(Some(&work.title));
label.set_halign(gtk::Align::Start);
let row = SelectorRow::new(index.try_into().unwrap(), &label);
row.show_all();
self.work_list.insert(&row, -1);
}
if recordings.is_empty() {
self.recording_box.hide();
} else {
self.recording_box.show();
}
self.content_stack.set_visible_child_name("content");
self.stack.set_visible_child_name("person_screen");
self.leaflet.set_visible_child_name("content");
}
} }
} }
fn back(&self) { fn back(&self) {
self.stack.set_visible_child_name("empty_screen"); self.stack.set_visible_child_name("empty_screen");
self.leaflet.set_visible_child(&self.sidebar_box); self.leaflet.set_visible_child_name("sidebar");
} }
} }