Start implementation of database functionality, starting with table generation.
This database will be stored in the user's XDG_DATA_HOME directory under a folder called `com.github.joshstrobl.koto`. Refactored Koto Track Listing into a dedicated Disc View component, break apart out CDs / Discs into relevant Disc View components, sorting them by the disc and showing a label if there are more than one discs / CDs. Started using the row-activated event for our Artist GtkListBox instead of having press events on the artist buttons. Makes switching between artists far more reliable. Added a slide left / right stack animation and set its animation to 400ms so it's in the goldilocks zone (IMO) of not being too fast or too slow. Fix a warning related to scale factor fetching in the PlayerBar.
This commit is contained in:
parent
134b4d79a8
commit
eac4940c77
17 changed files with 434 additions and 61 deletions
|
@ -19,8 +19,8 @@
|
|||
#include <gtk-4.0/gtk/gtk.h>
|
||||
#include "../../indexer/album.h"
|
||||
#include "../../indexer/artist.h"
|
||||
#include "../../koto-track-item.h"
|
||||
#include "album-view.h"
|
||||
#include "disc-view.h"
|
||||
#include "koto-config.h"
|
||||
#include "koto-utils.h"
|
||||
|
||||
|
@ -29,7 +29,7 @@ struct _KotoAlbumView {
|
|||
KotoIndexedAlbum *album;
|
||||
GtkWidget *main;
|
||||
GtkWidget *album_tracks_box;
|
||||
GtkWidget *tracks;
|
||||
GtkWidget *discs;
|
||||
|
||||
GtkWidget *album_label;
|
||||
GHashTable *cd_to_track_listbox;
|
||||
|
@ -71,13 +71,15 @@ static void koto_album_view_init(KotoAlbumView *self) {
|
|||
gtk_widget_set_can_focus(self->main, FALSE);
|
||||
self->album_tracks_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
|
||||
|
||||
self->tracks = gtk_list_box_new(); // Create our list of our tracks
|
||||
gtk_list_box_set_sort_func(GTK_LIST_BOX(self->tracks), koto_album_view_sort_tracks, NULL, NULL); // Ensure we can sort our tracks
|
||||
gtk_widget_add_css_class(self->tracks, "track-list");
|
||||
gtk_widget_set_size_request(self->tracks, 600, -1);
|
||||
self->discs = gtk_list_box_new(); // Create our list of our tracks
|
||||
gtk_list_box_set_selection_mode(GTK_LIST_BOX(self->discs), GTK_SELECTION_NONE);
|
||||
gtk_list_box_set_sort_func(GTK_LIST_BOX(self->discs), koto_album_view_sort_discs, NULL, NULL); // Ensure we can sort our discs
|
||||
gtk_widget_add_css_class(self->discs, "discs-list");
|
||||
gtk_widget_set_can_focus(self->discs, FALSE);
|
||||
gtk_widget_set_size_request(self->discs, 600, -1);
|
||||
|
||||
gtk_box_append(GTK_BOX(self->main), self->album_tracks_box); // Add the tracks box to the art info combo box
|
||||
gtk_box_append(GTK_BOX(self->album_tracks_box), self->tracks); // Add the tracks list box to the albums tracks box
|
||||
gtk_box_append(GTK_BOX(self->album_tracks_box), self->discs); // Add the discs list box to the albums tracks box
|
||||
}
|
||||
|
||||
GtkWidget* koto_album_view_get_main(KotoAlbumView *self) {
|
||||
|
@ -134,40 +136,49 @@ void koto_album_view_set_album(KotoAlbumView *self, KotoIndexedAlbum *album) {
|
|||
gtk_widget_set_halign(self->album_label, GTK_ALIGN_START);
|
||||
gtk_box_prepend(GTK_BOX(self->album_tracks_box), self->album_label); // Prepend our new label to the album + tracks box
|
||||
|
||||
GList *t;
|
||||
for (t = koto_indexed_album_get_files(self->album); t != NULL; t = t->next) { // For each file / track
|
||||
KotoIndexedFile *file = (KotoIndexedFile*) t->data;
|
||||
KotoTrackItem *track_item = koto_track_item_new(file); // Create our new track item
|
||||
gtk_list_box_prepend(GTK_LIST_BOX(self->tracks), GTK_WIDGET(track_item)); // Add to our tracks list box
|
||||
GHashTable *discs = g_hash_table_new(g_str_hash, g_str_equal);
|
||||
GList *tracks = koto_indexed_album_get_files(album); // Get the tracks for this album
|
||||
|
||||
for (guint i = 0; i < g_list_length(tracks); i++) {
|
||||
KotoIndexedFile *file = (KotoIndexedFile*) g_list_nth_data(tracks, i); // Get the
|
||||
guint *disc_number;
|
||||
g_object_get(file, "cd", &disc_number, NULL);
|
||||
gchar *disc_num_as_str = g_strdup_printf("%u", GPOINTER_TO_UINT(disc_number));
|
||||
|
||||
if (g_hash_table_contains(discs, disc_num_as_str)) { // Already have this added
|
||||
continue; // Skip
|
||||
}
|
||||
|
||||
g_hash_table_insert(discs, disc_num_as_str, "0"); // Mark this disc number in the hash table
|
||||
KotoDiscView *disc_view = koto_disc_view_new(album, disc_number);
|
||||
gtk_list_box_append(GTK_LIST_BOX(self->discs), GTK_WIDGET(disc_view)); // Add the Disc View to the List Box
|
||||
}
|
||||
|
||||
if (g_list_length(g_hash_table_get_keys(discs)) == 1) { // Only have one album
|
||||
GtkListBoxRow *row = gtk_list_box_get_row_at_index(GTK_LIST_BOX(self->discs), 0); // Get the first item
|
||||
|
||||
if (GTK_IS_LIST_BOX_ROW(row)) { // Is a row
|
||||
koto_disc_view_set_disc_label_visible((KotoDiscView*) gtk_list_box_row_get_child(row), FALSE); // Get
|
||||
}
|
||||
}
|
||||
|
||||
g_hash_table_destroy(discs);
|
||||
}
|
||||
|
||||
int koto_album_view_sort_tracks(GtkListBoxRow *track1, GtkListBoxRow *track2, gpointer user_data) {
|
||||
int koto_album_view_sort_discs(GtkListBoxRow *disc1, GtkListBoxRow *disc2, gpointer user_data) {
|
||||
(void) user_data;
|
||||
KotoTrackItem *track1_item = KOTO_TRACK_ITEM(gtk_list_box_row_get_child(track1));
|
||||
KotoTrackItem *track2_item = KOTO_TRACK_ITEM(gtk_list_box_row_get_child(track2));
|
||||
KotoDiscView *disc1_item = KOTO_DISC_VIEW(gtk_list_box_row_get_child(disc1));
|
||||
KotoDiscView *disc2_item = KOTO_DISC_VIEW(gtk_list_box_row_get_child(disc2));
|
||||
|
||||
KotoIndexedFile *track1_file;
|
||||
KotoIndexedFile *track2_file;
|
||||
guint disc1_num;
|
||||
guint disc2_num;
|
||||
|
||||
g_object_get(track1_item, "track", &track1_file, NULL);
|
||||
g_object_get(track2_item, "track", &track2_file, NULL);
|
||||
g_object_get(disc1_item, "disc", &disc1_num, NULL);
|
||||
g_object_get(disc2_item, "disc", &disc2_num, NULL);
|
||||
|
||||
guint16 *track1_pos;
|
||||
guint16 *track2_pos;
|
||||
|
||||
g_object_get(track1_file, "position", &track1_pos, NULL);
|
||||
g_object_get(track2_file, "position", &track2_pos, NULL);
|
||||
|
||||
if (track1_pos == track2_pos) { // Identical positions (like reported as 0)
|
||||
gchar *track1_name;
|
||||
gchar *track2_name;
|
||||
|
||||
g_object_get(track1_file, "parsed-name", &track1_name, NULL);
|
||||
g_object_get(track2_file, "parsed-name", &track2_name, NULL);
|
||||
|
||||
return g_utf8_collate(track1_name, track2_name);
|
||||
} else if (track1_pos < track2_pos) {
|
||||
if (disc1_num == disc2_num) { // Identical positions (like reported as 0)
|
||||
return 0;
|
||||
} else if (disc1_num < disc2_num) {
|
||||
return -1;
|
||||
} else {
|
||||
return 1;
|
||||
|
|
|
@ -32,6 +32,6 @@ KotoAlbumView* koto_album_view_new(KotoIndexedAlbum *album);
|
|||
GtkWidget* koto_album_view_get_main(KotoAlbumView *self);
|
||||
void koto_album_view_add_track_to_listbox(KotoIndexedAlbum *self, KotoIndexedFile *file);
|
||||
void koto_album_view_set_album(KotoAlbumView *self, KotoIndexedAlbum *album);
|
||||
int koto_album_view_sort_tracks(GtkListBoxRow *track1, GtkListBoxRow *track2, gpointer user_data);
|
||||
int koto_album_view_sort_discs(GtkListBoxRow *track1, GtkListBoxRow *track2, gpointer user_data);
|
||||
|
||||
G_END_DECLS
|
||||
|
|
218
src/pages/music/disc-view.c
Normal file
218
src/pages/music/disc-view.c
Normal file
|
@ -0,0 +1,218 @@
|
|||
/* disc-view.c
|
||||
*
|
||||
* Copyright 2021 Joshua Strobl
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <gtk-4.0/gtk/gtk.h>
|
||||
#include "../../indexer/album.h"
|
||||
#include "../../koto-track-item.h"
|
||||
#include "disc-view.h"
|
||||
|
||||
struct _KotoDiscView {
|
||||
GtkBox parent_instance;
|
||||
KotoIndexedAlbum *album;
|
||||
GtkWidget *header;
|
||||
GtkWidget *label;
|
||||
GtkWidget *list;
|
||||
|
||||
guint *disc_number;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(KotoDiscView, koto_disc_view, GTK_TYPE_BOX);
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_DISC,
|
||||
PROP_ALBUM,
|
||||
N_PROPERTIES
|
||||
};
|
||||
|
||||
static GParamSpec *props[N_PROPERTIES] = { NULL, };
|
||||
static void koto_disc_view_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec);
|
||||
static void koto_disc_view_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec);
|
||||
|
||||
static void koto_disc_view_class_init(KotoDiscViewClass *c) {
|
||||
GObjectClass *gobject_class;
|
||||
gobject_class = G_OBJECT_CLASS(c);
|
||||
gobject_class->set_property = koto_disc_view_set_property;
|
||||
gobject_class->get_property = koto_disc_view_get_property;
|
||||
|
||||
props[PROP_DISC] = g_param_spec_uint(
|
||||
"disc",
|
||||
"Disc",
|
||||
"Disc",
|
||||
0,
|
||||
G_MAXUINT16,
|
||||
1,
|
||||
G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE
|
||||
);
|
||||
|
||||
props[PROP_ALBUM] = g_param_spec_object(
|
||||
"album",
|
||||
"Album",
|
||||
"Album",
|
||||
KOTO_TYPE_INDEXED_ALBUM,
|
||||
G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE
|
||||
);
|
||||
|
||||
g_object_class_install_properties(gobject_class, N_PROPERTIES, props);
|
||||
}
|
||||
|
||||
static void koto_disc_view_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec) {
|
||||
KotoDiscView *self = KOTO_DISC_VIEW(obj);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_DISC:
|
||||
g_value_set_uint(val, GPOINTER_TO_UINT(self->disc_number));
|
||||
break;
|
||||
case PROP_ALBUM:
|
||||
g_value_set_object(val, self->album);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, spec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void koto_disc_view_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec) {
|
||||
KotoDiscView *self = KOTO_DISC_VIEW(obj);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_DISC:
|
||||
koto_disc_view_set_disc_number(self, g_value_get_uint(val));
|
||||
break;
|
||||
case PROP_ALBUM:
|
||||
koto_disc_view_set_album(self, (KotoIndexedAlbum*) g_value_get_object(val));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, spec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void koto_disc_view_init(KotoDiscView *self) {
|
||||
gtk_widget_add_css_class(GTK_WIDGET(self), "disc-view");
|
||||
gtk_widget_set_can_focus(GTK_WIDGET(self), FALSE);
|
||||
self->header = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
gtk_widget_set_hexpand(self->header, TRUE);
|
||||
gtk_widget_set_size_request(self->header, 16, -1);
|
||||
|
||||
GtkWidget *ico = gtk_image_new_from_icon_name("drive-optical-symbolic");
|
||||
gtk_box_prepend(GTK_BOX(self->header), ico);
|
||||
|
||||
self->label = gtk_label_new(NULL); // Create an empty label
|
||||
gtk_widget_set_halign(self->label, GTK_ALIGN_START);
|
||||
gtk_widget_set_valign(self->label, GTK_ALIGN_CENTER);
|
||||
gtk_box_append(GTK_BOX(self->header), self->label);
|
||||
|
||||
gtk_box_append(GTK_BOX(self), self->header);
|
||||
}
|
||||
|
||||
void koto_disc_view_set_album(KotoDiscView *self, KotoIndexedAlbum *album) {
|
||||
if (album == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (self->album != NULL) {
|
||||
g_free(self->album);
|
||||
}
|
||||
|
||||
self->album = album;
|
||||
|
||||
if (GTK_IS_LIST_BOX(self->list)) { // Already have a listbox
|
||||
gtk_box_remove(GTK_BOX(self), self->list); // Remove the box
|
||||
g_object_unref(self->list); // Unref the list
|
||||
}
|
||||
|
||||
self->list = gtk_list_box_new(); // Create our list of our tracks
|
||||
gtk_list_box_set_selection_mode(GTK_LIST_BOX(self->list), GTK_SELECTION_MULTIPLE);
|
||||
gtk_list_box_set_sort_func(GTK_LIST_BOX(self->list), koto_album_view_sort_tracks, NULL, NULL); // Ensure we can sort our tracks
|
||||
gtk_widget_add_css_class(self->list, "track-list");
|
||||
gtk_widget_set_size_request(self->list, 600, -1);
|
||||
gtk_box_append(GTK_BOX(self), self->list);
|
||||
|
||||
GList *t;
|
||||
for (t = koto_indexed_album_get_files(self->album); t != NULL; t = t->next) { // For each file / track
|
||||
KotoIndexedFile *file = (KotoIndexedFile*) t->data;
|
||||
|
||||
guint *disc_number;
|
||||
g_object_get(file, "cd", &disc_number, NULL); // get the disc number
|
||||
|
||||
if (GPOINTER_TO_UINT(self->disc_number) != GPOINTER_TO_UINT(disc_number)) { // Track does not belong to this CD
|
||||
continue;
|
||||
}
|
||||
|
||||
KotoTrackItem *track_item = koto_track_item_new(file); // Create our new track item
|
||||
gtk_list_box_prepend(GTK_LIST_BOX(self->list), GTK_WIDGET(track_item)); // Add to our tracks list box
|
||||
}
|
||||
}
|
||||
|
||||
void koto_disc_view_set_disc_number(KotoDiscView *self, guint disc_number) {
|
||||
if (disc_number == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
self->disc_number = GUINT_TO_POINTER(disc_number);
|
||||
|
||||
gchar *disc_label = g_strdup_printf("Disc %u", disc_number);
|
||||
gtk_label_set_text(GTK_LABEL(self->label), disc_label); // Set the label
|
||||
|
||||
g_free(disc_label);
|
||||
}
|
||||
|
||||
void koto_disc_view_set_disc_label_visible(KotoDiscView *self, gboolean visible) {
|
||||
(visible) ? gtk_widget_show(self->header) : gtk_widget_hide(self->header);
|
||||
}
|
||||
|
||||
int koto_album_view_sort_tracks(GtkListBoxRow *track1, GtkListBoxRow *track2, gpointer user_data) {
|
||||
(void) user_data;
|
||||
KotoTrackItem *track1_item = KOTO_TRACK_ITEM(gtk_list_box_row_get_child(track1));
|
||||
KotoTrackItem *track2_item = KOTO_TRACK_ITEM(gtk_list_box_row_get_child(track2));
|
||||
|
||||
KotoIndexedFile *track1_file;
|
||||
KotoIndexedFile *track2_file;
|
||||
|
||||
g_object_get(track1_item, "track", &track1_file, NULL);
|
||||
g_object_get(track2_item, "track", &track2_file, NULL);
|
||||
|
||||
guint16 *track1_pos;
|
||||
guint16 *track2_pos;
|
||||
|
||||
g_object_get(track1_file, "position", &track1_pos, NULL);
|
||||
g_object_get(track2_file, "position", &track2_pos, NULL);
|
||||
|
||||
if (track1_pos == track2_pos) { // Identical positions (like reported as 0)
|
||||
gchar *track1_name;
|
||||
gchar *track2_name;
|
||||
|
||||
g_object_get(track1_file, "parsed-name", &track1_name, NULL);
|
||||
g_object_get(track2_file, "parsed-name", &track2_name, NULL);
|
||||
|
||||
return g_utf8_collate(track1_name, track2_name);
|
||||
} else if (track1_pos < track2_pos) {
|
||||
return -1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
KotoDiscView* koto_disc_view_new(KotoIndexedAlbum *album, guint *disc_number) {
|
||||
return g_object_new(KOTO_TYPE_DISC_VIEW,
|
||||
"disc", disc_number,
|
||||
"album", album,
|
||||
"orientation", GTK_ORIENTATION_VERTICAL,
|
||||
NULL
|
||||
);
|
||||
}
|
36
src/pages/music/disc-view.h
Normal file
36
src/pages/music/disc-view.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
/* disc-view.h
|
||||
*
|
||||
* Copyright 2021 Joshua Strobl
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <glib-2.0/glib-object.h>
|
||||
#include <gtk-4.0/gtk/gtk.h>
|
||||
#include "../../indexer/album.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define KOTO_TYPE_DISC_VIEW (koto_disc_view_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE(KotoDiscView, koto_disc_view, KOTO, DISC_VIEW, GtkBox)
|
||||
|
||||
KotoDiscView* koto_disc_view_new(KotoIndexedAlbum *album, guint *disc);
|
||||
void koto_disc_view_set_album(KotoDiscView *self, KotoIndexedAlbum *album);
|
||||
void koto_disc_view_set_disc_label_visible(KotoDiscView *self, gboolean visible);
|
||||
void koto_disc_view_set_disc_number(KotoDiscView *self, guint disc_number);
|
||||
int koto_album_view_sort_tracks(GtkListBoxRow *track1, GtkListBoxRow *track2, gpointer user_data);
|
||||
|
||||
G_END_DECLS
|
|
@ -117,17 +117,12 @@ void koto_page_music_local_add_artist(KotoPageMusicLocal *self, KotoIndexedArtis
|
|||
KotoArtistView *artist_view = koto_artist_view_new(); // Create our new artist view
|
||||
koto_artist_view_add_artist(artist_view, artist); // Add the artist
|
||||
gtk_stack_add_named(GTK_STACK(self->stack), koto_artist_view_get_main(artist_view), artist_name);
|
||||
|
||||
GtkGesture *controller = gtk_gesture_click_new(); // Create a new GtkGestureClick
|
||||
g_signal_connect(controller, "pressed", G_CALLBACK(koto_page_music_local_handle_artist_click), self);
|
||||
gtk_widget_add_controller(GTK_WIDGET(artist_button), GTK_EVENT_CONTROLLER(controller));
|
||||
}
|
||||
|
||||
void koto_page_music_local_handle_artist_click(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data) {
|
||||
(void) n_press; (void) x; (void) y;
|
||||
void koto_page_music_local_handle_artist_click(GtkListBox *box, GtkListBoxRow *row, gpointer data) {
|
||||
(void) box;
|
||||
KotoPageMusicLocal *self = (KotoPageMusicLocal*) data;
|
||||
GtkWidget *btn_widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); // Get the widget that applied to this gesture
|
||||
KotoButton *btn = KOTO_BUTTON(btn_widget);
|
||||
KotoButton *btn = KOTO_BUTTON(gtk_list_box_row_get_child(row));
|
||||
|
||||
gchar *artist_name;
|
||||
g_object_get(btn, "button-text", &artist_name, NULL);
|
||||
|
@ -169,6 +164,7 @@ void koto_page_music_local_set_library(KotoPageMusicLocal *self, KotoIndexedLibr
|
|||
gboolean list_created = GTK_IS_LIST_BOX(self->artist_list);
|
||||
|
||||
if (list_created) { // Successfully created our list
|
||||
g_signal_connect(GTK_LIST_BOX(self->artist_list), "row-activated", G_CALLBACK(koto_page_music_local_handle_artist_click), self);
|
||||
gtk_list_box_set_activate_on_single_click(GTK_LIST_BOX(self->artist_list), TRUE);
|
||||
gtk_list_box_set_selection_mode(GTK_LIST_BOX(self->artist_list), GTK_SELECTION_BROWSE);
|
||||
gtk_list_box_set_sort_func(GTK_LIST_BOX(self->artist_list), koto_page_music_local_sort_artists, NULL, NULL); // Add our sort function
|
||||
|
@ -181,6 +177,8 @@ void koto_page_music_local_set_library(KotoPageMusicLocal *self, KotoIndexedLibr
|
|||
gtk_widget_set_size_request(GTK_WIDGET(self->artist_list), 300, -1);
|
||||
|
||||
self->stack = gtk_stack_new(); // Create a new stack
|
||||
gtk_stack_set_transition_duration(GTK_STACK(self->stack), 400);
|
||||
gtk_stack_set_transition_type(GTK_STACK(self->stack), GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT);
|
||||
gtk_widget_set_hexpand(self->stack, TRUE);
|
||||
gboolean stack_created = GTK_IS_STACK(self->stack);
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ G_DECLARE_FINAL_TYPE (KotoPageMusicLocal, koto_page_music_local, KOTO, PAGE_MUSI
|
|||
|
||||
KotoPageMusicLocal* koto_page_music_local_new();
|
||||
void koto_page_music_local_add_artist(KotoPageMusicLocal *self, KotoIndexedArtist *artist);
|
||||
void koto_page_music_local_handle_artist_click(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data);
|
||||
void koto_page_music_local_handle_artist_click(GtkListBox *box, GtkListBoxRow *row, gpointer data);
|
||||
void koto_page_music_local_set_library(KotoPageMusicLocal *self, KotoIndexedLibrary *lib);
|
||||
int koto_page_music_local_sort_artists(GtkListBoxRow *artist1, GtkListBoxRow *artist2, gpointer user_data);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue