Deprecate KotoFlipperButton, integrate flip functionality with an alt image into KotoButton.

We are now leveraging KotoButton in the KotoPlayerBar and KotoExpander. Dropped Glade UI templating from KotoWindow, set its default size using gtk_widget_set_size_request to force a minimum window size, set window title, WMClass, and icon name.

Start implementing KotoIndexedFile class to handle our provided audio files, setting its file name and attempting to parse the file name when we are not using ID3 data. The parsing is as follows:

- All `_` are replaced with whitespace
- We will attempt to remove nested references to the artist and album name (we need to implemented the relevant classes to leverage that).
- Remove any references to ` - ` followed by any stragglers `-` (without the whitespace around it).
- Split based on `.` and remove the trailing file extension, preserving the rest (so something like `Ch. 01.ogg` would be considered just `Ch. 01`).
This commit is contained in:
Joshua Strobl 2021-02-12 12:56:41 +02:00
parent 625c1be645
commit 9b6fa4593a
19 changed files with 472 additions and 333 deletions

View file

@ -18,14 +18,9 @@
#include <dirent.h>
#include <magic.h>
#include <sys/stat.h>
#include "file.h"
#include "file-indexer.h"
struct KotoIndexedFile {
GObject parent_instance;
gchar *file_name;
gchar *path;
};
struct KotoIndexedAlbum {
GObject parent_instance;
gboolean has_album_art;
@ -41,7 +36,7 @@ struct _KotoIndexedArtist {
gchar *artist_name;
GHashTable *albums;
gchar *path;
}
};
struct _KotoIndexedLibrary {
GObject parent_instance;
@ -74,12 +69,16 @@ static void koto_indexed_library_class_init(KotoIndexedLibraryClass *c) {
"Path",
"Path to Music",
NULL,
G_PARAM_CONSTRUCT_ONLY|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE
G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE
);
g_object_class_install_properties(gobject_class, N_PROPERTIES, props);
}
static void koto_indexed_library_init(KotoIndexedLibrary *self) {
self->music_artists = g_hash_table_new(g_str_hash, g_str_equal);
}
static void koto_indexed_library_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec) {
KotoIndexedLibrary *self = KOTO_INDEXED_LIBRARY(obj);
@ -175,18 +174,29 @@ void index_file(KotoIndexedLibrary *self, gchar *path) {
g_str_has_prefix(mime_info[0], "audio/") || // Is audio
g_str_has_prefix(mime_info[0], "image/") // Is image
) {
g_message("File Name: %s", path);
//g_message("File Name: %s", path);
}
if (g_str_has_prefix(mime_info[0], "audio/")) { // Is an audio file
KotoIndexedFile *file = koto_indexed_file_new(path);
gchar *filepath;
gchar *parsed_name;
g_object_get(file,
"path", &filepath,
"parsed-name", &parsed_name,
NULL);
g_free(filepath);
g_free(parsed_name);
g_object_unref(file);
}
g_strfreev(mime_info); // Free our mimeinfo
}
static void koto_indexed_library_init(KotoIndexedLibrary *self) {
self->files = g_hash_table_new(g_str_hash, g_str_equal);
}
KotoIndexedLibrary* koto_indexed_library_new(const gchar *path) {
return g_object_new(KOTO_INDEXED_TYPE_LIBRARY,
return g_object_new(KOTO_TYPE_INDEXED_LIBRARY,
"path", path,
NULL
);

View file

@ -20,14 +20,10 @@
G_BEGIN_DECLS
#define KOTO_INDEXED_TYPE_FILE koto_indexed_file_get_type()
G_DECLARE_FINAL_TYPE(KotoIndexedFile, koto_indexed_file, KOTO, INDEXED_FILE, GObject);
#define KOTO_INDEXED_TYPE_LIBRARY koto_indexed_library_get_type()
#define KOTO_TYPE_INDEXED_LIBRARY koto_indexed_library_get_type()
G_DECLARE_FINAL_TYPE(KotoIndexedLibrary, koto_indexed_library, KOTO, INDEXED_LIBRARY, GObject);
KotoIndexedLibrary* koto_indexed_library_new(const gchar *path);
KotoIndexedFile* koto_indexed_file_new(gchar *path);
void start_indexing(KotoIndexedLibrary *self);
void index_folder(KotoIndexedLibrary *self, gchar *path);

274
src/indexer/file.c Normal file
View file

@ -0,0 +1,274 @@
/* file.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 <glib-2.0/glib.h>
#include "file.h"
struct _KotoIndexedFile {
GObject parent_instance;
gchar *path;
gchar *file_name;
gchar *parsed_name;
gchar *artist;
gchar *album;
guint position;
gboolean acquired_metadata_from_id3;
};
G_DEFINE_TYPE(KotoIndexedFile, koto_indexed_file, G_TYPE_OBJECT);
enum {
PROP_0,
PROP_PATH,
PROP_ARTIST,
PROP_ALBUM,
PROP_FILE_NAME,
PROP_PARSED_NAME,
PROP_POSITION,
N_PROPERTIES
};
static GParamSpec *props[N_PROPERTIES] = { NULL };
static void koto_indexed_file_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec);
static void koto_indexed_file_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec);
static void koto_indexed_file_class_init(KotoIndexedFileClass *c) {
GObjectClass *gobject_class;
gobject_class = G_OBJECT_CLASS(c);
gobject_class->set_property = koto_indexed_file_set_property;
gobject_class->get_property = koto_indexed_file_get_property;
props[PROP_PATH] = g_param_spec_string(
"path",
"Path",
"Path to File",
NULL,
G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE
);
props[PROP_ARTIST] = g_param_spec_string(
"artist",
"Name of Artist",
"Name of Artist",
NULL,
G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE
);
props[PROP_ALBUM] = g_param_spec_string(
"album",
"Name of Album",
"Name of Album",
NULL,
G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE
);
props[PROP_FILE_NAME] = g_param_spec_string(
"file-name",
"Name of File",
"Name of File",
NULL,
G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE
);
props[PROP_PARSED_NAME] = g_param_spec_string(
"parsed-name",
"Parsed Name of File",
"Parsed Name of File",
NULL,
G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE
);
props[PROP_POSITION] = g_param_spec_uint(
"position",
"Position in Audiobook, Album, etc.",
"Position in Audiobook, Album, etc.",
0,
G_MAXUINT16,
0,
G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE
);
g_object_class_install_properties(gobject_class, N_PROPERTIES, props);
}
static void koto_indexed_file_init(KotoIndexedFile *self) {
self->acquired_metadata_from_id3 = FALSE;
}
static void koto_indexed_file_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec) {
KotoIndexedFile *self = KOTO_INDEXED_FILE(obj);
switch (prop_id) {
case PROP_PATH:
g_value_set_string(val, self->path);
break;
case PROP_ARTIST:
g_value_set_string(val, self->artist);
break;
case PROP_ALBUM:
g_value_set_string(val, self->album);
break;
case PROP_FILE_NAME:
g_value_set_string(val, self->file_name);
break;
case PROP_PARSED_NAME:
g_value_set_string(val, self->parsed_name);
break;
case PROP_POSITION:
g_value_set_uint(val, self->position);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, spec);
break;
}
}
static void koto_indexed_file_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec) {
KotoIndexedFile *self = KOTO_INDEXED_FILE(obj);
switch (prop_id) {
case PROP_PATH:
self->path = g_strdup(g_value_get_string(val)); // Update our path
koto_indexed_file_set_file_name(self, g_path_get_basename(self->path)); // Update our file name
break;
case PROP_ARTIST:
self->artist = g_strdup(g_value_get_string(val));
break;
case PROP_ALBUM:
self->album = g_strdup(g_value_get_string(val));
break;
case PROP_FILE_NAME:
koto_indexed_file_set_file_name(self, g_strdup(g_value_get_string(val))); // Update the file name
break;
case PROP_PARSED_NAME:
koto_indexed_file_set_parsed_name(self, g_strdup(g_value_get_string(val)));
break;
case PROP_POSITION:
self->position = g_value_get_uint(val);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, spec);
break;
}
}
void koto_indexed_file_set_file_name(KotoIndexedFile *self, gchar *new_file_name) {
if (new_file_name == NULL) {
return;
}
if ((self->file_name != NULL) && (strcmp(self->file_name, new_file_name) == 0)) { // Not null and the same
return; // Don't do anything
}
if (self->file_name != NULL) { // If it is defined
g_free(self->file_name);
}
self->file_name = g_strdup(new_file_name);
g_object_notify_by_pspec(G_OBJECT(self), props[PROP_FILE_NAME]);
if (!self->acquired_metadata_from_id3) { // Haven't acquired our information from ID3
koto_indexed_file_parse_name(self); // Update our parsed name
}
}
void koto_indexed_file_set_parsed_name(KotoIndexedFile *self, gchar *new_parsed_name) {
if (new_parsed_name == NULL) {
return;
}
if ((self->parsed_name != NULL) && (strcmp(self->parsed_name, new_parsed_name) == 0)) { // Not null and the same
return; // Don't do anything
}
if (self->parsed_name != NULL) {
g_free(self->parsed_name);
}
self->parsed_name = g_strdup(new_parsed_name);
g_object_notify_by_pspec(G_OBJECT(self), props[PROP_PARSED_NAME]);
}
void koto_indexed_file_parse_name(KotoIndexedFile *self) {
gchar *copied_file_name = g_strdelimit(g_strdup(self->file_name), "_", ' '); // Replace _ with whitespace for starters
if (self->artist != NULL && strcmp(self->artist, "") != 0) { // If we have artist set
gchar **split = g_strsplit(copied_file_name, self->artist, -1); // Split whenever we encounter the artist
copied_file_name = g_strjoinv("", split); // Remove the artist
g_strfreev(split);
}
if (self->artist != NULL && strcmp(self->album, "") != 0) { // If we have album set
gchar **split = g_strsplit(copied_file_name, self->album, -1); // Split whenever we encounter the album
copied_file_name = g_strjoinv("", split); // Remove the album
g_strfreev(split);
split = g_strsplit(copied_file_name, g_utf8_strdown(self->album, g_utf8_strlen(self->album, -1)), -1); // Split whenever we encounter the album lowercased
copied_file_name = g_strjoin("", split, NULL); // Remove the lowercased album
g_strfreev(split);
}
if (g_str_match_string(copied_file_name, "-", FALSE)) { // Contains - like a heathen
gchar **split = g_strsplit(copied_file_name, " - ", -1); // Split whenever we encounter " - "
copied_file_name = g_strjoin("", split, NULL); // Remove entirely
g_strfreev(split);
if (g_str_match_string(copied_file_name, "-", FALSE)) { // If we have any stragglers
split = g_strsplit(copied_file_name, "-", -1); // Split whenever we encounter -
copied_file_name = g_strjoin("", split, NULL); // Remove entirely
g_strfreev(split);
}
}
gchar **split = g_strsplit(copied_file_name, ".", -1); // Split every time we see .
g_free(copied_file_name);
guint len_of_extension_split = g_strv_length(split);
if (len_of_extension_split == 2) { // Only have two elements
copied_file_name = g_strdup(split[0]); // Get the first element
} else {
gchar *new_parsed_name = "";
for (guint i = 0; i < len_of_extension_split - 1; i++) { // Iterate over everything except the last item
if (g_strcmp0(new_parsed_name, "") == 0) { // Currently empty
new_parsed_name = g_strdup(split[i]); // Just duplicate this string
} else {
gchar *tmp_copy = g_strdup(new_parsed_name);
g_free(new_parsed_name); // Free the old
new_parsed_name = g_strdup(g_strjoin(".", tmp_copy, split[i], NULL)); // Join the two strings with a . again and duplicate it, setting it to our new_parsed_name
g_free(tmp_copy); // Free our temporary copy
}
}
copied_file_name = g_strdup(new_parsed_name);
g_free(new_parsed_name);
}
g_strfreev(split);
koto_indexed_file_set_parsed_name(self, copied_file_name);
g_free(copied_file_name);
}
KotoIndexedFile* koto_indexed_file_new(const gchar *path) {
return g_object_new(KOTO_TYPE_INDEXED_FILE,
"path", path,
NULL
);
}

View file

@ -1,4 +1,4 @@
/* koto-flipper-button.h
/* file.h
*
* Copyright 2021 Joshua Strobl
*
@ -16,17 +16,17 @@
*/
#pragma once
#include <gtk-3.0/gtk/gtk.h>
#include <glib-2.0/glib-object.h>
G_BEGIN_DECLS
#define KOTO_TYPE_FLIPPER_BUTTON (koto_flipper_button_get_type())
#define KOTO_TYPE_INDEXED_FILE koto_indexed_file_get_type()
G_DECLARE_FINAL_TYPE(KotoIndexedFile, koto_indexed_file, KOTO, INDEXED_FILE, GObject);
G_DECLARE_FINAL_TYPE (KotoFlipperButton, koto_flipper_button, KOTO, FLIPPER_BUTTON, GtkButton)
KotoIndexedFile* koto_indexed_file_new(const gchar *path);
KotoFlipperButton* koto_flipper_button_new(gchar *initial_icon, gchar *flipped_icon, GtkIconSize size);
void koto_flipper_button_flip(KotoFlipperButton *self);
void koto_flipper_button_set_icon(KotoFlipperButton *self, gchar *name);
void koto_indexed_file_set_file_name(KotoIndexedFile *self, gchar *new_file_name);
void koto_indexed_file_set_parsed_name(KotoIndexedFile *self, gchar *new_parsed_name);
void koto_indexed_file_parse_name(KotoIndexedFile *self);
G_END_DECLS

View file

@ -1,4 +1,5 @@
indexer_sources = [
'file.c',
'file-indexer.c',
]

View file

@ -50,19 +50,21 @@ guint koto_get_pixbuf_size(KotoButtonPixbufSize s) {
}
enum {
PROP_0,
PROP_BTN_0,
PROP_PIX_SIZE,
PROP_TEXT,
PROP_BADGE_TEXT,
PROP_PIX,
PROP_ICON_NAME,
N_PROPERTIES
PROP_ALT_ICON_NAME,
N_BTN_PROPERTIES
};
static GParamSpec *props[N_PROPERTIES] = { NULL, };
static GParamSpec *btn_props[N_BTN_PROPERTIES] = { NULL, };
struct _KotoButton {
GtkBox parent_instance;
GtkEventBox parent_instance;
GtkBox *content;
guint pix_size;
GtkWidget *button_image;
@ -71,16 +73,18 @@ struct _KotoButton {
gchar *badge_text;
gchar *icon_name;
gchar *alt_icon_name;
gchar *text;
GdkPixbuf *pix;
gboolean currently_showing_alt;
};
struct _KotoButtonClass {
GtkBoxClass parent_class;
};
G_DEFINE_TYPE(KotoButton, koto_button, GTK_TYPE_BOX);
G_DEFINE_TYPE(KotoButton, koto_button, GTK_TYPE_EVENT_BOX);
static void koto_button_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec);
static void koto_button_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec);
@ -91,7 +95,7 @@ static void koto_button_class_init(KotoButtonClass *c) {
gobject_class->set_property = koto_button_set_property;
gobject_class->get_property = koto_button_get_property;
props[PROP_PIX_SIZE] = g_param_spec_uint(
btn_props[PROP_PIX_SIZE] = g_param_spec_uint(
"pixbuf-size",
"Pixbuf Size",
"Size of the pixbuf",
@ -101,7 +105,7 @@ static void koto_button_class_init(KotoButtonClass *c) {
G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE
);
props[PROP_TEXT] = g_param_spec_string(
btn_props[PROP_TEXT] = g_param_spec_string(
"button-text",
"Button Text",
"Text of Button",
@ -109,7 +113,7 @@ static void koto_button_class_init(KotoButtonClass *c) {
G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE
);
props[PROP_BADGE_TEXT] = g_param_spec_string(
btn_props[PROP_BADGE_TEXT] = g_param_spec_string(
"badge-text",
"Badge Text",
"Text of Badge",
@ -117,7 +121,7 @@ static void koto_button_class_init(KotoButtonClass *c) {
G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE
);
props[PROP_PIX] = g_param_spec_object(
btn_props[PROP_PIX] = g_param_spec_object(
"pixbuf",
"Pixbuf",
"Pixbuf",
@ -125,7 +129,7 @@ static void koto_button_class_init(KotoButtonClass *c) {
G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE
);
props[PROP_ICON_NAME] = g_param_spec_string(
btn_props[PROP_ICON_NAME] = g_param_spec_string(
"icon-name",
"Icon Name",
"Name of Icon",
@ -133,12 +137,23 @@ static void koto_button_class_init(KotoButtonClass *c) {
G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE
);
g_object_class_install_properties(gobject_class, N_PROPERTIES, props);
btn_props[PROP_ALT_ICON_NAME] = g_param_spec_string(
"alt-icon-name",
"Name of an Alternate Icon",
"Name of an Alternate Icon",
NULL,
G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE
);
g_object_class_install_properties(gobject_class, N_BTN_PROPERTIES, btn_props);
}
static void koto_button_init(KotoButton *self) {
GtkStyleContext *style = gtk_widget_get_style_context(GTK_WIDGET(self));
gtk_style_context_add_class(style, "koto-button");
self->currently_showing_alt = FALSE;
self->content = GTK_BOX(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0));
gtk_container_add(GTK_CONTAINER(self), GTK_WIDGET(self->content));
}
static void koto_button_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec) {
@ -157,6 +172,9 @@ static void koto_button_get_property(GObject *obj, guint prop_id, GValue *val, G
case PROP_ICON_NAME:
g_value_set_string(val, self->icon_name);
break;
case PROP_ALT_ICON_NAME:
g_value_set_string(val, self->alt_icon_name);
break;
case PROP_PIX:
g_value_set_object(val, self->pix);
break;
@ -183,7 +201,16 @@ static void koto_button_set_property(GObject *obj, guint prop_id, const GValue *
koto_button_set_pixbuf(self, (GdkPixbuf*) g_value_get_object(val));
break;
case PROP_ICON_NAME:
koto_button_set_icon_name(self, g_strdup(g_value_get_string(val)));
koto_button_set_icon_name(self, g_strdup(g_value_get_string(val)), FALSE);
if (!self->currently_showing_alt) { // Not showing alt
koto_button_show_image(self, FALSE);
}
break;
case PROP_ALT_ICON_NAME:
koto_button_set_icon_name(self, g_strdup(g_value_get_string(val)), TRUE);
if (self->currently_showing_alt) { // Currently showing the alt image
koto_button_show_image(self, TRUE);
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, spec);
@ -191,6 +218,10 @@ static void koto_button_set_property(GObject *obj, guint prop_id, const GValue *
}
}
void koto_button_flip(KotoButton *self) {
koto_button_show_image(self, !self->currently_showing_alt);
}
void koto_button_set_badge_text(KotoButton *self, gchar *text) {
if ((text == NULL) || (strcmp(text, "") == 0)) { // If the text is empty
self->badge_text = g_strdup("");
@ -203,7 +234,7 @@ void koto_button_set_badge_text(KotoButton *self, gchar *text) {
gtk_label_set_text(GTK_LABEL(self->badge_label), self->badge_text);
} else {
self->badge_label = gtk_label_new(self->badge_text); // Create our label
gtk_box_pack_end(GTK_BOX(self), self->badge_label, FALSE, FALSE, 0); // Add to the end of the box
gtk_box_pack_end(self->content, self->badge_label, FALSE, FALSE, 0); // Add to the end of the box
}
if (strcmp(self->badge_text, "") != 0) { // Empty badge
@ -212,17 +243,34 @@ void koto_button_set_badge_text(KotoButton *self, gchar *text) {
gtk_widget_show(self->badge_label); // Show our badge
}
g_object_notify_by_pspec(G_OBJECT(self), props[PROP_BADGE_TEXT]);
g_object_notify_by_pspec(G_OBJECT(self), btn_props[PROP_BADGE_TEXT]);
}
void koto_button_set_icon_name(KotoButton *self, gchar *icon_name) {
void koto_button_set_icon_name(KotoButton *self, gchar *icon_name, gboolean for_alt) {
gchar *copied_icon_name = g_strdup(icon_name);
g_message("icon name set in koto button: %s", icon_name);
g_free(self->icon_name);
self->icon_name = copied_icon_name;
if ((self->icon_name == NULL) || (strcmp(self->icon_name,"") == 0)) { // Have no icon name now
g_message("Have no icon name now?");
if (for_alt) { // Is for the alternate icon
if ((self->alt_icon_name != NULL) && strcmp(icon_name, self->alt_icon_name) != 0) { // If the icons are different
g_free(self->alt_icon_name);
}
self->alt_icon_name = copied_icon_name;
} else {
if ((self->icon_name != NULL) && strcmp(icon_name, self->icon_name) != 0) {
g_free(self->icon_name);
}
self->icon_name = copied_icon_name;
}
gboolean hide_image = FALSE;
if (for_alt && self->currently_showing_alt && ((self->alt_icon_name == NULL) || strcmp(self->alt_icon_name, "") == 0)) { // For alt, alt is currently showing, and no longer have alt
hide_image = TRUE;
} else if (!for_alt && ((self->icon_name == NULL) || (strcmp(self->icon_name,"") == 0))) { // Not for alt, no icon
hide_image = TRUE;
}
if (hide_image) { // Should hide the image
if (GTK_IS_IMAGE(self->button_image)) { // If we already have a button image
gtk_widget_hide(self->button_image); // Hide
}
@ -230,12 +278,7 @@ void koto_button_set_icon_name(KotoButton *self, gchar *icon_name) {
return;
}
GtkIconTheme *theme = gtk_icon_theme_get_default(); // Get the default icon theme
GdkPixbuf* icon_pix = gtk_icon_theme_load_icon_for_scale(theme, self->icon_name, (gint) self->pix_size, 1, GTK_ICON_LOOKUP_USE_BUILTIN & GTK_ICON_LOOKUP_GENERIC_FALLBACK, NULL);
g_return_if_fail(GDK_IS_PIXBUF(icon_pix)); // Return if not a pixbuf
koto_button_set_pixbuf(self, icon_pix);
g_object_notify_by_pspec(G_OBJECT(self), props[PROP_ICON_NAME]);
g_object_notify_by_pspec(G_OBJECT(self), for_alt ? btn_props[PROP_ALT_ICON_NAME] : btn_props[PROP_ICON_NAME]);
}
void koto_button_set_pixbuf(KotoButton *self, GdkPixbuf *pix) {
@ -260,11 +303,11 @@ void koto_button_set_pixbuf(KotoButton *self, GdkPixbuf *pix) {
GtkWidget *new_image = gtk_image_new_from_pixbuf(use_pix); // Create our new image
g_return_if_fail(GTK_IS_IMAGE(new_image)); // Return if we failed to create our image
self->button_image = new_image;
gtk_box_pack_start(GTK_BOX(self), self->button_image, FALSE, FALSE, 0); // Prepend the image
gtk_box_reorder_child(GTK_BOX(self), self->button_image, 0);
gtk_box_pack_start(self->content, self->button_image, FALSE, FALSE, 0); // Prepend the image
gtk_box_reorder_child(self->content, self->button_image, 0);
}
g_object_notify_by_pspec(G_OBJECT(self), props[PROP_PIX]);
g_object_notify_by_pspec(G_OBJECT(self), btn_props[PROP_PIX]);
}
void koto_button_set_pixbuf_size(KotoButton *self, guint size) {
@ -276,7 +319,7 @@ void koto_button_set_pixbuf_size(KotoButton *self, guint size) {
koto_button_set_pixbuf(self, self->pix);
}
g_object_notify_by_pspec(G_OBJECT(self), props[PROP_PIX_SIZE]);
g_object_notify_by_pspec(G_OBJECT(self), btn_props[PROP_PIX_SIZE]);
}
void koto_button_set_text(KotoButton *self, gchar *text) {
@ -300,30 +343,43 @@ void koto_button_set_text(KotoButton *self, gchar *text) {
if (strcmp(self->text, "") != 0) { // If we have text
self->button_label = gtk_label_new(self->text); // Create our label
gtk_label_set_xalign(GTK_LABEL(self->button_label), 0);
gtk_box_pack_start(GTK_BOX(self), self->button_label, FALSE, FALSE, 0); // Add to the beginning of the box
gtk_box_pack_start(self->content, self->button_label, FALSE, FALSE, 0); // Add to the beginning of the box
if (GTK_IS_IMAGE(self->button_image)) { // If we have an image
gtk_box_reorder_child(GTK_BOX(self), self->button_image, 0); // Move to the beginning
gtk_box_reorder_child(self->content, self->button_image, 0); // Move to the beginning
}
}
}
g_object_notify_by_pspec(G_OBJECT(self), props[PROP_TEXT]);
g_object_notify_by_pspec(G_OBJECT(self), btn_props[PROP_TEXT]);
}
void koto_button_show_image(KotoButton *self, gboolean use_alt) {
if (use_alt && ((self->alt_icon_name == NULL) || (strcmp(self->alt_icon_name, "") == 0))) { // Don't have an alt icon set
return;
} else if (!use_alt && ((self->icon_name == NULL) || (strcmp(self->icon_name, "") == 0))) { // Don't have icon set
return;
}
GtkIconTheme *theme = gtk_icon_theme_get_default(); // Get the default icon theme
GdkPixbuf* icon_pix = gtk_icon_theme_load_icon_for_scale(theme, use_alt ? self->alt_icon_name : self->icon_name, (gint) self->pix_size, 1, GTK_ICON_LOOKUP_USE_BUILTIN & GTK_ICON_LOOKUP_GENERIC_FALLBACK, NULL);
g_return_if_fail(GDK_IS_PIXBUF(icon_pix)); // Return if not a pixbuf
koto_button_set_pixbuf(self, icon_pix);
self->currently_showing_alt = use_alt;
}
KotoButton* koto_button_new_plain(gchar *label) {
return g_object_new(KOTO_TYPE_BUTTON,
"button-text", label,
"orientation", GTK_ORIENTATION_HORIZONTAL,
NULL
);
}
KotoButton* koto_button_new_with_icon(gchar *label, gchar *icon_name, KotoButtonPixbufSize size) {
KotoButton* koto_button_new_with_icon(gchar *label, gchar *icon_name, gchar *alt_icon_name, KotoButtonPixbufSize size) {
return g_object_new(KOTO_TYPE_BUTTON,
"button-text", label,
"icon-name", icon_name,
"orientation", GTK_ORIENTATION_HORIZONTAL,
"alt-icon-name", alt_icon_name,
"pixbuf-size", koto_get_pixbuf_size(size),
NULL
);
@ -333,7 +389,6 @@ KotoButton* koto_button_new_with_pixbuf(gchar *label, GdkPixbuf *pix, KotoButton
return g_object_new(KOTO_TYPE_BUTTON,
"button-text", label,
"pixbuf", pix,
"orientation", GTK_ORIENTATION_HORIZONTAL,
"pixbuf-size", koto_get_pixbuf_size(size),
NULL
);

View file

@ -16,9 +16,6 @@
*/
#pragma once
#ifndef __GTK_ENUMS_H__
#define __GTK_ENUMS_H__
#endif
#include <glib-object.h>
#include <gdk-pixbuf-2.0/gdk-pixbuf/gdk-pixbuf.h>
@ -40,18 +37,20 @@ typedef enum {
#define KOTO_TYPE_BUTTON (koto_button_get_type())
G_DECLARE_FINAL_TYPE (KotoButton, koto_button, KOTO, BUTTON, GtkBox)
G_DECLARE_FINAL_TYPE (KotoButton, koto_button, KOTO, BUTTON, GtkEventBox)
guint koto_get_pixbuf_size(KotoButtonPixbufSize size);
KotoButton* koto_button_new_plain(gchar *label);
KotoButton* koto_button_new_with_icon(gchar *label, gchar *icon_name, KotoButtonPixbufSize size);
KotoButton* koto_button_new_with_icon(gchar *label, gchar *icon_name, gchar *alt_icon_name, KotoButtonPixbufSize size);
KotoButton* koto_button_new_with_pixbuf(gchar *label, GdkPixbuf *pix, KotoButtonPixbufSize size);
void koto_button_flip(KotoButton *self);
void koto_button_set_badge_text(KotoButton *self, gchar *text);
void koto_button_set_icon_name(KotoButton *self, gchar *icon_name);
void koto_button_set_icon_name(KotoButton *self, gchar *icon_name, gboolean for_alt);
void koto_button_set_pixbuf(KotoButton *self, GdkPixbuf *pix);
void koto_button_set_pixbuf_size(KotoButton *self, guint size);
void koto_button_set_text(KotoButton *self, gchar *text);
void koto_button_show_image(KotoButton *self, gboolean use_alt);
G_END_DECLS

View file

@ -19,20 +19,18 @@
#include <gtk-3.0/gtk/gtk.h>
#include "koto-config.h"
#include "koto-button.h"
#include "koto-flipper-button.h"
#include "koto-expander.h"
#include "koto-utils.h"
enum {
PROP_0,
PROP_EXP_0,
PROP_HEADER_ICON_NAME,
PROP_HEADER_LABEL,
PROP_HEADER_SECONDARY_BUTTON,
PROP_CONTENT,
N_PROPERTIES
N_EXP_PROPERTIES
};
static GParamSpec *props[N_PROPERTIES] = { NULL, };
static GParamSpec *expander_props[N_EXP_PROPERTIES] = { NULL, };
struct _KotoExpander {
GtkBox parent_instance;
@ -43,8 +41,8 @@ struct _KotoExpander {
gchar *icon_name;
gchar *label;
GtkWidget *header_secondary_button;
KotoFlipperButton *header_expand_button;
KotoButton *header_secondary_button;
KotoButton *header_expand_button;
GtkWidget *revealer;
GtkWidget *content;
@ -65,7 +63,7 @@ static void koto_expander_class_init(KotoExpanderClass *c) {
gobject_class->set_property = koto_expander_set_property;
gobject_class->get_property = koto_expander_get_property;
props[PROP_HEADER_ICON_NAME] = g_param_spec_string(
expander_props[PROP_HEADER_ICON_NAME] = g_param_spec_string(
"icon-name",
"Icon Name",
"Name of the icon to use in the Expander",
@ -73,7 +71,7 @@ static void koto_expander_class_init(KotoExpanderClass *c) {
G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE
);
props[PROP_HEADER_LABEL] = g_param_spec_string(
expander_props[PROP_HEADER_LABEL] = g_param_spec_string(
"label",
"Label",
"Label for the Expander",
@ -81,15 +79,15 @@ static void koto_expander_class_init(KotoExpanderClass *c) {
G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE
);
props[PROP_HEADER_SECONDARY_BUTTON] = g_param_spec_object(
expander_props[PROP_HEADER_SECONDARY_BUTTON] = g_param_spec_object(
"secondary-button",
"Secondary Button",
"Secondary Button to be placed next to Expander button",
GTK_TYPE_WIDGET,
KOTO_TYPE_BUTTON,
G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE
);
props[PROP_CONTENT] = g_param_spec_object(
expander_props[PROP_CONTENT] = g_param_spec_object(
"content",
"Content",
"Content inside the Expander",
@ -97,7 +95,7 @@ static void koto_expander_class_init(KotoExpanderClass *c) {
G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE
);
g_object_class_install_properties(gobject_class, N_PROPERTIES, props);
g_object_class_install_properties(gobject_class, N_EXP_PROPERTIES, expander_props);
}
static void koto_expander_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec) {
@ -126,7 +124,7 @@ static void koto_expander_set_property(GObject *obj, guint prop_id, const GValue
KotoExpander *self = KOTO_EXPANDER(obj);
if (!GTK_IS_WIDGET(self->header_button)) { // Header Button is not a widget
KotoButton *new_button = koto_button_new_with_icon("Temporary Text", "emblem-favorite-symbolic", KOTO_BUTTON_PIXBUF_SIZE_SMALL);
KotoButton *new_button = koto_button_new_with_icon("Temporary Text", "emblem-favorite-symbolic", NULL, KOTO_BUTTON_PIXBUF_SIZE_SMALL);
if (GTK_IS_WIDGET(new_button)) { // Created our widget successfully
self->header_button = new_button;
@ -137,14 +135,14 @@ static void koto_expander_set_property(GObject *obj, guint prop_id, const GValue
switch (prop_id) {
case PROP_HEADER_ICON_NAME:
g_return_if_fail(GTK_IS_WIDGET(self->header_button));
koto_button_set_icon_name(self->header_button, g_strdup(g_value_get_string(val)));
koto_button_set_icon_name(self->header_button, g_strdup(g_value_get_string(val)), FALSE);
break;
case PROP_HEADER_LABEL:
g_return_if_fail(GTK_IS_WIDGET(self->header_button));
koto_button_set_text(self->header_button, g_strdup(g_value_get_string(val)));
break;
case PROP_HEADER_SECONDARY_BUTTON:
koto_expander_set_secondary_button(self, (GtkWidget*) g_value_get_object(val));
koto_expander_set_secondary_button(self, (KotoButton*) g_value_get_object(val));
break;
case PROP_CONTENT:
koto_expander_set_content(self, (GtkWidget*) g_value_get_object(val));
@ -171,7 +169,7 @@ static void koto_expander_init(KotoExpander *self) {
gtk_revealer_set_reveal_child(GTK_REVEALER(self->revealer), TRUE); // Set to be revealed by default
gtk_revealer_set_transition_type(GTK_REVEALER(self->revealer), GTK_REVEALER_TRANSITION_TYPE_SLIDE_DOWN);
self->header_expand_button = koto_flipper_button_new("pan-down-symbolic", "pan-up-symbolic", GTK_ICON_SIZE_SMALL_TOOLBAR);
self->header_expand_button = koto_button_new_with_icon("", "pan-down-symbolic", "pan-up-symbolic", KOTO_BUTTON_PIXBUF_SIZE_SMALL);
gtk_box_pack_end(GTK_BOX(self->header), GTK_WIDGET(self->header_expand_button), FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(self), self->header, FALSE, FALSE, 0);
@ -179,27 +177,26 @@ static void koto_expander_init(KotoExpander *self) {
self->constructed = TRUE;
g_signal_connect(self->header_expand_button, "clicked", G_CALLBACK(koto_expander_toggle_content), self);
g_signal_connect(self->header_expand_button, "button-release-event", G_CALLBACK(koto_expander_toggle_content), self);
}
void koto_expander_set_secondary_button(KotoExpander *self, GtkWidget *new_button) {
void koto_expander_set_secondary_button(KotoExpander *self, KotoButton *new_button) {
if (!self->constructed) {
return;
}
if (!GTK_IS_BUTTON(new_button)) {
if (!GTK_IS_WIDGET(new_button)) {
return;
}
if (GTK_IS_BUTTON(self->header_secondary_button)) { // Already have a button
gtk_container_remove(GTK_CONTAINER(self->header), self->header_secondary_button);
//g_free(self->header_secondary_button);
if (GTK_IS_WIDGET(self->header_secondary_button)) { // Already have a button
gtk_container_remove(GTK_CONTAINER(self->header), GTK_WIDGET(self->header_secondary_button));
}
self->header_secondary_button = new_button;
gtk_box_pack_end(GTK_BOX(self->header), self->header_secondary_button, FALSE, FALSE, 0);
gtk_box_pack_end(GTK_BOX(self->header), GTK_WIDGET(self->header_secondary_button), FALSE, FALSE, 0);
g_object_notify_by_pspec(G_OBJECT(self), props[PROP_HEADER_SECONDARY_BUTTON]);
g_object_notify_by_pspec(G_OBJECT(self), expander_props[PROP_HEADER_SECONDARY_BUTTON]);
}
void koto_expander_set_content(KotoExpander *self, GtkWidget *new_content) {
@ -215,12 +212,12 @@ void koto_expander_set_content(KotoExpander *self, GtkWidget *new_content) {
self->content = new_content;
gtk_container_add(GTK_CONTAINER(self->revealer), self->content);
g_object_notify_by_pspec(G_OBJECT(self), props[PROP_CONTENT]);
g_object_notify_by_pspec(G_OBJECT(self), expander_props[PROP_CONTENT]);
}
void koto_expander_toggle_content(GtkWidget *button, gpointer data) {
void koto_expander_toggle_content(GtkWidget *button, GdkEvent *event, gpointer data) {
KotoExpander* self = data;
koto_flipper_button_flip(KOTO_FLIPPER_BUTTON(button));
koto_button_flip(KOTO_BUTTON(button));
GtkRevealer* rev = GTK_REVEALER(self->revealer);
gtk_revealer_set_reveal_child(rev, !gtk_revealer_get_reveal_child(rev)); // Invert our values
}
@ -234,7 +231,7 @@ KotoExpander* koto_expander_new(gchar *primary_icon_name, gchar *primary_label_t
);
}
KotoExpander* koto_expander_new_with_button(gchar *primary_icon_name, gchar *primary_label_text, GtkWidget *secondary_button) {
KotoExpander* koto_expander_new_with_button(gchar *primary_icon_name, gchar *primary_label_text, KotoButton *secondary_button) {
return g_object_new(KOTO_TYPE_EXPANDER,
"orientation", GTK_ORIENTATION_VERTICAL,
"icon-name", primary_icon_name,

View file

@ -18,6 +18,7 @@
#pragma once
#include <gtk-3.0/gtk/gtk.h>
#include "koto-button.h"
G_BEGIN_DECLS
@ -26,11 +27,11 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (KotoExpander, koto_expander, KOTO, EXPANDER, GtkBox)
KotoExpander* koto_expander_new(gchar *primary_icon_name, gchar *primary_label_text);
KotoExpander* koto_expander_new_with_button(gchar *primary_icon_name, gchar *primary_label_text, GtkWidget *secondary_button);
KotoExpander* koto_expander_new_with_button(gchar *primary_icon_name, gchar *primary_label_text, KotoButton *secondary_button);
void koto_expander_set_icon_name(KotoExpander *self, const gchar *in);
void koto_expander_set_label(KotoExpander *self, const gchar *label);
void koto_expander_set_secondary_button(KotoExpander *self, GtkWidget *new_button);
void koto_expander_set_secondary_button(KotoExpander *self, KotoButton *new_button);
void koto_expander_set_content(KotoExpander *self, GtkWidget *new_content);
void koto_expander_toggle_content(GtkWidget *button, gpointer data);
void koto_expander_toggle_content(GtkWidget *button, GdkEvent *event, gpointer data);
G_END_DECLS

View file

@ -1,129 +0,0 @@
/* koto-flipper-button.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-3.0/gtk/gtk.h>
#include "koto-config.h"
#include "koto-flipper-button.h"
enum {
PROP_0,
PROP_SIZE,
PROP_INITIAL_IMAGE,
PROP_FLIPPED_IMAGE,
N_PROPERTIES
};
static GParamSpec *props[N_PROPERTIES] = { NULL, };
struct _KotoFlipperButton {
GtkButton parent_instance;
GtkIconSize size;
gboolean flipped;
gchar *initial_image;
gchar *flipped_image;
};
struct _KotoFlipperButtonClass {
GtkButtonClass parent_class;
};
G_DEFINE_TYPE(KotoFlipperButton, koto_flipper_button, GTK_TYPE_BUTTON);
static void koto_flipper_button_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec);
static void koto_flipper_button_class_init(KotoFlipperButtonClass *c) {
GObjectClass *gobject_class;
gobject_class = G_OBJECT_CLASS(c);
gobject_class->set_property = koto_flipper_button_set_property;
props[PROP_SIZE] = g_param_spec_enum(
"size",
"Icon Size",
"Size of the icon",
GTK_TYPE_ICON_SIZE,
GTK_ICON_SIZE_MENU,
G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_WRITABLE
);
props[PROP_INITIAL_IMAGE] = g_param_spec_string(
"initial-image",
"Initial Image",
"Image to use initially for the button",
NULL,
G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_WRITABLE
);
props[PROP_FLIPPED_IMAGE] = g_param_spec_string(
"flipped-image",
"Flipped Image",
"Image to use when the button is flipped",
NULL,
G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_WRITABLE
);
g_object_class_install_properties(gobject_class, N_PROPERTIES, props);
}
static void koto_flipper_button_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec) {
KotoFlipperButton *self = KOTO_FLIPPER_BUTTON(obj);
if (prop_id == PROP_INITIAL_IMAGE) {
g_free(self->initial_image);
self->initial_image = g_strdup(g_value_get_string(val));
koto_flipper_button_set_icon(self, self->initial_image);
} else if (prop_id == PROP_FLIPPED_IMAGE) {
g_free(self->flipped_image);
self->flipped_image = g_strdup(g_value_get_string(val));
} else if (prop_id == PROP_SIZE) {
self->size = (GtkIconSize) g_value_get_enum(val);
if (self->initial_image != NULL && !self->flipped) {
koto_flipper_button_set_icon(self, self->flipped ? self->initial_image : self->flipped_image);
}
} else {
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, spec);
return;
}
g_object_notify_by_pspec(obj, props[prop_id]);
}
static void koto_flipper_button_init(KotoFlipperButton *self) {
self->flipped = FALSE;
GtkStyleContext *button_style = gtk_widget_get_style_context(GTK_WIDGET(self)); // Get the styling for the flipper button
gtk_style_context_add_class(button_style, "flat"); // Set it to flat
}
void koto_flipper_button_flip(KotoFlipperButton *self) {
koto_flipper_button_set_icon(self, self->flipped ? self->initial_image : self->flipped_image);
self->flipped = !self->flipped;
}
void koto_flipper_button_set_icon(KotoFlipperButton *self, gchar *name) {
GtkWidget *new_image = gtk_image_new_from_icon_name(name, self->size);
gtk_button_set_image(GTK_BUTTON(self), new_image);
}
KotoFlipperButton* koto_flipper_button_new(gchar *initial_icon, gchar *flipped_icon, GtkIconSize size) {
return g_object_new(KOTO_TYPE_FLIPPER_BUTTON,
"initial-image", initial_icon,
"flipped-image", flipped_icon,
"size", size,
NULL
);
}

View file

@ -20,7 +20,6 @@
#include "koto-button.h"
#include "koto-expander.h"
#include "koto-nav.h"
#include "koto-utils.h"
struct _KotoNav {
GtkScrolledWindow parent_instance;
@ -68,7 +67,7 @@ static void koto_nav_init(KotoNav *self) {
gtk_container_add(GTK_CONTAINER(self), self->content);
KotoButton *h_button = koto_button_new_with_icon("Home", "user-home-symbolic", KOTO_BUTTON_PIXBUF_SIZE_SMALL);
KotoButton *h_button = koto_button_new_with_icon("Home", "user-home-symbolic", NULL, KOTO_BUTTON_PIXBUF_SIZE_SMALL);
if (h_button != NULL) {
self->home_button = h_button;
@ -80,8 +79,7 @@ static void koto_nav_init(KotoNav *self) {
koto_nav_create_podcasts_section(self);
GtkWidget *playlist_add_button = koto_create_flat_icon_button("list-add-symbolic", GTK_ICON_SIZE_SMALL_TOOLBAR);
KotoButton *playlist_add_button = koto_button_new_with_icon("", "list-add-symbolic", NULL, KOTO_BUTTON_PIXBUF_SIZE_SMALL);
KotoExpander *pl_expander = koto_expander_new_with_button("playlist-symbolic", "Playlists", playlist_add_button);
if (pl_expander != NULL) {

View file

@ -15,10 +15,9 @@
* limitations under the License.
*/
#include <glib/gi18n.h>
#include "koto-button.h"
#include "koto-config.h"
#include "koto-playerbar.h"
#include "koto-utils.h"
struct _KotoPlayerBar {
GtkBox parent_instance;
@ -29,13 +28,13 @@ struct _KotoPlayerBar {
GtkWidget *secondary_controls_section;
/* Primary Buttons */
GtkWidget *back_button;
GtkWidget *play_pause_button;
GtkWidget *forward_button;
GtkWidget *repeat_button;
GtkWidget *shuffle_button;
GtkWidget *playlist_button;
GtkWidget *eq_button;
KotoButton *back_button;
KotoButton *play_pause_button;
KotoButton *forward_button;
KotoButton *repeat_button;
KotoButton *shuffle_button;
KotoButton *playlist_button;
KotoButton *eq_button;
GtkWidget *volume_button;
/* Selected Playback Section */
@ -113,9 +112,9 @@ void koto_playerbar_create_playback_details(KotoPlayerBar* bar) {
gtk_box_pack_start(GTK_BOX(bar->playback_section), bar->artwork, FALSE, FALSE, 0);
}
bar->playback_title = gtk_label_new(_("Title"));
bar->playback_album = gtk_label_new(_("Album"));
bar->playback_artist = gtk_label_new(_("Artist"));
bar->playback_title = gtk_label_new("Title");
bar->playback_album = gtk_label_new("Album");
bar->playback_artist = gtk_label_new("Artist");
gtk_box_pack_start(GTK_BOX(bar->playback_details_section), GTK_WIDGET(bar->playback_title), TRUE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(bar->playback_details_section), GTK_WIDGET(bar->playback_album), TRUE, TRUE, 0);
@ -125,45 +124,45 @@ void koto_playerbar_create_playback_details(KotoPlayerBar* bar) {
}
void koto_playerbar_create_primary_controls(KotoPlayerBar* bar) {
bar->back_button = koto_create_flat_icon_button("media-skip-backward-symbolic", GTK_ICON_SIZE_LARGE_TOOLBAR);
bar->play_pause_button = koto_create_flat_icon_button("media-playback-start-symbolic", GTK_ICON_SIZE_DND); // TODO: Have this take in a state and switch to a different icon if necessary
bar->forward_button = koto_create_flat_icon_button("media-skip-forward-symbolic", GTK_ICON_SIZE_LARGE_TOOLBAR);
bar->back_button = koto_button_new_with_icon("", "media-skip-backward-symbolic", NULL, KOTO_BUTTON_PIXBUF_SIZE_NORMAL);
bar->play_pause_button = koto_button_new_with_icon("", "media-playback-start-symbolic", NULL, KOTO_BUTTON_PIXBUF_SIZE_LARGE); // TODO: Have this take in a state and switch to a different icon if necessary
bar->forward_button = koto_button_new_with_icon("", "media-skip-forward-symbolic", NULL, KOTO_BUTTON_PIXBUF_SIZE_NORMAL);
if (bar->back_button != NULL) {
gtk_box_pack_start(GTK_BOX(bar->primary_controls_section), bar->back_button, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(bar->primary_controls_section), GTK_WIDGET(bar->back_button), FALSE, FALSE, 0);
}
if (bar->play_pause_button != NULL) {
gtk_box_pack_start(GTK_BOX(bar->primary_controls_section), bar->play_pause_button, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(bar->primary_controls_section), GTK_WIDGET(bar->play_pause_button), FALSE, FALSE, 0);
}
if (bar->forward_button != NULL) {
gtk_box_pack_start(GTK_BOX(bar->primary_controls_section), bar->forward_button, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(bar->primary_controls_section), GTK_WIDGET(bar->forward_button), FALSE, FALSE, 0);
}
}
void koto_playerbar_create_secondary_controls(KotoPlayerBar* bar) {
bar->repeat_button = koto_create_flat_icon_button("media-playlist-repeat-symbolic", GTK_ICON_SIZE_LARGE_TOOLBAR);
bar->shuffle_button = koto_create_flat_icon_button("media-playlist-shuffle-symbolic", GTK_ICON_SIZE_LARGE_TOOLBAR);
bar->playlist_button = koto_create_flat_icon_button("playlist-symbolic", GTK_ICON_SIZE_LARGE_TOOLBAR);
bar->eq_button = koto_create_flat_icon_button("multimedia-equalizer-symbolic", GTK_ICON_SIZE_LARGE_TOOLBAR);
bar->repeat_button = koto_button_new_with_icon("", "media-playlist-repeat-symbolic", NULL, KOTO_BUTTON_PIXBUF_SIZE_NORMAL);
bar->shuffle_button = koto_button_new_with_icon("", "media-playlist-shuffle-symbolic", NULL, KOTO_BUTTON_PIXBUF_SIZE_NORMAL);
bar->playlist_button = koto_button_new_with_icon("", "playlist-symbolic", NULL, KOTO_BUTTON_PIXBUF_SIZE_NORMAL);
bar->eq_button = koto_button_new_with_icon("", "multimedia-equalizer-symbolic", NULL, KOTO_BUTTON_PIXBUF_SIZE_NORMAL);
bar->volume_button = gtk_volume_button_new(); // Have this take in a state and switch to a different icon if necessary
gtk_scale_button_set_value(GTK_SCALE_BUTTON(bar->volume_button), 0.5);
if (bar->repeat_button != NULL) {
gtk_box_pack_start(GTK_BOX(bar->secondary_controls_section), bar->repeat_button, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(bar->secondary_controls_section), GTK_WIDGET(bar->repeat_button), FALSE, FALSE, 0);
}
if (bar->shuffle_button != NULL) {
gtk_box_pack_start(GTK_BOX(bar->secondary_controls_section), bar->shuffle_button, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(bar->secondary_controls_section), GTK_WIDGET(bar->shuffle_button), FALSE, FALSE, 0);
}
if (bar->playlist_button != NULL) {
gtk_box_pack_start(GTK_BOX(bar->secondary_controls_section), bar->playlist_button, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(bar->secondary_controls_section), GTK_WIDGET(bar->playlist_button), FALSE, FALSE, 0);
}
if (bar->eq_button != NULL) {
gtk_box_pack_start(GTK_BOX(bar->secondary_controls_section), bar->eq_button, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(bar->secondary_controls_section), GTK_WIDGET(bar->eq_button), FALSE, FALSE, 0);
}
if (bar->volume_button != NULL) {

View file

@ -1,28 +0,0 @@
/* koto-utils.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 "koto-utils.h"
GtkWidget* koto_create_flat_icon_button(gchar *icon_name, GtkIconSize size) {
GtkWidget* button;
button = gtk_button_new_from_icon_name(icon_name, size);
GtkStyleContext *button_style = gtk_widget_get_style_context(button);
gtk_style_context_add_class(button_style, "flat");
return button;
}

View file

@ -1,24 +0,0 @@
/* koto-utils.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.
*/
#include <gtk-3.0/gtk/gtk.h>
G_BEGIN_DECLS
GtkWidget* koto_create_flat_icon_button(gchar *icon_name, GtkIconSize size);
G_END_DECLS

View file

@ -37,12 +37,9 @@ G_DEFINE_TYPE (KotoWindow, koto_window, GTK_TYPE_APPLICATION_WINDOW)
static void koto_window_class_init (KotoWindowClass *klass) {
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
gtk_widget_class_set_template_from_resource (widget_class, "/com/github/joshstrobl/koto/koto-window.ui");
}
static void koto_window_init (KotoWindow *self) {
gtk_widget_init_template (GTK_WIDGET (self));
GtkCssProvider* provider = gtk_css_provider_new();
gtk_css_provider_load_from_resource(provider, "/com/github/joshstrobl/koto/style.css");
gtk_style_context_add_provider_for_screen(gdk_screen_get_default(), GTK_STYLE_PROVIDER(provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
@ -75,8 +72,12 @@ static void koto_window_init (KotoWindow *self) {
}
gtk_container_add(GTK_CONTAINER(self), self->primary_layout);
gtk_widget_show_all(GTK_WIDGET(self));
gtk_widget_set_size_request(GTK_WIDGET(self), 1200, 675);
gtk_window_set_title(GTK_WINDOW(self), "Koto");
gtk_window_set_wmclass(GTK_WINDOW(self), "com.github.joshstrobl.koto", "com.github.joshstrobl.koto");
gtk_window_set_icon_name(GTK_WINDOW(self), "audio-headphones");
gtk_widget_show_all(GTK_WIDGET(self));
g_thread_new("load-library", load_library, self);
}

View file

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.2 -->
<interface>
<requires lib="gtk+" version="3.24"/>
<template class="KotoWindow" parent="GtkApplicationWindow">
<property name="can-focus">False</property>
<property name="default-width">1200</property>
<property name="default-height">675</property>
</template>
</interface>

View file

@ -2,7 +2,6 @@
<gresources>
<gresource prefix="/com/github/joshstrobl/koto">
<file>koto-headerbar.ui</file>
<file>koto-window.ui</file>
<file alias="style.css">../data/style.css</file>
</gresource>
</gresources>

View file

@ -1,13 +1,12 @@
koto_sources = [
'indexer/file.c',
'indexer/file-indexer.c',
'main.c',
'koto-button.c',
'koto-expander.c',
'koto-flipper-button.c',
'koto-headerbar.c',
'koto-nav.c',
'koto-playerbar.c',
'koto-utils.c',
'koto-window.c',
]