Work leading up to and including Day 4.
- Initial window bits - Preliminary Nav sidebar - Expanders - Koto Button to reduce code duplication - Started work on indexer
This commit is contained in:
parent
9aa493c51a
commit
6fb3852f09
37 changed files with 2094 additions and 0 deletions
21
build-aux/meson/postinstall.py
Executable file
21
build-aux/meson/postinstall.py
Executable file
|
@ -0,0 +1,21 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
from os import environ, path
|
||||
from subprocess import call
|
||||
|
||||
prefix = environ.get('MESON_INSTALL_PREFIX', '/usr/local')
|
||||
datadir = path.join(prefix, 'share')
|
||||
destdir = environ.get('DESTDIR', '')
|
||||
|
||||
# Package managers set this so we don't need to run
|
||||
if not destdir:
|
||||
print('Updating icon cache...')
|
||||
call(['gtk-update-icon-cache', '-qtf', path.join(datadir, 'icons', 'hicolor')])
|
||||
|
||||
print('Updating desktop database...')
|
||||
call(['update-desktop-database', '-q', path.join(datadir, 'applications')])
|
||||
|
||||
print('Compiling GSettings schemas...')
|
||||
call(['glib-compile-schemas', path.join(datadir, 'glib-2.0', 'schemas')])
|
||||
|
||||
|
37
com.github.joshstrobl.koto.json
Normal file
37
com.github.joshstrobl.koto.json
Normal file
|
@ -0,0 +1,37 @@
|
|||
{
|
||||
"app-id" : "com.github.joshstrobl.koto",
|
||||
"runtime" : "org.gnome.Platform",
|
||||
"runtime-version" : "3.38",
|
||||
"sdk" : "org.gnome.Sdk",
|
||||
"command" : "com.github.joshstrobl.koto",
|
||||
"finish-args" : [
|
||||
"--share=network",
|
||||
"--share=ipc",
|
||||
"--socket=fallback-x11",
|
||||
"--socket=wayland"
|
||||
],
|
||||
"cleanup" : [
|
||||
"/include",
|
||||
"/lib/pkgconfig",
|
||||
"/man",
|
||||
"/share/doc",
|
||||
"/share/gtk-doc",
|
||||
"/share/man",
|
||||
"/share/pkgconfig",
|
||||
"*.la",
|
||||
"*.a"
|
||||
],
|
||||
"modules" : [
|
||||
{
|
||||
"name" : "koto",
|
||||
"builddir" : true,
|
||||
"buildsystem" : "meson",
|
||||
"sources" : [
|
||||
{
|
||||
"type" : "git",
|
||||
"url" : "file:///home/joshua/Code/Personal/Koto"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
8
data/com.github.joshstrobl.koto.appdata.xml.in
Normal file
8
data/com.github.joshstrobl.koto.appdata.xml.in
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<component type="desktop">
|
||||
<id>com.github.joshstrobl.koto.desktop</id>
|
||||
<metadata_license>CC0-1.0</metadata_license>
|
||||
<project_license></project_license>
|
||||
<description>
|
||||
</description>
|
||||
</component>
|
7
data/com.github.joshstrobl.koto.desktop.in
Normal file
7
data/com.github.joshstrobl.koto.desktop.in
Normal file
|
@ -0,0 +1,7 @@
|
|||
[Desktop Entry]
|
||||
Name=koto
|
||||
Exec=koto
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Categories=GTK;
|
||||
StartupNotify=true
|
5
data/com.github.joshstrobl.koto.gschema.xml
Normal file
5
data/com.github.joshstrobl.koto.gschema.xml
Normal file
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<schemalist gettext-domain="koto">
|
||||
<schema id="com.github.joshstrobl.koto" path="/com/github/joshstrobl/koto/">
|
||||
</schema>
|
||||
</schemalist>
|
41
data/meson.build
Normal file
41
data/meson.build
Normal file
|
@ -0,0 +1,41 @@
|
|||
desktop_file = i18n.merge_file(
|
||||
input: 'com.github.joshstrobl.koto.desktop.in',
|
||||
output: 'com.github.joshstrobl.koto.desktop',
|
||||
type: 'desktop',
|
||||
po_dir: '../po',
|
||||
install: true,
|
||||
install_dir: join_paths(get_option('datadir'), 'applications')
|
||||
)
|
||||
|
||||
desktop_utils = find_program('desktop-file-validate', required: false)
|
||||
if desktop_utils.found()
|
||||
test('Validate desktop file', desktop_utils,
|
||||
args: [desktop_file]
|
||||
)
|
||||
endif
|
||||
|
||||
appstream_file = i18n.merge_file(
|
||||
input: 'com.github.joshstrobl.koto.appdata.xml.in',
|
||||
output: 'com.github.joshstrobl.koto.appdata.xml',
|
||||
po_dir: '../po',
|
||||
install: true,
|
||||
install_dir: join_paths(get_option('datadir'), 'appdata')
|
||||
)
|
||||
|
||||
appstream_util = find_program('appstream-util', required: false)
|
||||
if appstream_util.found()
|
||||
test('Validate appstream file', appstream_util,
|
||||
args: ['validate', appstream_file]
|
||||
)
|
||||
endif
|
||||
|
||||
install_data('com.github.joshstrobl.koto.gschema.xml',
|
||||
install_dir: join_paths(get_option('datadir'), 'glib-2.0/schemas')
|
||||
)
|
||||
|
||||
compile_schemas = find_program('glib-compile-schemas', required: false)
|
||||
if compile_schemas.found()
|
||||
test('Validate schema file', compile_schemas,
|
||||
args: ['--strict', '--dry-run', meson.current_source_dir()]
|
||||
)
|
||||
endif
|
20
data/style.css
Normal file
20
data/style.css
Normal file
|
@ -0,0 +1,20 @@
|
|||
.primary-nav > .frame > box >.koto-button {
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.primary-nav .expander .expander-header {
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.expander > revealer > box > .koto-button {
|
||||
min-height: 40px;
|
||||
}
|
||||
|
||||
.koto-button > image {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.primary-nav label,
|
||||
.expander-header label {
|
||||
font-size: large;
|
||||
}
|
27
meson.build
Normal file
27
meson.build
Normal file
|
@ -0,0 +1,27 @@
|
|||
project('koto', 'c',
|
||||
version: '0.1.0',
|
||||
meson_version: '>= 0.50.0',
|
||||
default_options: [ 'warning_level=2',
|
||||
'c_std=gnu11',
|
||||
],
|
||||
)
|
||||
|
||||
i18n = import('i18n')
|
||||
|
||||
config_h = configuration_data()
|
||||
config_h.set_quoted('PACKAGE_VERSION', meson.project_version())
|
||||
config_h.set_quoted('GETTEXT_PACKAGE', 'koto')
|
||||
config_h.set_quoted('LOCALEDIR', join_paths(get_option('prefix'), get_option('localedir')))
|
||||
configure_file(
|
||||
output: 'koto-config.h',
|
||||
configuration: config_h,
|
||||
)
|
||||
add_project_arguments([
|
||||
'-I' + meson.build_root(),
|
||||
], language: 'c')
|
||||
|
||||
subdir('data')
|
||||
subdir('src')
|
||||
subdir('po')
|
||||
|
||||
meson.add_install_script('build-aux/meson/postinstall.py')
|
0
po/LINGUAS
Normal file
0
po/LINGUAS
Normal file
7
po/POTFILES
Normal file
7
po/POTFILES
Normal file
|
@ -0,0 +1,7 @@
|
|||
data/com.github.joshstrobl.koto.desktop.in
|
||||
data/com.github.joshstrobl.koto.appdata.xml.in
|
||||
data/com.github.joshstrobl.koto.gschema.xml
|
||||
src/koto-window.ui
|
||||
src/main.c
|
||||
src/koto-window.c
|
||||
|
1
po/meson.build
Normal file
1
po/meson.build
Normal file
|
@ -0,0 +1 @@
|
|||
i18n.gettext('koto', preset: 'glib')
|
33
src/indexer/album.h
Normal file
33
src/indexer/album.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
/* album.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>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define KOTO_INDEXED_ALBUM_TYPE koto_indexed_album_get_type()
|
||||
G_DECLARE_FINAL_TYPE (KotoIndexedAlbum, koto_indexed_album, KOTO, INDEXED_ALBUM, GObject);
|
||||
|
||||
KotoIndexedAlbum* koto_indexed_album_new(const gchar *path);
|
||||
|
||||
void add_song(KotoIndexedAlbum *self, KotoIndexedFile *file);
|
||||
KotoIndexedFile** get_songs(KotoIndexedAlbum *self);
|
||||
void remove_song(KotoIndexedAlbum *self, KotoIndexedFile *file);
|
||||
void remove_song_by_name(KotoIndexedAlbum *self, gchar *file_name);
|
||||
|
||||
G_END_DECLS
|
33
src/indexer/artist.h
Normal file
33
src/indexer/artist.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
/* artist.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>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define KOTO_INDEXED_ARTIST_TYPE koto_indexed_artist_get_type()
|
||||
G_DECLARE_FINAL_TYPE (KotoIndexedArtist, koto_indexed_artist, KOTO, INDEXED_ARTIST, GObject);
|
||||
|
||||
KotoIndexedArtist* koto_indexed_artist_new(const gchar *path);
|
||||
|
||||
void add_album(KotoIndexedArtist *self, KotoIndexedAlbum *album);
|
||||
KotoIndexedAlbum** get_albums(KotoIndexedArtist *self);
|
||||
void remove_album(KotoIndexedArtist *self, KotoIndexedAlbum *album);
|
||||
void remove_album_by_name(KotoIndexedArtist *self, gchar *album_name);
|
||||
|
||||
G_END_DECLS
|
193
src/indexer/file-indexer.c
Normal file
193
src/indexer/file-indexer.c
Normal file
|
@ -0,0 +1,193 @@
|
|||
/* file-indexer.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 <dirent.h>
|
||||
#include <magic.h>
|
||||
#include <sys/stat.h>
|
||||
#include "file-indexer.h"
|
||||
|
||||
struct KotoIndexedFile {
|
||||
GObject parent_instance;
|
||||
gchar *file_name;
|
||||
gchar *path;
|
||||
};
|
||||
|
||||
struct KotoIndexedAlbum {
|
||||
GObject parent_instance;
|
||||
gboolean has_album_art;
|
||||
gchar *album_name;
|
||||
gchar *art_path;
|
||||
gchar *path;
|
||||
GHashTable *songs;
|
||||
};
|
||||
|
||||
struct _KotoIndexedArtist {
|
||||
GObject parent_instance;
|
||||
gboolean has_artist_art;
|
||||
gchar *artist_name;
|
||||
GHashTable *albums;
|
||||
gchar *path;
|
||||
}
|
||||
|
||||
struct _KotoIndexedLibrary {
|
||||
GObject parent_instance;
|
||||
gchar *path;
|
||||
magic_t magic_cookie;
|
||||
GHashTable *music_artists;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(KotoIndexedLibrary, koto_indexed_library, G_TYPE_OBJECT);
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_PATH,
|
||||
N_PROPERTIES
|
||||
};
|
||||
|
||||
static GParamSpec *props[N_PROPERTIES] = { NULL, };
|
||||
|
||||
static void koto_indexed_library_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec);
|
||||
static void koto_indexed_library_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec);
|
||||
|
||||
static void koto_indexed_library_class_init(KotoIndexedLibraryClass *c) {
|
||||
GObjectClass *gobject_class;
|
||||
gobject_class = G_OBJECT_CLASS(c);
|
||||
gobject_class->set_property = koto_indexed_library_set_property;
|
||||
gobject_class->get_property = koto_indexed_library_get_property;
|
||||
|
||||
props[PROP_PATH] = g_param_spec_string(
|
||||
"path",
|
||||
"Path",
|
||||
"Path to Music",
|
||||
NULL,
|
||||
G_PARAM_CONSTRUCT_ONLY|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE
|
||||
);
|
||||
|
||||
g_object_class_install_properties(gobject_class, N_PROPERTIES, props);
|
||||
}
|
||||
|
||||
static void koto_indexed_library_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec) {
|
||||
KotoIndexedLibrary *self = KOTO_INDEXED_LIBRARY(obj);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_PATH:
|
||||
g_value_set_string(val, self->path);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, spec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void koto_indexed_library_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec){
|
||||
KotoIndexedLibrary *self = KOTO_INDEXED_LIBRARY(obj);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_PATH:
|
||||
self->path = g_strdup(g_value_get_string(val));
|
||||
g_message("Set to %s", self->path);
|
||||
start_indexing(self);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, spec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void start_indexing(KotoIndexedLibrary *self) {
|
||||
struct stat library_stat;
|
||||
int success = stat(self->path, &library_stat);
|
||||
|
||||
if (success != 0) { // Failed to read the library path
|
||||
return;
|
||||
}
|
||||
|
||||
if (!S_ISDIR(library_stat.st_mode)) { // Is not a directory
|
||||
g_warning("%s is not a directory", self->path);
|
||||
return;
|
||||
}
|
||||
|
||||
self->magic_cookie = magic_open(MAGIC_MIME);
|
||||
|
||||
if (self->magic_cookie == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (magic_load(self->magic_cookie, NULL) != 0) {
|
||||
magic_close(self->magic_cookie);
|
||||
return;
|
||||
}
|
||||
|
||||
index_folder(self, self->path);
|
||||
magic_close(self->magic_cookie);
|
||||
}
|
||||
|
||||
void index_folder(KotoIndexedLibrary *self, gchar *path) {
|
||||
DIR *dir = opendir(path); // Attempt to open our directory
|
||||
|
||||
if (dir == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct dirent *entry;
|
||||
|
||||
while ((entry = readdir(dir))) {
|
||||
if (!g_str_has_prefix(entry->d_name, ".")) { // Not a reference to parent dir, self, or a hidden item
|
||||
gchar *full_path = g_strdup_printf("%s%s%s", path, G_DIR_SEPARATOR_S, entry->d_name);
|
||||
|
||||
if (entry->d_type == DT_DIR) { // Directory
|
||||
index_folder(self, full_path); // Index this directory
|
||||
} else if (entry->d_type == DT_REG) { // Regular file
|
||||
index_file(self, full_path); // Index the file
|
||||
}
|
||||
|
||||
g_free(full_path);
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir); // Close the directory
|
||||
}
|
||||
|
||||
void index_file(KotoIndexedLibrary *self, gchar *path) {
|
||||
const char *mime_type = magic_file(self->magic_cookie, path);
|
||||
|
||||
if (mime_type == NULL) { // Failed to get the mimetype
|
||||
return;
|
||||
}
|
||||
|
||||
gchar** mime_info = g_strsplit(mime_type, ";", 2); // Only care about our first item
|
||||
|
||||
if (
|
||||
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_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,
|
||||
"path", path,
|
||||
NULL
|
||||
);
|
||||
}
|
36
src/indexer/file-indexer.h
Normal file
36
src/indexer/file-indexer.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
/* file-indexer.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>
|
||||
|
||||
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()
|
||||
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);
|
||||
void index_file(KotoIndexedLibrary *self, gchar *path);
|
||||
|
||||
G_END_DECLS
|
8
src/indexer/meson.build
Normal file
8
src/indexer/meson.build
Normal file
|
@ -0,0 +1,8 @@
|
|||
indexer_sources = [
|
||||
'file-indexer.c',
|
||||
]
|
||||
|
||||
indexer_deps = [
|
||||
dependency('glib-2.0', version: '>= 2.66'),
|
||||
dependency('gio-2.0', version: '>= 2.66'),
|
||||
]
|
340
src/koto-button.c
Normal file
340
src/koto-button.c
Normal file
|
@ -0,0 +1,340 @@
|
|||
/* koto-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-button.h"
|
||||
#include "koto-config.h"
|
||||
|
||||
struct _PixbufSize {
|
||||
guint size;
|
||||
};
|
||||
|
||||
typedef struct _PixbufSize PixbufSize;
|
||||
|
||||
static PixbufSize *pixbuf_sizes = NULL;
|
||||
static guint pixbuf_sizes_allocated = 0;
|
||||
|
||||
static void init_pixbuf_sizes() {
|
||||
if (pixbuf_sizes == NULL) {
|
||||
pixbuf_sizes = g_new(PixbufSize, NUM_BUILTIN_SIZES);
|
||||
|
||||
pixbuf_sizes[KOTO_BUTTON_PIXBUF_SIZE_INVALID].size = 0;
|
||||
pixbuf_sizes[KOTO_BUTTON_PIXBUF_SIZE_TINY].size = 16;
|
||||
pixbuf_sizes[KOTO_BUTTON_PIXBUF_SIZE_SMALL].size = 24;
|
||||
pixbuf_sizes[KOTO_BUTTON_PIXBUF_SIZE_NORMAL].size = 32;
|
||||
pixbuf_sizes[KOTO_BUTTON_PIXBUF_SIZE_LARGE].size = 64;
|
||||
pixbuf_sizes[KOTO_BUTTON_PIXBUF_SIZE_MASSIVE].size = 96;
|
||||
pixbuf_sizes[KOTO_BUTTON_PIXBUF_SIZE_GODLIKE].size = 128;
|
||||
pixbuf_sizes_allocated = NUM_BUILTIN_SIZES;
|
||||
}
|
||||
}
|
||||
|
||||
guint koto_get_pixbuf_size(KotoButtonPixbufSize s) {
|
||||
init_pixbuf_sizes();
|
||||
|
||||
return pixbuf_sizes[s].size;
|
||||
}
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_PIX_SIZE,
|
||||
PROP_TEXT,
|
||||
PROP_BADGE_TEXT,
|
||||
PROP_PIX,
|
||||
PROP_ICON_NAME,
|
||||
N_PROPERTIES
|
||||
};
|
||||
|
||||
static GParamSpec *props[N_PROPERTIES] = { NULL, };
|
||||
|
||||
struct _KotoButton {
|
||||
GtkBox parent_instance;
|
||||
guint pix_size;
|
||||
|
||||
GtkWidget *button_image;
|
||||
GtkWidget *badge_label;
|
||||
GtkWidget *button_label;
|
||||
|
||||
gchar *badge_text;
|
||||
gchar *icon_name;
|
||||
gchar *text;
|
||||
|
||||
GdkPixbuf *pix;
|
||||
};
|
||||
|
||||
struct _KotoButtonClass {
|
||||
GtkBoxClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(KotoButton, koto_button, GTK_TYPE_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);
|
||||
|
||||
static void koto_button_class_init(KotoButtonClass *c) {
|
||||
GObjectClass *gobject_class;
|
||||
gobject_class = G_OBJECT_CLASS(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(
|
||||
"pixbuf-size",
|
||||
"Pixbuf Size",
|
||||
"Size of the pixbuf",
|
||||
koto_get_pixbuf_size(KOTO_BUTTON_PIXBUF_SIZE_TINY),
|
||||
koto_get_pixbuf_size(KOTO_BUTTON_PIXBUF_SIZE_GODLIKE),
|
||||
koto_get_pixbuf_size(KOTO_BUTTON_PIXBUF_SIZE_SMALL),
|
||||
G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE
|
||||
);
|
||||
|
||||
props[PROP_TEXT] = g_param_spec_string(
|
||||
"button-text",
|
||||
"Button Text",
|
||||
"Text of Button",
|
||||
NULL,
|
||||
G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE
|
||||
);
|
||||
|
||||
props[PROP_BADGE_TEXT] = g_param_spec_string(
|
||||
"badge-text",
|
||||
"Badge Text",
|
||||
"Text of Badge",
|
||||
NULL,
|
||||
G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE
|
||||
);
|
||||
|
||||
props[PROP_PIX] = g_param_spec_object(
|
||||
"pixbuf",
|
||||
"Pixbuf",
|
||||
"Pixbuf",
|
||||
GDK_TYPE_PIXBUF,
|
||||
G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE
|
||||
);
|
||||
|
||||
props[PROP_ICON_NAME] = g_param_spec_string(
|
||||
"icon-name",
|
||||
"Icon Name",
|
||||
"Name of Icon",
|
||||
NULL,
|
||||
G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE
|
||||
);
|
||||
|
||||
g_object_class_install_properties(gobject_class, N_PROPERTIES, 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");
|
||||
}
|
||||
|
||||
static void koto_button_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec) {
|
||||
KotoButton *self = KOTO_BUTTON(obj);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_PIX_SIZE:
|
||||
g_value_set_uint(val, self->pix_size);
|
||||
break;
|
||||
case PROP_TEXT:
|
||||
g_value_set_string(val, self->text);
|
||||
break;
|
||||
case PROP_BADGE_TEXT:
|
||||
g_value_set_string(val, self->badge_text);
|
||||
break;
|
||||
case PROP_ICON_NAME:
|
||||
g_value_set_string(val, self->icon_name);
|
||||
break;
|
||||
case PROP_PIX:
|
||||
g_value_set_object(val, self->pix);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, spec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void koto_button_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec) {
|
||||
KotoButton *self = KOTO_BUTTON(obj);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_PIX_SIZE:
|
||||
koto_button_set_pixbuf_size(self, g_value_get_uint(val));
|
||||
break;
|
||||
case PROP_TEXT:
|
||||
koto_button_set_text(self, g_strdup(g_value_get_string(val)));
|
||||
break;
|
||||
case PROP_BADGE_TEXT:
|
||||
koto_button_set_badge_text(self, g_strdup(g_value_get_string(val)));
|
||||
break;
|
||||
case PROP_PIX:
|
||||
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)));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, spec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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("");
|
||||
} else {
|
||||
g_free(self->badge_text);
|
||||
self->badge_text = g_strdup(text);
|
||||
}
|
||||
|
||||
if (GTK_IS_LABEL(self->badge_label)) { // If badge label already exists
|
||||
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
|
||||
}
|
||||
|
||||
if (strcmp(self->badge_text, "") != 0) { // Empty badge
|
||||
gtk_widget_hide(self->badge_label); // Hide our badge
|
||||
} else { // Have some text
|
||||
gtk_widget_show(self->badge_label); // Show our badge
|
||||
}
|
||||
|
||||
g_object_notify_by_pspec(G_OBJECT(self), props[PROP_BADGE_TEXT]);
|
||||
}
|
||||
|
||||
void koto_button_set_icon_name(KotoButton *self, gchar *icon_name) {
|
||||
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 (GTK_IS_IMAGE(self->button_image)) { // If we already have a button image
|
||||
gtk_widget_hide(self->button_image); // Hide
|
||||
}
|
||||
|
||||
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]);
|
||||
}
|
||||
|
||||
void koto_button_set_pixbuf(KotoButton *self, GdkPixbuf *pix) {
|
||||
g_return_if_fail(self->pix_size != 0); // Return if don't have a pixbuf size to indicate what to scale to
|
||||
|
||||
if (!GDK_IS_PIXBUF(pix)) {
|
||||
return;
|
||||
}
|
||||
|
||||
self->pix = pix;
|
||||
|
||||
GdkPixbuf *use_pix = pix; // Default to using our provided pixbuf
|
||||
if (gdk_pixbuf_get_height(pix) > (int) self->pix_size) { // If our height is greater than our desired pixel size
|
||||
use_pix = gdk_pixbuf_scale_simple(pix, -1, self->pix_size, GDK_INTERP_BILINEAR); // Scale using bilnear
|
||||
g_return_if_fail(use_pix != NULL); // Return if we could not allocate memory for the scaling
|
||||
}
|
||||
|
||||
if (GTK_IS_IMAGE(self->button_image)) { // If we already have a button image
|
||||
gtk_image_set_from_pixbuf(GTK_IMAGE(self->button_image), use_pix); // Update our pixbuf
|
||||
gtk_widget_show(self->button_image); // Ensure we show the image
|
||||
} else { // No image set
|
||||
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);
|
||||
}
|
||||
|
||||
g_object_notify_by_pspec(G_OBJECT(self), props[PROP_PIX]);
|
||||
}
|
||||
|
||||
void koto_button_set_pixbuf_size(KotoButton *self, guint size) {
|
||||
g_return_if_fail(size != self->pix_size); // If the sizes aren't different, return
|
||||
|
||||
self->pix_size = size;
|
||||
|
||||
if (GDK_PIXBUF(self->pix)) { // If we already have a pixbuf set and we're changing the size
|
||||
koto_button_set_pixbuf(self, self->pix);
|
||||
}
|
||||
|
||||
g_object_notify_by_pspec(G_OBJECT(self), props[PROP_PIX_SIZE]);
|
||||
}
|
||||
|
||||
void koto_button_set_text(KotoButton *self, gchar *text) {
|
||||
gchar *copied_text = g_strdup(text); // Copy our text
|
||||
|
||||
if (strcmp(copied_text, "") == 0) { // Clearing our text
|
||||
g_free(self->text); // Free existing text
|
||||
}
|
||||
|
||||
self->text = copied_text;
|
||||
|
||||
if (GTK_IS_LABEL(self->button_label)) { // If we have a button label
|
||||
if (strcmp(self->text, "") != 0) { // Have text set
|
||||
gtk_label_set_text(GTK_LABEL(self->button_label), self->text);
|
||||
gtk_widget_show(self->button_label); // Show the label
|
||||
} else { // Have a label but no longer text
|
||||
gtk_container_remove(GTK_CONTAINER(self), self->button_label); // Remove the label
|
||||
g_free(self->button_label);
|
||||
}
|
||||
} else { // If we do not have a button label
|
||||
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
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_object_notify_by_pspec(G_OBJECT(self), props[PROP_TEXT]);
|
||||
}
|
||||
|
||||
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) {
|
||||
return g_object_new(KOTO_TYPE_BUTTON,
|
||||
"button-text", label,
|
||||
"icon-name", icon_name,
|
||||
"orientation", GTK_ORIENTATION_HORIZONTAL,
|
||||
"pixbuf-size", koto_get_pixbuf_size(size),
|
||||
NULL
|
||||
);
|
||||
}
|
||||
|
||||
KotoButton* koto_button_new_with_pixbuf(gchar *label, GdkPixbuf *pix, KotoButtonPixbufSize size) {
|
||||
return g_object_new(KOTO_TYPE_BUTTON,
|
||||
"button-text", label,
|
||||
"pixbuf", pix,
|
||||
"orientation", GTK_ORIENTATION_HORIZONTAL,
|
||||
"pixbuf-size", koto_get_pixbuf_size(size),
|
||||
NULL
|
||||
);
|
||||
}
|
57
src/koto-button.h
Normal file
57
src/koto-button.h
Normal file
|
@ -0,0 +1,57 @@
|
|||
/* koto-button.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
|
||||
#ifndef __GTK_ENUMS_H__
|
||||
#define __GTK_ENUMS_H__
|
||||
#endif
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <gdk-pixbuf-2.0/gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <gtk-3.0/gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef enum {
|
||||
KOTO_BUTTON_PIXBUF_SIZE_INVALID,
|
||||
KOTO_BUTTON_PIXBUF_SIZE_TINY,
|
||||
KOTO_BUTTON_PIXBUF_SIZE_SMALL,
|
||||
KOTO_BUTTON_PIXBUF_SIZE_NORMAL,
|
||||
KOTO_BUTTON_PIXBUF_SIZE_LARGE,
|
||||
KOTO_BUTTON_PIXBUF_SIZE_MASSIVE,
|
||||
KOTO_BUTTON_PIXBUF_SIZE_GODLIKE
|
||||
} KotoButtonPixbufSize;
|
||||
|
||||
#define NUM_BUILTIN_SIZES 7
|
||||
|
||||
#define KOTO_TYPE_BUTTON (koto_button_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (KotoButton, koto_button, KOTO, BUTTON, GtkBox)
|
||||
|
||||
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_pixbuf(gchar *label, GdkPixbuf *pix, KotoButtonPixbufSize size);
|
||||
|
||||
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_pixbuf(KotoButton *self, GdkPixbuf *pix);
|
||||
void koto_button_set_pixbuf_size(KotoButton *self, guint size);
|
||||
void koto_button_set_text(KotoButton *self, gchar *text);
|
||||
|
||||
G_END_DECLS
|
245
src/koto-expander.c
Normal file
245
src/koto-expander.c
Normal file
|
@ -0,0 +1,245 @@
|
|||
/* koto-expander.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/gi18n.h>
|
||||
#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_HEADER_ICON_NAME,
|
||||
PROP_HEADER_LABEL,
|
||||
PROP_HEADER_SECONDARY_BUTTON,
|
||||
PROP_CONTENT,
|
||||
N_PROPERTIES
|
||||
};
|
||||
|
||||
static GParamSpec *props[N_PROPERTIES] = { NULL, };
|
||||
|
||||
struct _KotoExpander {
|
||||
GtkBox parent_instance;
|
||||
gboolean constructed;
|
||||
GtkWidget *header;
|
||||
KotoButton *header_button;
|
||||
|
||||
gchar *icon_name;
|
||||
gchar *label;
|
||||
|
||||
GtkWidget *header_secondary_button;
|
||||
KotoFlipperButton *header_expand_button;
|
||||
|
||||
GtkWidget *revealer;
|
||||
GtkWidget *content;
|
||||
};
|
||||
|
||||
struct _KotoExpanderClass {
|
||||
GtkBoxClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(KotoExpander, koto_expander, GTK_TYPE_BOX);
|
||||
|
||||
static void koto_expander_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec);
|
||||
static void koto_expander_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec);
|
||||
|
||||
static void koto_expander_class_init(KotoExpanderClass *c) {
|
||||
GObjectClass *gobject_class;
|
||||
gobject_class = G_OBJECT_CLASS(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(
|
||||
"icon-name",
|
||||
"Icon Name",
|
||||
"Name of the icon to use in the Expander",
|
||||
"emblem-favorite-symbolic",
|
||||
G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE
|
||||
);
|
||||
|
||||
props[PROP_HEADER_LABEL] = g_param_spec_string(
|
||||
"label",
|
||||
"Label",
|
||||
"Label for the Expander",
|
||||
NULL,
|
||||
G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE
|
||||
);
|
||||
|
||||
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,
|
||||
G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE
|
||||
);
|
||||
|
||||
props[PROP_CONTENT] = g_param_spec_object(
|
||||
"content",
|
||||
"Content",
|
||||
"Content inside the Expander",
|
||||
GTK_TYPE_WIDGET,
|
||||
G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE
|
||||
);
|
||||
|
||||
g_object_class_install_properties(gobject_class, N_PROPERTIES, props);
|
||||
}
|
||||
|
||||
static void koto_expander_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec) {
|
||||
KotoExpander *self = KOTO_EXPANDER(obj);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_HEADER_ICON_NAME:
|
||||
g_value_set_string(val, self->icon_name);
|
||||
break;
|
||||
case PROP_HEADER_LABEL:
|
||||
g_value_set_string(val, self->label);
|
||||
break;
|
||||
case PROP_HEADER_SECONDARY_BUTTON:
|
||||
g_value_set_object(val, (GObject *) self->header_secondary_button);
|
||||
break;
|
||||
case PROP_CONTENT:
|
||||
g_value_set_object(val, (GObject *) self->content);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, spec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void koto_expander_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec) {
|
||||
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);
|
||||
|
||||
if (GTK_IS_WIDGET(new_button)) { // Created our widget successfully
|
||||
self->header_button = new_button;
|
||||
gtk_box_pack_start(GTK_BOX(self->header), GTK_WIDGET(self->header_button), TRUE, TRUE, 0); // Add it
|
||||
}
|
||||
}
|
||||
|
||||
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)));
|
||||
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));
|
||||
break;
|
||||
case PROP_CONTENT:
|
||||
koto_expander_set_content(self, (GtkWidget*) g_value_get_object(val));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, spec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void koto_expander_init(KotoExpander *self) {
|
||||
GtkSettings *settings = gtk_settings_get_default();
|
||||
g_object_set(settings, "gtk_application_prefer_dark_theme", TRUE, NULL);
|
||||
|
||||
GtkStyleContext *style = gtk_widget_get_style_context(GTK_WIDGET(self));
|
||||
gtk_style_context_add_class(style, "expander");
|
||||
|
||||
self->header = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10);
|
||||
|
||||
GtkStyleContext *header_style = gtk_widget_get_style_context(self->header);
|
||||
gtk_style_context_add_class(header_style, "expander-header");
|
||||
|
||||
self->revealer = gtk_revealer_new();
|
||||
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);
|
||||
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);
|
||||
gtk_box_pack_end(GTK_BOX(self), self->revealer, TRUE, TRUE, 0);
|
||||
|
||||
self->constructed = TRUE;
|
||||
|
||||
g_signal_connect(self->header_expand_button, "clicked", G_CALLBACK(koto_expander_toggle_content), self);
|
||||
}
|
||||
|
||||
void koto_expander_set_secondary_button(KotoExpander *self, GtkWidget *new_button) {
|
||||
if (!self->constructed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!GTK_IS_BUTTON(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);
|
||||
}
|
||||
|
||||
self->header_secondary_button = new_button;
|
||||
gtk_box_pack_end(GTK_BOX(self->header), self->header_secondary_button, FALSE, FALSE, 0);
|
||||
|
||||
g_object_notify_by_pspec(G_OBJECT(self), props[PROP_HEADER_SECONDARY_BUTTON]);
|
||||
}
|
||||
|
||||
void koto_expander_set_content(KotoExpander *self, GtkWidget *new_content) {
|
||||
if (!self->constructed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (self->content != NULL) { // Already have content
|
||||
gtk_container_remove(GTK_CONTAINER(self->revealer), self->content);
|
||||
g_free(self->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]);
|
||||
}
|
||||
|
||||
void koto_expander_toggle_content(GtkWidget *button, gpointer data) {
|
||||
KotoExpander* self = data;
|
||||
koto_flipper_button_flip(KOTO_FLIPPER_BUTTON(button));
|
||||
GtkRevealer* rev = GTK_REVEALER(self->revealer);
|
||||
gtk_revealer_set_reveal_child(rev, !gtk_revealer_get_reveal_child(rev)); // Invert our values
|
||||
}
|
||||
|
||||
KotoExpander* koto_expander_new(gchar *primary_icon_name, gchar *primary_label_text) {
|
||||
return g_object_new(KOTO_TYPE_EXPANDER,
|
||||
"orientation", GTK_ORIENTATION_VERTICAL,
|
||||
"icon-name", primary_icon_name,
|
||||
"label", primary_label_text,
|
||||
NULL
|
||||
);
|
||||
}
|
||||
|
||||
KotoExpander* koto_expander_new_with_button(gchar *primary_icon_name, gchar *primary_label_text, GtkWidget *secondary_button) {
|
||||
return g_object_new(KOTO_TYPE_EXPANDER,
|
||||
"orientation", GTK_ORIENTATION_VERTICAL,
|
||||
"icon-name", primary_icon_name,
|
||||
"label", primary_label_text,
|
||||
"secondary-button", secondary_button,
|
||||
NULL
|
||||
);
|
||||
}
|
36
src/koto-expander.h
Normal file
36
src/koto-expander.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
/* koto-expander.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 <gtk-3.0/gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define KOTO_TYPE_EXPANDER (koto_expander_get_type())
|
||||
|
||||
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);
|
||||
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_content(KotoExpander *self, GtkWidget *new_content);
|
||||
void koto_expander_toggle_content(GtkWidget *button, gpointer data);
|
||||
|
||||
G_END_DECLS
|
129
src/koto-flipper-button.c
Normal file
129
src/koto-flipper-button.c
Normal file
|
@ -0,0 +1,129 @@
|
|||
/* 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
|
||||
);
|
||||
}
|
32
src/koto-flipper-button.h
Normal file
32
src/koto-flipper-button.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
/* koto-flipper-button.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 <gtk-3.0/gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define KOTO_TYPE_FLIPPER_BUTTON (koto_flipper_button_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (KotoFlipperButton, koto_flipper_button, KOTO, FLIPPER_BUTTON, GtkButton)
|
||||
|
||||
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);
|
||||
|
||||
G_END_DECLS
|
47
src/koto-headerbar.c
Normal file
47
src/koto-headerbar.c
Normal file
|
@ -0,0 +1,47 @@
|
|||
/* koto-headerbar.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-config.h"
|
||||
#include "koto-headerbar.h"
|
||||
|
||||
struct _KotoHeaderBar {
|
||||
GtkHeaderBar parent_instance;
|
||||
GtkButton *menu_button;
|
||||
GtkWidget *search;
|
||||
};
|
||||
|
||||
struct _KotoHeaderBarClass {
|
||||
GtkHeaderBarClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(KotoHeaderBar, koto_headerbar, GTK_TYPE_HEADER_BAR)
|
||||
|
||||
static void koto_headerbar_class_init(KotoHeaderBarClass *c) {
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(c);
|
||||
gtk_widget_class_set_template_from_resource(widget_class, "/com/github/joshstrobl/koto/koto-headerbar.ui");
|
||||
//gtk_widget_class_bind_template_child(widget_class, KotoHeaderBar, menu_button);
|
||||
//gtk_widget_class_bind_template_child(widget_class, KotoHeaderBar, search);
|
||||
}
|
||||
|
||||
static void koto_headerbar_init(KotoHeaderBar *self) {
|
||||
gtk_widget_init_template(GTK_WIDGET(self));
|
||||
gtk_widget_show_all(GTK_WIDGET(self));
|
||||
}
|
||||
|
||||
KotoHeaderBar* koto_headerbar_new(void) {
|
||||
return g_object_new(KOTO_TYPE_HEADERBAR, NULL);
|
||||
}
|
30
src/koto-headerbar.h
Normal file
30
src/koto-headerbar.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
/* koto-headerbar.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 <gtk-3.0/gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define KOTO_TYPE_HEADERBAR (koto_headerbar_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (KotoHeaderBar, koto_headerbar, KOTO, HEADERBAR, GtkHeaderBar)
|
||||
|
||||
KotoHeaderBar* koto_headerbar_new (void);
|
||||
|
||||
G_END_DECLS
|
40
src/koto-headerbar.ui
Normal file
40
src/koto-headerbar.ui
Normal file
|
@ -0,0 +1,40 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.38.2 -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.24"/>
|
||||
<object class="GtkImage" id="audioHeadphonesMenuImage">
|
||||
<property name="can-focus">False</property>
|
||||
<property name="icon-name">audio-headphones</property>
|
||||
<property name="icon_size">3</property>
|
||||
</object>
|
||||
<template class="KotoHeaderBar" parent="GtkHeaderBar">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="show-close-button">True</property>
|
||||
<property name="decoration-layout">appmenu:minimize,maximize,close</property>
|
||||
<child type="title">
|
||||
<object class="GtkSearchEntry" id="search">
|
||||
<property name="width-request">400</property>
|
||||
<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...</property>
|
||||
<property name="input-hints">GTK_INPUT_HINT_NO_EMOJI | GTK_INPUT_HINT_NONE</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="menu_button">
|
||||
<property name="name">menu_button</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">True</property>
|
||||
<property name="image">audioHeadphonesMenuImage</property>
|
||||
<style>
|
||||
<class name="flat"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
155
src/koto-nav.c
Normal file
155
src/koto-nav.c
Normal file
|
@ -0,0 +1,155 @@
|
|||
/* koto-nav.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-button.h"
|
||||
#include "koto-expander.h"
|
||||
#include "koto-nav.h"
|
||||
#include "koto-utils.h"
|
||||
|
||||
struct _KotoNav {
|
||||
GtkScrolledWindow parent_instance;
|
||||
GtkWidget *content;
|
||||
|
||||
KotoButton *home_button;
|
||||
KotoExpander *audiobook_expander;
|
||||
KotoExpander *music_expander;
|
||||
KotoExpander *podcast_expander;
|
||||
KotoExpander *playlists_expander;
|
||||
|
||||
// Audiobooks
|
||||
|
||||
KotoButton *audiobooks_local;
|
||||
KotoButton *audiobooks_audible;
|
||||
KotoButton *audiobooks_librivox;
|
||||
|
||||
// Music
|
||||
|
||||
KotoButton *music_local;
|
||||
KotoButton *music_radio;
|
||||
|
||||
// Podcasts
|
||||
|
||||
KotoButton *podcasts_local;
|
||||
KotoButton *podcasts_discover;
|
||||
};
|
||||
|
||||
struct _KotoNavClass {
|
||||
GtkScrolledWindowClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(KotoNav, koto_nav, GTK_TYPE_SCROLLED_WINDOW);
|
||||
|
||||
static void koto_nav_class_init(KotoNavClass *c) {
|
||||
|
||||
}
|
||||
|
||||
static void koto_nav_init(KotoNav *self) {
|
||||
gtk_widget_set_size_request(GTK_WIDGET(self), 300, -1); // Take up 300px width
|
||||
self->content = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10);
|
||||
|
||||
GtkStyleContext *style = gtk_widget_get_style_context(GTK_WIDGET(self));
|
||||
gtk_style_context_add_class(style, "primary-nav");
|
||||
|
||||
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);
|
||||
|
||||
if (h_button != NULL) {
|
||||
self->home_button = h_button;
|
||||
gtk_box_pack_start(GTK_BOX(self->content), GTK_WIDGET(self->home_button), FALSE, FALSE, 0);
|
||||
}
|
||||
|
||||
koto_nav_create_audiobooks_section(self);
|
||||
koto_nav_create_music_section(self);
|
||||
koto_nav_create_podcasts_section(self);
|
||||
|
||||
|
||||
|
||||
GtkWidget *playlist_add_button = koto_create_flat_icon_button("list-add-symbolic", GTK_ICON_SIZE_SMALL_TOOLBAR);
|
||||
KotoExpander *pl_expander = koto_expander_new_with_button("playlist-symbolic", "Playlists", playlist_add_button);
|
||||
|
||||
if (pl_expander != NULL) {
|
||||
self->playlists_expander = pl_expander;
|
||||
gtk_box_pack_start(GTK_BOX(self->content), GTK_WIDGET(self->playlists_expander), FALSE, FALSE, 0);
|
||||
}
|
||||
|
||||
gtk_widget_show_all(GTK_WIDGET(self));
|
||||
}
|
||||
|
||||
void koto_nav_create_audiobooks_section(KotoNav *self) {
|
||||
KotoExpander *a_expander = koto_expander_new("ephy-bookmarks-symbolic", "Audiobooks");
|
||||
|
||||
self->audiobook_expander = a_expander;
|
||||
gtk_box_pack_start(GTK_BOX(self->content), GTK_WIDGET(self->audiobook_expander), FALSE, FALSE, 0);
|
||||
|
||||
GtkWidget *new_content = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
|
||||
|
||||
self->audiobooks_local = koto_button_new_plain("Local Library");
|
||||
self->audiobooks_audible = koto_button_new_plain("Audible");
|
||||
self->audiobooks_librivox = koto_button_new_plain("LibriVox");
|
||||
|
||||
gtk_box_pack_start(GTK_BOX(new_content), GTK_WIDGET(self->audiobooks_local), FALSE, FALSE, 0);
|
||||
gtk_box_pack_start(GTK_BOX(new_content), GTK_WIDGET(self->audiobooks_audible), FALSE, FALSE, 0);
|
||||
gtk_box_pack_start(GTK_BOX(new_content), GTK_WIDGET(self->audiobooks_librivox), FALSE, FALSE, 0);
|
||||
|
||||
koto_expander_set_content(a_expander, new_content);
|
||||
}
|
||||
|
||||
void koto_nav_create_music_section(KotoNav *self) {
|
||||
KotoExpander *m_expander = koto_expander_new("emblem-music-symbolic", "Music");
|
||||
self->music_expander = m_expander;
|
||||
gtk_box_pack_start(GTK_BOX(self->content), GTK_WIDGET(self->music_expander), FALSE, FALSE, 0);
|
||||
|
||||
GtkWidget *new_content = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
|
||||
|
||||
self->music_local = koto_button_new_plain("Local Library");
|
||||
self->music_radio = koto_button_new_plain("Radio");
|
||||
|
||||
gtk_box_pack_start(GTK_BOX(new_content), GTK_WIDGET(self->music_local), FALSE, FALSE, 0);
|
||||
gtk_box_pack_start(GTK_BOX(new_content), GTK_WIDGET(self->music_radio), FALSE, FALSE, 0);
|
||||
|
||||
koto_expander_set_content(m_expander, new_content);
|
||||
}
|
||||
|
||||
void koto_nav_create_podcasts_section(KotoNav *self) {
|
||||
KotoExpander *p_expander = koto_expander_new("microphone-sensitivity-high-symbolic", "Podcasts");
|
||||
self->podcast_expander = p_expander;
|
||||
gtk_box_pack_start(GTK_BOX(self->content), GTK_WIDGET(self->podcast_expander), FALSE, FALSE, 0);
|
||||
|
||||
GtkWidget *new_content = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
|
||||
|
||||
self->podcasts_local = koto_button_new_plain("Library");
|
||||
self->podcasts_discover = koto_button_new_plain("Find New Podcasts");
|
||||
|
||||
gtk_box_pack_start(GTK_BOX(new_content), GTK_WIDGET(self->podcasts_local), FALSE, FALSE, 0);
|
||||
gtk_box_pack_start(GTK_BOX(new_content), GTK_WIDGET(self->podcasts_discover), FALSE, FALSE, 0);
|
||||
|
||||
koto_expander_set_content(p_expander, new_content);
|
||||
}
|
||||
|
||||
KotoNav* koto_nav_new(void) {
|
||||
return g_object_new(KOTO_TYPE_NAV,
|
||||
"hscrollbar-policy", GTK_POLICY_NEVER,
|
||||
"min-content-width", 300,
|
||||
"max-content-width", 300,
|
||||
"propagate-natural-height", TRUE,
|
||||
"propagate-natural-width", TRUE,
|
||||
"shadow-type", GTK_SHADOW_NONE
|
||||
,NULL);
|
||||
}
|
32
src/koto-nav.h
Normal file
32
src/koto-nav.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
/* koto-nav.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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <gtk-3.0/gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define KOTO_TYPE_NAV (koto_nav_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (KotoNav, koto_nav, KOTO, NAV, GtkScrolledWindow)
|
||||
|
||||
KotoNav* koto_nav_new (void);
|
||||
void koto_nav_create_audiobooks_section(KotoNav *self);
|
||||
void koto_nav_create_music_section(KotoNav *self);
|
||||
void koto_nav_create_podcasts_section(KotoNav *self);
|
||||
|
||||
G_END_DECLS
|
172
src/koto-playerbar.c
Normal file
172
src/koto-playerbar.c
Normal file
|
@ -0,0 +1,172 @@
|
|||
/* koto-playerbar.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/gi18n.h>
|
||||
#include "koto-config.h"
|
||||
#include "koto-playerbar.h"
|
||||
#include "koto-utils.h"
|
||||
|
||||
struct _KotoPlayerBar {
|
||||
GtkBox parent_instance;
|
||||
|
||||
/* Sections */
|
||||
GtkWidget *playback_section;
|
||||
GtkWidget *primary_controls_section;
|
||||
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;
|
||||
GtkWidget *volume_button;
|
||||
|
||||
/* Selected Playback Section */
|
||||
|
||||
GtkWidget *playback_details_section;
|
||||
GtkWidget *artwork;
|
||||
GtkWidget *playback_title;
|
||||
GtkWidget *playback_album;
|
||||
GtkWidget *playback_artist;
|
||||
};
|
||||
|
||||
struct _KotoPlayerBarClass {
|
||||
GtkBoxClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE(KotoPlayerBar, koto_playerbar, GTK_TYPE_BOX);
|
||||
|
||||
static void koto_playerbar_constructed(GObject *obj);
|
||||
|
||||
static void koto_playerbar_class_init(KotoPlayerBarClass *c) {
|
||||
GObjectClass *gobject_class;
|
||||
gobject_class = G_OBJECT_CLASS(c);
|
||||
|
||||
gobject_class->constructed = koto_playerbar_constructed;
|
||||
}
|
||||
|
||||
static void koto_playerbar_constructed(GObject *obj) {
|
||||
KotoPlayerBar *self = KOTO_PLAYERBAR(obj);
|
||||
self->playback_section = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
self->primary_controls_section = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
self->secondary_controls_section = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
|
||||
gtk_box_pack_start(GTK_BOX(self), GTK_WIDGET(self->primary_controls_section), FALSE, FALSE, 0);
|
||||
gtk_box_pack_start(GTK_BOX(self), GTK_WIDGET(self->playback_section), TRUE, FALSE, 0);
|
||||
gtk_box_pack_start(GTK_BOX(self), GTK_WIDGET(self->secondary_controls_section), FALSE, FALSE, 0);
|
||||
|
||||
koto_playerbar_create_playback_details(self);
|
||||
koto_playerbar_create_primary_controls(self);
|
||||
koto_playerbar_create_secondary_controls(self);
|
||||
|
||||
gtk_widget_set_margin_top(GTK_WIDGET(self), 10);
|
||||
gtk_widget_set_margin_bottom(GTK_WIDGET(self), 10);
|
||||
gtk_widget_set_margin_start(GTK_WIDGET(self), 10);
|
||||
gtk_widget_set_margin_end(GTK_WIDGET(self), 10);
|
||||
}
|
||||
|
||||
static void koto_playerbar_init(KotoPlayerBar *self) {
|
||||
gtk_widget_show_all(GTK_WIDGET(self));
|
||||
}
|
||||
|
||||
KotoPlayerBar* koto_playerbar_new(void) {
|
||||
return g_object_new(KOTO_TYPE_PLAYERBAR, "orientation", GTK_ORIENTATION_HORIZONTAL, NULL);
|
||||
}
|
||||
|
||||
void koto_playerbar_create_playback_details(KotoPlayerBar* bar) {
|
||||
bar->playback_details_section = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
|
||||
|
||||
GtkIconTheme* default_icon_theme = gtk_icon_theme_get_default();
|
||||
|
||||
if (default_icon_theme != NULL) {
|
||||
gint scale_factor = gtk_widget_get_scale_factor(GTK_WIDGET(bar));
|
||||
GdkPixbuf* audio_pixbuf = gtk_icon_theme_load_icon_for_scale(default_icon_theme, "audio-x-generic-symbolic", 96, scale_factor, GTK_ICON_LOOKUP_USE_BUILTIN & GTK_ICON_LOOKUP_FORCE_SIZE, NULL);
|
||||
|
||||
if (audio_pixbuf != NULL) {
|
||||
bar->artwork = gtk_image_new_from_pixbuf(audio_pixbuf);
|
||||
}
|
||||
}
|
||||
|
||||
if (bar->artwork == NULL) {
|
||||
bar->artwork = gtk_image_new_from_icon_name("audio-x-generic-symbolic", GTK_ICON_SIZE_DIALOG);
|
||||
}
|
||||
|
||||
if (bar->artwork != NULL) {
|
||||
gtk_widget_set_margin_end(bar->artwork, 10);
|
||||
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"));
|
||||
|
||||
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);
|
||||
gtk_box_pack_start(GTK_BOX(bar->playback_details_section), GTK_WIDGET(bar->playback_artist), TRUE, TRUE, 0);
|
||||
|
||||
gtk_box_pack_end(GTK_BOX(bar->playback_section), GTK_WIDGET(bar->playback_details_section), FALSE, FALSE, 0);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (bar->back_button != NULL) {
|
||||
gtk_box_pack_start(GTK_BOX(bar->primary_controls_section), 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);
|
||||
}
|
||||
|
||||
if (bar->forward_button != NULL) {
|
||||
gtk_box_pack_start(GTK_BOX(bar->primary_controls_section), 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->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);
|
||||
}
|
||||
|
||||
if (bar->shuffle_button != NULL) {
|
||||
gtk_box_pack_start(GTK_BOX(bar->secondary_controls_section), 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);
|
||||
}
|
||||
|
||||
if (bar->eq_button != NULL) {
|
||||
gtk_box_pack_start(GTK_BOX(bar->secondary_controls_section), bar->eq_button, FALSE, FALSE, 0);
|
||||
}
|
||||
|
||||
if (bar->volume_button != NULL) {
|
||||
gtk_box_pack_start(GTK_BOX(bar->secondary_controls_section), bar->volume_button, FALSE, FALSE, 0);
|
||||
}
|
||||
}
|
32
src/koto-playerbar.h
Normal file
32
src/koto-playerbar.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
/* koto-playerbar.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 <gtk-3.0/gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define KOTO_TYPE_PLAYERBAR (koto_playerbar_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (KotoPlayerBar, koto_playerbar, KOTO, PLAYERBAR, GtkBox)
|
||||
|
||||
KotoPlayerBar* koto_playerbar_new (void);
|
||||
void koto_playerbar_create_playback_details(KotoPlayerBar* bar);
|
||||
void koto_playerbar_create_primary_controls(KotoPlayerBar* bar);
|
||||
void koto_playerbar_create_secondary_controls(KotoPlayerBar* bar);
|
||||
|
||||
G_END_DECLS
|
28
src/koto-utils.c
Normal file
28
src/koto-utils.c
Normal file
|
@ -0,0 +1,28 @@
|
|||
/* 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;
|
||||
}
|
24
src/koto-utils.h
Normal file
24
src/koto-utils.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
/* 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
|
89
src/koto-window.c
Normal file
89
src/koto-window.c
Normal file
|
@ -0,0 +1,89 @@
|
|||
/* koto-window.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 "indexer/file-indexer.h"
|
||||
#include "koto-config.h"
|
||||
#include "koto-headerbar.h"
|
||||
#include "koto-nav.h"
|
||||
#include "koto-playerbar.h"
|
||||
#include "koto-window.h"
|
||||
|
||||
struct _KotoWindow {
|
||||
GtkApplicationWindow parent_instance;
|
||||
KotoIndexedLibrary *library;
|
||||
KotoHeaderBar *header_bar;
|
||||
GtkWidget *primary_layout;
|
||||
GtkWidget *content_layout;
|
||||
|
||||
KotoNav *nav;
|
||||
KotoPlayerBar *player_bar;
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
//KotoHeaderBar *header = koto_headerbar_new();
|
||||
self->header_bar = koto_headerbar_new();
|
||||
|
||||
if (self->header_bar != NULL) {
|
||||
gtk_window_set_titlebar(GTK_WINDOW(self), GTK_WIDGET(self->header_bar));
|
||||
}
|
||||
|
||||
self->primary_layout = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
|
||||
self->content_layout = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
|
||||
self->nav = koto_nav_new();
|
||||
|
||||
if (self->nav != NULL) {
|
||||
gtk_box_pack_start(GTK_BOX(self->content_layout), GTK_WIDGET(self->nav), FALSE, TRUE, 10);
|
||||
|
||||
GtkWidget *sep = gtk_separator_new(GTK_ORIENTATION_VERTICAL);
|
||||
gtk_box_pack_end(GTK_BOX(self->content_layout), sep, FALSE, TRUE, 0);
|
||||
}
|
||||
|
||||
gtk_box_pack_start(GTK_BOX(self->primary_layout), self->content_layout, TRUE, TRUE, 0);
|
||||
|
||||
self->player_bar = koto_playerbar_new();
|
||||
|
||||
if (self->player_bar != NULL) {
|
||||
gtk_box_pack_start(GTK_BOX(self->primary_layout), GTK_WIDGET(self->player_bar), FALSE, FALSE, 0);
|
||||
}
|
||||
|
||||
gtk_container_add(GTK_CONTAINER(self), self->primary_layout);
|
||||
gtk_widget_show_all(GTK_WIDGET(self));
|
||||
|
||||
g_thread_new("load-library", load_library, self);
|
||||
}
|
||||
|
||||
void load_library(KotoWindow *self) {
|
||||
KotoIndexedLibrary *lib = koto_indexed_library_new(g_get_user_special_dir(G_USER_DIRECTORY_MUSIC));
|
||||
|
||||
if (lib != NULL) {
|
||||
self->library = lib;
|
||||
}
|
||||
}
|
30
src/koto-window.h
Normal file
30
src/koto-window.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
/* koto-window.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 <gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define KOTO_TYPE_WINDOW (koto_window_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (KotoWindow, koto_window, KOTO, WINDOW, GtkApplicationWindow)
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
void load_library(KotoWindow *self);
|
10
src/koto-window.ui
Normal file
10
src/koto-window.ui
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?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>
|
8
src/koto.gresource.xml
Normal file
8
src/koto.gresource.xml
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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>
|
50
src/main.c
Normal file
50
src/main.c
Normal file
|
@ -0,0 +1,50 @@
|
|||
/* main.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/gi18n.h>
|
||||
|
||||
#include "koto-config.h"
|
||||
#include "koto-window.h"
|
||||
|
||||
static void on_activate (GtkApplication *app) {
|
||||
g_assert(GTK_IS_APPLICATION (app));
|
||||
|
||||
GtkWindow *window;
|
||||
|
||||
window = gtk_application_get_active_window (app);
|
||||
if (window == NULL) {
|
||||
window = g_object_new(KOTO_TYPE_WINDOW, "application", app, "default-width", 600, "default-height", 300, NULL);
|
||||
}
|
||||
|
||||
gtk_window_present(window);
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[]) {
|
||||
g_autoptr(GtkApplication) app = NULL;
|
||||
int ret;
|
||||
|
||||
/* Set up gettext translations */
|
||||
bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
|
||||
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
|
||||
textdomain (GETTEXT_PACKAGE);
|
||||
|
||||
app = gtk_application_new ("com.github.joshstrobl.koto", G_APPLICATION_FLAGS_NONE);
|
||||
g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
|
||||
ret = g_application_run (G_APPLICATION (app), argc, argv);
|
||||
|
||||
return ret;
|
||||
}
|
31
src/meson.build
Normal file
31
src/meson.build
Normal file
|
@ -0,0 +1,31 @@
|
|||
koto_sources = [
|
||||
'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',
|
||||
]
|
||||
|
||||
koto_deps = [
|
||||
dependency('glib-2.0', version: '>= 2.66'),
|
||||
dependency('gio-2.0', version: '>= 2.66'),
|
||||
dependency('gtk+-3.0', version: '>= 3.24'),
|
||||
dependency('libmagic', version: '>=5.39'),
|
||||
]
|
||||
|
||||
gnome = import('gnome')
|
||||
|
||||
koto_sources += gnome.compile_resources('koto-resources',
|
||||
'koto.gresource.xml',
|
||||
c_name: 'koto'
|
||||
)
|
||||
|
||||
executable('com.github.joshstrobl.koto', koto_sources,
|
||||
dependencies: koto_deps,
|
||||
install: true,
|
||||
)
|
Loading…
Add table
Add a link
Reference in a new issue