Compare commits

...

2836 Commits

Author SHA1 Message Date
Anna Schumaker 45d2422be3 gui: Refilter playlists when adding tracks
I was running into a situation where new tracks added to a playlist were
showing up even if they didn't match the current filter text.  Let's fix
this by refiltering the current playlist when new tracks are added to
it.

Fixes #114: New tracks added to filtered view
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-08-28 08:58:45 -04:00
Anna Schumaker 54138d8814 Ocarina 6.5.10-rc
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-08-20 08:34:15 -04:00
Anna Schumaker 6ab3cff28f gui/playlist: Support drag and drop for adding tracks to playlists
Dragging onto a sidebar row without a valid playlist will prompt the
user to create a new playlist.  I could probably add a "New Playlist"
row at some point, but this is easier for now :)

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-05-16 07:35:28 -04:00
Anna Schumaker 0972e027ed gui/treeview: Connect to the drag-and-drop signals
We only support drag-and-drop one row at a time, even though multiple
rows can be selected in the treeview.  If this is a problem, then we can
figure it out later!

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-05-16 07:35:28 -04:00
Anna Schumaker 77efa0c631 gui/model: Configure the gui model as a drag source
We'll need to do this to enable drag and drop to reorder playlists.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-05-16 07:35:28 -04:00
Anna Schumaker a9970c455f gui/sidebar: Add a function for getting an iter from x, y coordinates
This will be used for drag and drop, so that we can figure out what
playlist tracks are being added to.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-05-16 07:35:28 -04:00
Anna Schumaker fc5e6eb043 gui/treeview: Add a function for accessing the tree selection
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-05-16 07:35:28 -04:00
Anna Schumaker a41652ab28 core/playlist: Add a function for manually rearranging playlists
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-05-16 07:35:28 -04:00
Anna Schumaker eca857cb3b core/playlists: Pass sort fields to playlist_generic_alloc()
This lets us configure sorting individually for each allocated playlist.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-05-16 07:35:28 -04:00
Anna Schumaker d7fb67ed51 core/playlists: Remove unsorted playlist_generic_init()
We can just pass 0 to the sorted function to indicate that the playlist
shouldn't be sorted by default.  Let's also take this chance to rename
playlist_generic_init_sorted() -> playlist_generic_init()

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-05-16 07:35:28 -04:00
Anna Schumaker 7df129d533 core/playlists: Accept an argument list for playlists initial sort order
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-05-16 07:35:28 -04:00
Anna Schumaker a4cdac7f22 core/playlists/user: Don't sort user playlists by default
Users should be able to add tracks in the order they want.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-05-16 07:35:28 -04:00
Anna Schumaker d5b0752497 core/playlists/generic: Add album sort to the default fields
If we have two albums by the same artist in the same year (such as a CD1
or CD2 postfix), then we'll end up mixing them together when sorting.
Fix this by changing the default sort order to
Artist -> Year -> Album -> Track Number

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-05-16 07:35:28 -04:00
Anna Schumaker 5fb46dc663 Ocarina 6.5.9
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-05-11 11:43:17 -04:00
Anna Schumaker d149289e00 gui/audio: Close popover menu after 10 seconds
And don't touch the pause count so we don't surprise the user later.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-05-02 11:13:32 -04:00
Anna Schumaker f167f968ba gui/audio: Add a popover menu to clear automatic pausing
The popover is shown whenever the user pauses manually with automatic
pausing enabled.  This will give the user a chance to disable pausing if
it is no longer needed.

Implements #113: Cancel "pause after" configuration when user manually pauses
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-05-02 10:45:23 -04:00
Anna Schumaker 94f3a7f387 Ocarina 6.5.9-rc
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-04-20 09:16:05 -04:00
Anna Schumaker 60e6e2a9eb gui/audio: Remove old pause_after combobox
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-03-02 16:42:55 -05:00
Anna Schumaker 1836104f40 gui/audio: Respond to the user editing the pause entry
We have to disable the up and down buttons when typing in the entry in
case the user decides to type a minus or plus sign.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-03-02 16:42:31 -05:00
Anna Schumaker cd7364300e gui/audio: Wire up the "spin button" increment and decrement buttons
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-03-02 16:42:21 -05:00
Anna Schumaker 994234caf2 gui/audio: Change down-button sensitivity based on pause count
The pause count can't go below -1, so disable the button once we reach
this limit.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-03-02 16:42:20 -05:00
Anna Schumaker af5bafb03e gui/audio: Set the pause entry text based on remaining tracks
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-03-02 16:40:48 -05:00
Anna Schumaker fd68cdf70a gui/audio: Add basic spin-button-like widgets
I set the "linked" property on the hbox to make everything look like a
single widget.  I'm doing this on my own to cut out the GtkAdjustment
and to just use the counter in the audio layer in its place.
Additionally, this will give me the ability to use "+" and "-" keyboard
shortcuts to activate the widgets.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-03-02 16:31:57 -05:00
Anna Schumaker 8a2c631a9b core/audio: Add a function for getting the current pause count
This will be needed by the gui to find the current count at any time,
without waiting for a callback.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-03-02 16:31:57 -05:00
Anna Schumaker e6ab06cf2b core/audio: Change audio_pause_after() to return a boolean
This will be useful later to let the gui know if their change had an
effect.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-03-02 16:31:57 -05:00
Anna Schumaker e6fb772cad Ocarina 6.5.8
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-03-02 16:18:27 -05:00
Anna Schumaker cce8666140 core/tags/album: Check for empty artist names before fetching album art
Otherwise we might crash when we attempt to look at ar_tokens[0].

Reported-by: Josh Larson <themutatedshrimp@gmail.com>
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-02-28 10:28:59 -05:00
Anna Schumaker edcba6a353 Ocarina 6.5.8-rc
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-02-27 08:29:21 -05:00
Anna Schumaker 59506d45e7 core/file: Rename cache_file_import() -> file_import()
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-02-27 08:25:40 -05:00
Anna Schumaker e1f13a7ef4 core/file: Create new functions for reading data from files
The readd(), readu(), and readhu() functions are all used to read
various forms of integers.  The readl() and readw() are for reading
either lines or individual whitespace-delimited words

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-02-21 16:01:15 -05:00
Anna Schumaker 111fcd4e72 core/file: Rename data_file_writef() -> file_writef()
For writing to files with printf-style formatting.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-02-21 08:19:19 -05:00
Anna Schumaker c5494811f4 core/file: Rework binary file IO
I rename cache_file_write() to file_write(), and implement the
corresponding file_read() for binary data.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-02-20 16:59:42 -05:00
Anna Schumaker 07f832ad26 core/file: Rename data_file_version() -> file_version()
Now it can be used by cache files, too.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-02-20 16:18:50 -05:00
Anna Schumaker 35d53855f5 core/file: Add write support to file_open()
I also take this opportunity to add a OPEN_WRITE_BINARY mode to support
writing binary data to files.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-02-20 16:18:49 -05:00
Anna Schumaker a848d5d03c core/file: Create a single file_open() function
This function currently only supports opening files for reading, but it
will soon be expanded to supporting writes as well.  To support binary
reads, I add a new OPEN_READ_BINARY open mode.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-02-20 16:16:23 -05:00
Anna Schumaker 0aaafcb5f7 core/file: Move versioning info into the main file structure
I'll eventually want to support text and binary files in both locations,
so cache files might need access to this too.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-02-20 16:16:22 -05:00
Anna Schumaker 8f13765b08 core/file: Make a common file_remove() function
This change means removing cache files is now supported.  As a bonus,
we try to remove empty subdirectories to keep down the clutter.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-02-20 16:09:42 -05:00
Anna Schumaker 84a1022bdf core/file: Create a single file_close() function
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-02-20 16:06:50 -05:00
Anna Schumaker 659aaff6a1 core/file: Move f_mode out of data files
This might also be useful for cache files to track their current state.
To help with accurate tracking, I take this opportunity to add a CLOSED
state that files default to.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-02-20 16:06:49 -05:00
Anna Schumaker 3736b6cf3b core/file: Create a single file_exists() function
We can use the single file_path() function to check if files exist, too.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-02-20 16:03:32 -05:00
Anna Schumaker 3fdf89c75e core/file: Create a single file_write_path() function
Similar to file_path(), I rely on the file ops struct to put files in
the right place.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-02-20 16:03:31 -05:00
Anna Schumaker 22854b2f25 core/file: Create a single file_path() function
I also introduce a "file_operations" struct that will be used in the
future to do slightly different things for cache and data files.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-02-20 16:01:14 -05:00
Anna Schumaker b6d45e666e core/file: Remove struct cache_file
And rework the init functions at the same time to reflect that data
files can now be placed under a subdirectory.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-02-20 15:39:33 -05:00
Anna Schumaker 842547d735 core/file: Move common items out of cache and data file structs
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-02-20 15:39:33 -05:00
Anna Schumaker 198fbf7f9b core/file: Create a new, unified file structure
We'll spend the next several patches slowly switching over to the new
way of accessing files.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-02-20 15:39:33 -05:00
Anna Schumaker 82280edfa2 core/file: Rename struct file -> struct data_file
I'm going to create a unified struct file that should be able to share
code between data and cache files.  The first step is to push the old
structure to the side so it can still be used in other places.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-02-20 15:39:33 -05:00
Anna Schumaker 48f79bdb49 core/file: Make name and subdir strings const for cache files
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-02-20 15:39:33 -05:00
Anna Schumaker d7d553b80f core/tags/album: Create a new structure to store name and subdir strings
I eventually want to make these fields const in the file code, so we
need a different way to manage and eventually free these strings.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-02-20 15:39:33 -05:00
Anna Schumaker a2854ef31e core/file: Remove the CACHE_FILE_INIT macro
It was only used by the testing code, so it's not seeing any use in the
real world.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-02-20 15:39:33 -05:00
Anna Schumaker d96e8ca1ca core/audio: Don't clear NULL audio_pipeline state
Doing so can cause a deadlock somewhere deep inside gstreamer.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2018-02-20 15:39:33 -05:00
Anna Schumaker 1940a31a77 Ocarina 6.5.7
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-12-21 09:16:15 -05:00
Anna Schumaker 07196a7cc8 gui/sidebar: Conditionally hide the rename menu option
We can only rename user-created playlists, so let's not even show this
option for the other playlist types.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-12-05 15:19:36 -05:00
Anna Schumaker 64e27c1221 gui/sidebar: Add a right click menu
Implements #112: Add sidebar right-click menu
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-12-05 15:19:24 -05:00
Anna Schumaker 31cda0eebd gui/sidebar: Add a function for selecting paths
Normally GTK will take care of this, but we'll need it for the
right-click menu so we might as well implement it.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-12-05 14:58:57 -05:00
Anna Schumaker 9b9be4e322 gui/sidebar: Rename playlists when pressing the Backspace key
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-12-05 14:58:57 -05:00
Anna Schumaker 1374a025e1 gui/sidebar: Split out __gui_sidebar_delete() into a new function
This gives me a function that I can reuse in the sidebar right-click
menu, and it cleans up the main keypress handler so more keys can be
added.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-12-05 14:58:57 -05:00
Anna Schumaker 21e1796b14 gui/sidebar: Add a function for finding the current playlist
This seems like a useful function to have, and we already need it for
deleting playlists.  Let's make it a real function so we don't need to
duplicate code.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-12-05 14:58:57 -05:00
Anna Schumaker b4347d5a34 ocarina.ui: Make sidebar shrinkable
Enabling this option resolves several "Negative content width" warnings
that I was seeing.  Normally I'd just ignore them, but these were
generating SIGTRAP during testing and causing the tests to fail
unnecessarily.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-12-05 14:57:42 -05:00
Anna Schumaker 386514ac5c Ocarina 6.5.7-rc
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-09-05 15:00:01 -04:00
Anna Schumaker 7558a32940 gui/ocarina: Load filepaths from the command line
If multiple paths are passed, then only load the first one to keep
things simple.

Implements #102: Allow outside tracks
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-09-05 14:59:46 -04:00
Anna Schumaker a8f94e9443 core/audio: Add a function to load tracks by filepath
If a matching track isn't found in the track database, then use the new
track_alloc_external() function to allocate an external track with the
correct tags.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-09-05 14:59:43 -04:00
Anna Schumaker cc464ed198 core/tags/track: Add support for allocating external tracks
There might be rare occasions where users want to play a track that
exists outside their music library.  This patch adds support for
allocating and freeing these external tracks without adding them to the
track database.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-09-05 14:59:43 -04:00
Anna Schumaker f9a573b6a3 core/tags/track: Add a function to look up tracks using only the path
I'm struggling to come up with a good way to combine code for this with
code for track_add(), since the lookup mechanism is basically the same.
I'll keep them separate for now and think on it some more.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-09-05 14:59:43 -04:00
Anna Schumaker e7ceed9b5d core/library: Improve subdirectory handling for lookup and find
It's possible that the user may pass us a subdirectory of a path that
has already been added to the library.  We can use this to prevent
double-adding tracks if the user does this.  Additionally, this function
can be used to help look up tracks using only a filepath.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-09-05 14:59:43 -04:00
Anna Schumaker 497ed57057 core/string: Add a function for checking if a string is a subdirectory
I want to use this to prevent users from adding a subdirectory of a path
that has already been added to the library.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-09-05 14:59:43 -04:00
Anna Schumaker e6f34d34f0 core/audio: Rework audio message handling
Let's just do everything inline and cut out the extra function calls to
make the code simpler.  I also created functions to help tests send EOS
or error messages.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-09-05 14:59:43 -04:00
Anna Schumaker 4986bdad13 core/audio: Rework how tracks are loaded
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-09-05 14:59:43 -04:00
Anna Schumaker fc6e3ff464 core/audio: Listen for GstStateChanged messages
And use these to trigger the state changed callback.  Additionally, this
callback can now be used by tests to determine when we're done seeking.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-09-05 14:59:43 -04:00
Anna Schumaker c03530f318 core/audio: Remove playbin-based player
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-09-05 14:59:43 -04:00
Anna Schumaker 0f2e30589d core/audio: Switch controls to the new pipeline player
Implements #103: Switch to custom GstPipeline
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-09-05 14:59:22 -04:00
Anna Schumaker 76e400e156 core/audio: Build up the rest of the pipeline
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-09-05 14:12:13 -04:00
Anna Schumaker 9c6a9f7759 core/audio: Add gstreamer elements for decoding files
We only play local music, so we know that we're using a file and we
don't need a uridecodebin to figure it out for us.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-09-05 14:12:13 -04:00
Anna Schumaker 1182e55df9 core/audio: Fix return type of audio_duration()
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-09-05 14:12:13 -04:00
Anna Schumaker b558a9043c core/audio: Rearrange global variables
Add some whitespace to make it easier to follow what everything is.  I
also rename audio_bus to audio_old_id to make it easier to add in a new
audio bus.  Additionally, I changed test_audio_player() to
test_old_player() to make room for the new pipeline.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-09-05 14:12:13 -04:00
Anna Schumaker d95c693db2 tests: Rename gui.h -> loop.h
I want to run a main loop during the audio tests, which aren't in gui/.
Let's rename this file to make me feel better about using it :)

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-09-05 14:12:13 -04:00
Anna Schumaker 36349e9890 Ocarina 6.5.6
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-09-05 14:09:40 -04:00
Anna Schumaker a7280356c8 gui/sidebar: Start editing on a double-middle click
A single middle click could happen by accident, especially if the user
has a touchpad.  A double click is more likely to be deliberate.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-08-29 09:38:31 -04:00
Anna Schumaker 8b17962b4e gui/sidebar: Don't set user playlists as editable by default
Instead, watch for a middle click and set the editable state manually
from there.  This fixes a bug where double clicking on a user playlist
put us in editing mode instead of selecting the playlist for playback.

Fixes #110: Cannot select user playlists
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-08-25 13:36:52 -04:00
Anna Schumaker 7e303fa2b1 gui/sidebar: Add functions for setting and getting editable state
I want to be able to change this when the user middle-clicks a row, so
let's start by adding in some support functions.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-08-25 13:16:11 -04:00
Anna Schumaker 79accb5bb0 core/playlists/system: Load favorites and hidden playlists first
If we don't, then the Collection playlist will include hidden tracks
when it initializes.

Fixes #109: Hidden tracks showing up in Collection
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-08-22 10:04:02 -04:00
Anna Schumaker 8614aa37cd Ocarina 6.5.6-rc
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-08-22 09:35:13 -04:00
Anna Schumaker 4990d68711 gui/playlists/user: Respond to the "edited" signal
We use this to perform user playlist renames with the user-entered text.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-08-22 09:16:20 -04:00
Anna Schumaker fac383e9fc gui/playlists/user: Respond to the "editing-started" signal
We use this to set the playlist name in the provided GtkEntry, clearing
out the number of tracks

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-08-22 09:16:13 -04:00
Anna Schumaker 466d9ce291 gui/sidebar: Enable editing playlist treeview entries
But only for user playlists.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-08-22 09:16:02 -04:00
Anna Schumaker 3f9372051f gui/sidebar: Add a function for setting an iterator from string
The GtkTreeView editing callbacks give me a path string that I'll need
to convert into an iterator to find the edited playlist.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-08-22 09:15:48 -04:00
Anna Schumaker 2cfccb8177 gui/sidebar: Add a playlist update function that takes a playlist
Once we change the name of a playlist, we won't be able to find it in
the sidebar model.  So let's add a way to update an iterator by passing
the playlist to use for updating.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-08-22 09:15:31 -04:00
Anna Schumaker e773ae6f82 core/playlists/user: Add support for renaming playlists
Users may make typos in naming playlists, or they might think up better
names for playlists later.  Let's be friendly and give users a way to
change playlist names if desired.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-08-22 09:15:22 -04:00
Anna Schumaker 042cddb65b core/idle: Don't allocate the thread pool unless we really need it
This saves ~75MB in my testing, and can be a useful memory savor for the
case where all album art has been downloaded.

Implements #96: Allocate g_thread_pool as needed
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-08-22 09:15:04 -04:00
Anna Schumaker 2a95031ee7 core/idle: Schedule async idle tasks directly
Rather than processing them twice.  This should speed things up a tiny
bit.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-08-22 09:14:18 -04:00
Anna Schumaker df21aa1299 gui: Header file cleanup
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-08-22 09:14:13 -04:00
Anna Schumaker 432d3e5d62 core: Add useful headers to core.h
This way we don't need to keep including the same core libraries in
almost every file.

Implements #83: Include useful headers in core/core.h
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-08-22 09:13:46 -04:00
Anna Schumaker a15ad67029 core: Remove struct core_init_data and pass parameters directly
The core_init_data only held three items, most of which don't get set
during testing.  Removing this struct means several tests no longer need
to define a "dummy" initdata object to pass around during init.

Implements #92: Remove core_init_data
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-08-22 09:13:13 -04:00
Anna Schumaker 5247bf2de0 core/audio: Rename audio_ops -> audio_callbacks
And make them optional, that way tests don't need to keep creating fake
callbacks if they don't need anything from the audio layer.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-08-22 09:12:33 -04:00
Anna Schumaker d3df9a69f2 gui/ocarina: Add a --sync option
Passing this option tells Ocarina that it should only process
synchronous idle tasks, such as library or playlist updates.  This
effectively disables album art fetching (and any async jobs we add in
the future).

Implements #91: Add --no-fetch option
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-08-22 09:10:52 -04:00
Anna Schumaker f46ef37630 core/idle: Change idle_init() to take an idle_sync_t
Rather than offering two init functions for testing.  This lets the UI
select if they want async idle tasks (like Album Art fetching).

Implements #90: Give idle_init an async flag
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-08-22 09:10:08 -04:00
Anna Schumaker 76ebfaa6d4 Ocarina 6.5.5
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-06-19 07:59:30 -04:00
Anna Schumaker cc5f65bf82 core/playlists/system: Reset queued tracks when empty
Users might not remember any sorting or random settings from the last
time they queued tracks, so saving these values could result in
selecting tracks in an unexpected order.  Fix this by resetting the
queued tracks options whenever the playlist is emptied.

Fixes #108: Unset random and sorting when finishing queued tracks
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-06-12 10:40:57 -04:00
Anna Schumaker bb40ef479f core/playlists/generic: Initialize pl_random and pl_length
These fields were working fine for statically initialized playlists, but
they get set to garbage values when g_malloc()-ing a playlist.  Let's
make sure they get initialized properly with the rest of the playlist.

Fixes #107: Initialize all values in playlist_generic_init()
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-06-12 08:19:21 -04:00
Anna Schumaker d1c682501f Ocarina 6.5.5-rc
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-05-13 09:31:53 -04:00
Anna Schumaker 448b4a16f4 Remove core/queue.c and associated files
Everything has been merged into the playlist layer to better match how
playlists are actually used.  This means we can remove the queue files.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-05-13 08:45:05 -04:00
Anna Schumaker 3286b61dcf core/playlist: Add playlist_generic_{alloc,free}() functions
Artist and library playlists are allocated manually, so there should be
generic functions that both can use to get a playlist pointer and free
it when we're done.

I also add a callback for telling the UI when new playlists have been
allocated.  This isn't needed for Library playlists, but this is the
only way the UI can know about new Artists.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-05-13 08:45:04 -04:00
Anna Schumaker 7f54562b71 core/playlist: Add a playlist_init_sorted() function
Sometimes we want to initialize the playlist with sort data, other times
we don't.  This gives us functions we can call for both!

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-05-13 08:45:04 -04:00
Anna Schumaker cdbf8b1736 core/playlist: Rename pl_private -> pl_search
And change its type to gchar **.  This lets the playlist code manage
setting and freeing search strings.  The UI is still responsible for
how this string is used.

This patch also  lets me remove the now-unused queue_deinit() function
and associated callback.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-05-13 08:45:04 -04:00
Anna Schumaker 1dd0b7c2aa core/playlist: Move playlist tracks into the playlist struct
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-05-13 08:45:04 -04:00
Anna Schumaker a808cac04c gui/model: Store a GList in the GtkTreeIter
Storing the current link from the playlist should give us immediate
access to the track, rather than needing to use playlist_at() all the
time.  Additionally, we can now use g_list_next() whenever we need to do
a gtk_tree_model_iter_next()

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-05-13 08:45:04 -04:00
Anna Schumaker 1c6305e24e core/playlist: Replace queue_at() with playlist_at()
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-05-13 08:45:04 -04:00
Anna Schumaker 8bf5aefd1a core/playlist: Replace queue_iter with a playlist_iter
The iterator only needs to point to the current position on the GQueue,
so we can do away with manual position tracking.  This lets us use a
GList pointer as an iterator instead of something more complicated.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-05-13 08:45:04 -04:00
Anna Schumaker 03e7346900 core/playlist: Move current track into the playlist struct
I keep using the queue_iter struct for now to reduce code churn in this
patch.  I'll be replacing it in the next patch.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-05-13 08:45:04 -04:00
Anna Schumaker 18f1bfe801 core/playlist: Move playlist iterator functions into the playlist layer
I also take this chance to add extra functions for directly manipulating
the current track, since this is something we do fairly often.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-05-13 08:45:04 -04:00
Anna Schumaker f25bdab367 core/playlist: Move playlist sort order into the playlist struct
Rather than using a variable from the queue layer.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-05-13 08:45:04 -04:00
Anna Schumaker 0c197c10f9 core/playlist: Move playlist length into the playlist struct
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-05-13 08:45:04 -04:00
Anna Schumaker fda29aaf13 core/playlist: Add a playlist_generic_deinit() function
We'll need this to clean up playlists once queue_deinit() goes away.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-05-13 08:45:04 -04:00
Anna Schumaker 2fb27178ee core/playlist: Implement playlist_add() directly
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-05-13 08:45:04 -04:00
Anna Schumaker efbbc4ceff core/playlist: Implement playlist_size() directly
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-05-13 08:45:04 -04:00
Anna Schumaker 92bb742f8f core/playlist: Implement playlist_generic_add_front() directly
This function adds a track directly to the front of the playlist,
without any existence checks.  This lets us use it for the History
playlist, which allows multiple tracks.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-05-13 08:45:04 -04:00
Anna Schumaker 6dbc574954 core/playlist: Implement playlist_generic_clear() directly
I can reuse the "removed" callback to for this, rather than implementing
a new "cleared" callback directly.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-05-13 08:45:04 -04:00
Anna Schumaker 859ff8656f core/playlist: Implement playlist_has() directly
We can make use of g_queue_find() to find the track for us, and then
convert its return value into a boolean.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-05-13 08:45:04 -04:00
Anna Schumaker a45c7d6889 gui/playlist: Implement playlist_generic_remove() directly
Rather than iterating over the entire playlist ourselves, we can instead
use the g_queue_remove_all() function to do most of the work for us and
then send an appropriate number of "removed" callbacks.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-05-13 08:45:04 -04:00
Anna Schumaker ca6c5293c6 core/playlist: Add a playlist_generic_update() function
This function simply triggers the "updated" callback for the given
playlist and track.  I updated the gui model to handle taking tracks
instead of row indexes, since this lets me reuse the same for-each
function that we do for sorting.  Additionally, this prevents UI updates
for playlists that aren't currently visible.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-05-13 08:45:04 -04:00
Anna Schumaker 287c6e0e9c core/queue: Remove unused queue_selected()
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-05-13 08:45:04 -04:00
Anna Schumaker 1d09e967d0 core/playlist: Move random setting into the playlist struct
I move the random variable into the playlist code since it is no longer
used by the queue layer.  This gives me the opportunity to change it
into a boolean rather than a bit flag.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-05-13 08:45:04 -04:00
Anna Schumaker f670a3796b core/playlist: Implement playlist_next() directly
Let's have the playlist generic functions pick the next track rather
than redirecting to the queue code.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-05-13 08:45:04 -04:00
Anna Schumaker bd8df2a169 core/playlist: Add playlist_selected() for selected tracks
In most cases this function just triggers a UI update, but system
playlists have a little extra bookkeeping to do to remove the track from
the Queued Tracks playlist.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-05-13 08:45:04 -04:00
Anna Schumaker 07bf09c2ad core/playlist: Add a playlist_generic_resort() function
This function is called to force-sort the playlist.  Additionally, we
trigger the "playlist-sorted" callback to to notify the gui that
playlist rows need to be updated.

Additionally, I implement the gui_model_update_all() function to loop
over the model and update all rows of the current playlist.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-05-13 08:45:04 -04:00
Anna Schumaker e74c1c053c core/playlist: Implement sorting directly
Rather than passing through to queue_sort().  Additionally, I remove the
queue_sort() function.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-05-13 08:45:04 -04:00
Anna Schumaker 793a8a5817 core/playlist: Add a playlist_clear_sort() function
This replaces the "reset" field that had been passed to sort.  I think
this makes things a little more straightforward, and gives us a function
we can call when freeing playlists.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-05-13 08:45:04 -04:00
Anna Schumaker d2335f5c6e core/playlist: Add a playlist_generic_save() function
This function uses the playlist save flags enum to determine what
exactly to save, including support for backwards compatibility with
6.4.x playlists.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-05-13 08:45:04 -04:00
Anna Schumaker 37d95656e9 core/playlist: Add playlist_generic_load() function
This function uses the playlist save flags enum to determine what
exactly to load, including support for backwards compatibility with
6.4.x playlists.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-05-13 08:45:04 -04:00
Anna Schumaker a87373f335 core/playlist: Add playlist_callbacks struct
This will be used to gradually phase out the queue_ops struct over the
next several patches.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-05-13 08:45:04 -04:00
Anna Schumaker 93cb7145e6 core/playlist: Clean up playlist headers
I renamed "type.h" to "playlist.h" to better match what it does.
Additionally, I moved generic playlist functions into a new header file.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-05-13 08:45:04 -04:00
Anna Schumaker ed095eb987 core/audio: Clean up loading tracks
This lets us call playlist_played() whenever we change tracks to send UI
updates once, rather than using multiple updates to change playcount and
now-playing status.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-05-13 08:45:04 -04:00
Anna Schumaker ee8825745b Ocarina 6.5.4
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-05-13 08:42:01 -04:00
Anna Schumaker 4ad9b39398 Ocarina 6.5.4-rc
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-05-01 07:36:53 -04:00
Anna Schumaker ae604ab4a8 core/playlists/system: Remove sys_playlist struct
It isn't needed now that playlist differences are handled in the upper
layer.  This also lets me create a shared set of operations for dynamic
playlists.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-28 09:40:02 -04:00
Anna Schumaker 2a8288e1b3 core/playlists/system: Cleanup system playlist updating
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-28 09:40:02 -04:00
Anna Schumaker 8af9148606 core/playlists/system: Clean up system playlist initialization
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-28 09:40:02 -04:00
Anna Schumaker 8a5163fb68 core/playlists/system: Clean up loading system playlists
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-28 09:40:02 -04:00
Anna Schumaker 8220dd9932 core/playlists/system: Clean up saving system playlists
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-28 09:40:02 -04:00
Anna Schumaker 0754f10883 core/playlist: Remove playlist_update()
This was only used by system playlists to keep the unplayed, most played,
and least played playlist up to date.  We can handle this internally
through the playlist_played() handler.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-28 09:40:02 -04:00
Anna Schumaker a33decf549 core/queue: Remove Q_REPEAT flag
It is unused now that the queued tracks playlist manually removes tracks
when picked.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-28 09:40:02 -04:00
Anna Schumaker 9fa5f0b0db core/queue: Remove unused queue_erase() function
It's just added complexity that we don't need to keep around at this
point.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-28 09:40:02 -04:00
Anna Schumaker b17585237a core/playlist: Add a playlist_played() function
This is used to notify when tracks have been played so dynamic playlists
can be updated, and so the model can display the correct playcount.

The old system playlist tests are mostly unnecessary at this point, so I
remove them as part of this patch.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-28 09:40:02 -04:00
Anna Schumaker 7655b0cae8 core/playlist: playlist_{next,prev}() uses a playlist function pointer
Allowing us to access the playlist directly, rather than going through
the playlist-type interface.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-28 09:40:02 -04:00
Anna Schumaker 1fa31c51a6 core/playlist: Remove playlist_get_queue()
We can just look up the playlist instead, and then access the queue
variable from there.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-28 09:40:02 -04:00
Anna Schumaker 72d0f9a248 core/playlist: Remove playlist_get_id() function
And replace its use with direct access of the playlist->pl_id variable.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-28 09:40:02 -04:00
Anna Schumaker b5c1af263a core/playlist: Rename playlist_cur() -> playlist_current()
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-28 09:40:02 -04:00
Anna Schumaker 5c215df0bf core/playlist: playlist_select() takes a playlist pointer
And stores it for future reference, so we don't have to keep looking up
current and previous playlists.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-28 09:40:02 -04:00
Anna Schumaker 73825dd916 core/playlist: Add a function to look up playlists by id
This is much more straightforward than converting an id to a name and
then looking up playlists from there.  This patch removes the now-unused
playlist_get_name() function.

This patch also lets me simplify the system playlist unit test, since I
can now check several similar operations using a loop.  Additionally, I
change calls to pl_system_lookup() into pl_system_get() for efficiency.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-28 09:40:02 -04:00
Anna Schumaker 09e358b96b core/playlist: Rename playlist_get() -> playlist_lookup()
I think "lookup" is a better name for this function, since it's similar
to performing a dictionary lookup.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-28 09:40:02 -04:00
Anna Schumaker bef0c70e5a core/playlist: playlist_sort() takes a playlist pointer
Additionally, it also uses a playlist-level function pointer to decide
what to do.  In most cases this calls the generic sort function, but the
history playlist should never be sorted.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-28 09:40:02 -04:00
Anna Schumaker 61e3137131 core/playlist: playlist_{get,set}_random() take a playlist pointer
Additionally, playlist_set_random() uses a playlist-level function
pointer to decide what to do.  In most cases this will simply toggle the
flag, but the history playlist does not support random playback.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-28 09:40:02 -04:00
Anna Schumaker 0c1147513e core/playlist: playlist_size() takes a playlist pointer
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-28 09:40:02 -04:00
Anna Schumaker 0e523ed279 core/playlist: playlist_has() takes a playlist pointer
Rather than going through a lookup step.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-28 09:40:02 -04:00
Anna Schumaker 3364d4733e core/playlist: playlist_remove() uses a playlist-level function pointer
Rather than going through playlist-type operations.  Additionally, I
take this opportunity to change playlist_remove() to take a playlist
struct directly.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-28 09:40:02 -04:00
Anna Schumaker 1b9cdf5a5c core/playlist: playlist_add() uses a playlist-level function pointer
Rather than going through playlist-type operations.  Additionally, I
take this opportunity to change playlist_add() to take a playlist struct
directly.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-28 09:40:02 -04:00
Anna Schumaker 066027ecb6 core/playlist: playlist_delete() uses a playlist-level function pointer
Rather than going through the playlist-type operations.  Additionally, I
take this opportunity to change playlist_delete() to take a playlist
struct directly.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-28 09:40:02 -04:00
Anna Schumaker ca5f0701e9 core/playlist: playlist_new() returns a playlist pointer
This is much more useful than a boolean status, since we can use the
playlist pointer right away.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-28 09:40:02 -04:00
Anna Schumaker 846f7df9c1 gui/sidebar: Add a gui_sidebar_iter_playlist() function
It's frequently useful to get the playlist directly, rather than looking
up type and name first.  Let's add a function to do just that!

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-28 09:40:02 -04:00
Anna Schumaker 4d68ce8ce6 gui/playlists/library: Return a new playlist pointer
This pointer can be used immediately by testing code instead of simply
looking at the return status.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-28 09:40:02 -04:00
Anna Schumaker 249de0da21 core/playlists/system: Add tests for new tracks and deleting tracks
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-28 09:40:02 -04:00
Anna Schumaker 58cd43c330 core/database: Pass database index when allocating dbes
This is useful for user playlists so they can store their playlist-id
directly, letting us remove the entire playlist_get_id() function.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-28 09:40:02 -04:00
Anna Schumaker 9b4a1785a1 core/queue: Remove Q_ADD_FRONT flag
And replace its use with a queue_add_front() function instead.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-28 09:40:02 -04:00
Anna Schumaker c59b097638 core/queue: Remove Q_ENABLED flag
Queues are always enabled now that we can select different playlists as
the default.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-28 09:40:02 -04:00
Anna Schumaker 7e3e4194f3 core/queue: Remove Q_NO_SORT
This flag was only used by the History playlist, but we have a noop
function to handle this instead.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-28 09:40:02 -04:00
Anna Schumaker 186367afe0 core/queue: Remove qop_save()
This callback is no longer used now that saving happens in the playlist
layer.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-28 09:40:02 -04:00
Anna Schumaker 62e494f2af core/queue: Remove Q_SAVE_FLAGS and Q_SAVE_SORT
These flags are unused now that the playlist layer handles saving.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-28 09:40:02 -04:00
Anna Schumaker 15ceda1194 Ocarina 6.5.3
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-28 09:38:17 -04:00
Anna Schumaker 638caeaa91 gui/sidebar: Set the playlist before changing the random button
Otherwise we could end up changing the random setting on the previous
playlist when displaying a new one.

Fixes #106: Switching playlists clears random setting
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-26 14:25:03 -04:00
Anna Schumaker a7565340d2 Ocarina 6.5.3-rc
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-14 13:59:08 -04:00
Anna Schumaker 0b231119d2 gui/artwork: Rework importing album art
And add a test to check that everything is set correctly.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-14 13:58:05 -04:00
Anna Schumaker fc1e917aee gui/artwork: Rework setting album art
I cleaned up several of the functions and added tests for making sure
everything is set correctly.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-14 13:58:05 -04:00
Anna Schumaker bc1c462d36 gui/artwork: Add an accessor function for the artwork image
This patch also adds a unit test checking that the image is initialized
properly.  In addition, I simplify things by changing the image widget
to be a direct child of the GtkButton.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-14 13:58:05 -04:00
Anna Schumaker 8fd4e4c637 gui/audio: Add a test for the volume button
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-14 13:58:05 -04:00
Anna Schumaker 96e5749e7f gui/audio: Add a test for seeking
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-14 13:58:05 -04:00
Anna Schumaker 2a845feb38 gui/audio: Move audio_ops struct towards the top
This keeps all the audio operations together, and matches how we define
operations structs throughout the rest of Ocarina.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-14 13:58:05 -04:00
Anna Schumaker f8c0668e5e gui/audio: Add an accessor function for the pause_after combo box
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-14 13:58:05 -04:00
Anna Schumaker 07d735eeee gui/audio: Add accessor functions for control buttons
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-14 13:58:05 -04:00
Anna Schumaker 943ab02aa5 gui/audio: Add position and duration label accessor functions
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-14 13:58:05 -04:00
Anna Schumaker 869e83b7bd gui/audio: Add accessor functions for audio tags
And begin working on new, cleaner unit test code.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-14 13:58:05 -04:00
Anna Schumaker 88bf71ac22 Remove gui/view.c
This code is obsolete now that gui/playlist.c handles keypress and
right-click events on the main treeview.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-14 13:58:05 -04:00
Anna Schumaker 3bf99b12eb gui/playlist: Respond to right-clicking the main treeview
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-14 13:58:05 -04:00
Anna Schumaker e660e3f0b2 gui/treeview: Add a "select path at pos" function
This function isn't easy to test without knowledge of screen
coordinates, so I didn't include a unit test this time.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-14 13:58:05 -04:00
Anna Schumaker 3ae5e0f535 gui/playlist: Handle key press events on the main treeview
Setting up a unit test for this is almost impossible, so we don't do
that here.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-14 13:58:05 -04:00
Anna Schumaker 39bc7492d4 gui/playlist: Clean up file and rewrite unit test
The unit test now checks how we respond to the row-activated signal.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-14 13:58:05 -04:00
Anna Schumaker e7d2fa5c4d gui/treeview: Add a function for listing selected tracks
This will be used by higher layers to add tracks to playlists.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-14 13:58:05 -04:00
Anna Schumaker 155b9c3ee6 gui/treeview: Add a test for the row-activated signal
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-14 13:58:05 -04:00
Anna Schumaker 7fbef057bf core: Add a field to initdata for enabling async idle tasks
I'll use this when testing gui album art to enable fetching the artwork.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-14 13:58:05 -04:00
Anna Schumaker d373c55320 core/queue: Add a queue_erase_track() function
Used to trigger the erase callback on tracks, rather than indexes.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-14 13:58:05 -04:00
Anna Schumaker f147c30c30 Ocarina 6.5.2
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-14 13:56:39 -04:00
Anna Schumaker 1e6ab2e23c gui/playlist: Unbold the previous playlist
Looks like this wasn't happening automatically, so let's be sure to
update the previous playlist's row after selecting a new playlist.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-04 11:27:47 -04:00
Anna Schumaker 83a21863b9 gui/sidebar: Select the current playlist on startup
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-04 11:27:45 -04:00
Anna Schumaker e876f8125f gui/sidebar: Restore expanded rows on startup
Fixes #94: Playlist heading not open by default
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-04 11:27:24 -04:00
Anna Schumaker dc53ae271b gui/sidebar: Store the row expanded setting for later use
I want to use this to track if the user has expanded or collapsed any of
the sidebar rows.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-04 10:04:33 -04:00
Anna Schumaker c9e9e3a340 Ocarina 6.5.2-rc
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-03 10:33:19 -04:00
Anna Schumaker d818688bfd gui/playlist: Update playlist sizes with a function pointer array
This lets us select the appropriate update function directly.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-03 10:33:19 -04:00
Anna Schumaker cebf2069cb gui/playlists/system: Respond to favorite and hide buttons
I also take this opportunity to rename these widgets and add accessor
functions.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-03 10:33:19 -04:00
Anna Schumaker 36f399ecb7 gui/playlists/system: Split into a new file and add a unit test
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-03 10:33:19 -04:00
Anna Schumaker 83db8e4ae7 gui/playlists/user: Add a function for getting a list of playlists
This is used to build a right-click menu with the names of each
playlist.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-03 10:33:19 -04:00
Anna Schumaker ad3e56250e gui/playlists/user: Split into a new file and add a unit test
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-03 10:33:19 -04:00
Anna Schumaker bb673ddb62 gui/playlists/artist: Split into a new file and add a unit test
Putting this code in a new file helps make gui/playlist.c less complex,
and better matches the organization of files in core/

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-03 10:33:19 -04:00
Anna Schumaker 4fee5f85f0 gui/playlists/library: Add a function for updating library paths
Finding the header first makes a lot of sense, and avoids iterating
through every playlist while trying to find the library playlist to
update.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-03 10:33:19 -04:00
Anna Schumaker ab47a7ac88 gui/playlists/library: Add new library paths to the sidebar
... without passing through gui/playlist.c first.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-03 10:33:19 -04:00
Anna Schumaker e550638823 gui/playlists/library: Write unit test for adding file paths
This functionality needs to be tested better.  I can't really test the
dialog, since it runs in the main thread, but I can test adding library
paths with the selected directory.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-03 10:33:19 -04:00
Anna Schumaker 3e17b7bc1f Rename gui/collection.c -> gui/playlists/library.c
This is to match how files are named and organized in core/

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-03 10:33:19 -04:00
Anna Schumaker b4e2770223 Remove gui/queue.c
This code is obsolete now that the sidebar handles setting the random
button when playlists are changed.

Implements #76: Remove struct gui_queue
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-04-03 10:33:05 -04:00
Anna Schumaker df2236db9f gui/sidebar: Add a function for selecting the default playlist
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-03-31 13:45:55 -04:00
Anna Schumaker 1291a0d139 gui/sidebar: Add a function for updating playlist text
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-03-31 13:45:55 -04:00
Anna Schumaker b3efd9d84d gui/sidebar: Respond to the Delete key
Gtk doesn't have a simple way to manually trigger this, so I didn't
write a unit test for this feature.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-03-31 13:45:55 -04:00
Anna Schumaker 828f861d9a gui/sidebar: Handle random button clicks
This makes the most sense here, and lets us remove gui/queue.c at some
point in the future.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-03-31 13:45:55 -04:00
Anna Schumaker 3562e164b0 gui/sidebar: Implement selection-changed handlers
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-03-31 13:45:55 -04:00
Anna Schumaker a152ed689f gui/sidebar: Move the visible function into sidebar.c
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-03-31 13:45:55 -04:00
Anna Schumaker a2113dc378 gui/sidebar: Add a function for inserting a playlist in sorted order
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-03-31 13:45:55 -04:00
Anna Schumaker 9885c60bff gui/sidebar: Add functions for appending child playlists
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-03-31 13:45:55 -04:00
Anna Schumaker 831a5379e5 gui/sidebar: Add a function for finding playlists
This function scans through the treestore at the current level, without
descending into children.  This is because we frequently know what
category playlists are under when searching for a child, so it makes
sense to find that first.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-03-31 13:45:55 -04:00
Anna Schumaker f3f8ad91c6 gui/sidebar: Add a function for adding playlists
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-03-31 13:45:55 -04:00
Anna Schumaker 4fc8c72ea8 gui/sidebar: Initialize the sidebar with default headers
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-03-31 13:45:55 -04:00
Anna Schumaker 18e76a7dca gui/sidebar: Add useful iterator functions
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-03-31 13:45:55 -04:00
Anna Schumaker bbac5e23be gui/sidebar: Add a function for getting the sidebar treeview
And rename the treeview from "o_playlist_view" to "sidebar_treeview"

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-03-31 13:45:55 -04:00
Anna Schumaker c1c197acb5 gui/sidebar: Add a function for getting the sidebar filter model
And rename the model from "o_playlist_filter" to "sidebar_filter"

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-03-31 13:45:55 -04:00
Anna Schumaker 4c3405e874 gui/sidebar: Add a function for getting the sidebar treestore
And rename the treestore from "o_playlist_store" to "sidebar_store"

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-03-31 13:45:55 -04:00
Anna Schumaker b3074979f7 gui/sidebar: Add a gui_sidebar() function
Called to access the GtkPaned widget.  I also rename the widget
"sidebar" to match the new convention.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-03-31 13:45:55 -04:00
Anna Schumaker fd84222c2b core/playlist: Add a function for getting the current playlist
This is useful to keep playlist settings variables hidden to the GUI.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-03-31 13:45:55 -04:00
Anna Schumaker 38cd2f761d Ocarina 6.5.1
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-03-31 13:43:16 -04:00
Anna Schumaker a36fd137d5 gui/audio: Disable the audio timeout function during shutdown
Otherwise we may try to use the gstreamer playbin after destroying it,
leading to various error messages showing up in the console.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-03-30 09:57:15 -04:00
Anna Schumaker a4049f8d01 gui/playlist: Expand playlists after adding user playlists
This will open up each of the playlist headings except for "Collection",
which I think is the behavior we want.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-03-30 08:21:09 -04:00
Anna Schumaker 9b04ebcd71 gui/playlist: Block __playlist_update_sizes() during startup
Otherwise we'll get a bunch of messages printed out saying that p_store
isn't a GtkTreeModel

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-03-27 09:04:02 -04:00
Anna Schumaker d3f505465c gui/view: Initialize all libraries before running the test
Otherwise we'll get a message saying that either the filter or the
treeview is not a GtkTreeModel

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-03-24 11:39:21 -04:00
Anna Schumaker 1d3438932e gui/window: Store window position
And restore it when restarting Ocarina.

Implements #88: Remember window position
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2017-03-24 11:38:18 -04:00
Anna Schumaker fa96def899 gui: Rename queue_model variable to gui_model
The concept of queues is going away over the next few releases, so we
should rename this variable for consistency.  I considered calling it
"playlist_model", but I think "gui_model" better matches naming
conventions in the gui.

Imlements #77: Rename queue_model to playlist_model
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-11-01 09:18:28 -04:00
Anna Schumaker 2431ad104e Ocarina 6.5.1-rc
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-11-01 08:51:23 -04:00
Anna Schumaker 1c386809d0 gui/treeview: Respond to the notify::width signal
I connect this in code so I can pass the column index as data to the
function, avoding the need for a "column index" lookup function.

I restore saved column widths during startup.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-11-01 08:51:23 -04:00
Anna Schumaker dbc1df154a gui/treeview: Add a row-activated signal handler
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-11-01 08:51:23 -04:00
Anna Schumaker 730395aeff gui/treeview: Add a function for scrolling the treeview
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-11-01 08:51:23 -04:00
Anna Schumaker 9e37062920 gui/treeview: Sort treeview when columns are clicked
I decided to manually connect signals this time so I can pass sort
information instead of needing to look up the column index.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-11-01 08:51:23 -04:00
Anna Schumaker df43010766 gui/treeview: Add an init function
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-11-01 08:51:23 -04:00
Anna Schumaker c49b77a24a gui/treeview: Add a function for accessing the treeview
And rename the widget from "o_treeview" to just "treeview".

I wanted to rename gui/view.c to gui/treeview.c at some point.  I
decided to gradually rework things into a new file to make it easier to
track progress.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-11-01 08:51:23 -04:00
Anna Schumaker 3fc19275f3 gui/filter: Add a function for loading a track from a tree path
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-11-01 08:51:23 -04:00
Anna Schumaker ac3c316d9a gui/filter: Add a function for getting filter treepaths from index
This keeps the treepath conversions contained to the filter code when
finding paths to scroll to.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-11-01 08:51:23 -04:00
Anna Schumaker 32d712c213 gui/filter: Remember search text when switching playlists
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-11-01 08:51:23 -04:00
Anna Schumaker 39d87f98f8 gui/filter: Move playlist filtering into filter.c
Implements #75: Move treeview filter to a new layer
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-11-01 08:51:23 -04:00
Anna Schumaker b9916706f1 gui/filter: Add functions for getting the SearchEntry and ComboBox
And take this chance to rename o_search -> filter_search.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-11-01 08:51:23 -04:00
Anna Schumaker ad29c520d4 gui/filter: Add a function for converting filter paths to indexes
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-11-01 08:51:23 -04:00
Anna Schumaker f550d45811 gui/filter: Add a function for converting GtkTreePaths into tracks
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-11-01 08:51:23 -04:00
Anna Schumaker 6325779062 gui/filter: Create a new file for treeview filter code
Right now filtering is split between queue.c and view.c, which can make
things somewhat complicated.  I think this is a sign that we need a new
file to manage filtering.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-11-01 08:51:23 -04:00
Anna Schumaker 27a1e2e12a gui/model: Add a function for accessing the runtime label
And rename the widget from "o_runtime" to just "runtime"

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-11-01 08:51:23 -04:00
Anna Schumaker 619ea0b559 gui/model: Use queue positions instead of queue iterator
This helps simplify the code, since we can reuse
gui_model_iter_nth_child() here.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-11-01 08:51:23 -04:00
Anna Schumaker 010969c7b3 gui/model: Convert set_queue() -> set_playlist()
Ocarina is moving in a playlist oriented direction, so move away from
using the queue directly in favor of using the playlist.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-11-01 08:51:23 -04:00
Anna Schumaker 82da46365f gui/model: Register the GuiModel type during gui_model_init()
This only needs to happen once, so let's do it when we initialize the
model rather than waiting for the first allocation.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-11-01 08:51:23 -04:00
Anna Schumaker e522475d38 gui/model: Various cleanups to code and test
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-11-01 08:51:23 -04:00
Anna Schumaker cdbe96c575 gui/model: Rename "Queue Model" to "Gui Model"
This is going to represent a playlist soon enough, so let's just name it
something more generic in case it ever has to change again.

Implements #87: Rename GuiQueueModel -> GuiModel
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-11-01 08:51:07 -04:00
Anna Schumaker 453f176d63 gui/idle: Rename widget to "progress_bar"
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-10-31 07:56:38 -04:00
Anna Schumaker 3383f9e32a gui/idle: Add a function for getting the progress bar
And add in various cleanups while we're at it.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-10-31 07:55:40 -04:00
Anna Schumaker f9238c34e4 tests/gui: Add a generic way to run a main loop
I've had to code this in several places, so creating a generic function
is long overdue.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-10-31 07:55:23 -04:00
Anna Schumaker 90b80fc8a7 gui/window: Rename widget to "window"
Drop the "o_" prefix since it doesn't really add anything.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-10-31 07:44:34 -04:00
Anna Schumaker 133efc0515 gui/window: Add a function for getting the window
This is cleaner and easier than calling into the gtk builder directly.
I bumped up the window layer so other gui components can use it.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-10-31 07:44:34 -04:00
Anna Schumaker 85bb67feed core/playlist: Add a private field to struct playlist
I intend to use this for playlist filtering to store filter text.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-10-31 07:44:34 -04:00
Anna Schumaker e7b4973a50 core/playlist: Add playlist_get() function
This is called to get the requested playlist.  I also reworked
playlist_get_queue() to call this function.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-10-31 07:44:34 -04:00
Anna Schumaker 7d0dbcbdc7 gui/view: Replace gtk_menu_popup() with gtk_menu_popup_at_pointer()
The function gtk_menu_popup() is deprecated as of Gtk 3.22, so replace
it with the simplified popup_at_pointer() function.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-10-31 07:44:34 -04:00
Anna Schumaker a89dc49609 Ocarina 6.5
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-10-29 17:35:26 -04:00
Anna Schumaker 34f21bf247 Update PKGBUILD
We build with CMake now, so update the PKGBUILD script to match.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-10-29 17:23:59 -04:00
Anna Schumaker 63951568af Replace README with README.md
The new file is written in the Gitlab markdown language.  I also update
the content to match how things are done now that we use CMake.

Implements #85: Update README
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-10-29 17:17:46 -04:00
Anna Schumaker be3b788380 core/playlists/system: Don't read 6.4.x playlists in new idle tasks
Track database defragmenting can happen before the new tasks are ever
scheduled, causing a crash when we try to find tracks with changed IDs.
After the crash, the Favorites and Hidden playlist data appears to be
lost.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-10-21 11:31:11 -04:00
Anna Schumaker 9df093ec85 tests/gui: Fix gtk css theme parsing errors
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-10-19 08:22:58 -04:00
Anna Schumaker 50207c5b79 core/playlist: Don't reselect the current playlist
We want playback to continue after the queued tracks playlist has run
out.  Allowing us to select the same playlist multiple times can cause
us to get stuck picking the next track.

Fixes #100: Finishing "Queued Tracks" playlist shouldn't stop playback
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-10-19 07:58:10 -04:00
Anna Schumaker 01927cf806 gui/model: Don't add tracks if queue_model is NULL
Otherwise we will crash with a memory error.  This only seems to be a
problem when Ocarina is started up after creating a user playlist.

Fixes #99: Ocarina crashes during startup with user playlists
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-10-17 08:03:57 -04:00
Anna Schumaker 59b2c854e7 Add a valgrind suppression file
I generated this file while hunting memory leaks and errors in core/

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-29 14:51:23 -04:00
Anna Schumaker e4e90f165e tests/core/audio: Process idle queue on EOS
Otherwise idle tasks will register as memory leaks.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-29 14:50:36 -04:00
Anna Schumaker 4250757b83 core/playlists: Don't leak playlist names while loading
We need to free the playlist name after looking up in case we hit the
case where the playlist isn't found.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-29 14:50:36 -04:00
Anna Schumaker cb2af114c5 core/playlists/user: Free playlist name during deinit
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-29 12:44:17 -04:00
Anna Schumaker b4d78b0d3d core/playlists/library: Free scan path when we're done with it
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-29 12:44:17 -04:00
Anna Schumaker d5de8e5dbf tests/core/queue: Deinitialize queues after testing
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-29 12:44:17 -04:00
Anna Schumaker 6120366da3 core/tags/album: __album_query_artist() needs to initialize "found"
Otherwise we could end up checking this variable uninitialized.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-29 12:44:17 -04:00
Anna Schumaker eb16d9c6fb tests/core/tags/album: Deinitialize genre after testing
Otherwise valgrind will report that we are leaking memory.
Additionally, only initialize the idle queue for sync idle tasks until
album artwork needs it.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-28 16:53:20 -04:00
Anna Schumaker 1d7cfa0e6d tests/core/tags: Don't call *_db_init() twice in unit tests
This could lead to a false-positive when looking for memory leaks.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-28 15:55:32 -04:00
Anna Schumaker 99faa0cf39 tests: g_assert_cmpstr_free() stores the lhs in a temporary variable
Valgrind told me that all calls to g_assert_cmpstr_free() weren't
actually freeing the string.  A closer look shows that if we pass a
function as "lhs" then the function will be called twice, allocating
twice as much memory.

Fix this by storing the result of lhs in a temporary variable so
functions are only ever called once.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-28 15:20:24 -04:00
Anna Schumaker 0407486316 tests: Rename CONFIG_TESTING_ALBUM_ARTWORK to CONFIG_TESTING_ARTWORK
This makes the flag a little easier to toggle for testing.  I also
rename the compiler option for consistency.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-28 15:20:19 -04:00
Anna Schumaker 9a216fee1e gui/queue: Remove unused GQ_CAN_REPEAT and GQ_CAN_DISABLE flags
These go unused as a result of our recent playlist changes, so we can
remove them now.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-28 10:04:28 -04:00
Anna Schumaker ae916eaf40 gui/queue: No need to change random image sensitivity
GtkThemes should be taking care of this indicator for us.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-28 10:00:25 -04:00
Anna Schumaker 9d279fe21e gui/playlist: Don't show Collection on startup
__gui_playlist_init_idle() will select the first visible playlist by
default, which is what we want.  Let's not override this by showing the
Collection later in this function.

Fixes #95: Startup shows Collection instead of Queued Tracks
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-28 09:33:27 -04:00
Anna Schumaker e25b8407b0 gui: Widget spacing tweaks
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-28 09:12:17 -04:00
Anna Schumaker d7709fd5fb gui: Replace "Add New ..." button with a single GtkButton
I find that I usually create playlists through either a right click
action or through a keyboard shortcut, so we don't need an extra option
hidden inside a MenuButton.  Let's remove the button and show the "Add
Library Path" option directly instead.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-27 14:12:21 -04:00
Anna Schumaker eb8a23f2ff core/tags/track: Add support for re-keying the track database
This lets up update track keys to prevent duplicates showing up during a
library path update.

Fixes #93: Library sometimes has duplicated tracks
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 15:41:56 -04:00
Anna Schumaker 811509ff80 core/database: Add a db_rekey() function
Sometimes database entry keys change, so this gives us a way to update
them in the database keys hash table.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 14:58:30 -04:00
Anna Schumaker cf4eedb592 core/database: Autosave databases if the file version changes
To make sure the latest changes are recorded to disk.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 12:02:45 -04:00
Anna Schumaker 93d1550763 core/settings: Check for a NULL key
This fixes a problem with restoring treeview columns.  Sometimes
"Played" gets allocated way too much space, so I solve this by changing
it's setting key to NULL so the column always gets whatever space is
leftover.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 12:02:23 -04:00
Anna Schumaker 2e38b3551e tests: Add a switch for disabling GUI tests
NoWheyCreamery.com doesn't run an Xserver, so we can't run UI tests.
Add a switch to disable these so test results can be reported
accurately.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:26:45 -04:00
Anna Schumaker ec3b9f7c8e .gitlab-ci.yml: Update for CMake conversion
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:23:09 -04:00
Anna Schumaker 142af976b3 Ocarina 6.5-rc
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:21:55 -04:00
Anna Schumaker 5a41eef8a2 gui/ocarina: Add basic command line options
These options are mostly used to communicate with a running Ocarina
instance to control playback.

Implements #37: Ocarina Command Line Commands
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:36 -04:00
Anna Schumaker 419d31d4c3 core/playlists/system: Drop support for looking up the "Banned" playlist
This playlist has been the same as the hidden playlist for several
releases now.  Let's make the change official!

Implements #28: Save hidden playlist as "hidden" instead of "banned"
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:36 -04:00
Anna Schumaker afbf9e0b1a gui/playlist: Change headers to "Playlists" and "Dynamic"
One word labels are always better.  I move the "Favorites" and "Hidden"
playlists under the "Playlists" header because they're manually
configured by the user.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:36 -04:00
Anna Schumaker ef8a764780 core/playlists: Allocate artist and library playlists during startup
Rather than waiting for them to load with an idle task.  This speeds up
Ocarina startup dramatically, since playlists can be added to the UI
with the correct size instead of needing extra callbacks to update the
size each time a track is added.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:36 -04:00
Anna Schumaker 27436115c7 core/database: Remove dbe_setup()
This was added so tracks could bump the libary tag size.  Now that the
size field has been removed, we can remove this function.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:36 -04:00
Anna Schumaker 1b18177d0a core/database: Remove db_load_idle()
This was added to help show the window faster.  Recent changes have made
it unnecessary.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:35 -04:00
Anna Schumaker 21a47ec3b8 gui: Rename ocarina6.glade -> ocarina.ui
The convention is for gtk builder files named with a ".ui" extension.
Let's rename our file to match, and drop the 6 while we're at it.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:35 -04:00
Anna Schumaker b39c4c9ba4 core/file: File version is OCARINA_MINOR_VERSION
This makes file versioning way easier, since every file will have the
same version.  I'll still need to manage minimum-supported versions, but
that shouldn't be too difficult going forward.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:35 -04:00
Anna Schumaker 43a0ffd54c ocarina: Add OCARINA_{MAJOR, MINOR}_VERSION constants
These can be used for version number comparisons as integers, which will
be useful once file version numbers are based off of minor versions.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:35 -04:00
Anna Schumaker 0cb44aaf3a gui/queue: Remove Repeat button
Most playlists don't allow changing this, and now that we have user
playlists it doesn't make sense to support repeating queued tracks.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:35 -04:00
Anna Schumaker 4a4ec3fa36 gui/audio: Add GtkVolumeButton for changing volume
Implements #38: Add volume slider
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:35 -04:00
Anna Schumaker d8c3fb9ace core/audio: Add support for changing audio volume
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:35 -04:00
Anna Schumaker f02dff4177 gui/view: Sort the user playlists menu
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:35 -04:00
Anna Schumaker ddb564ed82 gui/view: Create a menu item for adding tracks to user playlists
This has to be created programmatically due to the dynamic nature of
user playlists.  The easiest way to do that is to list user playlists in
a submenu and switch them out as needed.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:35 -04:00
Anna Schumaker ecebd20a0b core/playlists: Select queued tracks playlist when adding tracks
This lets me "pause" playing queued tracks in favor of other playlists.
I remember the previous playlist so we can resume track picking once the
queued tracks playlist is empty.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:35 -04:00
Anna Schumaker f0e9e1f1e4 gui/playlist: Add user playlists during init
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:35 -04:00
Anna Schumaker e2d4dd61fb gui/view: Add "New Playlist" menu options
And pop up a dialog mox to ask the user for the name of the new
playlist.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:35 -04:00
Anna Schumaker 1b9101cf26 gui/collection: Replace Add Library Path GtkButton with a GtkMenuButton
This lets me add new options without needing to clutter the gui with
lots of rarely-used buttons.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:35 -04:00
Anna Schumaker dcbf2dff72 core/playlists/user: Add support for user created playlists
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:35 -04:00
Anna Schumaker d6e5e6c773 core: Defragment databases on startup
Databases can change either as part of an upgrade or through adding and
removing entries.  We can save a bit of memory by removing unallocated
entries during startup.

Implements #47: Automatic database defragment
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:35 -04:00
Anna Schumaker 85bfe717dd core/tags/library: Remove unused li_size variable
This was used to display the number of tracks in each library path.  We
can use playlist functions to get this information now.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:35 -04:00
Anna Schumaker 30cebb4a45 core/tags/library: Remove unused "enabled" field
This was used to enable and disable library paths in previous Ocarina
versions.  This isn't used anymore now that we have library-based
playlists.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:35 -04:00
Anna Schumaker 784cd3eb91 core/tags/track: Remove redundant artist and genre tags
The track tag doesn't need these tags now that they can be found in the
album tag.

Implements #64: Remove Artist and Genre pointers from Tracks
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:35 -04:00
Anna Schumaker 71ee59ae22 core/tags/track: Reduce amount of saved data
Artist and genre information are already saved by the album tag.  In
addition, we can save a single date stamp instead of (year, day, month)
triplets.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:35 -04:00
Anna Schumaker 0cefd158d9 core/tags/album: Add artist and genre information to saved data
And perform an upgrade when reading back in.  After track tags are read,
we can save the database in the new format and remove the old tags.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:35 -04:00
Anna Schumaker 0ea75ccb29 core/tags/album: Add artist and genre arguments to album_find()
And propegate these through the alloc steps to create an album with the
correct artist and genre tags set.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:35 -04:00
Anna Schumaker ffd09d410c core/tags/album: Add Genre ID to album keys
This allows for representing albums with multiple genres.  I know this
doesn't happen too often, but it doesn't hurt to be covered.  At the
very least, now we have a genre id for constructing new albums!

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:35 -04:00
Anna Schumaker a85a1df7de core/tags/album: Add Artist ID to album keys
I need a way to represent the same album with different artists to
account for multi-artist albums.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:35 -04:00
Anna Schumaker 50db0db06a core/date: Add functions for reading and writing date stamps
The date stamp is a single value that represents year, month, and day.
This should be slightly easier than working with three separate values.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:35 -04:00
Anna Schumaker 86d7fe43ed core/database: Add support for defragmenting databases
Removing items from the database leaves a NULL pointer "hole" that is
never filled in.  This doesn't affect correctness, but it could be
wasteful as items are added and removed.  This patch adds a function to
defragment the database without changing the order of items.

Implements #66: Add support for rebalancing databases
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:35 -04:00
Anna Schumaker 8d9139aea5 core/database: Add file versioning to databases
I plan to change the file format of some tags, so add versioning so we
can change things at different times.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:35 -04:00
Anna Schumaker 2f098a2af6 core/file: Set minimum version from passed arguments
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:35 -04:00
Anna Schumaker 939ebeac13 core/audio: Expose the audio_save() function
This will be used to re-save the current track after defragmenting the
track database.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:35 -04:00
Anna Schumaker f726b6994c core/playlist: Add a function to force save playlists
This is needed to handle track database defragmentation, but could also
be expanded on later to save playlists from a generic place.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:35 -04:00
Anna Schumaker 54bb0ffe2b core/playlists/library: Save playlist flags between sessions
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:35 -04:00
Anna Schumaker a4692c0fe0 core/playlists/artist: Save playlist flags between sessions
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:35 -04:00
Anna Schumaker d33245f604 core/playlists/system: Clean up saving playlists
This prevents double-saves in both the playlist entrance function and in
the overridden function.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:34 -04:00
Anna Schumaker 6fc965e80d core/playlists/system: Remove legacy saving code
And delete files as they are upgraded.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:34 -04:00
Anna Schumaker 33894d7068 core/playlists/system: Add a new function for loading playlists
This function loads playlist information from a single file, falling
back to multi-file loading if playlist.system doesn't exist yet.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:34 -04:00
Anna Schumaker 87f0847f91 core/playlists/system: Add a new function for saving playlists
This saves playlists to a single file, rather than splitting them across
several.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:34 -04:00
Anna Schumaker 28e5045975 core/queue: Give queues the option to save and load iterator positions
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:34 -04:00
Anna Schumaker 84661c4797 gui/playlist: Hide empty playlists
I need to disable filtering when adding artist playlists to avoid some
weird memory corruption issues.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:34 -04:00
Anna Schumaker 278a54f7ec gui/playlist: Add a GtkTreeFilter to the playlist treeview
I intend to use this to hide empty playlists, but it could potentially
also be used to search for a specific playlist.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:34 -04:00
Anna Schumaker c6e9c176d8 gui/playlist: Select playlists by double clicking
I make the current playlist bold so the user has an easier time finding
it.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:34 -04:00
Anna Schumaker 7a79ac26b0 core/playlists/system: Make sure Favorites and Hidden repeat
Otherwise playing tracks from these playlists will cause the tracks to
get removed.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:34 -04:00
Anna Schumaker 64ceca84c5 core/playlists: Pick the next track from the currently selected playlist
Unless the user has queued tracks, of course.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:34 -04:00
Anna Schumaker 8985e70439 core/playlists: Add a playlist_select() function
I query the underlying playlist to see if it is selectable, and then
update the settings file if it is.

Implements #10: Select default playlist
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:34 -04:00
Anna Schumaker bfcfaae977 core/playlists: Add functions for converting between names and ids
I need to have integer playlist ids to store into the settings database
once I allow changing the default playlist.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:34 -04:00
Anna Schumaker da19ddd388 gui/playlist: Set playlist size when cleared
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:34 -04:00
Anna Schumaker 5232217eeb core/playlists/system: Overload playlist_delete() function
Instead of deleting a playlist, we can use this to clear
user-configurable playlists.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-26 08:07:34 -04:00
Anna Schumaker e4cd59b895 core/tempq: Remove tempq.c
Multiple temporary queues has been replaced with a single Queued Tracks
playlist.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-09-26 08:07:34 -04:00
Anna Schumaker 69e628f505 gui/tempq: Remove tempq.c
Temporary queues are being replaced by the Queued Tracks playlist.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-09-26 08:07:34 -04:00
Anna Schumaker 69b39ea717 gui/sidebar: Remove unused sidebar liststore
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-09-26 08:07:34 -04:00
Anna Schumaker 017da02827 gui/playlist: Add Queued Tracks playlist
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-09-26 08:07:34 -04:00
Anna Schumaker eb1361248d core/playlists/system: Add queued tracks playlist
Right now tracks are picked from this playlist whenever possible.  A
system for selecting the default playlist will be added shortly.

Implements #20: Only one queue for "Up Next"
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-09-26 08:07:20 -04:00
Anna Schumaker a775eeb761 core/playlists: Add a pl_next() playlist operation
This is mostly needed so the queued tracks playlist can be saved after
picking a track.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-23 16:11:08 -04:00
Anna Schumaker 903357395b core/audio: Save current track in settings database
The settings code is designed to map strings to unsigned integers, which
is exactly what we do here.  This lets us cut out an extra file access,
which is always a plus.  We remove the audio file after upgrading to
prevent reading it multiple times.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-09-23 16:11:08 -04:00
Anna Schumaker 7e00c8ed10 core/settings: Move settings into core/
Implements issue #9: Move settings into core/
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-09-23 16:11:08 -04:00
Anna Schumaker 524d1886f9 tests: Remove scons-based testing code
Completes issue #4: Investigate CTest
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-09-23 16:11:08 -04:00
Anna Schumaker a8abbdfdcc Remove scons build files
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-09-23 16:11:08 -04:00
Anna Schumaker 19ca9d932b tests: Build gui audio test with ctest
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-09-23 16:11:02 -04:00
Anna Schumaker 59839547e2 tests: Build gui playlist test with ctest
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-09-23 16:11:02 -04:00
Anna Schumaker dd268a24fe tests: Build sidebar test with ctest
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-09-23 16:11:02 -04:00
Anna Schumaker 0470c6efa6 tests: Build gui idle test with ctest
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-09-23 16:11:02 -04:00
Anna Schumaker 4e9c5e0a00 tests: Build window test with ctest
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-09-23 16:11:02 -04:00
Anna Schumaker 6a1c27e9a4 tests: Build gui queue test with ctest
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-09-23 16:11:02 -04:00
Anna Schumaker b2dbbbaae6 tests: Build treeview test with ctest
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-09-23 16:11:02 -04:00
Anna Schumaker c671c7aefc tests: Build model test with ctest
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-09-23 16:11:02 -04:00
Anna Schumaker 3e2ed7761c tests: Build settings test with ctest
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-09-23 16:11:02 -04:00
Anna Schumaker 1710c8076a tests: Build gtk builder test with ctest
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-09-23 16:11:02 -04:00
Anna Schumaker 8f8e4a4459 tests: Build audio test with ctest
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-09-23 16:11:02 -04:00
Anna Schumaker 926ca09275 tests: Build tempq test with ctest
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-09-23 16:11:02 -04:00
Anna Schumaker 7e09375325 tests: Remove core/playlist.c test
The playlist code is heavily tested by unit tests for the files in
core/playlists/, so we no longer need to have a separate playlist test.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-09-23 16:11:02 -04:00
Anna Schumaker 9b7c45634c tests: Build core/playlists/library test with ctest
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-09-23 16:11:02 -04:00
Anna Schumaker 487274ff00 tests: Build core/playlists/artist test with ctest
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-09-23 16:11:02 -04:00
Anna Schumaker c67d09740c tests: Build core/playlists/system test with ctest
I initially tried making several helper functions to reuse code and make
it easier to add new playlists.  This didn't work all that well, mostly
because glib wasn't able to expand variable values or find the line
number that errors occured on.  Macros don't have this problem, since
they are expanded at compile time.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-09-23 16:11:02 -04:00
Anna Schumaker f9dd51170d tests: Build queue test with ctest
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-09-23 16:11:02 -04:00
Anna Schumaker 8327d77ddd tests: Build tags/track test with ctest
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-09-23 16:11:02 -04:00
Anna Schumaker 5e65414263 build: Generate albums through cmake
This is much more straightforward than having scons call a bash script.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-09-23 16:11:02 -04:00
Anna Schumaker 921a04e28e tests: Build tags/library test with ctest
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-09-23 16:11:02 -04:00
Anna Schumaker ca2f35a848 tests: Build tags/genre test with ctest
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-09-23 16:11:02 -04:00
Anna Schumaker 3b03301e61 tests: Allow disabling the Album Art Fetching test
This test can take a long time to run, especially on slow internet
connections.  Let's add a way to disable it when testing other things.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-23 16:11:02 -04:00
Anna Schumaker 65bbd21669 tests: Build tags/album test with ctest
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-09-23 16:11:02 -04:00
Anna Schumaker 8c875acec9 tests: Build tags/artist test with ctest
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-09-23 16:11:02 -04:00
Anna Schumaker 1b83978b09 tests: Build containers/database test with ctest
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-09-23 16:11:02 -04:00
Anna Schumaker 10f81461d9 tests: Build idle test with ctest
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-09-23 16:11:02 -04:00
Anna Schumaker 4fb854d0b1 tests: Build date test with ctest
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-09-23 16:11:02 -04:00
Anna Schumaker fc88f68d6b tests: Build file test with ctest
This changes test output slightly, in that files are now placed under
subdirectories of $XDG_USER_DATA_DIR/ocarina-test/ instead of in this
directory directly.  This should help avoid conflicting files, and lets
me use a single "rm" command to remove everything before testing.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-09-23 16:11:02 -04:00
Anna Schumaker 9f2811a343 tests: Build string test with CTest
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-09-23 16:11:02 -04:00
Anna Schumaker 2f559b2fb3 tests: Build version test with CTest
This begins the conversion to CTest and the GLib unit test framework.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-09-23 16:11:02 -04:00
Anna Schumaker 0e171012ce Add CMakeLists.txt
For using cmake to generate a makefile instead of building through
scons.

Implements issue #3: Investigate CMake
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-09-23 16:11:02 -04:00
Anna Schumaker 17150b1791 Ocarina 6.4.20
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-23 16:04:45 -04:00
Anna Schumaker 257ef3612f gui/audio: Enable idle polling when the track changes
Unplayed, Most Played, and Least Played tracks playlists update
themselves with an idle task when tracks have been played.  It looks
like we haven't been processing these tasks, so the queue was just
building up after every track.  Fix this by enabling the GTK idle
callback whenever a track is played.

Fixes #89: Dynamic playlists aren't updating
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-19 14:45:11 -04:00
Anna Schumaker b35b1eb132 Ocarina 6.4.20-rc
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-11 10:52:29 -04:00
Anna Schumaker 1bc43a9e2c gui/queue: Remove unused fields from struct gui_queue
Now that we have a single model and filter there is no need to attach
them to every gui_queue.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-11 10:52:29 -04:00
Anna Schumaker 336c0a01af gui/queue: Only allocate a single GtkTreeModelFilter
The view is now responsible for allocating the filter, but the gui_queue
still needs to set the filter function during an init step.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-11 10:52:29 -04:00
Anna Schumaker 65b43c7ae5 gui/model: Make sure that the queue model can represent a NULL queue
Otherwise this could lead to crashes or buggy behavior.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-11 10:52:29 -04:00
Anna Schumaker 40bce8cc59 gui/model: Don't require a GuiQueueModel for public functions
We can get by without this now that the model is shared across all
queues.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-11 10:52:29 -04:00
Anna Schumaker 5c426fc8d7 gui/model: Update runtime label when the model changes
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-11 10:52:29 -04:00
Anna Schumaker f58cc8da46 gui/model: Add a function for getting the current queue
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-11 10:52:29 -04:00
Anna Schumaker a28b5c4ec5 gui/model: Create a static, shared GuiQueueModel
Now that we can switch between different queues we no longer need to
allocate multiple models.

Implements #72: Only allocate a single GuiQueueModel for all playlists
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-11 10:52:29 -04:00
Anna Schumaker a9aa3c297d gui/model: Add support for changing the represented queue
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-11 10:52:27 -04:00
Anna Schumaker 53285534b9 gui/model: Improve the efficiency of gui_queue_model_clear()
We can cut out several thousand function calls and allocations by
reusing the same GtkTreePath structure.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-11 10:50:50 -04:00
Anna Schumaker c2178bc265 core: Cut back on hardcoded dbe_index uses
The dbe_index of a given database item might change in the future, so we
can't rely on it everywhere.  Let's just use it for saving and loading
files, with the expectation that changes will happen sometime after
startup.

Implements #69: Reduce use of dbe_index in Ocarina code
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-11 10:50:45 -04:00
Anna Schumaker e82beb719f core/tags/track: Reduce the size of the track tag
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-11 10:50:34 -04:00
Anna Schumaker d222c306e0 core/date: Force struct date into 32bits
Three unsigned integers is overkill for handling dates.

Implements #65: Date structure can be represented with a single 32bit
value
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-11 10:50:22 -04:00
Anna Schumaker 65b547f60b core/tags/album: Add pointer to genre tag
Albums tend to have a single genre for all tracks, so it makes more
sense for an album to point to genre information.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-11 10:25:43 -04:00
Anna Schumaker 629f81da17 Ocarina 6.4.19
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-11 10:22:40 -04:00
Anna Schumaker 76d8b00ecc core/playlists/library: Use library tag path when allocating playlists
This isn't as important for established playlists, but this string could
quickly become an invalid pointer for new playlists that are added.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-09-01 12:05:02 -04:00
Anna Schumaker 00c4c8a418 gui/collection: Set dialog default response
This gives users the ability to add new library paths by pressing the
"Enter" key instead of needing to click a button with their mouse.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-08-31 15:35:10 -04:00
Anna Schumaker ae851ab4ea core/playlists/library: Remove tracks from artist playlist when deleting
Otherwise we could leave artist playlists with invalid pointers.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-08-31 15:34:29 -04:00
Anna Schumaker 21718c4179 gui/collection: Select user's music directory when creating file chooser
Most users will have their music in their ~/Music directory, so it makes
sense to select this path by default.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-08-30 07:47:07 -04:00
Anna Schumaker 15807434a4 gui/view: Unit test cleanups
- Define __queue_filter_how_changed() for tests that need queue
  callback functions
- Increase column sizes in the view test to make test more reliable

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-08-29 07:59:11 -04:00
Anna Schumaker 1d02024505 gui/queue: Check for gq_queue before dereferencing it
Otherwise Ocarina will crash.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-08-29 07:55:15 -04:00
Anna Schumaker 20f10c163d core/playlists/artist: Add pl_artist_delete_track()
Library playlists call this when deleting tracks, otherwise we could end
up dereferencing invalid pointers the next time we use the artist
playlist.

Fixes #81: Remove deleted tracks from artist playlists
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-08-29 07:53:13 -04:00
Anna Schumaker 4e5ae5e57c Ocarina 6.4.19-rc
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-08-29 07:38:49 -04:00
Anna Schumaker d7322c1f07 gui/queue: Add a selector for filtering by different fields
Implements #63: Add field selector for filtering
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-29 07:33:00 -04:00
Anna Schumaker 11ef52b5de core/string: Remove unused string functions
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-29 07:33:00 -04:00
Anna Schumaker aead4939c3 core/filter: Remove filter.c
It is unused now that I have a token matching system in place.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-29 07:33:00 -04:00
Anna Schumaker 2e753b6f52 gui/queue: Switch over to using token matches for filtering
This patch also adds the genre field to the list of fields that can be
searched.

Implements #62: Replace filter layer with token matching
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-29 07:33:00 -04:00
Anna Schumaker d16e06111d core/tags/track: Add track_match_token() function
This is used to check if a track has a token that begins with the
requested string.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-29 07:33:00 -04:00
Anna Schumaker 6ad4325f22 core/tags/track: Convert lowercased string into tokens
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-29 07:33:00 -04:00
Anna Schumaker 2e1c27294b core/tags/genre: Add genre_match_token() function
This is called to check if any string in a genre's token list is
prefixed by the given string.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-29 07:33:00 -04:00
Anna Schumaker 1ca9bb36c1 core/tags/genre: Convert lowercased string into tokens
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-29 07:33:00 -04:00
Anna Schumaker a70b27779f core/tags/artist: Add artist_match_token() function
This is called to check if any string in an artist's token list is
prefixed by the given string.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-29 07:33:00 -04:00
Anna Schumaker b643b532d7 core/tags/artist: Convert lowercased string into tokens
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-29 07:32:59 -04:00
Anna Schumaker be29f53eaa core/tags/album: Add album_match_token() function
This is called to check if any string in an album's token list is
prefixed by the given string.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-29 07:32:59 -04:00
Anna Schumaker c3bc8e9c02 core/tags/album: Convert lowercased string into tokens
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-29 07:32:59 -04:00
Anna Schumaker f70920015c core/string: Add a function for matching tokens
This will be used to replace the current filtering code with a token
comparison for each track.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-29 07:32:59 -04:00
Anna Schumaker de0446120e core/string: Add a comparison function for tokenized strings
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-29 07:32:59 -04:00
Anna Schumaker b3750aa31c core/playlists/system: Compare playlist names in a loop
This is easier to maintain than a giant switch statement, and should
make it easier to add new playlist types in the future.

Implements #61: Clean up system playlists
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-08-29 07:32:44 -04:00
Anna Schumaker d3e2f069fd core/playlists/system: Load collection in a separate idle task
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-08-29 07:31:29 -04:00
Anna Schumaker 81aea3017e core/playlists/system: Trigger an update during playlist init
This is a bit cleaner, and helps to simplify the system playlist
initialization process.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-08-29 07:31:29 -04:00
Anna Schumaker f4b12c5a83 core/playlists/system: Define each playlist near it's associated functions
I think this is a bit cleaner, and helps to keep similar things
together.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-08-29 07:31:20 -04:00
Anna Schumaker 532d55ba4f core/playlists/system: Clean up collection save and load function
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-28 10:13:03 -04:00
Anna Schumaker 019137e4ed core/playlists/generic: Add a playlist_generic_update() function
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-28 10:13:03 -04:00
Anna Schumaker dddb098354 core/playlists/generic: Add a playlist_generic_init() function
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-28 10:13:03 -04:00
Anna Schumaker 1a29458d7c core/playlists/generic: Add a playlist_generic_remove() function
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-28 10:13:03 -04:00
Anna Schumaker c2a7d0289f core/playlists/generic: Add a playlist_generic_add_track() function
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-28 10:13:02 -04:00
Anna Schumaker 8f7e8be39d core/playlists/generic: Add a playlist_generic_set_flag() function
The history playlist uses a noop function, since changing random or
repeat settings doesn't make sense for this playlist.  The collection
playlist uses a custom function to save changes after setting a flag.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-28 10:13:02 -04:00
Anna Schumaker a80a84a955 core/playlists/generic: Add a playlist_generic_sort() function
I set the history playlist to use a noop function, since changing the
history doesn't really make sense.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-28 10:13:02 -04:00
Anna Schumaker d460bcaee8 core/playlists/system: Add struct sys_playlist
This will contain the playlist and operations for each secific type.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-28 10:13:02 -04:00
Anna Schumaker 3d85f0fdc5 Ocarina 6.4.18
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-08-28 10:08:10 -04:00
Anna Schumaker 1633946981 core/file: Check if a file is too new to be opened
I'm hitting this problem while developing 6.5, since file formats are
going to change.  Let's handle this situation gracefully rather than
segfaulting.

This patch changes versioning problems into fatal errors to prevent us
from overwriting data already on disk.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-08-28 10:07:27 -04:00
Anna Schumaker 3806577154 gui/playlists: Add artist playlists when they are created
We only need to do this after Ocarina init has completed, otherwise
artist playlists will be added twice.

Fixes #79: Artist playlists not updated when tracks are added
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-08-28 09:48:12 -04:00
Anna Schumaker a430c5b117 core/playlists/artist: Add artist playlists as artists are added
Scanning new library paths should also add artist playlists, otherwise
they won't show up until Ocarina is restarted.

Fixes #79: Artist playlists not updated when tracks are added
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-08-28 09:46:16 -04:00
Anna Schumaker 3d31349cca gui/playlist: Random state isn't saved when random button is clicked
We were calling the queue function directly, rather than passing through
the playlist layer.  This means random state isn't saved when the button
is clicked and Ocarina is closed.

Fixes #78: Call playlist_set_random() when clicking random button
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-08-28 09:06:33 -04:00
Anna Schumaker f855eaea58 gui/collection: Run FileChooserDialog on startup
But only if the library database is empty.  This patch also changes the
prompt of the dialog to "Add Music" so users know what is going on.

Fixes #80: Pop up FileChooserDialog the first time Ocarina is run
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-08-16 13:38:58 -04:00
Anna Schumaker 5964c508ce core/playlists/artists: Load each playlist with a different idle task
This seems less efficient overall, since we now need to take several
passes over the track database.  What I've noticed is that the
single-pass option creates a lot of UI notifications that makes the gui
unresponsive for a large amount of time.  Breaking this into smaller
chunks gives us a chance to handle any user actions between loading each
playlist.

Fixes #71: Initalize artist playlists with more idle tasks
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-08-13 09:50:24 -04:00
Anna Schumaker 73b33e9718 gui: UI spacing improvements
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-08-13 09:49:21 -04:00
Anna Schumaker f3360f6da5 Ocarina 6.4.18-rc
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-08-13 09:07:26 -04:00
Anna Schumaker 9733b82ae8 core/collection: Remove file
I have replaced everything in this file with the code in
core/playlists/library.c

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-13 08:31:30 -04:00
Anna Schumaker bddbd04ef5 gui: Remove stack widget
It isn't needed now that we pop up a file choose dialog for selecting
library paths.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-13 08:31:30 -04:00
Anna Schumaker b3476e15e9 gui/collection: Remove unused collection code
And the now unused sidebar widget.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-13 08:31:30 -04:00
Anna Schumaker 73c70678bb gui/collection: add button for adding library paths
This is easier than responding to events from the treeview.  Let's just
pop up a dialog and let the user select from there, rather than doing
something complicated with a stack.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-13 08:31:30 -04:00
Anna Schumaker 62e1b27b6c gui/playlist: Add support for deleting playlists
System playlists cannot be deleted, but library playlists can.  Deleting
a library playlist removes the library and associated tracks from the database.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-13 08:31:30 -04:00
Anna Schumaker 382ee79c2e gui/playlist: Add artist playlists to the playlist sidebar
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-13 08:31:30 -04:00
Anna Schumaker f2597a8e6c gui/playlist: Add library playlists to the playlist sidebar
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-13 08:31:30 -04:00
Anna Schumaker 8abc45b1ae gui/playlist: Store the playlist type in the sidebar treemodel
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-13 08:31:30 -04:00
Anna Schumaker 871bf88b94 gui/queue: Store playlist in the gui queue
I'll need to know the playlist type to set artist information properly.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-13 08:31:30 -04:00
Anna Schumaker f70b2b940f core/playlists/artist: Add basic artist operations
For now, hidden tracks are shown in artist queues.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-13 08:31:30 -04:00
Anna Schumaker 24448aefec core/playlists/artist: Add tracks to the artist playlists
I use a single idle task to scan the track database and add to the
appropriate playlist.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-13 08:31:30 -04:00
Anna Schumaker 12ae7cfee6 core/playlists/artist: Add pl_artist_{init, deinit}() functions
The pl_artist_init() function is used to allocate a playlist for each
artist already in the database, and pl_artist_deinit() is then used to
free up this memory during cleanup.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-13 08:31:30 -04:00
Anna Schumaker 11430f89cf core/playlists/library: Add pl_library_update() function
This is called to find and add new tracks to the library.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-13 08:31:30 -04:00
Anna Schumaker e1a722d04b core/playlists/library: Adding a library starts a directory scan
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-13 08:31:30 -04:00
Anna Schumaker c448db2665 core/playlists: Add playlist_{new, delete}() functions
System playlists cannot be created or deleted, so these functions simply
return false in this case.  Library playlists will use this to add new
library paths to Ocarina.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-13 08:31:30 -04:00
Anna Schumaker 78aa0f9ff6 core/playlists/library: Add pl_library_sort() function
Used to sort library playlists.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-13 08:31:30 -04:00
Anna Schumaker 7f867199cb core/playlists/library: Add pl_library_set_flag() function
I also take the opportunity to add in a generic lookup function to
convert a library path into a playlist.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-13 08:31:30 -04:00
Anna Schumaker 1599897fbf core/playlists/library: Add pl_library_add_rm() function
This function is for both adding and removing tracks, and only returns
false.  Tracks will only be added and removed through the update
function.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-13 08:31:30 -04:00
Anna Schumaker c5a0a3470e core/playlists/library: Add pl_library_get_queue() function
Called to access the track queue associated with the given playlist.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-13 08:31:30 -04:00
Anna Schumaker 4d5569ef7a core/playlists/library: Add tracks to library playlists
This needs to happen in an idle task since the track database is loaded
when idle.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-13 08:31:30 -04:00
Anna Schumaker 261f6d91d7 core/playlists/library: Add pl_library_{init, deinit}() functions
The pl_library_init() function is used to allocate a playlist for each
library path already in the database, and pl_library_deinit() is then
used to free this memory during cleanup.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-13 08:31:30 -04:00
Anna Schumaker e4930704a2 core/playlists/system: Add pl_system_delete_track()
Called to remove a track from all system playlists.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-13 08:31:30 -04:00
Anna Schumaker 03ed7c4b84 core/playlists/system: Add pl_system_new_track()
Called to tell system playlists that a new track has been added to the
database.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-13 08:31:30 -04:00
Anna Schumaker 20e0a85a5d core/tags/artist: Add an artist_db_get() function
This will be called to scan the artist database when setting up
playlists.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-13 08:31:30 -04:00
Anna Schumaker b3922cc731 core/tags/artist: Add an artist_lookup() function
For looking up artist tags without allocating a new one.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-13 08:31:30 -04:00
Anna Schumaker e41f554b2e core/tags/artist: Add a pointer to store a playlist
Similar to the library tag, this is a void pointer that should only be
used by the playlist layer.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-13 08:31:30 -04:00
Anna Schumaker 938bbc92f2 core/tags/library: Add a library_lookup() function
I want a way to lookup library paths without allocating new ones, so
let's add this now.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-13 08:31:30 -04:00
Anna Schumaker 6e02f75262 core/tags/library: Add a pointer to store a playlist
I decided to set this as a void pointer to keep other layers from using
the playlist without our knowledge.  The only user of this variable
should be the playlist code.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-13 08:31:30 -04:00
Anna Schumaker cfeca9ae4b core/playlist: Add playlist_type enum
I'm going to use this to distinguish between various playlist types that
are about to be added.  Let's update the playlist functions first, and
then add more types in a future patch.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-08-13 08:31:30 -04:00
Anna Schumaker 6019f07bd3 Ocarina 6.4.17
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-08-13 08:27:55 -04:00
Anna Schumaker 004d4578d4 gui/queue: Set gq_queue->gq_search to NULL after freeing
Otherwise we can attempt to free the search text again when the queue is
destroyed.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-08-13 08:26:00 -04:00
Anna Schumaker 085701ad9d gui/queue: Set gq_queue->gq_visible to NULL after destroying
Otherwise the existance check will still pass the next time
__queue_filter() is called, and we will attempt to destroy it again.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-08-13 08:21:22 -04:00
Anna Schumaker f7e9e8b321 gui/queue: Remember search text when switching queues
I wasn't doing this, but I also wasn't refiltering queues when they were
changed.  This resulted in showing a filtered queue, but without a way
to clear it.  Remembering the text lets me simply set the text, instead
of refiltering queues whenever they are changed.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-08-10 07:31:03 -04:00
Anna Schumaker 44a6ad0d78 gui/playlist: Make sure we free text from tree_model_get()
Otherwise this leads to a memory leak.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-08-01 12:06:25 -04:00
Anna Schumaker e578e0e6dd Ocarina 6.4.17-rc
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-07-29 17:09:39 -04:00
Anna Schumaker 34447007f9 core/history: Remove unused queue
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-29 17:09:38 -04:00
Anna Schumaker 5a54fb69b6 core/collection: Remove unused queue
And remove collection_ops from the core initdata

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-29 17:09:33 -04:00
Anna Schumaker dc07d637f6 gui/history: Remove unused gui queue code
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-29 17:06:06 -04:00
Anna Schumaker 64fc5a9a0d gui/collection: Remove unused gui queue code
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-29 17:06:06 -04:00
Anna Schumaker 15ed068e13 gui/playlist: Select Collection playlist during startup
This preserves the original behavior, where the collection is always
selected from the beginning.  This can be improved upon later, once
queued tracks are implemented as a playlist.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-07-29 17:06:06 -04:00
Anna Schumaker 696173b03e gui/playlist: Add Collection and History playlists to the sidebar
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-29 17:06:06 -04:00
Anna Schumaker dfae74dd50 gui/playlist: Set gui queue name based on passed playlist
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-29 17:06:06 -04:00
Anna Schumaker 8eaf6506e8 core/playlist: Add playlist_{next, prev}() functions
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-29 17:06:06 -04:00
Anna Schumaker efae58c356 core/playlists/system: Add history playlist
Implements #8: Convert history queue into a playlist
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-29 17:06:04 -04:00
Anna Schumaker 6265b937c7 core/playlists/system: Add collection playlist
Implements #7: Convert collection queue into a playlist
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-29 17:06:03 -04:00
Anna Schumaker 5d4de9c5b0 core/playlist: Add playlist_sort() function
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-29 17:06:03 -04:00
Anna Schumaker c7bc2062d2 core/playlist: Add playlist_{get,set}_random()
I'll need this to toggle the random flag for the Collection playlist to
avoid cycling through the GUI in order to save.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-29 17:06:03 -04:00
Anna Schumaker 62123eb025 core/playlists: Add struct playlist
Containing the playlist name and queue.  I pass this to the gui through
the queue_init() function.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-29 17:06:03 -04:00
Anna Schumaker 44a57ed863 core/queue: Add extra paramater to queue_init()
This is used to pass through a value to the GUI during queue
initialization.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-29 17:06:03 -04:00
Anna Schumaker 7f0e1ecc99 core/queue: Add queue_{save, load}_flags() function
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-29 17:06:03 -04:00
Anna Schumaker 92a53d90b4 core/database: Move database out of containers/ subdirectory
It doesn't make sense to have a subdirectory with a single file.  Let's
move it back to core/

Implements #45: Move database into core/
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-29 17:06:01 -04:00
Anna Schumaker fa0dee5921 core/containers: Remove unused set class
Implements #48: Remove set code
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-29 17:06:00 -04:00
Anna Schumaker 98fe6d3bbb core/containers: Remove unused index class
Implements #44: Remove Index code
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-29 17:05:59 -04:00
Anna Schumaker 93fb40360d core/filter: filter_search() returns a new GHashTable
I think this is cleaner than having an upper layer allocate the results
set manually.  This also lets me return NULL in the case that there were
no results.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-29 17:05:59 -04:00
Anna Schumaker fda3f761a0 core/filter: Call GHashTable functions directly
Implements #43: Filter code can use a GHashTable directly
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-29 17:05:54 -04:00
Anna Schumaker 63b46b6161 core/filter: Implement copy and intersect directly
I intend to remove the set class, so we still need a way to handle
filter results.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-29 17:05:54 -04:00
Anna Schumaker 29b2b6f6f4 core/filter: Store track pointers directly
I was storing database indexes, but this assumes that database indexes
are constant.  I intend to change this with database defragmentation.

Implements #46: Filter stores a track pointer
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-29 17:05:47 -04:00
Anna Schumaker 415bd9731a core/filter: Add filter_remove()
This is used to remove tracks from the filtering index.  We'll need this
once we switch over to storing pointers to keep the same track from
getting added multiple times.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-29 15:46:11 -04:00
Anna Schumaker 04a175d3e3 core/filter: Switch from using Index to a GHashTable
This is more straightforward than using my custom index code without
adding too much work.

Implements #43: Filter code can use a GHashTable directly
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-29 15:46:11 -04:00
Anna Schumaker ee4bbacf81 core/containers/set: Add set_alloc() and set_free() functions
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-29 15:46:11 -04:00
Anna Schumaker da3dd60ef3 Ocarina 6.4.16
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-07-29 15:41:05 -04:00
Anna Schumaker 951624c82f core/audio: Update Most and Least Played playlists
We need to do this when tracks are played to keep playlist counts
accurate.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-07-29 10:14:35 -04:00
Anna Schumaker 17910c72b2 tests: Add extra underscore to placeholder callback function
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-07-28 16:53:18 -04:00
Anna Schumaker 779969f28b core/idle: Let tests run without the thread pool
The thread pool is used to fetch album art in the background, but this
can slow down most tests that aren't interested in album art.  Adding a
(testing-only) function for running without the thread pool speeds
things up a bit.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-07-28 16:17:43 -04:00
Anna Schumaker bd8f3754e7 CHANGELOG updates
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-07-28 09:17:11 -04:00
Anna Schumaker 1d1e41916a core/playlists/system: Check that we read a valid playlist name
Otherwise we could crash when we try to access an out of bounds area of
the playlist array.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-07-28 08:55:53 -04:00
Anna Schumaker 3098282382 gui/artwork: Don't destroy objects twice
The file filter and preview widget are both cleaned up when the file
chooser dialog is destroyed.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-07-27 10:51:59 -04:00
Anna Schumaker 3b62125135 gui/artwork: Show hidden folders when selecting new images
Sometimes Ocarina gets the correct image for CD1, but not for CD2.
Allow traversing into hidden folders so users can select the correct
image out of the artwork cache.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-07-27 10:51:42 -04:00
Anna Schumaker 4de869d691 gui/artwork: Clear __artwork_cur_album when selecting album art
Otherwise the new image will never be updated due to the "did the album
change?" check in __artwork_set_pixbuf()

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-07-27 10:48:13 -04:00
Anna Schumaker 160295a6cc gui/artwork: Add a preview widget to the file chooser dialog
This lets users actually see images before selecting them for ablum art.

Implements #59: Add preview widget to album art chooser
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-07-27 10:45:59 -04:00
Anna Schumaker 343dec5d8d gui/artwork: Fix blurry album art
Using gdk_pixbuf_new_from_file_at_scale() can result in a blurry image
due to something in the gdk backend.  I want to have a sharper image, so
we need to perform the scale manually through Cairo.

Fixes issue #60: Album art is blurry
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-07-25 10:00:09 -04:00
Anna Schumaker 7dff5412bc gui/artwork: Reduce time spent polling for artwork
Since MusicBrainz limits us to one request each second, it doesn't
really make sense to poll for new artwork every half second.  Instead,
let's just put this into a new timeout function that gets called every
two seconds.  This should also let us stop polling once artwork has been
found.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-07-22 09:40:03 -04:00
Anna Schumaker 83724c5f6f gui/artwork: Split out album art functions into a new file
I think this is cleaner, and it should make it easier to maintain this
code.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-07-22 09:40:03 -04:00
Anna Schumaker 8893cdb58b tests: Unit test fixes
These should have been included as part of 6.4.15.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-07-22 09:40:02 -04:00
Anna Schumaker c5a563c112 Fix PKGBUILD dependency
We depend on the libmusicbrainz5 library, not libmusicbrainz.

Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-07-19 17:02:13 -04:00
Anna Schumaker 6ab5d99d71 Ocarina 6.4.16-rc
Signed-off-by: Anna Schumaker <Anna@NoWheyCreamery.com>
2016-07-19 17:01:02 -04:00
Anna Schumaker e24ab97545 gui/playlist: Add size information to playlist sidebar
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-19 16:03:11 -04:00
Anna Schumaker 2c18f9e715 core/playlist: Add playlist_size() function
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-19 16:03:11 -04:00
Anna Schumaker 00dd72d46e core/playlist: Remove unused playlist_t enum
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-19 16:03:11 -04:00
Anna Schumaker 5e9b6bc975 core/playlist: Access playlists through a string
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-19 16:03:11 -04:00
Anna Schumaker 90e0b3ed78 core/playlist: Remove remaining dynamic playlist code
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-19 16:03:11 -04:00
Anna Schumaker 2ff7113668 core/playlists/system: Move the least played playlist into system.c
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-19 16:03:10 -04:00
Anna Schumaker 9d3cc2e5ab core/playlists/system: Move the most played playlist into system.c
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-19 16:03:09 -04:00
Anna Schumaker 5ab2e63734 core/playlists/system: Move the unplayed tracks playlist into system.c
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-19 16:03:06 -04:00
Anna Schumaker 1527ee0e6d core/playlist: Add playlist_update() function
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-19 16:03:06 -04:00
Anna Schumaker 5a0fc355e4 core/playlist: Remove __playlist_is_{dynamic, static}() functions
This helps prepare for moving dynamic playlists into the system playlist
code.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-19 16:03:06 -04:00
Anna Schumaker a465577c86 core/playlists/system: Move system playlists into a new file
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-19 16:03:06 -04:00
Anna Schumaker e3d4143565 core/playlist: Add new playlist_type struct
I intend to use this for creating playlists with different properties,
such as using the playlist interface to add library paths.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-19 16:03:06 -04:00
Anna Schumaker 140abe79bc core/playlist: Split out system playlist load and save functions
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-19 16:03:06 -04:00
Anna Schumaker 8026207037 core/playlist: Split out basic system playlist functions
I'm going to use this as a starting point for creating a new playlist
interface.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-19 16:03:06 -04:00
Anna Schumaker 0f5d4e6a34 core/playlist: Remove __playlist_fill_static()
And other support code for filling the obsolete playlist_q with tracks.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-19 16:03:06 -04:00
Anna Schumaker 151c446635 core/playlist: Use separate queues for favorite and hidden playlists
Implements issue #6: Store playlists as queues
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-19 16:03:04 -04:00
Anna Schumaker e5dc36ca6e core/playlist: Store a struct queue in the playlist_db
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-19 08:13:10 -04:00
Anna Schumaker 90fc9bff0a core/playlist: Convert playlist_db to a GHashTable
I want to manage this container on my own, rather than relying on the
generic index code.  This will eventually make it easier to store a
playlist as a queue, instead of a set.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-19 08:13:10 -04:00
Anna Schumaker c845530812 core/queue: Resort the queue when unsetting Q_ADD_FRONT
This flag is used for bulk inserts to cut down on the number of gui
operations during startup.  Let's just make it standard that unsetting
the flag causes the queue to resort itself.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-19 08:13:10 -04:00
Anna Schumaker 9a98a009e9 core/queue: Add queue_{save|load}_tracks() function
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-19 08:13:10 -04:00
Anna Schumaker 9ec2497ac5 core/queue: Add a queue_has() function
Used to check if a track is on a queue.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-19 08:13:10 -04:00
Anna Schumaker afb2653f65 core/queue: queue_remove_all() returns count of tracks removed
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-19 08:13:10 -04:00
Anna Schumaker 378ff72307 Remove core/containers/queue
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-19 08:13:10 -04:00
Anna Schumaker db01ed3208 core/queue: Use a GQueue directly
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-19 08:13:10 -04:00
Anna Schumaker 2b426cff48 core/queue: Switch over to using struct queue_iter
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-19 08:13:10 -04:00
Anna Schumaker 9835235acd core/queue: Implement a new queue_iter
I plan to remove the containers/queue implementation, so we need a new
iterator for queue access.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-19 08:13:10 -04:00
Anna Schumaker 6bb08ddbaa core/queue: Call g_queue_*() functions directly
This is a first step to removing core/containers/queue

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-19 08:13:10 -04:00
Anna Schumaker e8d7576704 core/containers/set: Return status of set_insert() and set_remove()
I use this status indicator in the playlist code fairly often, so let's
return it directly rather than needing to code around it.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-19 08:13:10 -04:00
Anna Schumaker 5a30a63904 core/string: Add string_match() function
This function is used to determine if both strings exist and have the
same contents.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-19 08:13:10 -04:00
Anna Schumaker b7cf2509f7 Ocarina 6.4.15
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-19 08:10:07 -04:00
Anna Schumaker 9928c3239f core/tags/album: Improve MusicBrainz query accuracy
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-15 09:37:54 -04:00
Anna Schumaker 4f1f76b764 gui/audio: Update album art when manually setting
If the user is fixing broken album art then we need to update the image
immediately, otherwise the user will be confused.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-14 13:36:33 -04:00
Anna Schumaker eb5c0185e7 core/tags/album: Album art fetching improvements
- Allocate CaaCoverArt as needed, rather than sharing one object
- Use MusicBrainz fuzzy search to match more albums
- Escape most special characters in filenames

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-14 11:38:05 -04:00
Anna Schumaker 617088c89b core/tags/album: Fix retrying MB5 query on error 503
Reusing the Mb5Query can have undesireable side effects, such as the
error code not getting reset between queries.  Fix this by allocating a
new Mb5Query before evey request.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-14 11:38:05 -04:00
Anna Schumaker c62a88ce09 gui/audio: Add support for manually setting album art
Implements #58: Manually set album art
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-14 11:37:53 -04:00
Anna Schumaker e30f7f8115 core/tags/album: Add support for importing album artwork
This is needed so the user can manually set album artwork in the cases
where either we don't fetch the right image or no image is found.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-12 14:36:40 -04:00
Anna Schumaker 80d921343d core/file: Add support for importing a file into the cache
This will be needed to allow the user to manually set album art from a
downloaded file.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-12 14:16:46 -04:00
Anna Schumaker 99b51f5257 core/tags/album: Make quotes around artist name configurable
This allows me to search for `"release" AND artist` but also `release
AND "artist"`

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-11 09:43:01 -04:00
Anna Schumaker df3436f68a core/tags/album: Search with quotes around artist instead of album name
I think this results in a slightly better search, although there are
still a few wrong images fetched.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-11 08:05:33 -04:00
Anna Schumaker c8ccf7b844 core/tags/album: Place multiple queries to find artwork
If searching for artist and album fails, then fall back on album and
year or even just album name.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-04 21:30:06 -04:00
Anna Schumaker b4218833c5 core/tags/album: Immediately retry query on 503 error
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-04 20:59:29 -04:00
Anna Schumaker 2ea5104d42 core/tags/album: Fetch album art in the same step as metadata
This will help prepare for running multiple queries to find a release.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-04 20:59:28 -04:00
Anna Schumaker 86b63298a5 gui/idle: Show the idle progress as a tooltip
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-07-04 20:07:50 -04:00
Anna Schumaker 3c9798a6b7 gui: Remove unused GtkAdjustment
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-30 11:19:59 -04:00
Anna Schumaker ecc7843ea5 gui: Clean up setting album art
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-30 10:28:17 -04:00
Anna Schumaker dd66b10dfa gui: Properly load a pixbuf
Using gdk_pixbuf_new_from_file_at_scale() will load a scaled pixbuf,
which looks better than loading a height x height square.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-30 10:28:17 -04:00
Anna Schumaker 9ef9b17b93 gui: Fix up main GtkGrid
Somewhere along the line the grid formatting got messed up, probably
after several merges while other bugs were fixed.  This patch reworks
the grid so everything is formatted correctly.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-30 10:27:57 -04:00
Anna Schumaker 1ac9e69128 gui: Minor spacing updates
This helps some widgets line up better, instead of looking slightly out
of place.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-30 09:19:15 -04:00
Anna Schumaker cbb9631877 gui: Add a function for determining the height of widgets
It's eaiser to do it in the builder code, rather than repeating this
code in several places.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-30 08:18:11 -04:00
Anna Schumaker 1e59968154 gui: Initialize track labels with whitespace
This gives labels the correct initial size, rather than forcing them to
resize after startup.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-30 08:08:56 -04:00
Anna Schumaker 5b7a985dc6 Ocarina 6.4.15-rc
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-24 11:13:55 -04:00
Anna Schumaker 54af68a57f gui/audio: Add album art support
Also add the "o_cover" widget to the glade file for setting album art.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-24 10:50:37 -04:00
Anna Schumaker d0dddeacdb core/tags/album: Add album_artwork_path() function
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-24 10:50:37 -04:00
Anna Schumaker 940d2d1dc2 core/tags/album: Query the Cover Art Archive for album art
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-24 10:50:37 -04:00
Anna Schumaker 570efda299 core/tags/album: Query MusicBrainz for album release information
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-24 10:50:37 -04:00
Anna Schumaker d79eb2c9b8 core/tags/album: Add album_artwork_exists() function
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-24 10:50:37 -04:00
Anna Schumaker 0d9b7baff6 core/tags/album: Add a pointer to the struct artist
This is needed for album art fetching to get more accurate results for
our MusicBrainz query.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-24 10:50:37 -04:00
Anna Schumaker 97c8f80393 core/idle: Add a way to reschedule idle tasks
This will be needed to reschedule MusicBrainz requests if the server is
busy.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-24 10:50:37 -04:00
Anna Schumaker 6b52775e58 core/idle: Add support for running idle tasks in a new thread
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-24 10:50:37 -04:00
Anna Schumaker 6a44f9e1a1 core/idle: Add idle_sync_t enum
I intend to use this to select between sync and async idle tasks.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-24 10:50:37 -04:00
Anna Schumaker a6bfbbb1c6 core/file: Add file_remove() function
I plan to use this for upgrades to remove obsolete files.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-24 10:50:37 -04:00
Anna Schumaker 0344a2088d core/file: Add cache_file_write() function
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-24 10:50:37 -04:00
Anna Schumaker 9db9df619f core/file: Add cache_file_close() function
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-24 10:50:37 -04:00
Anna Schumaker e137eb0108 core/file: Add cache_file_open() function
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-24 10:50:37 -04:00
Anna Schumaker 3723dff87d core/file: Add cache_file_exists() function
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-24 10:50:37 -04:00
Anna Schumaker 79ecaa11fb core/file: Add cache_file_write_path() function
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-24 10:50:37 -04:00
Anna Schumaker 5dcf681e48 core/file: Add cache_file_path() function
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-24 10:50:37 -04:00
Anna Schumaker b5e13af30c core/file: Add cache_file_init() function
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-24 10:50:37 -04:00
Anna Schumaker 12949651f7 core/file: Add struct cache_file
I want to reuse as much file code as I can for cache files, but I need a
new struct since data and cache files track different properties.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-24 10:50:37 -04:00
Anna Schumaker 9e0f017e61 core/file: Build in minimum version checks
I don't think it makes sense that callers of file_open() are expected to
check the file version after opening.  This should be something handled
by the file code so we can print a consistent error message.

Implements issue #5: Better file versioning
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-24 10:50:37 -04:00
Anna Schumaker fe6f31b1e5 core/file: Rework REPORT_ERROR() function
I want to be able to print any message as an error message without
relying on errno.  Let's handle this by introducing REPORT_ERRNO() to
look up the right error message for a given errno.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-24 10:50:37 -04:00
Anna Schumaker ee4f0d4c89 core/file: Writes go to a temporary file first
And then rename the temporary file when closed.  This protects users
data in case Ocarina gets killed.

Implements issue #31: Make file writes seem atomic
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-24 10:50:37 -04:00
Anna Schumaker c308ba7f8e core/file: Rewrite file opening
There are enough differences in the read and write paths that
__file_open_common() was still trying to account for.  Let's make a
simpler wrapper around g_fopen() and move differing code into
__file_open_read() and __file_open_write().

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-24 10:50:37 -04:00
Anna Schumaker 224290d4eb core/file: file->f_name can be a pointer
I'm only setting this to a static string, so it doesn't make sense to
store this as a char array.  Let's use a string pointer instead.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-24 10:50:37 -04:00
Anna Schumaker 427319b72e core/file: Move OCARINA_NAME configuration into version.h
I'm going to use this for saving album art to the right place.  I moved
it into an include file to avoid duplicating code.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-24 10:50:37 -04:00
Anna Schumaker 98faba93d1 core/string: Add a string_length() function
This is a wrapper around strlen(), but checks for a NULL pointer first.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-24 10:50:37 -04:00
Anna Schumaker 096c0e8eaa Ocarina 6.4.14
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-24 10:22:55 -04:00
Anna Schumaker c4e0efbe72 gui: GtkPaned spacing improvements
Use a smaller handle, but add more space to the child widgets margins.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-20 10:05:15 -04:00
Anna Schumaker 2f3bdf353d Ocarina 6.4.14-rc
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-16 14:50:00 -04:00
Anna Schumaker ea10b7e630 core/playlist: Improve average playcount calculation
The track database now tallys total play count and unplayed track count,
so we can use this information for calculating averages.  I also changed
the least played tracks playlist to allow tracks with play count equal
to the average.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-14 17:11:25 -04:00
Anna Schumaker 4998b0867b core/tags/track: Find the average play count of tracks
This function returns the average count of tracks that have been played,
and not the average count of all tracks.

Implements #29: Efficiently calculate average play count of tracks
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-14 17:11:06 -04:00
Anna Schumaker 1973d15605 core/tags/track: Count the total number of tracks played
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-14 17:10:52 -04:00
Anna Schumaker a97ec66e7f core/tags/track: Count the number of unplayed tracks
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-14 17:10:47 -04:00
Anna Schumaker d825e2d481 core: Remove random functions
I no longer need these now that the queue is using the glib
g_random_int_range() function.

Implements #32: Remove custom RNG code
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-14 17:10:30 -04:00
Anna Schumaker f1bcc7746e core/queue: Call g_random_int_range() rather than random_range()
Using somebody else's library is probably better than relying on my own
random number function.

Implements #32: Remove custom RNG code
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-14 17:09:46 -04:00
Anna Schumaker bc513532c1 gui/idle: Add a function to disable processing idle tasks
This is needed during ocarina shutdown to prevent a segfault.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-14 17:09:39 -04:00
Anna Schumaker fff2da5439 gui/ocarina: Deinitialize gui with the GtkApplication "shutdown" signal
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-14 17:09:38 -04:00
Anna Schumaker d0179a9bfa gui/ocarina: Initialize gui with the GtkApplication "startup" signal
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-14 17:09:34 -04:00
Anna Schumaker 9a209d098b core/tags: Switch over to db_load_idle()
Load all tag databases with the new load function.

Implements #15: Load track database through an idle task
Implements #16: Load library database through an idle task
Implements #17: Load genre database through an idle task
Implements #18: Load artist database through an idle task
Implements #19: Load album database through an idle task
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-14 17:07:55 -04:00
Anna Schumaker 223a1e47c1 core/playlist: Switch over to db_load_idle()
Implements #14: Load playlists through an idle task
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-14 17:07:16 -04:00
Anna Schumaker 0bcfa06bfb core/containers/database: Add a function for loading databases when idle
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-14 17:06:57 -04:00
Anna Schumaker 2ab0c6957b core/idle: Test idle queue before containers
This will let databases use the idle queue for loading.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-14 17:06:41 -04:00
Anna Schumaker f706ccb77c core/collection: Initialize the collection through an idle task
Scan over all tracks in the database first, and then schedule a
collection update.

Implements #13: Load collection queue through an idle task
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-14 17:06:20 -04:00
Anna Schumaker bd1e20bc56 core/tempq: Load the tempq file through an idle task
This will help reduce disk accesses during thet main startup sequence.

Implements #12: Load temporary queues through an idle task
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-14 17:05:11 -04:00
Anna Schumaker 279d6e0228 core/audio: Load initial track through an idle task
Let's save this disk access for when we're idle.

Implements #11: Load initial track through an idle task
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-14 17:04:28 -04:00
Anna Schumaker cb6d451fb1 gui/collection: Add library paths through an idle task
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-13 09:47:46 -04:00
Anna Schumaker f01cce3b47 gui/idle: Split out idle queue functions
I want to use this outside of the collection, so let's move these
functions into a new file.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-13 09:47:46 -04:00
Anna Schumaker fc03b6cb95 Ocarina 6.4.13
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-13 09:42:00 -04:00
Anna Schumaker f50c1541a1 gui/view: Scrolling improvements
This patch fixes two issues.  First, I disable scrolling when the user
has manually selected a track.  I've found that extra scrolling in this
case can be disorienting, and frequently ends up with the wrong track
selected due to how queue iterators are set so it's probably best just
to disable scrolling in this case.

This patch also changes the order of calls to set_cursor() and
scroll_to_cell().  I've found that scrolling before setting the cursor
causes the GtkTreeView to ignore alignment settings unless the row is
already on the screen.  Switching the order makes everything work
properly.

Fixes #57: Wrong track is sometimes scrolled to
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-08 08:23:53 -04:00
Anna Schumaker dfb023a0fc gui/model: Set text to bold for the currently playing track
This patch adds support for changing a rows font face to bold for the
currently playing track.  This should make it easier to find what track
is playing while quickly skimming through the list.

Fixes #22: Highlight the currently-playing song in the collection
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-07 09:14:52 -04:00
Anna Schumaker a89aa5a201 core/audio: Trigger queue updates when changing tracks
I need to do this for temporary queues in addition to the collection for
bolding to work properly.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-07 09:01:13 -04:00
Anna Schumaker b2a61a60f3 core/queue: Trigger an update when tracks are selected
This will let us turn tracks bold as they are selected.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-04 17:10:05 -04:00
Anna Schumaker 1ad112e217 gui/sidebar: Select first enabled queue during startup
Otherwise the list of tracks is left blank, which the user might not be
expecting.

Fixes #55: Collection should be selected by default
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-04 13:52:09 -04:00
Anna Schumaker df93ad06df gui/tempq: Don't save queues from __tempq_cleared()
Cleared is only called during Ocarina shutdown, so calling save here
wipes out any temporary queues as they are written to disk.

Fixes #24: Temporary queues not saving
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-04 13:41:21 -04:00
Anna Schumaker 3a08828dda gui: Enable GtkTreeView fixed-height mode
Tracks information should always be the same height, so we can safely
enable this as a quick speed up to the treeview.

Fixes #52: Enable GtkTreeView fixed height mode
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-06-03 13:11:40 -04:00
Anna Schumaker 6c8733bbbb gui: Remove unused ui files
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-27 12:05:36 -04:00
Anna Schumaker 490370b759 Ocarina 6.4.13-rc
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-27 12:04:14 -04:00
Anna Schumaker 061dbc4575 gui/ocarina: Convert file to C
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-27 12:01:43 -04:00
Anna Schumaker 4dbaf12701 gui/ocarina: Switch to C-style GtkApplication
The right way to do this would be to respond to the "activate",
"startup", and "shutdown" signals.  I can't to this easily, because
gstreamer needs argc and argv.  Let's fake things up now and sort it out
later.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-27 12:01:43 -04:00
Anna Schumaker 108dbacf41 gui/ocarina: Replace share_file() with find_file_path()
And don't keep the result around any longer than we need to.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-27 12:01:43 -04:00
Anna Schumaker 2c65584e2d gui: Remove o_notebook
Now that nothing uses it.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-27 12:01:43 -04:00
Anna Schumaker e97939a9cd gui: Remove old Tab and QueueTab code
Now that nothing uses it

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-27 12:01:43 -04:00
Anna Schumaker c0a6c663d1 gui: Move tempq operations into tempq.c
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-27 12:01:43 -04:00
Anna Schumaker bd22c8da6d gui/collection: Move collection_ops into collection.c
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-27 12:01:43 -04:00
Anna Schumaker 27a4cc23ed gui: Remove C++ collection tab code
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-27 12:01:43 -04:00
Anna Schumaker e290552812 gui/history: Convert file to C
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-27 12:01:43 -04:00
Anna Schumaker 5a9c6a1dd1 gui/history: Remove obsolete HistoryTab code
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-27 12:01:43 -04:00
Anna Schumaker d769140e35 gui: Remove C++ playlist code
And notebook switching code in playlist.c

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-27 12:01:43 -04:00
Anna Schumaker 7995e381c0 gui/playlist: Move playlist_ops into playlist.c
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-27 12:01:43 -04:00
Anna Schumaker a1c6502226 gui/audio: Handle favorite and hide buttons
This lets me remove gui/playlist_tab.cpp

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-27 12:01:43 -04:00
Anna Schumaker f328b1686d gui/view: Scroll to the current queue's iterator position
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-27 12:01:43 -04:00
Anna Schumaker d5c365ddf0 gui/view: Show sort indicators on columns
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-27 12:01:43 -04:00
Anna Schumaker cacd344741 gui/view: Sort queue when columns are clicked
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-27 12:01:43 -04:00
Anna Schumaker 8e6b963eb8 gui/view: Add a right-click menu
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-27 12:01:43 -04:00
Anna Schumaker c9eb9d724b gui/view: Add keypress events
- Press "f" to add tracks to the Favorites playlist
- Press "q" to create a new temporary queue
- Press "r" to create a new temporary queue with Q_RANDOM set
- Press 0 .. 9 to add tracks to a temporary queue
- Delete to remove tracks from a queue

I also removed the corresponding keypress events from the C++ code to
make progress easier to track.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-27 12:01:43 -04:00
Anna Schumaker aee4764a2c core/queue: Add queue_erase() and qop_erase()
This function is similar to queue_remove(), except the remove can be
prevented if qop_erase() returns false.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-27 12:01:43 -04:00
Anna Schumaker 8d2b0caf6c core/tempq: Store queue operations passed to tempq_init()
We don't need different operations for each queue.  If we store this
then a higher layer doesn't need to keep passing the same structure over
and over again.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-27 12:01:43 -04:00
Anna Schumaker 87c59ce888 gui/queue: Control runtime display
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-27 12:01:43 -04:00
Anna Schumaker 2d1ddd5a35 gui/view: Load a track when treeview is double clicked
And remove this feature from the C++ code.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-27 12:01:43 -04:00
Anna Schumaker bbf111ecb0 gui/view: Add gui_view_set_model()
To set the currently displayed treemodel

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-27 12:01:43 -04:00
Anna Schumaker 76a6eba537 gui/queue: Add functions to filter the currently displayed queue
And remove the ability to filter from the C++ code.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-27 12:01:43 -04:00
Anna Schumaker 4c784366d7 gui/view: Save and restore column widths
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-27 12:01:43 -04:00
Anna Schumaker 13525eda22 gui/queue: Add a single treeview instance
And swap out the model when queues are shown.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-27 12:01:43 -04:00
Anna Schumaker c5e03d98cf Ocarina 6.4.12
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-27 11:49:33 -04:00
Anna Schumaker f42c3d41d1 gui: Vertically center the playback controls
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-26 13:22:41 -04:00
Anna Schumaker d07b7e68ac core/tempq: Don't enable all queues by default
Enabling all queues by default, even ones read from disk, is incorrect
as it leads to all queues getting reenabled when restarting Ocarina.

Fixes #56: Enabled status of temporary queues not saving
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-19 07:33:45 -04:00
Anna Schumaker 4fd4f75f0e TODO list updates
I can cross off a few more items after the last couple of releases.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-16 14:27:06 -04:00
Anna Schumaker b01f61f8e4 gui: Refer to "this track" instead of "current track"
Saying current track sounds too formal, and adds extra space to the
pause-after widget.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-16 14:27:03 -04:00
Anna Schumaker d874c0e408 gui: More widget spacing updates
Fixes #54: Fix On/Off switch size group
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-16 14:26:39 -04:00
Anna Schumaker b59b2a2daf gui/audio: Remove old pause after configuration code
And rearrange UI widgets a bit

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-14 12:03:53 -04:00
Anna Schumaker bf73685098 gui/audio: Add new GtkComboBox for controlling automatic pausing
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-14 11:55:46 -04:00
Anna Schumaker ac468ec3de gui: Spacing tweaks in the top section
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-14 08:13:42 -04:00
Anna Schumaker cdf91cc59b gui: Move position slider into the current track header
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-14 08:05:42 -04:00
Anna Schumaker 48b59bd6c4 gui: Tooltip updates for random, repeat, favorite, and hide buttons
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-14 07:56:27 -04:00
Anna Schumaker e5711c26f0 gui: Swap positions of random/repeat and favorite/hide buttons
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-14 07:53:41 -04:00
Anna Schumaker b6488b6c39 Ocarina 6.4.12-rc
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-14 07:41:44 -04:00
Anna Schumaker ada392550a gui: Switch over to using a GuiQueueModel
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-14 07:37:24 -04:00
Anna Schumaker ea149d57df gui/model: Convert iters and paths into tracks
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-14 07:37:17 -04:00
Anna Schumaker 87e547d85d gui: Wire up gui_queue functions to various tabs
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-14 07:37:11 -04:00
Anna Schumaker e8681e4c92 gui/queue: Add functions to update the model
These are simple passthrough functions to convert a struct queue into a
GuiQueueModel.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-14 07:37:03 -04:00
Anna Schumaker 70803cc199 gui/queue: Create a GuiQueueModel as part of the gui_queue
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-14 07:36:56 -04:00
Anna Schumaker 4fd370ceb6 gui/model: Send tree model signals
"row-inserted", "row-deleted", and "row-changed"

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-14 07:36:50 -04:00
Anna Schumaker dd2adc6307 gui/model: Add support for gtk_tree_model_iter_parent()
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-14 07:36:43 -04:00
Anna Schumaker ccf6e4c61f gui/model: Add support for gtk_tree_model_iter_nth_child()
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-14 07:36:36 -04:00
Anna Schumaker ba59d6bd29 gui/model: Add support for gtk_tree_model_iter_n_children()
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-14 07:36:30 -04:00
Anna Schumaker 13223427c1 gui/model: Add support for gtk_tree_model_iter_has_children()
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-14 07:36:23 -04:00
Anna Schumaker b34fd6d522 gui/model: Add support for gtk_tree_model_iter_children()
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-14 07:36:16 -04:00
Anna Schumaker ed69e3d2b8 gui/model: Add support for gtk_tree_model_iter_next()
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-14 07:36:09 -04:00
Anna Schumaker e59617ffa7 gui/model: Add support for gtk_tree_model_get_value()
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-14 07:36:03 -04:00
Anna Schumaker 9c3adf2b09 gui/model: Add support for gtk_tree_model_get_path()
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-14 07:35:56 -04:00
Anna Schumaker eb481b8d09 gui/model: Add support for gtk_tree_model_get_iter()
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-14 07:35:50 -04:00
Anna Schumaker ff81af24fc gui/model: Add support for gtk_tree_model_get_column_type()
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-14 07:35:40 -04:00
Anna Schumaker 6acee801ab gui/model: Add support for gtk_tree_model_get_n_columns()
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-14 07:35:33 -04:00
Anna Schumaker f5fba1680a gui/model: Add support for gtk_tree_model_get_flags()
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-14 07:35:27 -04:00
Anna Schumaker ddcb973d8e gui/model: Begin new custom tree model for queues
I'm not even going to try converting my C++ code.  Let's just start
fresh, and write unit tests as we build this up.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-14 07:35:20 -04:00
Anna Schumaker a313160f94 gui: Put file chooser and notebook onto a stack
The eventual goal is to replace the notebook, but this is a good start.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-14 07:35:14 -04:00
Anna Schumaker 21eb09ced3 gui: Remove old TabToolbar code
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-14 07:35:08 -04:00
Anna Schumaker bc9efade75 gui/queue: Add a switch to enable and disable tempqueues
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-14 07:35:01 -04:00
Anna Schumaker d19e0b2cc0 gui/queue: Add a search entry widget
This gets cleared every time the queue is changed and disabled when we
show pages that cannot be filtered.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-14 07:34:55 -04:00
Anna Schumaker 24f53d88b6 gui/queue: Respond to toggling the random and repeat buttons
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-14 07:34:48 -04:00
Anna Schumaker ddbc040a3b gui/queue: Set state of random and repeat buttons
I need to change the state of these toggle buttons whenever the
sidebar's current selection changes.  Some gtk themes have trouble
showing the state of toggle buttons, so I change the sensitivity of both
the button and associated image so users know the current state.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-14 07:34:40 -04:00
Anna Schumaker 2c676631a4 gui: Add shuffle and repeat buttons
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-14 07:34:37 -04:00
Anna Schumaker 410a784ede gui/queue: Add flags to the gui queue
This will be used to determine if the random and random buttons should
be enabled.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-13 16:36:44 -04:00
Anna Schumaker ce8ec63886 gui/sidebar: Switch over to using the new gui queues
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-13 16:36:44 -04:00
Anna Schumaker f098811a28 gui: Wire up gui_queue_{alloc|free}() in the queue operations
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-13 16:36:44 -04:00
Anna Schumaker 2d6e42832b gui/queue: Add a text field to the gui queue
The sidebar is going to look at this when setting queue sizes.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-13 16:36:44 -04:00
Anna Schumaker f85ad3a9c3 gui/queue: Add a new gui_queue struct
This will be used to store queue state once I no longer support notebook
tabs.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-13 16:36:44 -04:00
Anna Schumaker 5bc9f65cd9 core/tempq: Add tempq_index() function
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-13 16:36:44 -04:00
Anna Schumaker 2770403c61 core/tempq: Add tempq ops to queues durinig init
Rather than setting them after.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-13 16:36:44 -04:00
Anna Schumaker 5419711409 core/queue: Add qop_deinit() queue operation
This function is used to notify a higher layer that a queue is being
deinitialized.  The higher layer should then clean up any state
associated with that queue.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-13 16:36:44 -04:00
Anna Schumaker 8bb7a20ff4 core/queue: Add qop_init() queue operation
This function is used to notify a higher layer that a queue has been
initialized.  That higher layer can return a pointer to be attached to
the "private data" field of the queue.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-13 16:36:44 -04:00
Anna Schumaker 6e3027d087 Ocarina 6.4.11
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-13 16:32:43 -04:00
Anna Schumaker f2222c1063 tests/gui: Add __collection_buttonpress() default handler
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-10 11:16:44 -04:00
Anna Schumaker 13dadd25ef core/audio: Remove audio_stop() function
It has no users now that the stop button has been removed.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-10 11:15:35 -04:00
Anna Schumaker 548852dc24 gui/audio: Remove stop button
Most of the time people want to pause playback, rather than stop
entirely.  Let's remove the button since it's not getting any use.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-10 11:14:52 -04:00
Anna Schumaker 909b50168f gui: Remove empty label between controls and tags
It's easier to have the controls expand into this column, but still
align them with the edge of the window.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-10 11:03:39 -04:00
Anna Schumaker 25211e93ac gui/collection: Convert checkbox into a right click menu
This feature isn't used very often, and keeping the checkbox in the
sidebar looks pretty ugly.

Fixes #50: Remove Collection checkbox
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-05 08:27:10 -04:00
Anna Schumaker d2c4a36945 gui/collection: Add icon to library paths
I'm surprised this wasn't already there.  I think the "folder" icon
works best, considering library paths are directories in the filesystem.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-04 16:51:52 -04:00
Anna Schumaker b91b898913 gui: Add expanders to Playlist and Collection treeviews
This is a UI tweak that I think looks nice.  Future work: store the
expander position between sessions.

Implements #40: Add expander to playlist and collection treeviews
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-02 11:18:46 -04:00
Anna Schumaker 02f5b13650 gui/collection: Remove image size from the collection liststore
This is to match the playlist treeview.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-05-02 11:18:35 -04:00
Anna Schumaker 5c34576e70 Update CHANGELOG
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-29 15:34:25 -04:00
Anna Schumaker 79f79405a8 gui/playlist: Remove image size from the playlist liststore
It's easier just to set all images to have the same size, rather than
making the header's image slightly larger.

Fixes #39: Remove GtkIconSize from Playlist treeview
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-29 14:58:40 -04:00
Anna Schumaker b4c81a4441 gui/playlist: Change "Banned" to "Hidden" in the sidebar
I also update the icon to match what is on the "Hide Track" button.

Fixes #49: Hidden playlist still says "Banned" in sidebar
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-29 14:42:02 -04:00
Anna Schumaker 9f3b8ae239 gui/window: Change default window height
I shrink it by a little bit to make the default ratio 10 x 6.

Fixes #42: Change default window size
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-29 14:18:50 -04:00
Anna Schumaker 088c2ec37f gui: Remove padding around Add Selected Path image
The xpad and ypad properties are deprecated, and this button looks fine
without anything set.

Fixes #41: Fix spacing on Add Selected Path button image
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-29 14:01:02 -04:00
Anna Schumaker bb9f220785 Ocarina 6.4.11-rc
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-29 13:18:28 -04:00
Anna Schumaker 8a72637fe9 gui: Remove notebook tabs and adjust margins
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-29 13:04:45 -04:00
Anna Schumaker 16b055f06b gui/sidebar: Add support for removing temporary queues
Either through the delete key or when the queue runs out of tracks.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-29 13:04:45 -04:00
Anna Schumaker 839f4c4aa1 gui/sidebar: Add support for adding temporary queues
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-29 13:04:45 -04:00
Anna Schumaker c663f287d4 gui/sidebar: Add sizes to Collection and History entries
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-29 13:04:45 -04:00
Anna Schumaker eb137c4339 gui/sidebar: Change notebook page through the sidebar
And make sure other sidebar views are deselected.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-29 13:04:45 -04:00
Anna Schumaker 6c653c6a79 gui/sidebar: Add Collection and History entries to the sidebar
I could do this as a treeview, but creating this as a liststore in glade
is WAY easier!

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-29 13:04:45 -04:00
Anna Schumaker 84ff59cf81 gui/playlist_tab: Remove custom list from tab
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-29 13:04:45 -04:00
Anna Schumaker 9ee00f9997 gui/sidebar: Add a function for deselecting treeviews
I'm using multiple treeviews, but only one should be selected at any
time.  Use this function to coordinate that.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-29 13:04:45 -04:00
Anna Schumaker 7439a2a73d gui/playlist: Change current playlist when selected
I also add a function to get the currently selected playlist.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-29 13:04:45 -04:00
Anna Schumaker fde59a1868 gui/playlist: Add 5 playlists to the sidebar
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-29 13:04:45 -04:00
Anna Schumaker be6895630d gui/playlist: Begin new playlist sidebar widget
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-29 13:04:45 -04:00
Anna Schumaker ca88bca999 gui: Rename playlist.cpp -> playlist_tab.cpp
I will soon have playlist.c to control the playlist sidebar widgets.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-29 13:04:45 -04:00
Anna Schumaker 3c3f11b958 gui/collection: Remove old collection manager code
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-29 13:04:45 -04:00
Anna Schumaker 8807f06fd6 gui/collection: Update collection on startup
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-29 13:04:45 -04:00
Anna Schumaker 2cae2cd525 gui/collection: Remove library paths with the Delete key
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-29 13:04:45 -04:00
Anna Schumaker 0afe46b5df gui/collection: Toggle library state through the gui
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-29 13:04:45 -04:00
Anna Schumaker 8dece02eed gui/collection: Update library paths when rows are clicked
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-29 13:04:45 -04:00
Anna Schumaker 2f9ee44000 gui/collection: Add library paths on startup
And change to them when selected.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-29 13:04:45 -04:00
Anna Schumaker 08910bef7c gui/collection: Add new library paths through the GUI
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-29 13:04:45 -04:00
Anna Schumaker f34e2cb57b gui/collection: Change tab page when "Add new Path" is selected
I also add in code that reuses the current file chooser for picking
paths.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-29 13:04:45 -04:00
Anna Schumaker eb81fa2e20 gui/collection: Add sidebar widget showing Collection header
And make it non-selectable.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-29 13:04:45 -04:00
Anna Schumaker 480090f78d gui: Rename collection.cpp -> collection_tab.cpp
I want to create a new file (collection.c) for the collection sidebar
code.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-29 13:04:45 -04:00
Anna Schumaker 58d61f52e2 gui/sidebar: Add new sidebar widget
This is a GtkPaned that remembers its size between Ocarina sessions.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-29 13:04:45 -04:00
Anna Schumaker 870a2b769b gui/window: Save width and height between sessions
Saving maximized state is too complicated, so let's just store width and
height of the window when it is not maximized.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-29 13:04:45 -04:00
Anna Schumaker 0c214dd1a9 gui/window: Add gui_window_deinit()
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-29 13:04:45 -04:00
Anna Schumaker 29985d2a69 gui/window: Add unit test
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-29 13:04:45 -04:00
Anna Schumaker 684d52c522 gui/window: Convert file to C
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-29 13:04:45 -04:00
Anna Schumaker 0c8bcfa552 gui/window: Switch to C-style gtk widgets
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-29 13:04:45 -04:00
Anna Schumaker 066d27a240 gui/window: Move keyboard shortcut handling into tabs.cpp
I handle the Escape key through gtkbuilder, so let's move the
tab-changing keys into the tabs source file.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-29 13:04:45 -04:00
Anna Schumaker 70dca79b41 Ocarina 6.4.10
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-29 12:01:22 -04:00
Anna Schumaker 44dbbff04b Add CHANGELOG
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-26 13:55:45 -04:00
Anna Schumaker acd9dccb56 gui: More tweaking to song information display
I need to enable the expand property, otherwise labels shift due to
changes in grid size.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-26 11:30:14 -04:00
Anna Schumaker c01561831c gui/audio: Remove "By:" and "From:"
I replaced these with images that have similar meanings.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-25 11:38:20 -04:00
Anna Schumaker e73ae0612d gui: Left justify song information
I think this looks a bit better.  I'm using an empty label as a spacer
between control buttons and text, but this can be replaced with album
art later.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-25 10:35:10 -04:00
Anna Schumaker 539b2b5ac3 gui: Fix up widget spacing
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-12 14:31:48 -04:00
Anna Schumaker f5af640202 gui: Don't use deprecated properties
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-12 12:37:49 -04:00
Anna Schumaker cb26d08315 gui: Move tooltip text to buttons
Looks like I accidentally attached these to images, but they should go
with the entire button.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-12 11:27:34 -04:00
Anna Schumaker 6aa64f0bc1 gui/audio: Block accelerators when a gtk entry is focused
Otherwise pressing the spacebar while searching could toggle the play /
pause status.

Fixes #36: Button accelerators always triggered
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-12 11:25:49 -04:00
Anna Schumaker 19afc4aeef gui: Use the window-close icon for the Hide Track button
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-11 15:53:38 -04:00
Anna Schumaker 2097f63f3d gui: Update playlists to say Hidden instead of Banned
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-11 15:34:21 -04:00
Anna Schumaker 5a4d5bcc44 tests: Don't run test if name or function is NULL
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-11 15:04:07 -04:00
Anna Schumaker 811270a832 build: Don't run gui tests if $DISPLAY is not set
I have tests running on ocarinaproject.net, which is headless and
doesn't run an X server.  Gui tests cann't run without an X server.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-11 15:02:24 -04:00
Anna Schumaker abf9cfe90e gui: Add tooltips to audio and playlist buttons
Fixes #35: Add Button Tooltips
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-11 14:27:57 -04:00
Anna Schumaker fa748a2eb1 gui: Clean up track progress bar widgets
Fixes #1: Fix track progress slider
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-08 13:56:04 -04:00
Anna Schumaker 7f0326be29 gui: Adjust icon sizes
xfce does not seem to handle scaling icons on hidpi displayes, and I
configured everything based on really tiny icons.  This can lead to
way-too-large icons on non-hidpi screens.  If your DE doesn't handle
icon scaling properly, then you might want to consider running ocarina
with:

GDK_SCALE=2 GDK_DPI_SCALE=0.5 /bin/ocarina

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-08 13:56:04 -04:00
Anna Schumaker 4bbf9472a5 Ocarina 6.4.10-rc
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-08 13:56:04 -04:00
Anna Schumaker 627619c391 gui/audio: Convert o_progress widget to use seconds
This feels better than using units of nanoseconds.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-08 13:39:43 -04:00
Anna Schumaker 5e96f40cf8 gui/audio: Unit test can simulate button presses
This is better than calling audio_*() functions directly, since we can
make sure signals are wired up properly in glade.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-08 13:39:39 -04:00
Anna Schumaker fd28d6830c gui/audio: Add unit test
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-08 13:39:34 -04:00
Anna Schumaker d8754e9a45 gui/audio: Control keyboard shortcuts from GtkBuilder
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-08 13:16:30 -04:00
Anna Schumaker f95a6d02ed gui/audio: Redesign some of the interface
I moved the location of buttons and text boxes, and also resized some of
the widgets.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-08 13:16:27 -04:00
Anna Schumaker 286085d248 gui/audio: Configure pause-after-N through glade
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-08 13:16:25 -04:00
Anna Schumaker 2d45e9e5c4 gui/audio: Pass the progress bar to __audio_timeout
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-08 13:16:24 -04:00
Anna Schumaker 36b8b29b0b gui/audio: Add __audio prefix to internal functions
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-08 13:16:22 -04:00
Anna Schumaker e5e2c87a86 gui/audio: Define seek controls completely in glade
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-08 13:16:20 -04:00
Anna Schumaker 50a7c83d61 gui/audio: Convert gst.cpp to audio.c
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-08 13:16:10 -04:00
Anna Schumaker c48e128d0a gui/gst: Configure timeout with the C interface
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-08 13:12:36 -04:00
Anna Schumaker 5368208a37 gui/gst: Remove gst :: pre_init() and rename gst_init()
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-08 13:12:19 -04:00
Anna Schumaker dee8b948b0 gui/gst: Remove gst :: toggle()
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-08 12:03:08 -04:00
Anna Schumaker bf39724a40 gui/gst: Set ban and favorite buttons through the C interface
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-08 12:03:08 -04:00
Anna Schumaker 71c4e6a1aa gui/gst: Completely define the positon and duration labels in glade
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-08 12:03:08 -04:00
Anna Schumaker 15da6b4249 gui/gst: Completely define title, artist, and album widgets in glade
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-08 12:03:08 -04:00
Anna Schumaker aacc1f876a gui/gst: Completely define the play button in glade
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-08 12:03:08 -04:00
Anna Schumaker 6723ef88c7 gui/gst: Completely define the pause button in glade
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-08 12:03:08 -04:00
Anna Schumaker 8ae31ed483 gui/gst: Completely define the stop button in glade
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-08 12:03:08 -04:00
Anna Schumaker 00899873bd gui/gst: Completely define the previous button in glade
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-08 12:03:08 -04:00
Anna Schumaker 6680cdbd0e gui/gst: Completely define the next button in glade
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-08 12:03:08 -04:00
Anna Schumaker f31a67f644 gui/gst: Use C-style gtk widgets
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-08 12:03:08 -04:00
Anna Schumaker 44d7f9a853 core/gst: Set ban / favorite status when tracks are loaded
It's easier to do this from the audio code than the plalist code.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-08 12:03:08 -04:00
Anna Schumaker 61436d5ccd gui: Switch over to the new gui_builder system
Glib::wrap() all the things!

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-08 12:03:08 -04:00
Anna Schumaker 0eb8521094 gui/builder: Get a widget from the GTK builder
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-08 12:03:08 -04:00
Anna Schumaker d4b27316c0 gui/builder: Get an object from the builder
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-08 12:03:08 -04:00
Anna Schumaker 961659bc66 gui/builder: Add a test UI file
This file creates a button that calls the test_builder_activated()
function when clicked.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-08 12:03:08 -04:00
Anna Schumaker 3bc5b1db9e gui/builder: Add new file for accessing the GtkBuilder
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-08 12:03:08 -04:00
Anna Schumaker 27e09f47a6 gui/ocarina: Initialize settings on startup
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-08 12:03:08 -04:00
Anna Schumaker c479042a86 gui/settings: Add gui_settings_has() function
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-08 12:03:08 -04:00
Anna Schumaker d292879837 gui/settings: Read settings file on startup
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-08 12:03:08 -04:00
Anna Schumaker a5f0da7a60 gui/settings: Store settings when changed
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-08 12:03:08 -04:00
Anna Schumaker 92c1b64b1a gui/settings: Add functions for setting and getting values
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-08 12:03:08 -04:00
Anna Schumaker f23fb9e0f5 gui/settings: Add new settings file
The settings layer will track various configuration options set by the
user.  This belongs in the gui, and not core, because it controls
settings specific to this gui implementation.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-08 12:03:08 -04:00
Anna Schumaker 727752df08 Ocarina 6.4.9
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-04-08 12:00:05 -04:00
Anna Schumaker 09e900eadf core/file: Free "dir" after reporting possible errors
Otherwise we're reading memory that has already been freed.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-31 14:20:44 -04:00
Anna Schumaker 8034a64f17 audio: Clean up audio loading
It's better to have a single function loading tracks and adding them to
the history queue.

Fixes #2: Initial track not added to history
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-28 08:22:08 -04:00
Anna Schumaker 711eb67f44 core/queue: Fix queue random and selection test
6.4.8 changed how random tracks are selected, but never updated the unit
test.  This patch fixes the unit test, and makes a few changes to make
sure the right tracks are getting selected.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-28 08:03:21 -04:00
Anna Schumaker cf861473df Ocarina 6.4.9-rc
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-28 08:02:45 -04:00
Anna Schumaker fc3f2d8491 Update TODO list
Remove completed items, or old items that are no longer necessary.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-28 08:01:30 -04:00
Anna Schumaker aac32681e5 tests: Create test{_not}_equal_common() functions
This lets me cut down on copied code.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-28 08:01:30 -04:00
Anna Schumaker df2d365b80 tests: Remove test_cp_data_dir()
This function is unused now.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-28 08:01:30 -04:00
Anna Schumaker eba243a22a core/tests: Remove test.h
This file is no longer needed now that everything has been converted to
C.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-28 08:01:30 -04:00
Anna Schumaker d81ef77fb3 tests/core: Add code for updating the .gitignore file
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-28 08:01:30 -04:00
Anna Schumaker ece432bb22 core/audio: audio_{load, next, prev}() should start playback
The GUI needed an extra function to do this manually, which means it's
something that core should do instead.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-28 08:01:30 -04:00
Anna Schumaker 0cf5187867 core/audio: Add on_state_change() audio operation
Called to notify when playback state has changed.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-28 08:01:30 -04:00
Anna Schumaker ed5f035855 core/audio: Rename audio_get_player() to test_audio_player()
Also, let's only have this function when CONFIG_TESTING is enabled.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-28 08:01:30 -04:00
Anna Schumaker 2586348921 core/audio: Convert file to C
I also convert core/core.c so the audio test can be converted at the
same time.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-28 08:01:30 -04:00
Anna Schumaker a59a71eb38 core/core: Move core_deinit() out of the core namespace
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-28 08:01:30 -04:00
Anna Schumaker 04291f4296 core/core: Move core_init() out of the core namespace
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-28 08:01:30 -04:00
Anna Schumaker 03196c3efa core/audio: Set up the gstreamer bus for the gui
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-28 08:01:30 -04:00
Anna Schumaker 1d76990fd1 core/audio: Add audio_error() to handle error messages
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-28 08:01:30 -04:00
Anna Schumaker a5556ac10a core/audio: Move audio_eos() out of the AudioDriver
This change lets me remove the AudioDriver, too.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-28 08:01:30 -04:00
Anna Schumaker 276c56406a core/audio: Move audio_pause_after() out of the audio namespace
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-28 08:01:30 -04:00
Anna Schumaker d18d3dd214 core/audio: Move audio_prev() out of the audio namespace
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-28 08:01:30 -04:00
Anna Schumaker 3f25369444 core/audio: Move audio_next() out of the audio namespace
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-28 08:01:30 -04:00
Anna Schumaker 7765c2bf57 core/audio: Remove unused on_error() AudioDriver function
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-28 08:01:30 -04:00
Anna Schumaker 2511db3a08 core/audio: Add audio_cur_state() function
This replaces the is_playing() function of the AudioDriver class.  I can
also make the GUIs GstDriver static.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-28 08:01:30 -04:00
Anna Schumaker 0a1a9f1394 core/audio: Move audio_cur_track() out of the audio namespace
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-28 08:01:30 -04:00
Anna Schumaker d1d722a163 core/audio: Move audio_stop() out of the audio namespace
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-28 08:01:30 -04:00
Anna Schumaker e1abe94b28 core/audio: Move audio_duration() out of the audio namespace
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-28 08:01:30 -04:00
Anna Schumaker 20bb01ef4e core/audio: Move audio_position() out of the audio namespace
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-28 08:01:30 -04:00
Anna Schumaker 566ef3bb50 core/audio: Move audio_seek() out of the audio namespace 2016-03-28 08:01:30 -04:00
Anna Schumaker 9097bd0ffc core/audio: Move audio_pause() out of the audio namespace
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-28 08:01:29 -04:00
Anna Schumaker 16c4c23a42 core/audio: Move audio_play() out of the audio namespace
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-28 08:01:29 -04:00
Anna Schumaker e5c3d8f02e core/audio: Move audio_load() out of the audio namespace
And add the on_load() audio operation.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-28 08:01:29 -04:00
Anna Schumaker e0c89556ed core/audio: Add audio_deinit() function
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-28 08:01:29 -04:00
Anna Schumaker d9540b29d6 core/audio: Move audio_init() out of the audio namespace
I also move the gstreamer playbin back into core/

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-28 08:01:29 -04:00
Anna Schumaker b7bd7622b3 Ocarina 6.4.8
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-25 15:12:11 -04:00
Anna Schumaker 4323461bc6 core/queue: Adjust random track selection
Dividing queue size by 3 seems to give a better distribution of tracks,
but only for a large set of tracks (such as the entire collection).
let's skip the division if the queue only has a small number of tracks.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-23 11:36:42 -04:00
Anna Schumaker 6358124ce8 gui: Check the return code from collection_check_library()
If the library isn't valid, then we shouldn't try to pick another track
until the user fixes things.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-23 09:58:17 -04:00
Anna Schumaker aad90782ba core/collection: Clean up error handling code
I was assuming that my disk returns -EIO when it enters its failed
state, but it really seems to be return -ENOENT.  Let's have this code
check for any error, rather than one specific one.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-23 09:42:05 -04:00
Anna Schumaker 08bf842767 gui: Don't update gui if zero tracks were cleared
I'm seeing Ocarina crash when a tempq finishes and gets removed.  For
now, let's only have the gui handle queue clearing if tracks were
actually removed.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-22 16:04:25 -04:00
Anna Schumaker 76985c8842 gui: Fix setting Q_RANDOM flag
I had the condition reversed for enabling random on temporary queues, so
the flag was getting set whenever I didn't want it.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-22 09:36:32 -04:00
Anna Schumaker 5979d1dcaf core/collection: Handle -EIO errors coming from the filesystem
One of my disks frequently returns this error, and has wiped out my
track database on more than one occasion.  Let's handle this error by
disabling the library until the user tells us it is safe to use again.

Fixes #33: Handle music directories disappearing better
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-21 08:36:48 -04:00
Anna Schumaker 2dd4f93bd0 gui: Don't call tempq_save() in the qop_cleared() handler
The first thing queue_deinit() does is clear the queue, so calling
tempq_save() here will overwrite any tempq state currently on disk.
This seems reasonable at first, but ends up erasing any temporary queues
during Ocarina shutdown.

Fixes #34: Temporary queues not saving
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-17 12:17:11 -04:00
Anna Schumaker fea5da5c10 tempq: Close file if version check fails
We were returning right away if the file version check fails, without
closing the file.  This could cause future reads or writes to fail to
open.

Fixes #25: File version checking doesn't look quite right
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-17 11:48:04 -04:00
Anna Schumaker 7ff3dc92a0 Ocarina 6.4.8-rc
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-11 11:04:47 -05:00
Anna Schumaker a248f8ebf7 core/tempq: Add a test for moving a NULL queue
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-11 10:40:34 -05:00
Anna Schumaker 06ea2d8c0e core/tempq: Add a deinit() / init() loop to test_next()
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-11 10:40:34 -05:00
Anna Schumaker 882ee6e1e7 core/tempq: Convert file to C
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-11 10:40:34 -05:00
Anna Schumaker 187c56f328 core/tempq: Clean up reading and writing queues
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-11 10:40:34 -05:00
Anna Schumaker 5c92d0771f core/tempq: Clean up tempq alloc and free
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-11 10:40:34 -05:00
Anna Schumaker 15f5b8fc87 core/tempq: Switch STL list for glib GSList
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-11 10:40:34 -05:00
Anna Schumaker 17981f4393 core/tempq: Switch queue list to store a queue pointer
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-11 10:40:34 -05:00
Anna Schumaker 27eab88b9c core/tempq: Remove unused TempQueue class
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-11 10:40:34 -05:00
Anna Schumaker 9633806c2d core/tempq: Merge TempQueue :: read() with tempq_init()
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-11 10:40:34 -05:00
Anna Schumaker 2102b1bfc9 core/tempq: Move tempq_save() out of the deck namespace
And remove the deck :: write() and TempQueue :: write() functions while
we're at it.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-11 10:40:34 -05:00
Anna Schumaker b919843717 core/tempq: Add tempq_deinit() function
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-11 10:40:34 -05:00
Anna Schumaker b3d95a06d4 core/tempq: Move tempq_next() out of the deck namespace
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-11 10:40:34 -05:00
Anna Schumaker ecda136015 core/tempq: Move tempq_move() out of the deck namespace
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-11 10:40:34 -05:00
Anna Schumaker c22b93b2cf core/tempq: Move tempq_get() out of the deck namespace
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-11 10:40:34 -05:00
Anna Schumaker 6bdc481cb4 core/tempq: Make __tempq_index() private
It has no users outside of unit tests.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-11 10:40:34 -05:00
Anna Schumaker 06d62240bb core/tempq: Move tempq_free() out of the deck namespace
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-11 10:40:34 -05:00
Anna Schumaker bce2ba33f7 core/tempq: Move tempq_alloc() out of the deck namespace
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-11 10:40:34 -05:00
Anna Schumaker 8c7550d5c3 core/tempq: Move tempq_init() out of the deck namespace
I also take this opportunity to drop support for upgrading from file
format 0.  I've had several releases since this format was supported, so
this should be safe to do.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-11 10:40:34 -05:00
Anna Schumaker 51379c7e8c core/history: Add history_prev() function
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-11 10:40:34 -05:00
Anna Schumaker c125b3893e core/history: Add history_add() function
I decided that having a uniqueue history queue doesn't really get me
anything, so I dropped that portion of the behavior.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-11 10:40:34 -05:00
Anna Schumaker 75c039f22d core/history: Add history_init() and history_deinit() functions
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-11 10:40:34 -05:00
Anna Schumaker 77d4815eb6 core/history: Move history queue into a new file
I think managing this separately from temporary queues will make the
code simpler.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-11 10:40:34 -05:00
Anna Schumaker 460aeded4e Ocarina 6.4.7
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-11 10:17:27 -05:00
Anna Schumaker 665e54a3bc Remove DESIGN file
I haven't referred to this in forever, and it's a few versions out of
date.  I don't think it's needed anymore.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-10 14:24:31 -05:00
Anna Schumaker b191a7f22c gui/ocarina: Deinitialize core first
This fixes a segfault I was getting when closing ocarina before the
directory scan finishes.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-09 09:59:06 -05:00
Anna Schumaker 8c8ab2a9eb core/idle: Add idle_cancel() function
This function is used to cancel all idle tasks and free the memory
allocated for them.  This needs to be called when Ocarina is shutting
down to prevent a possible hang with the gtk idle callback continuing to
process tasks.

Fixes #30: Closing Ocarina should cancel idle tasks
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-03-01 08:27:13 -05:00
Anna Schumaker b3592e40c0 core/playlist: Rename PL_BANNED -> PL_HIDDEN
"Banning" a track is a bit harsh.  Let's talking about hiding tracks
instead, so that it sounds friendlier.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-29 13:22:31 -05:00
Anna Schumaker 7cdc5678c6 Set gitlab-ci stages on one line
Rather than doing this in two separate lines.  Also drop the -j2
argument to scons to help with memory issues.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-26 14:31:12 -05:00
Anna Schumaker 6e838ffba3 core/collection: Make sure we run all idle tasks
GitLab CI failed on this test because the last remaining idle task was
the one to scan the new directory.  Let's make sure we've run through
all idle tasks before continuing on with this test.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-26 13:15:05 -05:00
Anna Schumaker 126ed4c15c Ocarina 6.4.7-rc
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-26 11:23:25 -05:00
Anna Schumaker 743a464f3f tests/core: CoreTest only needs to take the name
We can detect C/C++ and set up everything else from there.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-26 11:04:42 -05:00
Anna Schumaker 5e74385fbb tests/core/containers: Don't pass source to ContainerTest
We can figure it out from the test name.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-26 11:04:42 -05:00
Anna Schumaker 8ad45ebef3 tests/core/tags: Don't pass source to TagTest
We can use the test name to find the source file.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-26 11:04:42 -05:00
Anna Schumaker 850af16c87 tests/core: Containers and Tags can call CoreTest
CoreTest will do most of the setup for us, so let's not duplicate code.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-26 11:04:42 -05:00
Anna Schumaker 5b921e7277 tests/core/tags: Give an order to tag tests
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-26 11:04:42 -05:00
Anna Schumaker 8a59485cbc tests/core/containers: Give an order to container tests
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-26 11:04:42 -05:00
Anna Schumaker 5d251365fd tests/core: Give an order to core tests
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-26 11:04:42 -05:00
Anna Schumaker bc0437b3fe tests: Clean up how the sanity test is scheduled
I created a new function for checking if a group of tests is running to
help determine if the sanity test needs to run before anything else.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-26 11:04:42 -05:00
Anna Schumaker fef3ef3353 core: Initialize the playlist before the collection
I think it makes more sense to have the collection manage if banned
tracks are displayed or not, rather than doing this from the playlist
layer.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-26 11:04:42 -05:00
Anna Schumaker beda9bfa3f core/collection: Add functions to ban and unban tracks
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-26 11:04:42 -05:00
Anna Schumaker 3b5bbf14af core/playlist: playlist_remove() can return a boolean
The collection will be using this soon to tell if a track was
successfully unbanned.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-26 11:04:42 -05:00
Anna Schumaker 20825613e9 core/playlist: playlist_add() can return a boolean
There is at least one place in the gui where it needs to know if a track
was actually added to a playlist.  Adding a return value is the best way
to know what happened.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-26 11:04:42 -05:00
Anna Schumaker 02c82c182e core/playlist: Convert file to C
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-26 11:04:42 -05:00
Anna Schumaker 5844402ee3 core/playlist: Merge __playlist_fill() with playlist_static()
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-26 11:04:42 -05:00
Anna Schumaker b7a4bb3872 core/playlist: Use playlist_t enum to access playlists
Using strings is pretty tedious, so let's restrict restrict playlist
access to known values.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-26 11:04:42 -05:00
Anna Schumaker 88f6fc526c core/playlist: Add a function to remove banned tracks
This replaces the get_tracks() function.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-26 11:04:42 -05:00
Anna Schumaker 135e0d95d6 core/playlist: Move dynamic playlists out of the PlaylistQueue class
This lets me remove the PlaylistQueue entirely.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-26 11:04:42 -05:00
Anna Schumaker 7a32fdb982 core/playlist: Add dynamic playlist generation unit test
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-26 11:04:42 -05:00
Anna Schumaker 73992ed912 core/playlist: Clean up how we fill in static playlists
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-26 11:04:42 -05:00
Anna Schumaker 4e6028cf6e core/playlist: Move playlist_remove() out of the playlist namespace
I also remove redundant unit tests.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-26 11:04:42 -05:00
Anna Schumaker 0e3d6251d3 core/playlist: Move playlist_add() out of the playlist namespace
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-26 11:04:42 -05:00
Anna Schumaker 82ed2f2dc0 core/playlist: Move playlist_get_queue() out of the playlist namespace
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-26 11:04:42 -05:00
Anna Schumaker 6f0b95608a core/playlist: Move playlist_select() out of the playlist namespace
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-26 11:04:42 -05:00
Anna Schumaker 1d3a762936 core/playlist: Move playlist_has() out of the playlist namespace
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-26 11:04:42 -05:00
Anna Schumaker 1f5ce9e0d1 core/playlist: Add playlist_deinit() function
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-26 11:04:42 -05:00
Anna Schumaker b1c5d42387 core/playlist: Move playlist_init() out of the playlist namespace
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-26 11:04:42 -05:00
Anna Schumaker ce618e35a1 Ocarina 6.4.6
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-26 10:54:26 -05:00
Anna Schumaker 65a81e5bb2 Add git protocol entry to the README
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-23 11:27:04 -05:00
Anna Schumaker 7fb584581b Rewrite .gitlab-ci.yml
I think this should get it running ...

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-23 11:27:01 -05:00
Anna Schumaker 219f8fa119 core/collection: Update collection on startup
This is much more convenient to users, since they don't need to update
the collection manually.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-23 07:55:56 -05:00
Anna Schumaker e22533e7ec Ocarina 6.4.6-rc
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-12 10:53:52 -05:00
Anna Schumaker 3ecb06bcb6 test: Remove library directory creating functions
Changes to the collections layer mean that I don't need this anymore.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-12 09:47:30 -05:00
Anna Schumaker 94f22c9fc5 core/collection: Statically initialize c_file
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-12 09:47:26 -05:00
Anna Schumaker 696933c6b4 core/collection: Rename library_q -> c_queue
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-12 09:47:21 -05:00
Anna Schumaker 7065b6312e core/collection: Convert file to C
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-12 09:47:16 -05:00
Anna Schumaker 49457751c9 core/collection: Clean up path scanning code
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-12 09:47:10 -05:00
Anna Schumaker 8e5cc543c3 core/collection: Fix some memory leaks
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-12 09:46:04 -05:00
Anna Schumaker ffa12a2c38 core/collection: Move file reading code into collection_init()
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-12 09:37:26 -05:00
Anna Schumaker 79af4513b0 core/collection: Directly save the queue in collection_save()
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-12 09:37:26 -05:00
Anna Schumaker f413d14720 core/collection: Move collection_save() out of the collection namespace
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-12 09:37:26 -05:00
Anna Schumaker 295a4424ed core/collection: Move collection_get_queue() out of the collection
namespace

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-12 09:37:26 -05:00
Anna Schumaker 89ce6d725c core/collection: Add collection_deinit()
To clean up the collection queue.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-12 09:37:26 -05:00
Anna Schumaker 62f0606cd6 core/collection: move collection_set_enabled() out of the collection
namespace

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-12 09:37:26 -05:00
Anna Schumaker 8a1f5403d0 core/collection: Move collection_update() out of the collection namespace
And bring collection_update_all() along with it.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-12 09:37:26 -05:00
Anna Schumaker 0cb16f5c64 core/collection: Move collection_remove() out of the collection
namespace

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-12 09:37:26 -05:00
Anna Schumaker 6e39e17060 core/collection: Move collection_add() out of the collection namespace
This patch breaks later tests, since I needed to remove the old ogg
files.  This will be fixed in a few more patches.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-12 09:37:26 -05:00
Anna Schumaker 3204fc0e44 core/collection: Move collection_init() out of the collection namespace
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-12 09:37:26 -05:00
Anna Schumaker d97ae38cc2 core/tests: Generate Ocarina of Time album
I'll need a second album for testing collections, and Ocarina of Time
seems like the obvious choice!

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-12 09:37:26 -05:00
Anna Schumaker 44bb25bff1 Ocarina 6.4.5
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-12 09:23:32 -05:00
Anna Schumaker d3b33f8c6a Add configuration for gitlab CI
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-02-05 16:01:53 -05:00
Anna Schumaker 68568b58d0 Update TODO list
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-29 10:13:56 -05:00
Anna Schumaker e47540a84e core/queue: Add queue_clear()
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-29 10:12:09 -05:00
Anna Schumaker cc164fc4ee core/queue: Add queue_deinit()
To clean up a queue when we're done with it.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-29 10:12:00 -05:00
Anna Schumaker 5e8ce4de86 Ocarina 6.4.5-rc
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-29 08:24:04 -05:00
Anna Schumaker 6a8e73375e gui/collection: Check for collection_q in on_track_removed()
So we don't segfault while removing banned tracks.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-29 08:22:10 -05:00
Anna Schumaker 9701da5392 core/queue: Add a function to resort the queue
This can be combined with the Q_ADD_FRONT flag for efficient bulk
insertions.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-29 08:22:10 -05:00
Anna Schumaker 0b84b6180c core/queue: Convert file to C
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-29 08:22:10 -05:00
Anna Schumaker 799a8d34b5 core/queue: Convert q_sort to a GSList
I needed to bump the track comparison fields by one so I can use signed
values to indicate sort order.  I updated core/library.cpp to add and
subtract one as needed.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-29 08:22:10 -05:00
Anna Schumaker 6fa78dbf3a core/queue: Convert q_cur into a queue iterator
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-29 08:22:10 -05:00
Anna Schumaker 8fb64015b4 core/queue: Replace vector with struct _queue
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-29 08:22:10 -05:00
Anna Schumaker 0a331a44f5 core/queue: Replace on_track_updated() with qop_updated()
This patch also removes the now-unused queue notifier class.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-29 08:22:10 -05:00
Anna Schumaker da0c96ac51 core/queue: Replace on_track_removed() with qop_removed()
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-29 08:22:10 -05:00
Anna Schumaker df06b444cf core/queue: Replace on_track_added() with qop_added()
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-29 08:22:10 -05:00
Anna Schumaker daa09becf7 core/queue: Remove queue destructor
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-29 08:22:10 -05:00
Anna Schumaker 6aab58629e core/queue: Move read() and write() into TempQueues
These functions are only used by temporary queues, and the collection
queue has its own save function.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-29 08:22:10 -05:00
Anna Schumaker acc78a6667 core/queue: Move queue_remove_all() out of the queue struct
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-29 08:22:10 -05:00
Anna Schumaker ea00b406e5 core/queue: Move queue_remove() out of the queue struct
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-29 08:22:10 -05:00
Anna Schumaker d5e34b76d4 core/queue: Add Q_ADD_FRONT flag
This tells the queue to always add tracks at the front.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-29 08:22:10 -05:00
Anna Schumaker 8fe85b9782 core/queue: Move queue_add() out of the queue struct
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-29 08:22:10 -05:00
Anna Schumaker 4c4d0ab6ce core/queue: Move queue_sort() out of the queue struct
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-29 08:22:10 -05:00
Anna Schumaker 13723856fc core/queue: Move queue_{set|unset}_flag() out of the queue struct
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-29 08:22:10 -05:00
Anna Schumaker be5d028fcf core/deck: Wire up the qop_save() function
So temporary queues can save when flags change or when sorted.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-29 08:22:10 -05:00
Anna Schumaker 9451a41ff1 core/collection: Wire up the qop_save() operation
This will be triggered both when queue flags are changed and when the
queue is sorted.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-29 08:22:10 -05:00
Anna Schumaker ce55ef2421 core/queue: Add queue operations vector
And a function to help with saving queues.  This patch also adds the
Q_SAVE_FLAGS and Q_SAVE_SORT queue flags to control if the queue should
be saved when flags are changed or when the queue is sorted.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-29 08:22:10 -05:00
Anna Schumaker b3a8fa293b core/queue: Move queue_has_flag() out of the queue struct
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-29 08:22:10 -05:00
Anna Schumaker 3e5bef5f3c core/queue: Move queue_updated() out of the queue struct
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-29 08:22:10 -05:00
Anna Schumaker ff0c2a09a8 core/queue: Move queue_at() out of the queue struct
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-29 08:22:10 -05:00
Anna Schumaker c259177dde core/queue: Move queue_size() out of the queue struct
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-29 08:22:10 -05:00
Anna Schumaker 331e56716a core/queue: Move queue_next() out of the queue struct
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-29 08:22:10 -05:00
Anna Schumaker 6bd625f65b core/queue: Move queue_selected() out of the queue struct
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-29 08:22:10 -05:00
Anna Schumaker d6ae61d915 core/queue: Remove queue :: set_notifier()
Let's just set the q_notify variable directly, rather than going through
a function.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-29 08:22:10 -05:00
Anna Schumaker a721a95604 core/queue: Remove queue :: length()
Let's just access the q_length variable directly.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-29 08:22:10 -05:00
Anna Schumaker 281947aded core/queue: Convert from class to struct
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-29 08:22:10 -05:00
Anna Schumaker 626eb48933 core/queue: Rewrite unit test
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-29 08:22:10 -05:00
Anna Schumaker 973dfb3b90 Ocarina 6.4.4
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-29 08:17:28 -05:00
Anna Schumaker 8fe65e68b4 tests: Check for ffmpeg and vorbiscomment before generating music
We can't run most of our tests without the generated tracks.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-25 10:29:59 -05:00
Anna Schumaker b586461104 core/containers/queue: Add _q_clear() function
This is used to clean up the items on a queue, and should be called to
prevent memory leaks.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-25 08:08:28 -05:00
Anna Schumaker 73ea514c27 Update TODO list
Some items have been accomplished, while others are obsolete.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-19 16:45:25 -05:00
Anna Schumaker 849892e66f Ocarina 6.4.4-rc
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-15 15:11:22 -05:00
Anna Schumaker 4e8a63cc36 core/tags/track: Expand track_compare() to compare by different fields
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-15 15:10:44 -05:00
Anna Schumaker 08c7323dfc core/tags/track: Move comparison fields into track.h
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-15 15:10:44 -05:00
Anna Schumaker 9a16a18b9f core/tags/album: Add an album_compare_year() function
With special handling for albums with the same year but different names.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-15 15:10:44 -05:00
Anna Schumaker f44710f7ae core/containers/queue: Add _q_add_sorted() function
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-15 15:10:44 -05:00
Anna Schumaker b36869ff93 core/containers/queue: Add _q_sort() function
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-15 15:10:44 -05:00
Anna Schumaker b7e4a1de23 core/containers/queue: Add _q_remove_it() function
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-15 15:10:44 -05:00
Anna Schumaker e87e37414d core/containers/queue: Add _q_for_each() function
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-15 15:10:44 -05:00
Anna Schumaker f26b50bdf8 core/containers/queue: Add _q_iter_set() and _q_iter_val()
This patch implements basic queue iterator functions for accessing
specific positions on the queue.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-15 15:10:44 -05:00
Anna Schumaker 1fefbb6b4a core/containers/queue: Add _q_add_head() function
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-15 15:10:44 -05:00
Anna Schumaker 6a653bd35e core/containers/queue: Add _q_add_tail() function
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-15 15:10:44 -05:00
Anna Schumaker bf332b36a5 core/containers/queue: Add _q_size() function
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-15 15:10:44 -05:00
Anna Schumaker 79627bb287 core/containers/queue: Add basic queue struct
This struct is a wrapper around the GQueue container, similar to how we
do sets.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-15 15:10:44 -05:00
Anna Schumaker 58a983efd1 core/containers: Move index into the containers/ directory
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-15 15:10:44 -05:00
Anna Schumaker c34f0c160d core/containers: Move database into the containers/ directory
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-15 15:10:44 -05:00
Anna Schumaker f02853e9c7 core/containers: Move set into the containers/ directory
This patch also creates the containers/ directory

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-15 15:10:44 -05:00
Anna Schumaker 3b630a0e78 Ocarina 6.4.3
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-15 15:08:12 -05:00
Anna Schumaker eac0b92f0d core/library: Close directory after reading
We were opening a directory for scanning, but we never closed when we
were done.  If we do this enough then the kernel starts telling us that
there are too many open files.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-11 10:03:08 -05:00
Anna Schumaker 4f3b05ebbb Ocarina 6.4.3-rc
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-11 09:45:14 -05:00
Anna Schumaker ad5726b542 core: Add core :: deinit() function
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-11 09:35:59 -05:00
Anna Schumaker a5963a553e core/tags/track: Convert file to C
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-11 09:35:59 -05:00
Anna Schumaker b5caf6faed core/tags/track: Convert std::string to gchar *
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-11 09:35:59 -05:00
Anna Schumaker 9e3e3e514c core/tags/track: Replace constructor with a backwards pointer
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-11 09:35:59 -05:00
Anna Schumaker 800aeda633 core/tags: Move tags_deinit() out of the tags namespace
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-11 09:35:59 -05:00
Anna Schumaker eb349c60e9 core/tags: Move tags_init() out of the tags namespace
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-11 09:35:59 -05:00
Anna Schumaker 1b4eb470a7 core/tags/library: Convert file to C
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-11 09:35:59 -05:00
Anna Schumaker 62fd782710 core/tags/library: Replace std::string with gchar *
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-11 09:35:59 -05:00
Anna Schumaker 5cc4efb6ac core/tags/library: Replace constructor with a backwards pointer
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-11 09:35:59 -05:00
Anna Schumaker 2755e8a09b core/tags/genre: Convert file to C
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-11 09:35:59 -05:00
Anna Schumaker 6c3d708576 core/tags/genre: Replace std::string with gchar *
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-11 09:35:59 -05:00
Anna Schumaker e98e74213e core/tags/genre: Replace constructor with a backwards pointer
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-11 09:35:59 -05:00
Anna Schumaker 6d9c89392e core/tags/artist: Convert file to C 2016-01-11 09:35:59 -05:00
Anna Schumaker c07d1e9024 core/tags/artist: Replace std:string with gchar *
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-11 09:35:59 -05:00
Anna Schumaker d404579297 core/tags/artist: Replace constructor with a backwards pointer
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-11 09:35:59 -05:00
Anna Schumaker 5309ea5931 core/tags/album: Convert file to C
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-11 09:35:59 -05:00
Anna Schumaker ad48d24533 core/tags/album: Replace std::string with gchar *
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-11 09:35:59 -05:00
Anna Schumaker 7c3bba11b5 core/tags/album: Replace constructor with a backwards pointer
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-11 09:35:59 -05:00
Anna Schumaker ab837b1a18 core/idle: Convert file to C
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-11 09:35:59 -05:00
Anna Schumaker 284e3466f4 core/idle: Replace C++ queue with a glib queue
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-11 09:35:59 -05:00
Anna Schumaker 8474ff1907 core/idle: Move idle_schedule() out of the idle namespace
And rewrite it to use void pointers instead of inheritance.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-11 09:35:59 -05:00
Anna Schumaker 8e25c4d89e core/idle: Move idle_run_task() out of the idle queue
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-11 09:35:59 -05:00
Anna Schumaker f17a19fe57 core/idle: Move idle_progress() out of the idle namespace
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-11 09:35:59 -05:00
Anna Schumaker cfd8ca8d43 core/filter: Convert file to C
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-11 09:35:59 -05:00
Anna Schumaker 91239a392d core/filter: Clean up header file
Adjust commends and remove the filter namespace.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-11 09:35:59 -05:00
Anna Schumaker f2664aa8f2 core/filter: Move filter_search() out of the filter namespace
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-11 09:35:59 -05:00
Anna Schumaker 90afcd6065 core/filter: Move filter_add() out of the filter namespace
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-11 09:35:59 -05:00
Anna Schumaker b98b1a5855 core/filter: Rewrite unit test
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-11 09:35:59 -05:00
Anna Schumaker 746c55ac56 core/database: Change db_insert() to insert-by-key
This means that databases completely manage when memory is allocated.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-11 09:35:59 -05:00
Anna Schumaker bd1de2262d core/tags/track: Wire up the dbe_alloc() database operation
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-11 09:35:59 -05:00
Anna Schumaker a9ec9aa7f2 Ocarina 6.4.2
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-08 15:04:50 -05:00
Anna Schumaker 8e02001373 gui/queue: Stop space bar from selecting new tracks
From Josh: Single-clicking a track in the collection queue and pressing the
space bar loads the selected track, but users would expect this to
toggle the play / pause state instead.

The solution is to watch for the on_key_press signal and tell GTK that
we have handled it if we see that the space bar was pressed.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-06 10:27:28 -05:00
Anna Schumaker 7e306de007 Update Sconstruct for 6.4.2-rc
I probably should have tagged this commit, but oh well.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2016-01-06 10:26:21 -05:00
Anna Schumaker 55a688cdcc core/index: Convert file to C
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:48:19 -05:00
Anna Schumaker 507ac4602d core/index: Replace index_entry constructor with backwards pointer
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:48:19 -05:00
Anna Schumaker b28b0c8464 core/database: Add C-style initializer macro
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:48:19 -05:00
Anna Schumaker 877d9ac1d7 core/database: Convert file to C
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:48:19 -05:00
Anna Schumaker 8dfe818a7a core/database: Replace constructors with a backwards pointer
This lets me use the struct db_entry without needing an inheritance
system.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:48:19 -05:00
Anna Schumaker 4a4529b158 core/database: Replace std::map with a glib hash table
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:48:19 -05:00
Anna Schumaker 9dd9d7d8f7 core/database: Replace std::vector with a glib array
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:48:19 -05:00
Anna Schumaker 1c22ecfda4 core/database: De-templatize the database
We now have an interface for controlling everything through struct
db_entry, so let's just have the database store a db_entry directly.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:48:18 -05:00
Anna Schumaker 1bef380ba7 core/database: Introduce the dbe_key() database operation
And store the result in the db_entry struct for use later.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:48:18 -05:00
Anna Schumaker f51852f62e core/database: Introduce the dbe_write() database operation
For writing database entries to disk.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:48:18 -05:00
Anna Schumaker 2da33f1c75 core/database: Introduce the dbe_read() database operation
This function allocates and returns a new database entry using
information read from a file.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:48:18 -05:00
Anna Schumaker c77ca65630 core/database: Introduce the dbe_setup() database operation
Track tags need to add themselves to the filter index and update the
library track count once added to the database.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:48:18 -05:00
Anna Schumaker c8021639ba core/database: Introduce the dbe_free() database operation
The Track tag needs to do some cleanup when removed from a database, so
we need to use this op when removing items.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:48:18 -05:00
Anna Schumaker 049156a523 core/database: Introduce the dbe_alloc() database operation
For allocating new database items from a given key.  Tracks do not need
this function since we have special handling for creation and insertion.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:48:18 -05:00
Anna Schumaker ab1572ed34 core/database: Add operations vector
I intend to replace C++ inheritance with this struct of function
pointers.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:48:18 -05:00
Anna Schumaker 847e4c1925 core/database: Remove db_entry::index() function
Let's just access the dbe_index variable directly.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:48:18 -05:00
Anna Schumaker 3eb27debfb core/database: Convert DatabaseEntry class into a struct
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:48:18 -05:00
Anna Schumaker 1c0235c8c7 core/tags/generic: Remove Generic tag
Nothing uses it anymore, so it can be safely removed :)

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:48:18 -05:00
Anna Schumaker cfd501c5d6 core/tags/track: Rewrite unit test
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:47:22 -05:00
Anna Schumaker 18311afcfe core/tests: Write a script to generate empty albums
gen_tracks.sh will read a specially configured file and create a
directory containing empty tracks to use for testing.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:46:35 -05:00
Anna Schumaker 92806c5201 core/tags/track: Clean up constructors
I replace the standard and copy constructors with one that tags a track
during construction.  This lets me clean up a lot of code, and keep
tagging functions internal to the track class.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker 33e20989fa core/tags/track: Directly inherit from DatabaseEntry
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker ee71786c09 core/tags/track: Move track_last_play() out of the track struct
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker 90cdfd4cbd core/tags/track: Move track_path() out of the track struct
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker c634f5d5e2 core/tags/track: Move track_played() out of the track struct
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker fb4933e418 core/tags/track: Remove track::compare_date()
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker 24d5c37a6c core/tags/track: Remove variable accessor functions
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker 9c1cbbf8cb core/tags/track: Remove tag accessor functions
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker 192bdc3ac7 core/tags/track: Replace tags :: track_size() with track_db_get()
We want to loop over the track database in several places, so let's make
this easier by just returning the database itself.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker eea0f57cf8 core/tags/track: Move track_commit_db() out of tags namespace
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker d3bdcf2edc core/tags/track: Move track_db_init() out of the tags namespace
And add the functions track_db_deinit() and tags :: db_deinit().

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker d0ec3e2cac core/tags/track: Move track_remove_all() out of the tags namespace
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker 7ffaf91617 core/tags/track: Move track_remove() out of the tags namespace
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker 83a945d3da core/tags/track: Move track_add() out of the tags namespace
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker c8061e2868 core/tags/track: Move track_get() out of the tags namespace
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker 765079df94 core/tags/track: Convert Track class into a struct
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker 446f1228cf core/tags/library: Add library_file() function
To help with finding the full path of files that are located in the
library's directory.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker 24504c7de8 core/tags/library: Remove library size() and {inc|dec}_size() functions
We can just access this variable directly instead.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker ac2b4ad52c core/tags/library: Remove library enabled() function
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker 47ab4c4b17 core/tags/library: Move library_set_enabled() out of the library struct
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker f41235e5b2 core/tags/library: Replace tags :: library_size() with library_db_get()
It's easier to just pass off the library database rather than forcing
higher layers to iterate over the entire thing (including possible
invalid entries).

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker 768f86e802 core/tags/library: Move library_db_init() out of the tags namespace
And add the function library_db_deinit().

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker d7cff5faf4 core/tags/library: Move library_remove() out of tags namespace
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker a288922b65 core/tags/library: Move library_find() out of the tags namespace
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker e1093f7eab core/tags/library: Move library_get() out of the tags namespace
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker ffa5e65ba7 core/tags/library: Convert Library class to a struct
I also have to replace the "library" namespace with the "collection"
namespace to avoid naming collisions.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker dbd4475815 core/tags/library: Rewrite unit test
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker cc3becd566 core/tags/genre: Directly inherit from DatabaseEntry
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker 8aa05ecedc core/tags/genre: Move genre_db_init() out of the tags namespace
And add the function genre_db_deinit().

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker 9522da88d0 core/tags/genre: Move genre_find() out of the tags namespace
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker c611eb306d core/tags/genre: Move genre_get() out of the tags namespace
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker 5e59166dab core/tags/genre: Convert Genre class to a struct
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker 4cba24e72a core/tags/genre: Rewrite unit test
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker fe3d7867d1 core/tags/artist: Directly inherit from DatabaseEntry
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker 405ff0cf88 core/tags/artist: Move artist_db_init() out of the tags namespace
And add the function artist_db_deinit().

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker 52886c926e core/tags/artist: Move artist_find() out of the tags namespace
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker 81518dce47 core/tags/artist: Move artist_get() out of the tags namespace
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker 2c5c0aa7e0 core/tags/artist: Convert Artist class to a struct
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker 5c56d53f9f core/tags/artist: Rewrite unit test
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker 928c215494 core/tags/album: Clean up constructors
Remove an unused constructor and share code between everything left.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker e5b0047812 core/tags/album: Directly inherit from DatabaseEntry
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker a7746cf901 core/tags/album: Remove album::year() function
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker abe12bac64 core/tags/album: Move album_db_init() out of the tags namespace
And add the function album_db_deinit().

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker 0fa2d8acc2 core/tags/album: Move album_find() out of the tags namespace
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker 1f5668bd72 core/tags/album: Move album_get() out of the tags namespace
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker e6bdf65606 core/tags/album: Convert Album class to a struct
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker 75d4bd2af3 core/tags/album: Rewrite unit test
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker 45207ebd2e core/index: Replace index_entry iterators with struct set_iter
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker a8bb7ffccd core/index: Remove index_entry :: size()
It was only used by the testing code, so there is really no reason to
keep it around.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker 58f704cdd2 core/index: Remove Index class
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker 025f13ffeb core/index: Move index_has() out of the index_entry struct
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker 7dcfc2ba78 core/index: Move index_init() out of the Index class
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker a580e5cdb5 core/index: Move index_remove() out of the Index class
And fold IndexEntry :: remove() into index_remove().

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker 46363b1406 core/index: Move index_insert() out of the Index class
And fold IndexEntry :: insert() into index_insert().

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker a91326551f core/index: Convert IndexEntry class to a struct
In addition, I added the prefix "ie_" to all member names.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker 1244531f0d core/index: Rewrite unit test
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker 2c5b14c7f3 core/database: Replace database constructor and destructor
Use db_init() and db_deinit() instead.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker 3ff992cf52 core/database: Replace database iterators with db_for_each()
This function is similar to Linux's list_for_each_safe(), and lets you
iterate over a database even if the current item is removed.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker ffd38bd28b core/database: Move db_find() out of the database struct
I also take the chance to modify this function slightly.  Now, if a
matching item could not be found a new item will be allocated.

I added the new function db_get() if callers just want to get an item
without allocating.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker f2f23cb225 core/database: Move db_at() out of the database struct
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker 929279259d core/database: Move db_remove() out of the database struct
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker 9c358539fe core/database: Move db_insert() out of the database struct
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker 68c953f186 core/database: Move db_{save|autosave}() out of the database struct
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker 8486fc6111 core/database: Move db_load() out of the database struct
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker 3a74cb0aa5 core/database: Move db_actual_size() out of the database struct
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker 1dcbc0c505 core/database: Remove database::size() function
We can just use the db_size variable directly.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker 8a4e9fc2bc core/database: Convert class to a struct
In addition, we lowercase variable names and add a db_ prefix to all
struct members.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker 385515edbc core/database: Rewrite unit test
I want a more thorough set of tests before I begin modifying the
database class.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:41:33 -05:00
Anna Schumaker 0b8dd94213 Ocarina v6.4.1
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-10 16:36:47 -05:00
Anna Schumaker db9be296cb core/file: Add better error reporting
Printing out the filename of the file that broke is generally helpful.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-04 10:11:33 -05:00
Anna Schumaker 5b5b7ebea6 core/playlist: Don't calculate an average if count is zero
This fixes a divide-by-zero segfault.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-12-02 15:25:59 -05:00
Anna Schumaker 1cd22a9454 core/set: Add functions for reading and writing sets
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-11-10 10:55:54 -05:00
Anna Schumaker 82a74dd5ec core/set: Add a function for clearing sets
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-11-10 10:55:54 -05:00
Anna Schumaker 09c87e14aa core/set: Add function for copying values between sets
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-11-10 10:55:54 -05:00
Anna Schumaker 73f61e13d7 core/set: Add function for finding set intersections
Finding an inline intersection is really easy using iterators, so I
wrote this function to modify one of the set rather than returning a new
one.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-11-10 10:55:54 -05:00
Anna Schumaker 4d065508cd core/set: Add new struct to act as a set
The glib library doesn't have a dedicated "set" container, so I need to
create a wrapper around a hash table to accomplish the same results.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-11-10 10:55:54 -05:00
Anna Schumaker 9e0c4404fc core/date: Add date_set() to directly set a date structure
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-11-10 10:55:54 -05:00
Anna Schumaker 422f6a389f core/tags/track: Clean up date handling unit test
Most of this isn't needed anymore now that date handling is being tested
elsewhere.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-11-10 10:55:54 -05:00
Anna Schumaker ea35d81c22 core/date: Add date_string() to convert a date to a string
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-11-10 10:55:54 -05:00
Anna Schumaker 0a2abb2b31 core/string: Add string_tm2str() function to get a date stringg
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-11-10 10:55:54 -05:00
Anna Schumaker f5d744a75c core/date: Add date_{read|write} functions for date IO
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-11-10 10:55:54 -05:00
Anna Schumaker af1939a6e7 core/date: Add date_compare() for comparing two dates
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-11-10 10:55:54 -05:00
Anna Schumaker cef39bc0fc core/date: Add date_today() function for finding today's date
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-11-10 10:55:54 -05:00
Anna Schumaker d230396cb2 core/date: Add new file for date structure code
Moving this out of the track class should help to simplify the code.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-11-10 10:55:54 -05:00
Anna Schumaker 7865557fd5 core/string: Realloc strings before returning
g_strchomp() modifies the string in place, but doesn't free up unused
memory at the end of the original string.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-11-10 10:55:38 -05:00
Anna Schumaker 461cbdb9c3 core/string: Use g_utf8_collate() for string comparisons
This function compares strings using "linguistically correct rules for
the current locale".

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-11-02 14:13:00 -05:00
Anna Schumaker 6b25987785 core/string: Add unicode handling to string_lowercase()
This helps improve filtering, since I drop all modifications to
characters (such as accents over an 'e').

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-11-02 14:13:00 -05:00
Anna Schumaker 91bbad90ff Ocarina 6.4
Rewrote unit testing framework and began conversion to C.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-11-02 13:58:00 -05:00
Anna Schumaker 08bef63918 core/tags/track: Add a space before title
I noticed that tracks beginning with a number were getting combined with
the seconds field, creating an inaccurate seconds count and modifying
the title at the same time.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-14 16:41:01 -04:00
Anna Schumaker b1ef40679b core/string: Add a test for several sec2str_long() fields
I also remove the swap() function I was using to reallocate strings out
of a static buffer.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-14 08:31:35 -04:00
Anna Schumaker 21f13b32c0 GTKMM now requires C++ 2011
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-13 10:04:09 -04:00
Anna Schumaker 08394c3168 core/file: Add a C-style initializer macro
I eventually intend to remove the file_init() function, once everything
has been converted to C.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-12 08:30:01 -04:00
Anna Schumaker cf6364f5d1 core/file.c: Convert file to C
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-12 08:23:06 -04:00
Anna Schumaker 7529ccd4cc core/file: Switch file_readl() to return a gchar *
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-12 08:23:06 -04:00
Anna Schumaker 471c773bd5 core/file: Switch file_path() to return a gchar *
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-12 08:23:06 -04:00
Anna Schumaker d306c809b6 core/file: Switch file_init() to take a gchar *
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-12 08:23:06 -04:00
Anna Schumaker d783c6b479 core/file: Remove NOT_OPEN open mode
I can use the file->f_file pointer for the same thing.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-12 08:23:06 -04:00
Anna Schumaker dbd27d1297 core/file: Use a C-style file stream for reading from files
I also introduced a file_readf() function to make it easier to read a
formatted string from the file.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-12 08:23:05 -04:00
Anna Schumaker f24da08d85 core/file: Use a C-style file stream for writing to files
I also introduced a file_writef() function to make it easier to write a
formatted string to the file.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-12 08:22:36 -04:00
Anna Schumaker 3b220d3f3a core/file: Move file_readl() out of the file struct
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-09 09:14:34 -04:00
Anna Schumaker 074339040b core/file: Remove the file struct constructor
And replace it with the function file_init().  Let's take this chance to
rework parts of the unit test as well.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-09 09:14:34 -04:00
Anna Schumaker 09c7164aee core/file: Move the close() function out of the file struct
This change also lets me remove the destructor, since code is expected
to call file_close() when IO is complete.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-09 09:14:34 -04:00
Anna Schumaker c88b796a7a core/file: Move the open() function out of the file struct
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-09 09:14:08 -04:00
Anna Schumaker a88da1dabf core/file: Refactor file opening code
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-08 15:46:15 -04:00
Anna Schumaker 7e9eb9e7d2 core/file: Move exists() out of the file struct
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-08 15:46:09 -04:00
Anna Schumaker aa21ede894 core/file: Move get_filepath() function out of the file struct
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-08 15:45:57 -04:00
Anna Schumaker ce94680d4d core/file: Move get_version() function out of the file struct
This is now a simple function for accessing the current version of the
file.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-08 15:45:51 -04:00
Anna Schumaker 1dcc56c87e core/file: Convert class to a struct
In addition, we lowercase variable names and add an f_ prefix to all
struct mebers.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-07 10:39:51 -04:00
Anna Schumaker 068afd6276 core/random: Convert to C
And convert the unit test while we're at it.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-07 10:05:58 -04:00
Anna Schumaker cea50ae37f core/random: Rename random() -> random_range()
This prevents a conflict with C's stdlib.h.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-07 10:05:52 -04:00
Anna Schumaker 023bae737c core/string: Add a function for comparing strings
And switch over the GenericTag to using it.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-07 09:59:41 -04:00
Anna Schumaker 60678d1ddb core/string: Convert file to C
And convert the unit test while we're at it.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-07 09:56:19 -04:00
Anna Schumaker 1a3735251d core/string: Move string_lowercase() out of "string" namespace
And refactor to use glib string functions while we're at it.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-07 09:54:16 -04:00
Anna Schumaker 83fe822dc7 core/string: Move sec2str_detailed() out of "string" namespace
I also take the opportunity to rename the function to
string_sec2str_long().

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-07 09:46:30 -04:00
Anna Schumaker 18b83f5c26 core/string: Refactor sec2str_detailed()
I only need one function to perform the entire conversion using
g_strdup_printf().  This helps to simplify the code before switching
over to C.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-07 09:41:17 -04:00
Anna Schumaker a314ee03ca core/string: Move sec2str() out of "string" namespace
And I replace it with a simple call to g_strdup_printf() that does the
exact same thing.  Note that callers are now required to free the
returned string with g_free().

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-07 09:33:50 -04:00
Anna Schumaker 82d1da491b core/string: Remove string :: utos()
I replace it with calls to g_strdup_printf().  This has the additional
benefit that I can do uint conversions at the same time as other
formatting options, so this seems like a win.  The only downside is that
I have to manually free the memory that glib allocates, but that's easy
enough.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-07 09:31:28 -04:00
Anna Schumaker d36457fd61 core/version: Header file comment cleanups
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-07 08:27:15 -04:00
Anna Schumaker 65fb3888b6 tests/core: Update audio test to the new framework
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-07 08:26:29 -04:00
Anna Schumaker 077c6bf0c8 tests/core: Update deck test to new framework
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-07 08:26:29 -04:00
Anna Schumaker 1cb7eff37d tests/core: Update playlist test to the new framework
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-07 08:26:29 -04:00
Anna Schumaker b81b1eeda7 tests/core: Update library test to the new framework
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-07 08:26:29 -04:00
Anna Schumaker ff26171d6f tests/core: Update queue test to the new framework
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-07 08:26:29 -04:00
Anna Schumaker cfca7fccb0 tests/core: Update random test to the new framework
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-07 08:26:29 -04:00
Anna Schumaker 9882727c81 tests/core: Update tags/track test to the new framework 2015-10-07 08:26:29 -04:00
Anna Schumaker cefadba363 tests/core: Update tags/library test to new framework
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-07 08:26:29 -04:00
Anna Schumaker a74c52e5cb tests/core: Update tags/genre test to new framework
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-07 08:26:28 -04:00
Anna Schumaker 0c294d2481 tests/core: Update tags/album unit test to the new framework
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-07 08:26:28 -04:00
Anna Schumaker e6f26d036c tests/core: Update tags/artist test to the new framework
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-07 08:26:28 -04:00
Anna Schumaker a6d206a003 tests/core: Update tags/generic test to the new framework
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-07 08:26:28 -04:00
Anna Schumaker 0dd91e25c7 tests/core: Update idle queue test to the new framework
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-07 08:26:28 -04:00
Anna Schumaker 583bb5d84b tests/core: Update filter test to new framework
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-07 08:26:28 -04:00
Anna Schumaker a9219d4f22 tests/core: Update index unit test to the new framework
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-07 08:26:28 -04:00
Anna Schumaker 7318363287 tests/core: Update database test to the new framework
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-07 08:26:28 -04:00
Anna Schumaker da8131aa6d tests/core: Update file test to new testing framework
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-07 08:26:27 -04:00
Anna Schumaker 2276a44a07 tests/core: Update string test to the new framework
I converted the test to the new framework, and I introduced a new
"test.h" file in the source directory to help with mixing C and C++
code.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-07 08:19:49 -04:00
Anna Schumaker 55a7673983 tests/core: Update version test to the new framework
The version test is fairly simple, since it only tests the values set in
a single header file.  The remaining tests will be more challenging,
since I'll have to modify core code and the test at the same time.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-07 08:19:45 -04:00
Anna Schumaker 63769c9c0b Convert unit test framework to C
I commented out most of the file and directory modification code while I
was at it.  I'll re-add these as I convert more files to C.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-10-07 08:19:37 -04:00
Anna Schumaker 34a15d58c4 Remove test_env
I want to make the scons files simpler, so I have decided to drop down
to only one test environment.  This patch disables
tests/core/Sconscript, but I'll add this back in as I make other changes
throughout the codebase.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-09-11 09:11:38 -04:00
Anna Schumaker 1a02bd5aff Ocarina 6.3.7
Remove doxygen config file and merge various widgets to simplify code.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-09-11 08:52:47 -04:00
Anna Schumaker ead1397b31 Remove Doxygen tags
I wasn't actually using Doxygen for anything, so it's probably best just
to remove it.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-09-02 14:24:42 -04:00
Anna Schumaker 1d0f392835 gui: Give tab labels a set_size() function
This lets them set themselves whenever values change.  Additionally, I
update the Tab class to take a QueueLabel instead of the "size label"

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-09-02 14:24:42 -04:00
Anna Schumaker 2c45cf3972 gui: Remove tab_finish_init()
It is no longer needed.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-09-02 14:24:42 -04:00
Anna Schumaker 9ddae1275f gui: Set up QueueWindow from a single place
I can't pack it directly into the tab_vbox because playlists need a way
to pack in their special window.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-09-02 14:24:42 -04:00
Anna Schumaker d0212d47aa gui: Create QueueToolbar from a single place
Derived classes should already have this available to configure as they
see fit.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-09-02 14:24:42 -04:00
Anna Schumaker 319838138a gui: Set up tab builder from a single place
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-09-02 14:24:42 -04:00
Anna Schumaker 682dca2339 gui: Set up each tab page vbox from a single place
This is better than having the same code in 4 places.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-09-02 14:24:42 -04:00
Anna Schumaker c9ca2604ee gui: Move on_row_activated() into the QueueWindow
And out of the Tab class.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-08-25 10:06:58 -04:00
Anna Schumaker 83414ca3ad gui: Trigger refiltering from the QueueToolbar
I also modify the QueueWindow to do the actual filtering.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-08-25 10:06:58 -04:00
Anna Schumaker 8c3b1489bd gui: Set up queue model and filter inside the QueueWindow
This lets me move functions affecting the treeview into the QueueWindow
class.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-08-25 10:06:58 -04:00
Anna Schumaker 5bf861b9f3 gui: Remove Tab post_init() function
Nothing uses this anymore.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-08-25 10:06:58 -04:00
Anna Schumaker 3d89bf2563 gui: Set up the switch from inside the toolbar
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-08-25 10:06:58 -04:00
Anna Schumaker 343426ddc3 gui: Tab labels should inherit from common type
This allows me to pass a pointer to the generic type to be used by other
classes.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-08-25 10:06:58 -04:00
Anna Schumaker 1423fe2b6e gui: Set up the repeat button from inside the toolbar
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-08-25 10:06:58 -04:00
Anna Schumaker fa2bf4637a gui: Set up the random button from inside the toolbar
This lets me change this variable to be completely internal to the
QueueToolbar.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-08-25 10:06:58 -04:00
Anna Schumaker acbafd2361 gui: Give the QueueToolbar an init() function
GtkBuilder doesn't let me pass additional parameters to classes
constructed with get_widget_derived(), so I have to use an init()
function for flags and other parameters.

This patch adds flags for which buttons to show on the queue toolbar.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-08-25 10:06:58 -04:00
Anna Schumaker 3ed32813da gui: Force playing on GST_MESSAGE_ERROR
I frequently hit a problem where playback stops when a track has an
error.  My gstreamer code was written assuming that the pipeline stayed
in GST_STATE_PLAYING if there was an error, but I think this assumption
is wrong.  For now, let's always restart playing on error.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-08-25 10:06:58 -04:00
Anna Schumaker 8f09daef5b Ocarina 6.3.6
This release features several gui cleanups, mostly related to using GTK+
template widgets.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-08-25 09:38:54 -04:00
Anna Schumaker 8f570f1f24 gui: Convert the playlist tab to use the new template files
I also created a new PlaylistWindow class for displaying the names of
each playlist.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-04-17 08:51:31 -04:00
Anna Schumaker b2b23bec46 gui: Convert the history tab to use the new template files
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-04-17 08:51:31 -04:00
Anna Schumaker 3dd123fbfd gui: History tab cleanups
This is a statically defined class, so we don't need to separate out the
function definitions.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-04-17 08:51:31 -04:00
Anna Schumaker a581b42649 gui: Convert the collection tab use the new template files
I expect most of the new constructor code to disappear once I start
using the .ui files in the parent class.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-04-17 08:51:31 -04:00
Anna Schumaker 2f1d0a3bb8 gui: Collection tab cleanups
This is a statically defined class, so we don't need to separate the
class and function code.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-04-17 08:51:31 -04:00
Anna Schumaker d746db6624 gui: Add a scrolled window around the treeview
I'm going to want this on all tab pages, so let's just add this to the
treeview widget definition.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-04-17 08:51:31 -04:00
Anna Schumaker d9a9b2b9ca gui: Set queue scale factor using GtkBuilder
Now I don't need to keep resetting the label's markup.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-04-17 08:51:31 -04:00
Anna Schumaker 494ef04e67 gui: Build TempLabel from a .ui file
This is better than needing to hard code in all of the widgets.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-04-17 08:51:31 -04:00
Anna Schumaker 5859adc074 TODO: Add a note for QueueModel changes
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-04-17 08:51:31 -04:00
Anna Schumaker da89012c7b gui: Build QueueToolbar from a separate file
This should help clean up the code a bit, especially once I convert all
queues to load with the template files.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-04-17 08:51:31 -04:00
Anna Schumaker 1e29ba8cc6 gui: Create a custom Gtk::TreeView for queues
The QueueView doesn't contain too much in terms of code, but the
corresponding QueueView.ui file lets me remove a lot of unnecessary
stuff from temporary queue creation!

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-04-17 08:51:31 -04:00
Anna Schumaker 6dfb3c31e2 gui: Rename model.cpp -> queue/model.cpp
I'm going to have a lot of queue-related files soon, so let's make
things easier by keeping everything in a new directory.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-04-17 08:51:30 -04:00
Anna Schumaker ec7352ac89 Ocarina 6.3.5
This release focuses on fixing the bugs I found while trying to run
Ocarina on a Raspberry Pi 2.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-04-17 08:46:23 -04:00
Anna Schumaker 91ad055001 gui: Remove stock icon lines from right click menu
This property is deprecated, and we had everything set to "false"
anyway.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-04-16 15:59:36 -04:00
Anna Schumaker 9edce54571 gui: xalign is deprecated
Remove references to it, fixing up the code where necessary.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-04-14 10:24:50 -04:00
Anna Schumaker 4a6c0dbaa5 gui: The treeview rules_hint property is deprecated
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-04-14 10:23:34 -04:00
Anna Schumaker 77d0f0d094 gui: Don't use stock icons
Stock icons have been deprecated, so let's switch over to using named
icons instead.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-04-14 10:23:32 -04:00
Anna Schumaker 66df7ddf4f PKGBUILD: Add armv7 to the list of supported architectures
Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
2015-04-14 09:06:49 -04:00
Anna Schumaker 3375e921c4 gui: Use the search entry's "search_changed" signal
This greatly improves usability while searching, since we no longer have
to refilter the song list for every key press.

Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
2015-04-14 09:06:45 -04:00
Anna Schumaker ec4d3b945e audio: Fix seeking on ARM
The on_seek() function needs to take an int64_t to avoid truncating on
ARM.

Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
2015-04-14 09:05:09 -04:00
Anna Schumaker 657ce8f0f4 audio: Ensure position and duration results are 64 bits
A long int is shorter on ARM than x86, which could cause position and
duration values to get truncated.  Additionally, quering gstreamer with
a long int causes a compile error on ARM.  Let's just do the right thing
and make this value an int64_t.

Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
2015-04-14 09:05:05 -04:00
Anna Schumaker ce4923f8b9 Ocarina 6.3.4
The main focus of this release was removing the clunky callback system
and replacing it with a way to notify queues directly that tracks have
been changed.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-04-10 09:07:13 -04:00
Anna Schumaker 1ec9d830cc gui: Remove references to the on_remove() notification
It no longer exists.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-04-09 09:28:32 -04:00
Anna Schumaker eabb5ef856 queue: Remove Q_NOTIFY_REMOVE flag
It no longer has any meaning.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-04-09 09:27:46 -04:00
Anna Schumaker 9ebb31e09b gui: Remove usage of Q_NOTIFY_REMOVE
The notification no longer exists, and the flag will soon be removed.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-04-09 09:27:32 -04:00
Anna Schumaker 9180545bc2 queue: Remove on_remove() notification
I no longer need it to pass queue-removed messages to the gui.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-04-09 09:26:36 -04:00
Anna Schumaker f15ed8635a gui: Disable Q_NOTIFY_REMOVED for temporary queues
Using this notification was causing segmentation faults when Ocarina was
closed with at least one temporary queue.  I can handle everything I
need directly in the GUI without problems, so this notification really
isn't necessary.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-04-09 09:26:26 -04:00
Anna Schumaker d0d00521db GOALS: Remove file
It was useful for the 6.3 development cycle, but I haven't been keeping
this updated for each micro-release.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-04-04 10:21:32 -04:00
Anna Schumaker c80468a739 callback: Remove all references to callbacks
Callbacks have no remaining users and can safely be removed :)

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-04-04 10:21:31 -04:00
Anna Schumaker e4ea994728 gui: QueueTabs should implement the on_remove() notification
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-04-04 10:21:15 -04:00
Anna Schumaker 116d1cd28f deck: Make sure that Q_NOTIFY_REMOVE is set
TempQueues need this to tell the GUI when they have been removed.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-04-04 10:20:53 -04:00
Anna Schumaker e8b68b84eb queue: Add an on_remove() notification to the QNotifier class
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-04-04 10:20:49 -04:00
Anna Schumaker c068cbb736 callbacks: Remove on_pq_track_changed()
It's been replaced with a function int he QNotifier class.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-04-03 21:03:05 -04:00
Anna Schumaker 44c702a302 gui: Implement on_track_updated() in the Tab class
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-04-03 20:59:01 -04:00
Anna Schumaker b95bbe6ad4 queue: Create an on_track_updated() callback
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-04-03 20:55:07 -04:00
Anna Schumaker 8cc48aa799 callbacks: Remove on_pq_track_deleted()
It's been replaced with a function in the QNotifier class.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-04-03 12:29:41 -04:00
Anna Schumaker 3b206948e1 gui: Implement on_track_removed() in the Tab class
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-04-03 12:27:32 -04:00
Anna Schumaker 9eef2ad35d queue: Create an on_track_removed() notification
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-04-03 12:24:37 -04:00
Anna Schumaker 89a13ff6f7 callback: Remove on_queue_track_add() callback
It no longer has any users.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-04-03 12:20:07 -04:00
Anna Schumaker 67228ef8b1 gui: Turn the Tab class into a QNotifier
Now we can respond to notifications directly.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-04-03 12:19:18 -04:00
Anna Schumaker 91fc9436a5 queue: Give notifiers an "on_track_added()" function
So they can tell GUIs that something has been added.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-04-03 12:19:08 -04:00
Anna Schumaker c5598293d6 queue: Create a notifier class
This class will be used to push queue changes directly to the GUI.
Currently changes get mapped through the old callbacks system, which can
lead to several inefficiencies because the GUI has to look up each queue
structure in a list.

This patch implements a basic QNotifier class and provides a function
for setting a Queue's notifier.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-04-03 12:16:40 -04:00
Anna Schumaker 8453b58ae3 queue: Fix punction on _sort_order documentation comment
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-04-03 10:27:08 -04:00
Anna Schumaker 5ba9a8fa0a Ocarina 6.3.3
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-03-04 10:02:04 -05:00
Anna Schumaker e064a8c934 gui: Remove hscrollbar from playlists treeview
This lets the treeview completely display all the playlists, rather than
cutting off the last few characters.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-03-04 10:00:56 -05:00
Anna Schumaker 119ea86401 gui: Add new playlists to the gui
Add gui controls for our new dynamic playlists:
- Unplayed Tracks,
- Most Played Tracks, and
- Least Played Tracks

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-02-06 15:33:42 -05:00
Anna Schumaker 75d39cbd85 playlist: Add a "least played tracks" playlist
This playlist will look for any track with a below average playcount.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-02-06 15:33:42 -05:00
Anna Schumaker 0997ffff99 playlist: Add a "most played tracks" playlist
This playlist will look for any track with an above average play count.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-02-06 15:10:38 -05:00
Anna Schumaker addc28491c Remove Unplayed Tracks from the TODO list
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-02-06 15:10:38 -05:00
Anna Schumaker 64291ff02c playlist: Add an "unplayed tracks" dynamic playlist
Unplayed tracks is a dynamic playlist generated whenever we are asked to
select the "Unplayed" playlist.  Note that dynamic playlists aren't
hooked up to the other playlist functions (has, add, del, or
get_tracks).  This is to avoid adding them to the index and potentially
writing out to disk.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-02-06 14:33:57 -05:00
Anna Schumaker 93c9877d57 playlist: Allow selecting same playlist again
This will go unnoticed for Favorites and Banned playlists, but will
allow dynamic playlists to be refreshed without switching to a different
playlist first.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-02-06 14:15:06 -05:00
Anna Schumaker d0fb9b2155 playlist: Give PlaylistQueues a clear() function
This is used to clear the queue before populating it with a different
playlist.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-02-06 14:12:28 -05:00
Anna Schumaker 5026e80eab gui: Fix setting autopause count
Once the check box was enabled, we were never setting the count again.
This means that changing pause count from 1 to 2 did not change the
count in the backend.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-02-04 08:39:40 -05:00
Anna Schumaker 99a1349336 Ocarina 6.3.2
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-02-03 08:21:28 -05:00
Anna Schumaker 5067782633 Scratch items off of the TODO list
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-30 11:15:30 -05:00
Anna Schumaker f7eb34c2af string: Make _time_detail() static
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-30 10:54:40 -05:00
Anna Schumaker 3f423fb3ae filter: Use string :: lowercase() for searching
This is a much simpler way of doing things.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-30 10:54:39 -05:00
Anna Schumaker 7e58a4fef8 filter: Simplify adding words to the filter
I can use the lowercase text from string :: lowercase() and take a
single pass over a single string (rather than iterating through a list
of strings).

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-30 10:54:38 -05:00
Anna Schumaker 6c4dc5b1db filter: Remove lowercase() function
And switch everything over to using the new implementation.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-30 09:35:55 -05:00
Anna Schumaker 7733e24c07 string: Add a lowercase() function
This function strips out special characters and returns the lowercase
version of the string.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-30 09:32:50 -05:00
Anna Schumaker cc6f4c9293 string: Add a function for creating a detailed time string
I use this to display the total running time of queues in the gui.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-29 08:27:25 -05:00
Anna Schumaker ed43fd3689 More utos() cleanups
I found a few other places where I can use utos() instead of
stringstreams.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-27 14:03:12 -05:00
Anna Schumaker 12260a3de9 string: Add a function for converting seconds to string
This is used to get a string representation of the number of seconds
passed in.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-27 09:23:14 -05:00
Anna Schumaker 6c6437c2bd string: Create a utos() function
This function converts unsigned ints into strings.  This allows me to
replace several almost identical functions with one function call.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-27 08:37:27 -05:00
Anna Schumaker e47eb69859 gui: Set a proper application_id
This silences a warning from gtk.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-26 17:13:09 -05:00
Anna Schumaker 77fc2fff5c version: Add a "+" to version string
I use this to show that there have been any changes since the last
release.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-26 08:43:14 -05:00
Anna Schumaker 93bac41ba6 Update PKGBUILD for 6.3.1
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-25 09:37:32 -05:00
Anna Schumaker a283ab7178 Ocarina 6.3.1
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-24 10:17:30 -05:00
Anna Schumaker 5045e3a8c8 gui: Remove unnecessary #includes
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-22 08:19:45 -05:00
Anna Schumaker ec83acbdfe gui: Initialization cleanups
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-21 09:08:45 -05:00
Anna Schumaker 8b4d99c50c gui: Rename main.cpp to ocarina.cpp
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-21 08:44:38 -05:00
Anna Schumaker e6d9a58be2 gui: Remove CONFIG_TEST macros
I haven't had gui unit tests in months, so these can be removed for now.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-21 08:43:55 -05:00
Anna Schumaker 74a557739d lib: Remove rest of lib/
This is all contained in the gui code now.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-21 08:39:02 -05:00
Anna Schumaker dc3e770c28 gui: Move GtkBuilder object into the gui
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-21 08:29:59 -05:00
Anna Schumaker 7f6f6395d7 gui: Schedule timeout function from gstreamer code directly
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-21 08:10:59 -05:00
Anna Schumaker 4cae9aaf2b gui: Have collection manager handle keypresses directly
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-21 08:06:10 -05:00
Anna Schumaker 2824ac33eb gui: Start idle callbacks directly from the collection manager
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-21 08:03:48 -05:00
Anna Schumaker 0f61114e15 gui: Remove unused connect_button() function
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-20 08:48:32 -05:00
Anna Schumaker f5ed438735 gui: Move the queue TreeModel class into the gui code
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-20 08:46:45 -05:00
Anna Schumaker c61dca7504 gui: Various collection manager cleanups
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-19 11:43:27 -05:00
Anna Schumaker 98ff0b79cd colmgr: Merge lib/ and gui/ code back together
The code is still messy now, but I'll be cleaning it up soon!

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-17 13:19:41 -05:00
Anna Schumaker 1935cf9c5e gui: Various playlist cleanups
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-17 11:27:32 -05:00
Anna Schumaker 4bfdb2d0d4 gui: Merge lib/plist.cpp back into gui/plist.cpp
The lib/ experiment made the gui code a little more complicated than I
was expecting, so I'm going to begin merging everything back into gui/

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-17 10:41:04 -05:00
Anna Schumaker b4db3ba98f gui: Put exported gst functions in a new namespace
I intend to put most gui functions in their own namespaces eventually.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-17 10:19:31 -05:00
Anna Schumaker 452e5228af build: Check for tests/ directory
I don't include unit tests in the tarball for releases, so I need to
check for this directory when telling Scons what to build.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-17 09:27:29 -05:00
Anna Schumaker cb6d8b3e29 Ocarina 6.3 2015-01-16 13:05:43 -05:00
Anna Schumaker 6a5eaa32f8 gui: Preserve "is playing" status when banning tracks
Just calling audio :: next() will advance to the next song, but won't
change if we're playing music or not.  I think this is what we want to
do when banning tracks.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-16 08:22:01 -05:00
Anna Schumaker ea49b374ee gui: Remove gui.cpp
This file doesn't do anything anymore, so move the init functions into
main.cpp and remove the file.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-15 09:40:17 -05:00
Anna Schumaker 4643a5ff22 gui: Move pause count widgets into gst.cpp
These values affect audio playback, so they should go with the other
audio widgets.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-15 09:35:33 -05:00
Anna Schumaker 88136c0c95 Determine debug builds by looking for a magic file
If .debug exists, then we'll compile as a debug build.  This will let me
toggle debug status during development without needing to worry about
committing the change.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-15 09:16:00 -05:00
Anna Schumaker d299bc464c gui: Move ban and favorite buttons into playlist code
These buttons directly change the playlists, so let's handle them there.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-15 09:08:02 -05:00
Anna Schumaker b940fe710c gui: Rearrange playlist tab
Other files in the gui implement their classes directly, rather than
making extra functions.  Let's do that here, too.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-15 08:33:20 -05:00
Anna Schumaker 300acde068 gui: Set artist, album, title, and duration from gst code
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-14 20:16:28 -05:00
Anna Schumaker 6fec8876a9 gui: Rename position and duration widgets
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-14 19:57:15 -05:00
Anna Schumaker ed88bb08bd gui: Move toggle function to gst code
This lets me remove the controls.cpp and controls.h files.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-14 19:50:26 -05:00
Anna Schumaker 434b278b61 gui: Move position tracking into gst code
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-14 19:50:25 -05:00
Anna Schumaker e539a2d208 gui: Move remaining buttons into gstreamer code
These buttons directly affect audio playback, so let's move them with
the rest of the audio buttons.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-14 19:19:50 -05:00
Anna Schumaker 9d84fdb8b7 lib: Make QueueModel variables private
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-13 20:34:33 -05:00
Anna Schumaker 4078f9a893 lib: QueueModel stamp cleanups
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-13 20:34:33 -05:00
Anna Schumaker e9e1e4fad8 lib: Clean up QueueModel on_row_*() functions 2015-01-13 20:34:33 -05:00
Anna Schumaker cba07b5957 lib: TreeIter cleanups
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-13 20:34:33 -05:00
Anna Schumaker ad584900fa lib: Clean up QueueModel switch statements
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-13 20:34:33 -05:00
Anna Schumaker 315a169136 lib: Model should use iter_to_id()
This is cleaner than doing the calculation in several places.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-13 20:34:33 -05:00
Anna Schumaker 06853b4f31 lib: Remove unused QueueModel functions
These are only needed if implementing a tree, and not a list.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-13 20:34:33 -05:00
Anna Schumaker 6564860d27 Add more ideas to the TODO list
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-13 20:34:33 -05:00
Anna Schumaker 27c7dc91d8 queue: Fix up sorting
If years are equal then sort by album name.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-13 10:08:53 -05:00
Anna Schumaker 6cfd0d5c51 tests: Rework much of the testing library
I move the code into a new cpp file, so it is no longer a header-only
library.  I also take the chance to add a for-each function for testing
iterators.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-13 09:35:26 -05:00
Anna Schumaker 8d3010a31e queue: minor cleanup
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-13 09:35:26 -05:00
Anna Schumaker 1dfe475ade idle: Clean up unit test
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-13 09:35:26 -05:00
Anna Schumaker afd47ce667 index: Clean up unit test
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-13 09:35:26 -05:00
Anna Schumaker 4b0c6121c3 database: Clean up the unit test
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-13 09:35:26 -05:00
Anna Schumaker ae1f0300f7 TODO: Add several new ideas
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-02 11:01:26 -05:00
Anna Schumaker 4e5566627c callbacks: Remove info from DESIGN file
The description is way out of date, so let's just remove it now.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-02 10:58:10 -05:00
Anna Schumaker 0abc562033 build: Remove unused global environment variables
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-02 10:43:44 -05:00
Anna Schumaker a371e832dd build: Remove valgrind support
I never actually used this.  Testing with valgrind should happen
manually if needed.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-02 10:32:16 -05:00
Anna Schumaker 694d3f0316 build: Add gstreamer package from gui/Sconscript
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-02 10:31:14 -05:00
Anna Schumaker 3750293ca0 tags: Fix expected years
Year is no longer 2014.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2015-01-02 10:26:52 -05:00
Anna Schumaker f84a1dd891 audio: Shuffle around the code a bit
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-20 16:05:01 -05:00
Anna Schumaker 21f3f7c828 Audio: Remove the _load_track_default() function
There are only two callers, and removing it makes the code more
obvious.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-20 15:58:29 -05:00
Anna Schumaker 92d264d4ac audio: Move Driver into audio.h
I also rename from Driver -> AudioDriver.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-20 15:48:07 -05:00
Anna Schumaker acac350879 audio: Remove on_pause_count_changed callback
The UI should handle this directly on end-of-stream messages.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-20 15:44:40 -05:00
Anna Schumaker 50147ef070 gui: Handle pause counts from the GSTDriver
I think it makes sense to handle this directly from the driver, rather
than going through a callback.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-20 15:27:18 -05:00
Anna Schumaker cd8c76e1b2 gst: Move play and pause button handling into gst code
I can handle these widgets directly from within the gst driver.  I think
this is easier (and more straightforward) than handling this in a
separate file.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-20 15:02:17 -05:00
Anna Schumaker 6a117c762e driver: play() and pause() shouldn't return a boolean
This value is never used in the audio layer so let's stop returning it
from the driver.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-20 14:32:31 -05:00
Anna Schumaker b633f3fa0c gst: Update the "now playing" fields through the GST driver
This lets me remove the on_track_loaded() callback function by handling
this event directly.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-20 12:05:22 -05:00
Anna Schumaker d7113cb124 driver: Pass Tracks to the load() function
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-20 12:01:38 -05:00
Anna Schumaker 9aaa8649ce gst: More driver cleanups
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-20 11:49:22 -05:00
Anna Schumaker 3da3c8aeea gst: Move the on_message() function out of the driver
This function doesn't use anything in the driver class anymore, so it
can be removed.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-20 11:34:29 -05:00
Anna Schumaker 955129edce gst: Various driver cleanups
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-20 11:16:19 -05:00
Anna Schumaker a4ad0aa79b driver: Fold eos() into the driver
With this patch I no longer need a Driver :: init() function to handle
picking the next track.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-20 11:04:14 -05:00
Anna Schumaker 882da67480 gst: Begin reworking gst driver
I removed the need for an overridden constructor and destructor.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-20 10:47:17 -05:00
Anna Schumaker e866ea2574 audio: Make audio functions more consistent
Sometimes I would check for cur_track, other times !cur_track.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-20 10:30:22 -05:00
Anna Schumaker fd2a251c14 audio: Initialize GST from the gui layer
This means I no longer need to pass argc and argv parameters to core/,
so I can eventually work towards removing the Driver :: init() function.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-20 10:16:44 -05:00
Anna Schumaker e7a8ad54bd Audio: Remove the driver on_error() callback function
This was used to get around layering issues with the gstreamer driver.
Now that the gstreamer implementation is in the gui code we can have it
call audio::next() directly.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-19 17:26:39 -05:00
Anna Schumaker 5b32bb16b4 Audio: Make the TestDriver class completely internal to the audio test
It's not used anywhere else except during this one test, so move it out
of the global include files.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-19 17:21:32 -05:00
Anna Schumaker b9d4c6749d audio: Move the get_driver() function into the audio namespace
It's already in the audio.cpp file, so just reshuffle things a little
bit.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-19 14:54:12 -05:00
Anna Schumaker f20898b79c driver: Merge code with audio.cpp
The driver is intended to be a small class, so put it in the audio code
now and we'll clean it up in future patches.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-19 14:37:56 -05:00
Anna Schumaker 1d2b52cc98 driver: Move the GST driver into the gui
This is a straight copy-and-paste of the header file and the code
implementing it.  I intent to clean this up with future patches.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-19 14:25:59 -05:00
Anna Schumaker c12dbae73a driver: Track current driver with a pointer
This will let me implement drivers outside of this file allowing for
easier customization.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-19 14:20:30 -05:00
Anna Schumaker c103f27381 DESIGN: Remove GUI section
I never really used this for anything, so it can be removed.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-19 13:46:53 -05:00
Anna Schumaker 4a57b170cd audio: Update doxygen documentation
And remove the Audio section of the DESIGN file.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-19 13:45:55 -05:00
Anna Schumaker 326865f6be driver: Update doxygen documentation
This lets me remove the Audio Driver section of the DESIGN document.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-19 13:37:44 -05:00
Anna Schumaker 31a405d3c6 deck: Update doxygen documentation
Also remove the deck section of the DESIGN document.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-12 08:25:53 -05:00
Anna Schumaker 9cbff6e9a1 Playlist: Update doxygen documentation
I also remove the playlist section of the DESIGN document.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-11 08:23:08 -05:00
Anna Schumaker 7ec7026863 Library: Update doxygen documentation
Also, remove the library section from the DESIGN document.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-10 08:23:53 -05:00
Anna Schumaker 0758f08642 Queue: Remove _del_at
I merged it with _del(index) since they are for exactly the same thing.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-09 08:50:03 -05:00
Anna Schumaker 39eb22f05c Queue: Update doxygen documentation
I also remove the related section of the DESIGN document.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-09 08:40:14 -05:00
Anna Schumaker 6f58813b3c Queue: Clean up doxygen comments for sorting flags
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-07 10:08:21 -05:00
Anna Schumaker a1b6955a1d Queue: Clean up queue flags
Reformat the doxygen comments and remove the unused Q_FLAG_MASK
constant.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-07 09:58:47 -05:00
Anna Schumaker 5a31963e30 tests: Tell doxygen to avoid looking at tag tests
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:37:07 -05:00
Anna Schumaker 30b2ba0fff Track: Doxygen documentation updates
This patch fixes up formatting a little bit and removes the Track
section of the DESIGN document.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:52 -05:00
Anna Schumaker e7e36caa3a tagdb: Remove tagdb
This shifts the taglib code into library.cpp.  I also remove the tagdb
section of the DESIGN document.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:52 -05:00
Anna Schumaker c7fe5b18d5 tagdb: Rip out most tagdb functions
Most of this are a straight replacement with the new versions in
tags/track.cpp.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:52 -05:00
Anna Schumaker 2394e46fb7 Track: Re-enable filtering
This has been disabled for some time.  I added a test for adding track
indexes to the filter upon creation, but it doesn't properly test adding
to the filter when reading from disk.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:52 -05:00
Anna Schumaker 09bf458d7a Track: Rename functional test to locale test
This code is really testing date and locale handling, so this patch
renames the function to match what it actually does.  While I'm at it, I
also introduce some cleanups.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:52 -05:00
Anna Schumaker 4224d89813 Track: Add a function for finding track_db size
This returns the actual size of the database, so be careful when using
it!  The intent of this function is to allow some kind of iteration when
loading databases.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:52 -05:00
Anna Schumaker 45c83ed2fd Track: Add a function for removing all tracks from a given library
This function will be called when doing library removals.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:52 -05:00
Anna Schumaker 9dfec9934c Track: Add a function for removing specific tracks from the track_db
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:52 -05:00
Anna Schumaker d5fc2a4de0 Track: Add a function for saving the track_db
The track_db doesn't have autosaving enabled for performance reasons.
This lets us add several tracks to the database between saves, but it
also means we need to provide a commit() function.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:52 -05:00
Anna Schumaker 83cc81c934 Track: Add a function to look up Track tags by index
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:52 -05:00
Anna Schumaker a30f5ef794 Track: Create an add_track() function
We return a new Track tag or NULL if we have already tagged this track.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:52 -05:00
Anna Schumaker d7ceadafb3 Track: Implement a copy constructor
This keeps library size accurate when adding new tracks to the track_db.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:52 -05:00
Anna Schumaker 44aac0dcec Generic: Create a copy constructor
Track tags need a copy constructor to keep library size accurate, so
create one here.
2014-12-04 08:31:52 -05:00
Anna Schumaker 4edbd69fa7 Track: Change constructor to take relative paths
I'm going to need to split this value earlier to do a unique lookup when
inserting, so the constructor can take the relative path to make things
easier.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:52 -05:00
Anna Schumaker cfef5c07a0 Track: Clean up test for reads and writes
I want to test basic reading and writing before running the functional
test, since the functional test will eventually trigger database
commits.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:52 -05:00
Anna Schumaker 2578cdadfe Track: Move read and write code into tags/track.cpp
Sadly, this patch disables filtering for tracks.  This will be reenabled
sometime soon!

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:52 -05:00
Anna Schumaker 39cc10bb3e Track: Prefetch artist, album, genre and library tags
This makes the code a little bit cleaner, since we don't need to keep
doing lookups for each test run.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:52 -05:00
Anna Schumaker 50a627412f Track: Move less_than() function into the queue code
The track provides ways of accessing these fields, but I want the queue
to decide how to sort.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:52 -05:00
Anna Schumaker b5a529795d Track: Add a function for comparing two dates
I don't want to expose the date structure outside of the track class, so
I'll provide a comparison function instead.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:51 -05:00
Anna Schumaker de1b5fcef3 Track: Remove old constructor and tag() function
The new constructor covers these cases without needing to do taglib
stuff inside the Track class.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:51 -05:00
Anna Schumaker a2b3ca1292 Track: Make last played date private
This patch creates a new structure to track the last played date, which
can be expanded into a class at some future point.  Additionally, I use
strftime() to calculate the current date based on the user's current
locale settings.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:51 -05:00
Anna Schumaker 6daa26f0d6 Track: Make filepath private
I don't want anybody outside of this class changing the value, so it
shouldn't be public.  I also change the primary key to use library index
instead of the full filepath while I'm at it.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:51 -05:00
Anna Schumaker cdd20da5c0 Track: Convert length_str into a function
I don't think this value needs to be stored anywhere in the Track class
since it's fairly easy to calculate.  Let's convert it into a function
for now and reevaluate later!

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:51 -05:00
Anna Schumaker 2540a6aa7a Track: Use GenericTag's _name and _lowercase fields
This lets me remove the duplicate title and title_lowercase fields from
the Track tag.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:51 -05:00
Anna Schumaker 1fdee864a2 Track: Hide length from the public
I provide an accessor function to keep this value from ever getting
changed outside of the Track class.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:51 -05:00
Anna Schumaker eb23127f6d Track: Hide the play count from the public
I provide an accessor function to keep this value from getting changed
outside of this class.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:51 -05:00
Anna Schumaker 468a4e79d5 Track: Hide the track number from the public
I provide an accessor function to keep this value from ever getting
changed.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:51 -05:00
Anna Schumaker 91f6f54b4e Track: Add a test for the Track destructor
We want to make sure that the _library size is decremented whenever a
track is removed or destroyed.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:51 -05:00
Anna Schumaker 2dfa9bf168 Track: Hide the genre tag from the public
And set it using the new constructor.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:51 -05:00
Anna Schumaker c6029f13f2 Track: Hide the album tag from the public
And set it using the new constructor.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:51 -05:00
Anna Schumaker 0a6ace3c14 Track: Hide the artist tag from the public
Also set it using our new constructor.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:51 -05:00
Anna Schumaker 6149c928d2 Track: Begin a new Track constructor
I want to provide the Library, Artist, Album, and Genre tags to the
Track on construction to (hopefully) eliminate the Track::tag()
function.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:51 -05:00
Anna Schumaker 37613573e4 Track: Hide the library field from the public
And provide an accessor function.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:51 -05:00
Anna Schumaker 7e52c9b364 Track: Move the default constructor to a new cpp file
I also use this opportunity to create a new default constructor test for
the Track tag.  This patch also disables the tags test since the tagdb
will be going away soon.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:51 -05:00
Anna Schumaker 3e0fb88b1d Track: Move the track tag into a new header file
This is the first step in converting it to use the GenericTag class.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:51 -05:00
Anna Schumaker cbcd9c594d GenericTag: Add a function for comparing tag names
I was only ever comparing the lowercase version of the name, so this
should be done in a single place (the GenericTag) to make maintenance
easier.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:51 -05:00
Anna Schumaker f433ced9cb Library: Add functions for looking up or creating Library tags
This patch moves the library_db into tags/library.cpp, where it can be
effectively managed by the Library tag.  For this to work, I need to add
some extra functions to the tags namespace to:

	- Create new Library tags,
	- Find tags by index,
	- Remove the Library at a specific index, and
	- Find the actual size of the library_db.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:51 -05:00
Anna Schumaker 8545837672 Genre: Add functions for looking up or creating Genre tags
The genre_db should really be controlled from within the Genre tag,
so this patch adds functions to find or create Genre tags to the tags
namespace.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:51 -05:00
Anna Schumaker 7d3e9a3d28 Album: Add functions for looking up or creating Album tags
The album_db should really be controlled from within the Album tag, so
this patch adds functions to find or create Album tags to the tags
namespace.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:51 -05:00
Anna Schumaker bac54857fd Artist: Add functions for looking up or creating Artist tags
The artist_db should really be controlled from within the Artist tag, so
this patch creates a new tags namespace containing functions that will
find or create tags as they are requested.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:51 -05:00
Anna Schumaker d88f008728 Library: Update documentation for the Library tag
I also take the chance to remove the corresponding section of the DESIGN
file.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:51 -05:00
Anna Schumaker ce8b3ada03 Library: Rename count -> _size
Also make it private and provide accessor functions.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:51 -05:00
Anna Schumaker 754d45efd0 Library: Make _enabled private
I added in accessor functions to get and set this value.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:51 -05:00
Anna Schumaker 01e514736e Library Tag: Make root_path private
And just change the name of the variable to "_path".

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:51 -05:00
Anna Schumaker f83765d11e Library: Add a unit test for the Library tag
This tests all the basic things that the tag does:  storing values and
reading / writing from file.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:51 -05:00
Anna Schumaker 4d6cb81f77 Library: Move the Library tag into a new file
No code or documentation changes yet, just split things out for now.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:51 -05:00
Anna Schumaker 1e6bcf7451 Genre: Move Genre tag into a new file
- This tag now inherits from GenericTag.
- Add a Genre-specific unit test.
- Remove the genre tag section of the DESIGN file.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:51 -05:00
Anna Schumaker 2d9d87afc9 Album: Move Album tag into a new file
Also make it inherit from the GenericTag base class.  Also also, add a
unit test specific to Album tags.  Finally, I remove the corresponding
section of the DESIGN file since it is no longer needed.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-04 08:31:49 -05:00
Anna Schumaker a9fc53964c Artist: The ArtistTag should inherit from GenericTag
The GenericTag class provides most of the implementation, so use it!

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-03 13:03:11 -05:00
Anna Schumaker fb4f523206 GenericTag: Create a generic tag that other tag classes can use
This implements the basics so I don't need to keep reimplementing
everything.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-03 13:03:10 -05:00
Anna Schumaker a1432a66e1 Artist: Update documentation
I add more details and remove this section of the DESIGN file.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-03 13:03:06 -05:00
Anna Schumaker b3d904c128 Artist: Move artist tag code into a new directory
core/tags.cpp was WAY too big, so I moved this code into a new file in
its own directory.  I also created a new unit test just for testing the
Artist tag.

This patch disables the "tags" test since it conflicts with the
tests/core/tags/ directory.  This is okay because the tagdb is gradually
being phased out!

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-03 13:02:49 -05:00
Anna Schumaker aa758481eb tags: Move artist tag to a new header file
I created a new directory for tag related code.  This keeps the core/
directory cleaner and prevents file name collisions between the library
layer and the library tag.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-03 13:02:47 -05:00
Anna Schumaker a34151365f Audio: Add version number to cur_track file
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-12-03 13:02:44 -05:00
Anna Schumaker 55c45e6004 Gitignore and TODO updates
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-11-24 16:30:22 -05:00
Anna Schumaker 38d2b6e57d goals: Updates
- Fix a typo in where the gstreamer code is going to end up
- Change testing goal to reflect that I rewrote the sconscript instead
  of creating a new bash script.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-11-08 12:05:35 -05:00
Anna Schumaker 09a8e26a6c random: Remove section from DESIGN
The documentation in the code looks fine, so it doesn't need to be
changed.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-11-08 11:59:58 -05:00
Anna Schumaker 72e55e8917 idle: Add more detailed documentation
Also remove the idle queue section from the DESIGN file.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-11-08 11:55:50 -05:00
Anna Schumaker 2a65fe8db0 Filter: Add more detailed documentation
Also remove the corresponding section of the DESIGN file.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-11-08 11:26:04 -05:00
Anna Schumaker e81f17360e Update TODO file
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-11-07 08:17:00 -05:00
Anna Schumaker 158c0acf60 Index: Add more detailed documentation
This lets me remove this section of the DESIGN file.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-11-07 08:14:27 -05:00
Anna Schumaker 2b71ecbeca IndexEntry: Make _values private
I don't want anybody outside of the IndexEntry class to modify the
values in this container.  This patch makes it private and provides
iterator access instead.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-11-06 09:03:51 -05:00
Anna Schumaker dcb79dceed IndexEntry: _key should be private
It doesn't have any users outside of the IndexEntry class.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-11-04 08:30:55 -05:00
Anna Schumaker e89941af31 IndexEntry: Write more detailed documentation
In addition to documentation updates, I also solve a few warnings that
Doxygen gives me.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-11-04 08:30:54 -05:00
Anna Schumaker e281286291 Database: Write more detailed documentation
I transferred information from my DESIGN file and worked it into Doxygen
comments.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-11-04 08:13:29 -05:00
Anna Schumaker 48b25945cc DatabaseEntry: Rename id to _index (and make it private)
This variable should only be set by the Database when a DatabaseItem is
first created.  This means I should hide _index from the rest of the
world to prevent accidental modifications.  I also add an accessor
function for other code that needs to read _index.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-11-02 10:25:41 -05:00
Anna Schumaker c3dc601f72 DatabaseEntry: Write more detailed documentation
I transfer everything from my DESIGN file into doxygen, and then remove
the section from DESIGN.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-11-02 10:21:11 -05:00
Anna Schumaker f25fa7bebc DESIGN: Add info about layers
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-11-01 21:57:00 -04:00
Anna Schumaker 47f6684923 file: Update documentation and various cleanups
I add more detailed documentation matching what was in my DESIGN file.
In addition, I also prefix private File members with an underscore like
I do in other Ocarina classes.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-11-01 21:56:59 -04:00
Anna Schumaker 23cc27c3ef print: Remove dprint()
dprint() has no users, so it can be removed.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-11-01 20:25:56 -04:00
Anna Schumaker 8128e5b5e1 tests: Remove unused testing options
I never really did anything with cppcheck or gcov, so I'm removing these
options.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-11-01 20:25:56 -04:00
Anna Schumaker 159f6098f3 tests: Reenable valgrind support
This lets me remove the unused OTest class which I was keeping around
for reference.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-11-01 20:25:56 -04:00
Anna Schumaker 97733aa40a tests: Create common functions for building tests
This continues to simplify my Sconscript files.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-11-01 20:25:56 -04:00
Anna Schumaker 89498ccc9e tests: Rewrite how lib tests are run
Similar to how core tests were just rewritten, only applied to lib.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-11-01 20:25:56 -04:00
Anna Schumaker 7faa895b22 tests: Rewrite how core tests are run
My old testing system was rather convoluted.  This patch makes the
Sconscript file easier to follow.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-11-01 20:25:56 -04:00
Anna Schumaker d944ed4e95 version: Update documentation
I added a little more detail about how this function works.  This lets
me remove this section from the DESIGN file.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-11-01 20:25:56 -04:00
Anna Schumaker 79e2153994 Define my goals for Ocarina 6.3
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-11-01 20:25:56 -04:00
Anna Schumaker e6e9fb08d0 Time to begin work on Ocarina 6.3!
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-11-01 20:25:55 -04:00
Anna Schumaker 3715e79401 Update PKGBUILD for 6.2.1
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-10-30 08:19:13 -04:00
Anna Schumaker e09b6f3b37 Ocarina v6.2.1
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-10-30 08:15:54 -04:00
Anna Schumaker 1be4c57244 gui: Use Gtk::Application() instead of Gtk::Main()
Gtk::Main() is deprecated, and causes several warnings to show up when
closing Ocarina.  I guess it's time to switch to Gtk::Application()!

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-10-29 18:08:28 -04:00
Anna Schumaker 979de94712 lib: Fix setting share dir
Setting from argv[0] seemed like a good idea at the time, but argv[0]
can change based on how the user calls Ocarina (ocarina, ./ocarina,
/usr/bin/ocarina, ...).  This patch changes back to using the reliable
/proc/self/exe method.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-10-29 18:07:10 -04:00
Anna Schumaker 9297f612de PKGBUILD: Update after the release!
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-10-27 08:16:36 -04:00
Anna Schumaker 9e4d408828 Ocarina 6.2
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-10-23 08:21:06 -04:00
Anna Schumaker cf940ed792 Create `scons docs`
This will build the documentation for the current release of Ocarina.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-10-23 08:16:37 -04:00
Anna Schumaker c19985fc7e tags: Add doxygen documentation
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-10-20 21:38:16 -04:00
Anna Schumaker 3d00a83b6a driver: Add doxygen documentation
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-10-20 21:38:09 -04:00
Anna Schumaker 9a5549a264 database: Add doxygen documentation
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-10-17 17:17:12 -04:00
Anna Schumaker 03e190149e index: Add doxygen documentation
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-10-17 16:49:17 -04:00
Anna Schumaker 59ffd5cbdf idle: Add doxygen documentation.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-10-17 09:56:54 -04:00
Anna Schumaker 5f56118c04 queue: Add doxygen documentation
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-10-17 09:42:45 -04:00
Anna Schumaker 7bde6d98aa file: Add doxygen documentation
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-09-16 08:22:44 -04:00
Anna Schumaker 0626141f7f filter: Add doxygen comments
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-09-16 08:09:40 -04:00
Anna Schumaker 73264e04ce playlist: Add doxygen comments.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-09-15 08:27:03 -04:00
Anna Schumaker d0fd103504 library: Add doxygen comments.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-09-13 10:39:30 -04:00
Anna Schumaker b68198028e deck: Add doxygen comments to deck.h
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-09-13 10:26:28 -04:00
Anna Schumaker 6adbf2d5fc Add doxygen comments to print.h
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-09-13 10:07:33 -04:00
Anna Schumaker ad48ac7d16 random: Add doxygen information
I updated the Doxyfile to extract static inline functions.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-09-13 10:00:03 -04:00
Anna Schumaker 86b15743a1 random: Rearrange random.h
I think ifdef is easier to read than ifndef.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-09-13 09:49:25 -04:00
Anna Schumaker 97c6c836d3 Add doxygen documentation for callbacks.
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-09-12 16:37:28 -04:00
Anna Schumaker 0a9c6d296b Add doxygen documentation for audio.h, core.h, and version.h
I want to have all of Ocarina documented in the code, rather than in a
difficult-to-maintain DESIGN file.  Let's get going on that!

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-09-12 16:36:46 -04:00
Anna Schumaker 5eeebe7854 gui: Move idle function into the collection manager
The collection manager is the only thing that uses the idle queue, so
let's keep all this code together.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-09-12 08:16:26 -04:00
Anna Schumaker 0b5478c591 lib: Move idle function setup into lib/
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-09-12 08:07:12 -04:00
Anna Schumaker bc5e53a423 gui: Store pointers to play and pause buttons
We use these every half-second, so let's not waste time looking them up
every call.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-09-11 08:28:23 -04:00
Anna Schumaker a2987c2952 gui: Call on_track_loaded() during startup
Also move the controls_init() function to be with other init()
functions.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-09-11 08:23:23 -04:00
Anna Schumaker 8152327f65 gui: Move o_seek() into controls.cpp
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-09-11 08:16:36 -04:00
Anna Schumaker 5e7a25e007 gui: Store position and progress widgets
Now we don't need to keep looking them up, and the code looks a little
bit cleaner =)

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-09-11 08:09:57 -04:00
Anna Schumaker 62cdc4c909 gui: Move remaning window setup into window.cpp
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-09-11 08:03:57 -04:00
Anna Schumaker acdeb785f5 gui: Move window keypress handling to window.cpp
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-09-11 08:01:08 -04:00
Anna Schumaker 253898e9b5 gui: Set tab size and runtime on startup
This used to happen by itself, but changing the order of how tabs are
initialized broke this.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-09-11 08:01:08 -04:00
Anna Schumaker 9b98788106 gui: Begin breaking out window code
I think this will help with maintainability.  We'll see ...

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-09-11 08:01:08 -04:00
Anna Schumaker 5c2bd9231d core: Remove on_play() callback
It has no users anymore.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-09-11 08:01:08 -04:00
Anna Schumaker df0d1496de lib: Create a schedule() function
This lets me clean up some of the code in controls.cpp

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-09-11 08:01:07 -04:00
Anna Schumaker 1c437c4957 gui: Move init() steps into controls.cpp
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-09-11 08:01:07 -04:00
Anna Schumaker 922830a2ab gui: Move o_next() into the controls.cpp file
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-09-11 08:01:06 -04:00
Anna Schumaker 78624a6d98 gui: Fix up how the gui pauses
I make it look more like o_play().

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-09-09 08:28:18 -04:00
Anna Schumaker 1a6b6d9c54 audio: Remove the on_play() callback
There are no more users of this function.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-09-08 17:26:21 -04:00
Anna Schumaker d68d5f2b40 gui: Create o_play() for handling the play function
This calls the audio :: play() function, rather than having the button
call into the audio layer directly.  With this patch, the on_play()
callback is unused.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-09-08 17:21:40 -04:00
Anna Schumaker c9cabb78f1 colmgr: Make sure banned tracks are removed when reenabling a library
This issue was solved in Ocarina 6.1.3, but I didn't add a unit test for
it.  This patch adds a test.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-08-19 08:57:36 -04:00
Anna Schumaker 412dc67e1f Merge branch 'master' into Ocarina-next
Conflicts:
	Sconstruct
	gui/collection_mgr.cpp
2014-08-19 08:08:55 -04:00
Anna Schumaker 345ad705ce PKGBUILD: Updates for 6.1.3
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-08-17 17:21:08 -04:00
Anna Schumaker 654bb99c6d Ocarina 6.1.3
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-08-17 17:18:45 -04:00
Anna Schumaker 41506f3177 gui: Remove banned songs from Collection when re-enabling
I wasn't doing this before, so banned songs were showing up in the
collection list again.  I think this is kind of an ugly fix, though.
Perhaps there is a better way to do it?

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-08-17 17:17:29 -04:00
Anna Schumaker cfa61fa816 gui: Play next song after banning
If the user tells us they don't like the current song then we shouldn't
keep playing it!

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-08-17 17:01:52 -04:00
Anna Schumaker d185b29d7b PKGBUILD: 6.1.2 Update
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-08-17 17:01:10 -04:00
Anna Schumaker 76a5e0b6ba Ocarina 6.1.2
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-08-12 10:40:52 -04:00
Anna Schumaker 8fd5d8173e filter: Clear the result set before filtering
Ocarina was preserving the results set even if there were 0 search
results for the entire search string.  So a search for "walllllll" would
still return results for "wall".

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-08-12 10:23:33 -04:00
Anna Schumaker be72339b2d filter: Check for empty results when filtering
The user could search for a term that isn't stored in the filter index.
This is represented through a NULL pointer returned from the
Index.find() function.  Let's check this pointer before attempting to
dereference it ...

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-08-12 09:59:00 -04:00
Anna Schumaker 2890819cd3 playlist tab cleanups
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-07-27 11:52:36 -04:00
Anna Schumaker 160d2ac3be plist: Move more playlist functions into lib/
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-07-27 11:41:40 -04:00
Anna Schumaker 97a8646977 plist: Move liststore into lib/
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-07-27 11:25:12 -04:00
Anna Schumaker 32bb1c670b model: Create a basic unit test
This test doesn't catch everything, but I want to move on anyway!

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-06-29 11:40:15 -04:00
Anna Schumaker 09af8d81d2 model: Move the custom TreeModel from gui/ to lib/
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-06-29 10:48:23 -04:00
Anna Schumaker b516afe832 core: Create a single init() function
Initialize everything from the core/ layer, that way lib/ doesn't need
to know the correct order.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-06-29 10:36:55 -04:00
Anna Schumaker 77616aa8d2 Merge branch 'master' into Ocarina-next
Conflicts:
	Sconstruct
	tests/Sconscript
2014-06-26 17:04:58 -04:00
Anna Schumaker b9c3d9684c PKGBUILD: 6.1.1 update
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-06-26 16:55:49 -04:00
Anna Schumaker c93b3f832f Ocarina 6.1.1
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-06-26 16:49:04 -04:00
Anna Schumaker 9d8455001f gen_library.sh: Only copy .ogg files
This excludes the invalid_track file I just added.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-06-22 12:59:28 -04:00
Anna Schumaker e274d6399b tags: Fix when library->count is modified
Whenever a Track is destructed, library->count is decremented.  This
means that even if tagging fails we need to increment library->count to
keep this value consistent.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-06-22 12:59:27 -04:00
Anna Schumaker a74eaaffa6 tags: Check that a Track was tagged correctly
Without this check we could end up creating a Track for a .ini file or
some other non-audio file.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-06-22 12:35:08 -04:00
Anna Schumaker d74d1ea634 Prepare for a bugfix release
Looks like I'll need to release a 6.1.1 soon

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-06-22 12:35:08 -04:00
Anna Schumaker 76f0b7b55f lib: Move keyval parsing into lib/
I'll eventually add in checks for keypad vs top row number keys.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-06-22 11:42:01 -04:00
Anna Schumaker 80bed8b956 collection manager: Rename widgets in the glade file
o_collection_* was easily confused with widgets on the collection tab,
so I renamed everything to be less confusing.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-06-22 11:19:05 -04:00
Anna Schumaker dd9f6de62f colmgr: Don't list NULL libraries
This leads to a segmentation fault...

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-06-22 11:14:54 -04:00
Anna Schumaker 8c7b1a9a27 ocarina6.glade: Polish the collection manager tab
- Adjust spacing of the FileChooser
- Rename button from OK -> Add
- Add tooltips to the buttons
- Rename column from Path -> Collection
- Filter out files that aren't directories
2014-06-22 11:03:37 -04:00
Anna Schumaker fdb31916a6 gui: Change chooser directory when selected path is changed
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-06-22 10:41:46 -04:00
Anna Schumaker 2094227f91 collection_mgr: Rename functions
Since these are all static functions, I don't need the _collection
part.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-06-22 10:22:05 -04:00
Anna Schumaker 3d067878f2 colmgr: Add a function for updating a specific path
On the gui end, call this function when a row in the "collected paths"
list is double-clicked.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-06-22 10:14:23 -04:00
Anna Schumaker 42ec504b90 gui: Collection manager cleanups
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-06-21 12:44:22 -04:00
Anna Schumaker a5f47e46a8 colmgr: Move some collection manager code into lib/
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-06-21 12:27:34 -04:00
Anna Schumaker 9ea0fd4f29 core: Update include file #ifndef guards
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-06-21 09:49:07 -04:00
Anna Schumaker 194a09bed4 lib: Initialize the GtkBuilder from the middle layer
This will provide an interface for accessing widgets, and make it easier
to swap out different builder files.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-06-15 11:31:04 -04:00
Anna Schumaker 4ed36c79df lib: Add support for looking up files from share/ocarina/
I replace the /proc/self/exe method with a simple hard-coded string.
This means that binaries run from the source directory need to be run
from the root of the source directory.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-06-15 10:12:55 -04:00
Anna Schumaker f2575d9799 tests: Add a test for lib :: init()
This just checks that the deck was initialized.  To really be complete,
it should really check that ALL core libraries are initialized.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-06-14 20:43:54 -04:00
Anna Schumaker 5b3f8b13e0 lib: Initialize core libraries from a new middle layer
My hope is that putting lib/ between core/ and gui/ will help clean up
gui code, since everything will no longer be in a single place.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-06-14 20:06:07 -04:00
Anna Schumaker 64354cec26 Let's start Ocarina 6.2!
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-06-14 19:32:23 -04:00
Anna Schumaker 8b053b8c85 PKGBUILD: Update to Ocarina 6.1
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-06-14 18:33:52 -04:00
Anna Schumaker 12548784ba Ocarina 6.1
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-06-14 18:33:45 -04:00
Anna Schumaker c88746d2da tests: Create a core/ directory
I move all of the core tests into the core/ directory to keep them
together.  Gui unit tests will be put in new directories.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-06-14 11:15:21 -04:00
Anna Schumaker 40a99f7eda Merge branch 'Ocarina-next'
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>

Conflicts:
	.gitignore
	Sconstruct
	gui/main.cpp
	include/deck.h
	include/playqueue.h
	lib/deck.cpp
	lib/playqueue.cpp
2014-06-11 12:12:43 -04:00
Anna Schumaker 5df79d3c08 callbacks: Remove unused queue callback
I now mimic the effects of the "changed" callback with inheritance.
This makes for a cleaner implementation.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-06-06 14:46:54 -04:00
Anna Schumaker 5bfdc31204 TODO: Remove completed items
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-06-06 09:57:31 -04:00
Anna Schumaker 70254e7aa1 Remove error.h
It's not used by anything anymore.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-06-06 09:40:14 -04:00
Anna Schumaker bd11a320e3 tags: Correctly find the next iterator location
We need to use Database::next() rather than it++ to skip over deleted
tracks.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-06-06 09:21:30 -04:00
Anna Schumaker ec2bd92bef gui: collection manager fixes
- Fill out the list of library paths
- Update size during scan

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-06-06 09:20:50 -04:00
Anna Schumaker 00ff9cd08f playlist: Fix a null pointer dereference in init()
This happens if we try to use the Banned playlist before it exists in
the database.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-06-06 08:21:56 -04:00
Anna Schumaker 43c8130ecc gui: Fix adding tracks to an existing queue
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-06-05 11:05:40 -04:00
Anna Schumaker 9e3399b619 deck: Reintroduce deck :: get()
This function turned out to be really useful for the gui.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-06-05 11:05:19 -04:00
Anna Schumaker eb777c04f1 Add missing deck file for tests
The .gitignore was set up to ignore this, so it was never included.
Oops.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-06-05 10:42:41 -04:00
Anna Schumaker 12c6f18540 Remove old deck test
This should have been removed a long time ago ...

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-06-05 10:35:14 -04:00
Anna Schumaker 95064e4537 Rename lib/ -> core/
I plan to introduce a new lib/ that sits between the gui and the backend
files (similar to how glibc sits between the kernel and userspace).
This gets the rename out of the way before I change my mind again.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-06-05 10:21:32 -04:00
Anna Schumaker 87af56ba85 Header file roundup
Create include/lib/ and include/gui/.  Move header files into the
appropriate directory.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-06-04 13:59:42 -04:00
Anna Schumaker 851be80a7d tags: Add artist and album names to the filter
Also decrement library count when deleting tracks.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-06-04 13:25:06 -04:00
Anna Schumaker 2f1d7a73ce database: Set an item's ID before reading it in
Tracks need to know their own ID to set up filtering properly.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-06-04 13:24:21 -04:00
Anna Schumaker 72a51fb78f gui: Properly create queue tabs
Changes to the deck removed the on_pq_created() callback that we looked
for to create new tabs.  This patch creates tabs correctly.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-06-04 09:35:41 -04:00
Anna Schumaker c803699215 GSTDriver: Call on_eos() at End Of Stream
We kind of need to do this this to pick the next song ...

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-06-04 09:34:32 -04:00
Anna Schumaker 06b36afec6 gui: Updates for the recent audio changes
Now the gui compiles again, yay!

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-06-01 17:59:27 -04:00
Anna Schumaker 1bfa299e08 audio: Update the code to match the design
This patch reworks the unit test using the TestDriver audio driver.  I
also recode the audio layer to match the design and drastically clean up
the code.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-06-01 17:53:41 -04:00
Anna Schumaker b8ea2c989d deck: Fix a segfault when calling next()
This can only be hit when the tagdb has no tracks in it, since you can't
add a NULL pointer to the recent queue.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-06-01 09:39:30 -04:00
Anna Schumaker 6f3fcaae6e audio: Update audio design
This patch updates the design to something that makes a bit more sense,
and works with the new audio drivers.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-05-31 21:11:59 -04:00
Anna Schumaker 1cacbf51e7 driver: Move Gst code into the GstDriver
This would have to happen eventually.  Might as well do it now!

I also updated the TestDriver test to match the changes I had to make.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-05-31 21:11:57 -04:00
Anna Schumaker edc4a2f4ee driver: Create an audio driver class
The driver is used to select between gstreamer playback and a fake
playback mode used only when testing.

Currently the GSTDriver has empty functions.  It will be implemented as
the audio.cpp file is updated.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-05-31 13:27:20 -04:00
Anna Schumaker f8f389c7ed deck: Create TempQueues
TempQueues create a way to trigger deck :: write() whenever a queue
changes.  This means higher layers don't need to remember to save after
changes!

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-05-31 09:11:04 -04:00
Anna Schumaker 36322a6ff8 Update code to match new deck layout
This patch actually breaks a bunch of things, but I just want to be done
with the deck changes for now.  I'll go back and fix things before
releasing!

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-05-26 22:33:16 -04:00
Anna Schumaker 211d240484 deck: Rework the deck code
I update the unit test and redo much of the code to be cleaner and make
more sense.  One big improvement is that the recently played queue will
now be managed by the deck.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-05-26 22:20:55 -04:00
Anna Schumaker b6156bab11 deck: Update the deck design for a new implementation
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-05-26 20:27:47 -04:00
Anna Schumaker a385727206 tests: Move sample files into the Data/ directory
Keeping separate directories for all of these files isn't the most
obvious way to do things.  Instead, move everything into the same
directory.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-05-26 19:12:14 -04:00
Anna Schumaker a96e6f6f2d file: Set version number on a per-file basis
I'm about to bump the version number for the deck layer, so it makes
senes that different files need different version numbers.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-05-26 12:14:28 -04:00
Anna Schumaker ddfdc7d6f6 Move error.h include into audio.cpp
The audio code still uses it, databases don't.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-05-24 13:38:20 -04:00
Anna Schumaker e4db93b8e2 playlist: Remove banned songs from the library queue
And put them back when they are unbanned.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-05-24 13:32:03 -04:00
Anna Schumaker 9ba4dbc218 Updates for recent library changes
This fixes the gui, deck, and audio code due to the library changes I
just did.

NOTE: Library updating callbacks have been disabled in the gui.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-05-24 13:07:54 -04:00
Anna Schumaker 208e53c7e9 library: Update the code and unit test
Lots of changes here!  I switched from using track and library ids to
passing pointers, renamed some functions, and made the code much
cleaner.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-05-24 12:48:47 -04:00
Anna Schumaker f995538a8c library: Initial design edits
More to come as I work on this bit of code!

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-05-23 22:10:03 -04:00
Anna Schumaker 59220cc2ce tags: Add Track->played()
This function is called to increment play count and set "date last
played" variables.  Moving this into the Track class lets me remove an
internal callback and a few other unnecessary functions.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-05-23 21:53:36 -04:00
Anna Schumaker ea369eb14e clean up use of print.h
Some files #including this file weren't using it for anything ...

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-05-23 21:15:30 -04:00
Anna Schumaker 53f0c2a6aa testing: Add gcov and cppcheck tests
It doesn't hurt to run even more tests on the code!

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-05-20 17:25:03 -04:00
Anna Schumaker 11df56139d playlist: Update the design and unit test
I updated the code to better match how I use playlists and to make sure
that everything is tested.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-05-18 21:34:14 -04:00
Anna Schumaker f6306faac8 queue: Remove old unit test
Also take a few moments to update the DESIGN.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-05-18 14:46:14 -04:00
Anna Schumaker b9e5ce3356 queue: Update reand and write code
And update the unit test at the same time.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-05-18 14:39:41 -04:00
Anna Schumaker 869d67558e queue: Update the track_selected code
I also put in other fixes to the unit test to make test_equal work.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-05-18 14:25:29 -04:00
Anna Schumaker 9a5caa29b3 queue: Update sorting code
I now have a single function rather than 4 individual functions.  The
code is cleaner, and I've added it to the unit test.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-05-18 14:12:16 -04:00
Anna Schumaker 124f275ffd queue: Update the next() function
I also added in code for testing.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-05-18 11:17:32 -04:00
Anna Schumaker 44f93d85e4 file: Fix memory errors
Apparently it's not okay to return str.c_str() to caller functions,
because str will go out of scope...

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-05-18 11:10:34 -04:00
Anna Schumaker 6dc8bf7329 random: Use a different RNG for testing
This RNG is more predictable, which makes it great for testing.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-05-18 11:10:29 -04:00
Anna Schumaker 7aa5f22777 Add valgrind support to testing
To help find memory leaks!

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-05-14 17:49:03 -04:00
Anna Schumaker bcfa735dd7 queue: Fix up the length_str() function
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-05-11 19:56:17 -04:00
Anna Schumaker 0cc8072159 queue: Update the updated() function
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-05-11 18:33:13 -04:00
Anna Schumaker 5520472f6f queue: Test and clean up the delete track function
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-05-11 13:37:15 -04:00
Anna Schumaker 74bf30bec5 queue: Remove the add_front() function
This is best implemented in a derived class, since it's only used by the
recently played queue.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-05-11 10:54:16 -04:00
Anna Schumaker 38ae4ba0f3 queue: Fix up queue :: add()
It should take a Track pointer, rather than a track_id.  This makes the
code easier to work with.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-05-11 10:41:50 -04:00
Anna Schumaker 69f4d21c04 tests: Create a fake library
This is loaded for testing so we don't have to scan a directory for each
test.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-05-11 10:20:06 -04:00
Anna Schumaker 24fe8e7ee2 queue: Fix compile errors related to recent changes
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-05-11 09:20:42 -04:00
Anna Schumaker 3fbb4d9735 Clean up test/ directory
Mostly remove files that are no longer used.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-05-06 23:05:18 -04:00
Anna Schumaker 7332ed1e8f queue: Move unit test up one directory
And modify it a bit to match my recent work.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-05-06 23:03:42 -04:00
Anna Schumaker 4dafe7270f tags: Update the unit test
While I'm at it, I also fix a refcounting issue with the Library pointer
each track has.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-05-06 22:57:07 -04:00
Anna Schumaker 34b0c56a70 Move tests out of tests/src/
... and just into the tests/ directory.  I also reworked the Sconscript
to compile everything using only the lib/ files that are needed.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-05-06 08:37:04 -04:00
Anna Schumaker 1f19987c53 idle: Update test for new system
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-05-05 09:41:49 -04:00
Anna Schumaker 70067a89cb filter: Update unit test
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-05-03 19:31:38 -04:00
Anna Schumaker 90bd93b10f index: Update the index test
I switched to the new testing functions, and now everything is cleaner.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-05-03 19:04:08 -04:00
Anna Schumaker f627f8337d database: Update unit test
As a bonus, I now have a test for manual database saving.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-04-27 17:09:47 -04:00
Anna Schumaker 968ca30484 database: Remove old db_entry test
This might have made more sense for an earlier version of the
DatabaseEntry class, but as far as I can tell this test only checks code
that exists inside this file.  This means I can removed it without
reducing code coverage.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-04-27 09:08:27 -04:00
Anna Schumaker 7b358259bd file: Finish updating the new file test
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-04-26 14:07:06 -04:00
Anna Schumaker 55f3f06ded file: More cleanups after removing legacy file support
Looks like I missed updating a few places in the File class.  I do that
now, and I also began updating the unit test to the new system.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-04-26 14:07:06 -04:00
Anna Schumaker 8aa121f291 tests: Update testing framework and begin reworking everything
Add in several new features like:
- Don't exit until the specific test function completes.
- Make it easier to run named tests from C++.
- Use a macro to find line number when calling test :: equal().
- Use a macro to do basic setup and cleanup between test functions.

Also update the version test while I'm at it.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-04-26 14:06:58 -04:00
Anna Schumaker 35f19d98ef queue: Add tests for queue flags
I remove the "on_queue_changed" callback in the flag handler functions,
so changes won't trigger a save until I can update later layers.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-04-26 11:03:07 -04:00
Anna Schumaker 78fe570e36 Add new tag layer idea to ease testing
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-04-26 10:40:51 -04:00
Anna Schumaker 38086f1e28 Update PKGBUILD and .gitignore
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-04-20 11:38:46 -04:00
Anna Schumaker 2f8dfa8f4b Ocarina 6.0
Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-04-20 11:14:13 -04:00
Anna Schumaker 30e12bcb68 Allow running single tests
This makes testing easier, since I'll only see the test I need and not
everything that runs before it.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-04-13 18:40:24 -04:00
Anna Schumaker 6ee68397fd queue: Improve the constructor to take multiple flags at once
It really should have been like this from the beginning.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-04-13 18:39:15 -04:00
Anna Schumaker d939dcab20 queue: Begin code updates
So far I have renamed variables, changed a few functions, and updated
all the code that was affected.

Oh, I also started a new unit test.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-04-13 12:27:15 -04:00
Anna Schumaker 44f62028c3 database: Return NULL when inserting a duplicate item
This provides us a more straightforward way to determine if the database
changed.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-04-13 11:14:11 -04:00
Anna Schumaker 8e9bc79e51 Set queue length on startup
Queues are read from disk *before* libraries are read, meaning we can't
calculate the length right away.  But if we don't calculate the length,
then the first time a track is removed from a queue the length will be
set to (0 - track_length).  This is wrong.

Signed-off-by: Anna Schumaker <Anna@OcarinaProject.net>
2014-04-11 08:28:03 -04:00
Anna Schumaker 5ff68140b5 Rip out import stuff
I only needed this to make the jump from Ocarina 5.10 -> Ocarina 6.0.
It's not needed anymore, now that 6.0 is out.

Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
2014-04-10 08:42:53 -04:00
Anna Schumaker 1c743239a0 Rename playqueue -> queue
Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
2014-04-09 21:10:08 -04:00
Anna Schumaker 57fa16d289 queue: Update design for queues
Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
2014-04-09 21:10:08 -04:00
Anna Schumaker a14f6145a5 Switch over to the new tagdb implementation
Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
2014-04-09 21:10:08 -04:00
Anna Schumaker 2a3d4ca2e0 tagdb: Implement init() and commit()
To save and restore the databases.

Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
2014-04-09 21:10:08 -04:00
Anna Schumaker 2a01ce5159 tagdb: Import track information
This allows upgrading from a previous Ocarina version.

Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
2014-04-09 21:10:08 -04:00
Anna Schumaker ac338c5704 track: Implement comparison function
Used later for sorting queues.

Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
2014-04-09 21:10:08 -04:00
Anna Schumaker c15c5149bc tags: Read and Write a Track tag
Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
2014-04-09 21:10:08 -04:00
Anna Schumaker 72cea29c61 tagdb: Find tags for each track
Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
2014-04-09 21:10:08 -04:00
Anna Schumaker f207ed94df filter: Make sure we don't crash when searching
This only seems to happen when the user searches for something not in
the filter.

Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
2014-04-09 21:10:08 -04:00
Anna Schumaker cac0aee2e6 database: Insert through a const reference
This should offer a performance increase since the item to insert will
only be copied if it is not already in the database.

Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
2014-04-09 21:10:08 -04:00
Anna Schumaker d452177f32 Make sure index test can handle n = 0
Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
2014-04-09 21:10:08 -04:00
Anna Schumaker 7490b98db6 Combine database and db_entry tests
These tests are designed to verify the database, which should include
the DatabaseEntry class.

Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
2014-04-09 21:10:08 -04:00
Anna Schumaker a9dae134d0 database: Store pointers in the database
Inserting into a vector can sometimes cause the entire vector to
reallocate itself.  The insert() function returns a pointer to the
caller, so this reallocation could invalidate the returned pointer.

This is not what we want.

Instead, store pointers to the data in the vector.  C++ provides a
default copy constructor that can be used to allocate a new item before
inserting.  By doing it this way callers won't have to allocate memory
themselves.  In addition, I will no longer need to keep a valid bit
since we can simply check for a NULL entry in the database.

Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
2014-04-09 21:10:08 -04:00
Anna Schumaker 38990748bb database: Return pointers for insert() at() and find()
This gives me the item directly, which is usually what I want when I
call these functions.  Save iterators for iterating.

Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
2014-04-09 21:10:08 -04:00
Anna Schumaker e2560f3134 tagdb: Add most functions
I implemented:

- add_track()
- remove_track()
- add_library()
- remove_library()
- lookup()
- get_track_db()
- get_library_db()

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-09 21:10:08 -04:00
Anna Schumaker 5d97c84d10 tagdb: Begin the Track class
I properly initialize variables, and I created supporting databases that
will be used to look up artist, album, genre and library information.

Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
2014-04-09 21:10:07 -04:00
Anna Schumaker 134348f253 tags: Begin creating the tag database
This patch adds classes for Artist, Album, Genre and Library.

Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
2014-04-09 21:10:07 -04:00
Anna Schumaker d61dbae47f Add more to the Track tag design
Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
2014-04-09 21:10:07 -04:00
Anna Schumaker 0fee94f76a tagdb: Add information about tag database layer
This layer will be separate from the library updating code.  This will
give me a place to manage the various databases without extra code to
scan and update paths.

Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
2014-04-09 21:10:07 -04:00
Anna Schumaker 89fd79e079 Database: Improve on the insert() return value
Rather than returning an index into the database, instead return an
iterator pointing at the item we just inserted.

Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
2014-04-09 21:10:07 -04:00
Anna Schumaker bfefd1761a Think out the design for each tag class
This gives me a chance to write out more information about each class,
so I'll have an easier time knowing what is going on if I ever need to
revisit the design.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-09 21:10:07 -04:00
Anna Schumaker 83118b3e8d Update version
Time to start Ocarina 6.1!

Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
2014-04-09 21:10:07 -04:00
Anna Schumaker 2eca396042 Rename config -> Sconstruct
I only had config so I could easily refer to the original Sconstruct.  I
don't need that anymore =)

Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
2014-04-09 21:09:49 -04:00
Anna Schumaker 887051e5c1 Add a `scons install` option
scons -c install to uninstall.

Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
2014-04-09 20:37:46 -04:00
Anna Schumaker cbe725d891 lib: Don't try to load a track that doesn't exist
This was causing me to throw an exception that never got caught.

Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
2014-04-09 19:32:46 -04:00
Anna Schumaker 8d29ce7169 library: Use track id directly
Calculating through the iterator may lead to unexpected problems.  We
already know the id of every database entry, so we might as well use it
directly.

Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
2014-04-09 19:28:04 -04:00
Anna Schumaker d28b3300f5 library: Put a space between track length and title
If a title began with a number then the number would be read as part of
the length, adding extra time.  So a track with length "100" and title
"42 abcde" would be read back as having length "10042" and title "abcde"

Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
2014-04-09 19:27:02 -04:00
Anna Schumaker 163d823c19 database: Don't write out unnecessary spaces
When items are deleted from a database we write out a line representing
"invalid entry".  This patch changes the invalid entry line from "0 " to
"0"

Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
2014-04-09 19:22:51 -04:00
Anna Schumaker 22322a9b12 playqueue: Correctly check for play count when sorting
Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
2014-04-08 08:26:15 -04:00
Anna Schumaker ad1c3d6f9d library: Scan fixes
- Double check that track->valid == true before notifying the UI that
  there is a new track.
- Use primary_key() instead of manually calculating the full filepath.

Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
2014-04-08 08:15:32 -04:00
Anna Schumaker a470b88a46 library: Save after library validation
Otherwise we won't remember what songs we forgot!

Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
2014-04-08 08:12:04 -04:00
Anna Schumaker 9b417e10aa library: Properly check if a track is in the database
The iterator will be set to db.end(), so we should verify that it IS
this value.

Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
2014-04-08 08:09:09 -04:00
Anna Schumaker 0d6dc76eb7 Update PKGBUILD
Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
2014-04-06 19:57:06 -04:00
Anna Schumaker 92e580b904 Create a .desktop file
Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
2014-04-06 19:57:06 -04:00
Anna Schumaker 9f54c23995 database: don't iterate if there are no entries
Checking the valid bit could lead to a segmentation fault.

Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
2014-04-06 19:57:06 -04:00
Anna Schumaker b75d13838f database: Properly test for double-removal
I found that databases were always decrementing _size when remove() was
called.  This patch fixes the bug by checking if the entry is valid
before removal.

Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
2014-04-06 19:57:06 -04:00
Anna Schumaker fc07e28201 library: Don't save length strings to disk
Recalculating this doesn't change the runtime significantly, so we might
as well save some disk space.

Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
2014-04-06 19:57:06 -04:00
Anna Schumaker 1e09406730 library: Don't attach artist_id to albums
This was an unnecessary field, and might potentally result in album
duplication.

Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
2014-04-06 19:57:06 -04:00
Anna Schumaker 2960b72967 audio: Save and load current trackid
Signed-off-by: Anna Schumaker <anna@ocarinaproject.net>
2014-04-06 19:57:06 -04:00
Anna Schumaker 81f3ef458f database: Each DatabaseEntry should know its id
This will let me set up a Track class that has pointers to the
corresponding artist, album and genre information without needing to
know their IDs directly.  Having this information available means I
won't need to keep a "join struct" when doing lookups - instead I can
return a pointer to a Track class that already knows everything.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:06 -04:00
Anna Schumaker 14879b03fd idle: Update design and unit test
I didn't have any changes to make to the IdleQueue itself, but I did
need to update the unit test and reword a few things in the design.

Signed-off-by: Anna Schuamker <schumaker.anna@gmail.com>
2014-04-06 19:57:06 -04:00
Anna Schumaker 58ed47b37c filter: Update design and rewrite the unit test
- filter :: add() now returns the lowercased text
- Don't cache lowercased strings
- Remove functions depending on CONFIG_TEST

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:06 -04:00
Anna Schumaker 7eddaac14e Remove some text from DESIGN
Because it is all in TODO already.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:06 -04:00
Anna Schumaker 08a69c2c81 Update the license
The SimPL was essentially a reworded GPL v2 license, so we might as well
have the original GPL v2 text.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:06 -04:00
Anna Schumaker 1b34a9a8a0 index: Update the index design
I updated the design and rewrote the unit tests.  This creates something
more consistent with how I ended up using the index.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:05 -04:00
Anna Schumaker fc8dc9d55e database: Design and test updates
I add:
- Autosaving option
- Real iterators
- Better accessor functions

The new design and unit test also allows me to remove the 300,000+ line
"database.good" file that the old tests were based on.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:05 -04:00
Anna Schumaker b251f27bb5 file: Don't use throw / catch to report errors
Needing to use throw / catch was getting in the way.  Instead, check for
a boolean return value.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:05 -04:00
Anna Schumaker 959cac0fe1 Database: Update design for database entries
I changed primary_key() into a function since it is only called once,
and there is no point in using more mmemory than I need to.  I also
created a basic unit test for everything that database entries are
supposed to do.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:05 -04:00
Anna Schumaker f7d08724a3 design: Cleanups to each section
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:05 -04:00
Anna Schumaker 0386b24309 Small file test cleanup
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:05 -04:00
Anna Schumaker 972eb3c2aa tests: Only enable CONFIG_TEST if we are building tests
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:05 -04:00
Anna Schumaker c263e0e524 tests: Change executable names
Make them end with .run so my .gitignore will pick them up.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:05 -04:00
Anna Schumaker 336024bae9 file: Update design and create a new unit test
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:05 -04:00
Anna Schumaker 3359cbae6f version: Update version test
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:05 -04:00
Anna Schumaker e2fd4773da Update design info for versions
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:05 -04:00
Anna Schumaker 73d3c68e9f error: Update design
To make sure all the info is up to date.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:05 -04:00
Anna Schumaker 0cf38aaf56 Introduce README
README has basic commands for building / cleaning
I also update the DESIGN file a bit.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:04 -04:00
Anna Schumaker 5109d629ae TODO: Remove already implemented features
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:04 -04:00
Anna Schumaker dd1db4645a Rename files
This matches how other projects do things.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:04 -04:00
Anna Schumaker a20407f2c0 Remove bin/ during clean
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:04 -04:00
Anna Schumaker 2e727ed704 gui: Add a switch to enable / disable queues
I also select the first enabled queue during startup.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:04 -04:00
Anna Schumaker 1394aaf37c gui: Show the first tab on startup
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:04 -04:00
Anna Schumaker 9b0499b3ce gui: Add to queue menu items
This commit finishes my tab rewrite.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:04 -04:00
Anna Schumaker 239c03b1ac playlist: playqueue should not remove tracks
I was double clicking tracks in the gui, and they were removed from the
playqueue!  This patch fixes that.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:04 -04:00
Anna Schumaker 3c8e967895 gui: Connect a menu item for creating new queues
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:04 -04:00
Anna Schumaker a529d569f6 gui: Implement add to {favorites, banned} menu items
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:04 -04:00
Anna Schumaker 2abc498fde gui: Rename wires.cpp
I think gui.cpp is a better name, since this file controls most of the
random gui components.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:04 -04:00
Anna Schumaker 44d1fcd1ad ocarina: Remove old ocarina code
I don't need it anymore, so it is just taking up space.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:04 -04:00
Anna Schumaker 968d723ec7 gui: Add a window icon
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:04 -04:00
Anna Schumaker 5b34b11dd8 gui: Move ocarina6.glade to share/ocarina/
This directory will be copied directly into /usr/ during an install.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:04 -04:00
Anna Schumaker 6f7ce86091 gui: Remove some old code
All that is left in the giant commented out section is right click menu
stuff.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:04 -04:00
Anna Schumaker ff925cf573 gui: Add songs to favorite playlist
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:04 -04:00
Anna Schumaker d83609bc21 gui: Delete key removes tracks from queues
This was the behavior before I started my rewrite.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:04 -04:00
Anna Schumaker 463409acdf gui: Playlists respond to the delete key
This key is used to remove tracks from a playlist.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:04 -04:00
Anna Schumaker 6c8ef37b2a gui: Ban tracks with the "delete" key
Press the delete key on the collection tab to ban all selected tracks.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:04 -04:00
Anna Schumaker cb59febd1c gui: Reenable sorting
This time I don't keep a global "sorting count".  Instead, this count
belongs to individual tabs so flipping between them quickly could
display different sorting fields.

Signed-off-by: Anna Schumaker <schuamker.anna@gmail.com>
2014-04-06 19:57:04 -04:00
Anna Schumaker 1da8c52b0c gui: Remove old glade file
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:04 -04:00
Anna Schumaker 58423c92e5 gui: Use common code for adding tracks to queue
Called both for adding and for creating a new queue

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:04 -04:00
Anna Schumaker f0006873b6 gui: Use number keys to add tracks to a queue
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:04 -04:00
Anna Schumaker 196088dcfa gui: Add columns to a queue treeview
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:04 -04:00
Anna Schumaker 2a1f695ea8 design: Remove design directory
Keeping these documents updated with the top-level design.txt was
annoying.  Moving forward, I would like to keep a single document up to
date without extra hassle.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:04 -04:00
Anna Schumaker be13c7dd87 Move the "todo" section into the toplevel
I am going to delete the design/ directory and just keep a single file
instead.  I don't want to lose my ideas!

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:03 -04:00
Anna Schumaker 871914ea90 Clean up the build system
I'm taking a break from gui code to clean up the build system and update
my unit tests.  This patch updates how code is built, and reworks my
"print" test to test version number instead.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:03 -04:00
Anna Schumaker bfcc94de21 gui: Generic toggle button function
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:03 -04:00
Anna Schumaker 73c4de13be gui: Update the repeat button
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:03 -04:00
Anna Schumaker 34de6874ff gui: Queue tabs now have a search bar
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:03 -04:00
Anna Schumaker 83a2908eb6 gui: Remove some reimplemented code
This helps to clean out tab.cpp so I can keep track of what still needs
to be done.  I also adjusted some of the spacing and section divisions.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:03 -04:00
Anna Schumaker 5acf8239c8 gui: Make sure queue tabs are removed from the notebook
This appears to happen automatically, but appearances can be deceiving.
Remove pages anywa just to be safe.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:03 -04:00
Anna Schumaker eb5a65069a gui: update tab reordering
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:03 -04:00
Anna Schumaker 587eacfdd4 gui: Reactivate the close queue tab button
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:03 -04:00
Anna Schumaker d465c2e894 gui: Begin creating playqueue tabs
I've been putting this off for a while since it seemed like a lot of
work.  Time to get it done!

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:03 -04:00
Anna Schumaker 6ecb8f6b7f gui: Reactivate the "slash" keyboard shortcut
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:03 -04:00
Anna Schumaker 697c07e2df gui: Update the track changed callback
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:03 -04:00
Anna Schumaker 3654644b1c gui: Update the row_activated signal
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:03 -04:00
Anna Schumaker 99e849a106 gui: Set the runtime label for each tab
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:03 -04:00
Anna Schumaker 4ce08ef22e gui: Begin yet another tab framework
This one is based on inheritance, and I think it will be the best way to
create several tab types that do things just slightly differently.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:03 -04:00
Anna Schumaker e3612b6e38 gui: Create a register_tab_type() function
Rather than returning tab types from init functions.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:03 -04:00
Anna Schumaker f68f03c057 gui: Create generic filtering functions
I need to create a FilterDesc struct with needed widgets and then
filtering can happen generically on all tabs!

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:03 -04:00
Anna Schumaker 5d365afae1 gui: Reenable filtering in the history tab
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:03 -04:00
Anna Schumaker 1ac05c6b52 gui: Rip out some code from tabs.cpp
Most of this was related to the playlist tab.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:03 -04:00
Anna Schumaker 1d4ba1474d gui: Begin the new playlist tab
The list of playlists is now created in glade, too =)

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:03 -04:00
Anna Schumaker 4104a4cede gui: Begin the redesigned history tab
This code will be in its own self-contained file: history.cpp

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:03 -04:00
Anna Schumaker 97511f82a9 gui: Begin a tab redesign
I'm creating as many "static tabs" as I can using GtkBuilder, and
splitting their code out of tabs.cpp.  This should help to contain the
growth of this file and make all the code easier to work with.

This patch begins the redesign and adds beginning code for a new
collection tab.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:03 -04:00
Anna Schumaker 1434618381 gui: More widget and spacing cleanups
Signed-off-by: Anna Schumaker <Schumaker.anna@gmail.com>
2014-04-06 19:57:03 -04:00
Anna Schumaker be60f9bff3 gui: Split out collection manager tab
This makes the code a little bit cleaner, since this tab is self
contained.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:03 -04:00
Anna Schumaker 480cf92519 gui: Improve functions for accessing widgets
I made a couple of templated functions to get widgets and objects out of
the Gtk::Builder easier.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:03 -04:00
Anna Schumaker 3eb5bd3adb gui: Disable focus on pause togglebutton
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:03 -04:00
Anna Schumaker 38c0009acd gui: Configure more keyboard shortcuts
- Number keys to switch pages
- c, h, p, m to switch to collection, history, playlist and collection
  manager tabs.
- Slash key to focus on the search entry

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:03 -04:00
Anna Schumaker 2957ea01d4 gui: Teach playlists about the f key
This key is used to add songs to the "favorites" playlist.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:03 -04:00
Anna Schumaker b161048f7f gui: Teach playqueues about the delete key
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:03 -04:00
Anna Schumaker 7d7c83c222 deck: Check if a playqueue is empty before calling next
I need this in case the user deletes all tracks from a playqueue without
adding anything by the time next() is called.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:02 -04:00
Anna Schumaker d665b7f167 gui: Use RefPtrs for menu items during init
I'm honestly not sure why this is needed, but using ref pointers
prevents several lines of warning messages.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:02 -04:00
Anna Schumaker 5761740f6b gui: Add a right click menu
At the moment it only adds tracks to a playqueue.  I will add in
removing tracks soon!

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:02 -04:00
Anna Schumaker 240ae7e21a audio: Remove duplicates from the recent playqueue
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:02 -04:00
Anna Schumaker 5f582e639b playqueue: Add a path_selected function
This is called by the GUI to tell the playqueue that a track has been
selected.  This gives the PQ a chance to (possibly) remove it.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:02 -04:00
Anna Schumaker 04ffffb4e8 gui: Fix flags on playlist manager tab
I wasn't initializing the variable, so it was sometimes drawing buttons
next to the filter entry bar.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:02 -04:00
Anna Schumaker 21c80ea1f9 lib: Import ban status from Ocarina 5.x
Now that I have a banned playlist working I can remember the ban status
easier.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:02 -04:00
Anna Schumaker a474712a22 lib: Remove track from library pq if banned
Put it back when unbanned.

Signed-off-by: Anna Schumaker <schumaker.ann@gmail.com>
2014-04-06 19:57:02 -04:00
Anna Schumaker 48cc1f992a gui: Add a playlist manager tab
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:02 -04:00
Anna Schumaker 3894c4ac97 playlist: Create a playqueue to store the current playlist
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:02 -04:00
Anna Schumaker 3fb8dfa534 gui: Playqueue spacing improvements
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:02 -04:00
Anna Schumaker d16ce77c0a gui: Change justify for some tabs
I think justify center looks better.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:02 -04:00
Anna Schumaker 82243cfdd1 gui: Add tracks to playqueue
I added tab numbers to make it easier to specify what playqueue to add
tracks to.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:02 -04:00
Anna Schumaker 0929418fb7 gui: Adjust toolbar spacing
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:02 -04:00
Anna Schumaker 2f2b01100e gui: Add playqueue filtering!
I love tis feature, and I've been missing it the last few days of
Ocarina 6.0 preview testing.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:02 -04:00
Anna Schumaker 72accfd26d library: Add tracks to the filter for searching
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:02 -04:00
Anna Schumaker 444e48f93b gui: Custom model fixes
- Initialize stamp with a random integer (this is how a Gtk::ListStore
  works)
- Increment the stamp in a way that it will never be 0 (AKA: invalid)
- iter_n_root_children() does not take any arguments, so fix up my
  function.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:02 -04:00
Anna Schumaker b2b1620116 gui: Change tab close name
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:02 -04:00
Anna Schumaker 0e4c05350a gui: Implement tab reordering
And prevent tabs from being moved into the perma-tab area.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:02 -04:00
Anna Schumaker cefd8b865b gui: Disable focus on click for buttons
Because I think this looks a bit nicer.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:02 -04:00
Anna Schumaker 946b1a1bc9 gui: Add better sorting display
I show the column that is currently being sorted by.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:02 -04:00
Anna Schumaker b571018a53 gui: Spacing improvements
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:02 -04:00
Anna Schumaker 5df8c94ae5 gui: Add a close tab button
Only visible for playqueue tabs

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:02 -04:00
Anna Schumaker 07a7f3d4a7 gui: Clean up tabs
Create various helper functions to call during construction
Create multiple tab label classes to use for each type of tab.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:02 -04:00
Anna Schumaker 4f0b7070f9 tabs: Turn OcarinaTab into a pointer
And have in inherit from Gtk::HBox

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:02 -04:00
Anna Schumaker a74cd5e6d1 tests: Update tests for recent deck change
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:02 -04:00
Anna Schumaker 6bd02bd46b gui: Press "s" to create a new playqueue
This playqueue will have random enabled.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:02 -04:00
Anna Schumaker 7dc57572aa deck: Pass a random-enabled flag when creating playqueues
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:02 -04:00
Anna Schumaker 37a776ef24 playqueue test fixes
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:02 -04:00
Anna Schumaker 86e35d4fae gui: Add a repeat button in temporary tabs
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:01 -04:00
Anna Schumaker 7ce3c4268f gui: Create new playqueue tabs
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:01 -04:00
Anna Schumaker 32841901db deck: Add callbacks for new playqueue creation
Used by the gui to set the playqueue on the correct page.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:01 -04:00
Anna Schumaker 1e4faeaff0 gui: Add basic keyboard shortcuts
n: play the next song
N: play the previous song
spacebar: play or pause

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:01 -04:00
Anna Schumaker e8d63a15cf audio: Add a function to toggle playing
This will be used by the gui when the spacebar is pressed by the user.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:01 -04:00
Anna Schumaker e752e0f826 audio: Don't escape filepaths
This will actually be done automatically by the gstreamer code.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:01 -04:00
Anna Schumaker e9c398f5ef model: Don't escape all fields
Only the tooltip column needs to have escaped text.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:01 -04:00
Anna Schumaker dfbb98b2c6 audio: Escape filepaths before loading
This is for filepaths containing special characters.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:01 -04:00
Anna Schumaker bf010f2a84 gui: re-add by / from lines to current track
These were accidentally removed a few days ago.  Put them back!

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:01 -04:00
Anna Schumaker 92f466c310 model: Escape text before setting column values
Otherwise there could be gtk errors.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:01 -04:00
Anna Schumaker 03b44b9e16 Update play count
When a track finishes, I tell the library to update playcount.  Then,
the library triggers a callback to the playqueue deck telling it to
update.

This patch also finds and prints the track that causes a gstreamer
error.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:01 -04:00
Anna Schumaker 30c0d97d56 gui: Use track filepath as tooltip
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:01 -04:00
Anna Schumaker d240ff44bc playqueue: Change cur when tracks are directly selected
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:01 -04:00
Anna Schumaker e9416e6ace library: Properly set the track primary_key from file
First this was missing, then I set it to the short path, now it's
correct.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:01 -04:00
Anna Schumaker 7a78e649a0 library: Separate error messages with line breaks
This condition is only hit when trying to tag files that aren't
recognized as audio files.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:01 -04:00
Anna Schumaker c9f1c07fa3 playqueue: Add a function to clear the playqueue sort order
I do this when reading in a saved library sort order to make sure the
correct values are set.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:01 -04:00
Anna Schumaker 8dbb4684c7 deck: Update test after sorting changes
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:01 -04:00
Anna Schumaker 63df51a847 library: Set primary key in the Library class
To prevent duplicates from being added to the library.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:01 -04:00
Anna Schumaker 362acf163b playqueue: More sorting improvements
- Reimplement binary search for neater code
- Flip sort order when resetting sort if the first field is the one we
  are sorting by.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:01 -04:00
Anna Schumaker 77e7101f85 playqueue: Binary seach edge cases
Because some things were still out of order.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:01 -04:00
Anna Schumaker 23a518cf5a playqueue: Sorting improvements
- Put empty tags last
- Correct and edge case in my binary search

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:01 -04:00
Anna Schumaker 2e67a645c8 design updates
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:01 -04:00
Anna Schumaker 782bcf0143 gui: Compress some of the model functions
This is to have a single function to set the user pointer value.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:01 -04:00
Anna Schumaker 6706a998ca gui: Improve sorting visuals
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:01 -04:00
Anna Schumaker 2962d792d7 playqueue: Add flags to disable sorting
The history playqueue should never change sort order, so use this flag
to prevent user changes.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:00 -04:00
Anna Schumaker 6a227df41b playqueue: Write library sort order to disk
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:00 -04:00
Anna Schumaker f83f8d47fa gui: Click columns to sort
I set up a 3-second timeout to decrement the count.  When the count is
at 0, I reset sorting on the playlist.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:00 -04:00
Anna Schumaker d430e09a59 playqueue: Generic sorting
I don't save the sort order yet.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:00 -04:00
Anna Schumaker 8ab973cd85 gui: Play tracks when rows are selected
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:00 -04:00
Anna Schumaker 6659f18de3 audio: Load tracks by trackid
Used to select specific tracks to play.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:00 -04:00
Anna Schumaker d434b7ebbb playqueue: Sort by a generic list of fields
Eventually I'll be able to click on column headers to change the sort
value.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:00 -04:00
Anna Schumaker ddbbf0ea49 playqueue: Improve insertion sort with a binary search
My test was done with a library size of 8040.

Before this patch, I make 21919628 calls to my "less_than" function.
With this patch, I now make 101205 calls to my "less than" function.

This comes out to a 216-X improvement.  I should have done this sooner.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:00 -04:00
Anna Schumaker e256c24b20 playqueue: Sort playqueues if PQ_SORTED is enabled
I don't have user-configurable sorting (yet), but for now I'm sorting by
Artist -> Year -> Track #.

I also fix a bug where the library wasn't lowercasing artist, album,
genere, and track fields when reading from file.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:00 -04:00
Anna Schumaker cde7e5d96c gui: Change default page
Start on the collection page.  I eventually want to display the first
enable playqueue, though.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:00 -04:00
Anna Schumaker 1b8c55b0fc gui: Escape text before setting labels
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:00 -04:00
Anna Schumaker 00706cc33f playqueue: Add a flag to disable unnecessary callbacks
The history and collection playqueues are never saved to disk, so I only
care about saving when a flag is changed.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:00 -04:00
Anna Schumaker b490322f55 library: Don't send notifications if the library is disabled
In other words, don't add tracks to the collection playqueue if they are
disabled.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:00 -04:00
Anna Schumaker 97be413bcf gui: Add a second-stage init function for tabs
This gives them a chance to check playqueue flags after the queues are
loaded.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:00 -04:00
Anna Schumaker 018c4747a2 gui: Watch for clicks on the random button
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:00 -04:00
Anna Schumaker a98443872c deck: Save the deck whenever a queue changes
I read in the saved file when init() is called.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:00 -04:00
Anna Schumaker e7ecbeacda gui: Use the playqueue flags for displaying the random button
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:00 -04:00
Anna Schumaker a4d680b00e gui: Make OcarinaPage inherit from a vbox
Now we are passed the page on the switch_page() signal.  This saves time
iterating and comparing.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:00 -04:00
Anna Schumaker aa40f1dfd5 gui: Create a history tab
Used to show tracks that have recently played.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:00 -04:00
Anna Schumaker 6446b7e5ad audio: Access function for recent playqueue
The recent playqueue is needed for the history tab.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:00 -04:00
Anna Schumaker 7d10ebe5c3 gui: Split apart tab and tab label
I made a new tab label class to make it easier to have a few labels with
different layouts.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:00 -04:00
Anna Schumaker 9e68f8213b gui: Adjust tab sizing
Because "year" only had 1 pixel and wasn't showing up.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:00 -04:00
Anna Schumaker 60c35219c2 gui: Implement seeking
You can either click + drag the slider or use the keyboard to change the
current position.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:57:00 -04:00
Anna Schumaker 00d5258902 gui: Begin playback when pressing the next() button
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:59 -04:00
Anna Schumaker 2b57be8c66 audio: Send on_pause() callback when autopausing
Also seek to 0 when choosing the next track.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:59 -04:00
Anna Schumaker e1dbdb3ffb playqueue: Fix generated status string
- Correct spelling of "minutes"
- Don't pluralize if duration is only 1

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:59 -04:00
Anna Schumaker 3d44d20b31 gui: Fix arguments to ocarina_init()
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:59 -04:00
Anna Schumaker 05148ba832 gui: Add UI controls for changing pause status
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:59 -04:00
Anna Schumaker 1c99042efd audio: Add callbacks for changing pause status
When the count is changed or pausing finishes, I trigger this callback
to notify the UI.  I also added in a line to enable pausing any time the
count is incremented.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:59 -04:00
Anna Schumaker c346a5860a gui: Implement control buttons
Play, pause, stop and so on.  I also update labels and progress bars
during playback.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:59 -04:00
Anna Schumaker a865ac36a3 gui: Respond to changing current tab
I display the runtime of the currently visible playqueue in the bottom
right of the screen.  When the collection manager is visible, I hide
this label.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:59 -04:00
Anna Schumaker bc3220ae85 playqueue: Generate a string representing current runtime.
I almost did this on the gui side, but then I remembered that this isn't
a trivial job.  I chose to stick with my rule: "if something can be done
in the backend then it should be done in the backend"

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:59 -04:00
Anna Schumaker 0f11ba0ee6 gui: Create a new test for the Collection tab
This is a bit cleaner that having one giant switch-statement based test.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:59 -04:00
Anna Schumaker 62a1b4dcb6 gui: Change name of library tab
Now it says "Collection" to match "Collection Manager" it was either
this or have a "Library" tab and a "Library Manager"

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:59 -04:00
Anna Schumaker 0e2cc50e7b library: Fix some bugs
- Check for path existing in the library already before adding again.
- Iterate over track database using <= for comparison, and not just <

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:59 -04:00
Anna Schumaker 078cb546f5 deck: Initialize deck before library during testing
To properly set up callbacks.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:59 -04:00
Anna Schumaker 1cf268c6bf playqueue: Implement a reset() function
Only available when CONFIG_TESTING is enabled.  Used to test clearing
the library and library playqueue for testing.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:59 -04:00
Anna Schumaker e94063473e database: Check if files exist before opening
This prevents an error message (and possible corruption) by continuing
with the open() function even if the file doesn't exist.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:59 -04:00
Anna Schumaker 36b76dcfc3 tests: Exit on test failure
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:58 -04:00
Anna Schumaker 22cb20d4ce audio: Change state to NULL before quitting
This prevents a possible hang when de-initializing gstreamer.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:58 -04:00
Anna Schumaker aa21ab5602 file: Strip leading whitespace when reading strings
This was a bug I discovered when double clicking on paths in the
collection manager to change the path in the FileChooserWidget.

Before this patch, strings could be read as:
	<string> /home/anna/Music</string>

Now, the same string will be read as:
	<string>/home/anna/Music</string>

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:58 -04:00
Anna Schumaker b50aaa8d9e build: Rename CONFIG.ENV to CONFIG.CCFLAGS
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:58 -04:00
Anna Schumaker 3d1e8872d3 gui: Create a common ocarina_init()
To initialize the needed backend modules, shared by normal main() and
testing main().

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:58 -04:00
Anna Schumaker e0770030d5 library: Load all databases
For some reason I was only loading the library_db, and ignoring the
others.  I fix this, and send out callbacks for each track loaded.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:58 -04:00
Anna Schumaker 2ecb37f6dc Everything for a custom Gtk::TreeModel
I implemented an entire Gtk::TreeModel in this commit, plus some minor
supporting code in the library to look up playlist entries by index.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:58 -04:00
Anna Schumaker 6c58f9bc2f gui: Create a treeview and add columns
I haven't created the model for the treeview yet, but it's coming!

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:58 -04:00
Anna Schumaker a0067c4542 gui: Respond to playqueue changed callbacks
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:58 -04:00
Anna Schumaker 42d57567e0 callbacks: Add callbacks for playqueue size modifications
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:58 -04:00
Anna Schumaker ea687408aa gui: Begin developing playqueue tabs
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:58 -04:00
Anna Schumaker 2724b90281 gui: Add initial extra notebook tab
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:58 -04:00
Anna Schumaker f80203c5fe gui: Delete and disable library paths
The signal connections for these features are really difficult to test
programmatically, but I can test the effects by calling each function
directly.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:58 -04:00
Anna Schumaker f51ba3e3ec library: Create a function for enabling and disabling paths
I also update the deck tests, since this is where changes will show up.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:58 -04:00
Anna Schumaker ae91d33baa gui: Show files in filechooser
I had these hidden so the users really, really know that they are
supposed to select directories.  Now I've made it easier to browse the
filesystem through the Collection Manager, so hiding files doesn't make
sense.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:58 -04:00
Anna Schumaker 99799bcc32 design: Add future ideas
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:58 -04:00
Anna Schumaker a077b8cbad gui: Change directory on row double click
This allows a user to explore what has been added in each of their
library paths.  Right now I filter for directories only, but it may be a
good idea to change this in the future.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:58 -04:00
Anna Schumaker 31af8482de gui: Adjust widget spacing
I add a little bit of spacing between widgets so they're not so crowded
together.  I also adjust things away from the edges of the window
because I tihnk it looks better this way.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:58 -04:00
Anna Schumaker 74da7beba1 deck: Add a library playqueue
When no songs are on the deck a track will be played from the library.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:58 -04:00
Anna Schumaker 25ee2e945c library: Add callbacks for adding and removing tracks
Useful for keeping a library playqueue up to date.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:58 -04:00
Anna Schumaker 2535a2fe56 playqueue: Add a way to delete rows by track_id
This will be used to delete tracks that no longer exist in the library.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:58 -04:00
Anna Schumaker 4c16f8370b gui: Listen for current library callbacks
This adds support for callbacks telling us when a new library path is
added and when a path has been updated.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:58 -04:00
Anna Schumaker c2e7772ebe callbacks: Add initial callbacks
This patch adds library callbacks for adding a new path and for updating
tracks in a path.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:58 -04:00
Anna Schumaker 11704b2bfa gui: Add some collection manager tests
Test ok, update, and import buttons in a Glib::timeout based simulator.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:58 -04:00
Anna Schumaker eff294a7c7 library: Added an update_all() function
To update all paths in a library.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:58 -04:00
Anna Schumaker becf7f94bc gui: Begin implementing the gui
This adds the ocarina6.glade file and code for clicking the library
import button.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:58 -04:00
Anna Schumaker bb7c3b334a audio: Update expected output file
Somehow I missed this during my updates earlier.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:58 -04:00
Anna Schumaker dcadcf61ab Git should ignore glade recovery files
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:57 -04:00
Anna Schumaker c39a9058f4 tests: Update the Sconscript file
I reordered all the tests and adjusted for the subsystem renaming.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:57 -04:00
Anna Schumaker 5c5e4a1a66 audio: Implement the previous() function
To iterate backwards through the list of recently played songs.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:57 -04:00
Anna Schumaker bd2aaf73d1 audio: Updates for spec changes
This is mostly to add in checks for try / catch style error handling.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:57 -04:00
Anna Schumaker 360ebed1fa errors: Rename error codes
Gstreamer includes <errno.h>, which already defines several of these
symbols.  I rename them to avoid namespace collisions.  Perhaps a better
solution would be to use the errno.h definitions directly?

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:57 -04:00
Anna Schumaker 1d559865c8 deck: Updates for the playlist -> playqueue renaming
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:57 -04:00
Anna Schumaker 8e363fe7b2 playqueue: Add a function for resetting the current pointer
This is used for the recently played playqueue to iterate backwards when
the previous() function is called.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:57 -04:00
Anna Schumaker e889ca538f playqueue: Implement length tracking
I use this to know the running time of the playqueue, which will be
displayed on the GUI.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:57 -04:00
Anna Schumaker 82a57ec2b5 playqueue: Updates for my recent renaiming
Rename everything from playlist -> playqueue.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:57 -04:00
Anna Schumaker 98e8324a61 library: Only enable some functions if CONFIG_TEST is enabled
I was using CONFIG_DEBUG for these, but they really should be under
CONFIG_TEST for use by the testing code ONLY.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:57 -04:00
Anna Schumaker 5dd5ec6db0 library: Add a lookup_path() function
This returns a pointer to the library :: Library structure requested.
The gui will use this to display information about each path.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:57 -04:00
Anna Schumaker fa51433b94 library: Track the size of each path
I track the size of each library path for display purposes.  I also had
to add in a check for if a new track already exists in the db before
tagging it so updating a library should be much faster now.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:57 -04:00
Anna Schumaker a2665d4e41 library: Implement importing old libraries
This adds backwards-compatibility for Ocarina 5.11 libraries.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:57 -04:00
Anna Schumaker 94fdfda9fb file: Point FILE_TYPE_LEGACY to ~/.ocarina/library/
The legacy file type will only be used for importing old libraries, so
point things to this directory on construction.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:57 -04:00
Anna Schumaker 371b988dac library: Various updates
- Combine Artist and Genre struct
- Add in exceptions, rather than boolean returns
- Update the library through idle tasks

I have not implemented importing Ocarina 5.11 libraries yet.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:57 -04:00
Anna Schumaker 8d8e9262d6 library: Initial backend updates
I do not make any of the library spec changes yet, instead I update the
backend code so it compiles and still works with the changes I have made
so far.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:57 -04:00
Anna Schumaker e484653d71 design: Draft out library changes
I added in an update_all() button and combined two identical database
structures.  Hopefully this will help to clean up the code.

I also added in wording for how to use the idle queue to scan paths.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:57 -04:00
Anna Schumaker 114c22bb12 playlist: Implement reachitecting of playlists
I changed the two playlists that are supported, added in exception
handling, and removed the list() function since I will always know the
names of playlists.  I also rename everything to "playlist" from
"group".

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:57 -04:00
Anna Schumaker 914473e10a Rename playlist and group source files
Playlist -> playqueue
Group -> playlist

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:57 -04:00
Anna Schumaker ee100c0238 filter: Implement a "to lowercase" function
This function will convert the provided text to lowercase.  This really
isn't a filter function, but the filter already implements a lowercase
cache that should be useful.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:57 -04:00
Anna Schumaker acd8bd7b23 database: Implement updates to match my current design
- Force the primary key to be a string
- Throw error codes rather than 0

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:57 -04:00
Anna Schumaker ab8c15ecb7 file: Implement minor design changes
I had been returning success / failed boolean values for various
operations.  I think it's better to throw an exception in these
"exceptional" circumstances since error values can give more information
about why a function failed.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:57 -04:00
Anna Schumaker dd87ec022c gitignore updates
I want glade temporary files to be ignored by git.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:57 -04:00
Anna Schumaker e4364e6ea2 gui: Add a button for importing a legacy library
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:57 -04:00
Anna Schumaker 0760b1fecd design: Add information about testing library importing
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:57 -04:00
Anna Schumaker f7a7710482 design: Rename a few subsystems
- Playlist -> playqueue.  Playqueue sounds more temporary, which better
  represents how I intend this code to be used.
- Groups -> playlist.  A playlist is the accepted term for what I am
  trying to create here.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:57 -04:00
Anna Schumaker 31e6bcef3b design: Modifications needed by the GUI
This patch writes out various modifications the GUI will require the
back-end library to make.  This includes:

- Rename playlists to playqueues and groups to playlists.
- Make library information accessable.
- Use try/catch style errors instead of returning bool in a few places.
- Extra playqueue accessablity functions.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:57 -04:00
Anna Schumaker e1d527f077 design: Update design.txt
This matches the current state of the backend library and does not have
any tweaks for the GUI.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:57 -04:00
Anna Schumaker 2c243194d7 gui: Create a glade file
I've taken a first pass at the Ocarina 6.0 GUI.  The backend will need
some tweaking before this design can be used.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:56 -04:00
Anna Schumaker 0281a7653d libsaria: Remove libsaria
My new implementation puts everything under lib/ instead of treating the
backend library as a different project.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:56 -04:00
Anna Schumaker c65c8b06f2 audio: Implement pause after N tracks feature
This patch implements the pause-after-N-tracks feature.  I also included
various improvements to the audio code.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:56 -04:00
Anna Schumaker ee9a98737a audio: New features and improvements
- Seek(), position() and duration() functions are implemented
  - There are bugs in the test program :(
- Clean up next()

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:56 -04:00
Anna Schumaker edbdd1c66f audio: Begin implementing audio code
I have written play(), pause(), next() and seek_to() so far.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:56 -04:00
Anna Schumaker b8b215be35 deck: Save and restore the playlist deck
The read and write functions will be called by a higher up layer, so I
need to open the file manually in the test.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:56 -04:00
Anna Schumaker 83a8b5ae1d deck: Implement next()
I make sure to remove empty playlists from the deck and throw an error
if there are no playable tracks on the deck.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:56 -04:00
Anna Schumaker fecc10ab5e deck: Implement basic deck features
- Add playlists
- Remove playlists
- Rearrange playlists
- Get a playlist based on id

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:56 -04:00
Anna Schumaker 0c01751946 playlist: Implement next()
Random and sequential next, for both locked and unlocked playlists.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:56 -04:00
Anna Schumaker 168f08392d playlist: Implement read() and write()
The file will be passed in by the deck layer, since it stores multiple
files.  I just fake up a file in test_2() that is used for storing the
playlist.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:56 -04:00
Anna Schumaker 3a478ddba7 playlist: Implement playlist modification functions
I can now add and remove tracks, in addition to asking for the playlist
size.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:56 -04:00
Anna Schumaker 2d13b74c12 playlist: Create the initial playlist class
Right now it just knows the value of its flags variable.  More to come
soon!

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:56 -04:00
Anna Schumaker 9aa2bc7df1 design: Split playlist design
To keep the design readable, I split the playlist class (playlist.txt)
from the playlist deck (deck.txt).

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:56 -04:00
Anna Schumaker a3cf5daa18 library: Test adding new files to a directory
I recreate the directory deleted in test 6c and make sure everything is
added back to the database in new rows.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:56 -04:00
Anna Schumaker ff0fead24e database: Mark new entries valid based on id
I was using _size as an index into the database, but _size represents
the total number of valid rows and not the id of the new item.  If a row
is deleted _size will decrease and the wrong entries will be marked
valid.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:56 -04:00
Anna Schumaker b759b9743d library: Implement library path validation
I scan the track database and remove files that no longer exist.  I
don't yet add in new tracks found in the directories.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:56 -04:00
Anna Schumaker e0f28cb366 library: Strip whitespace from genre and tracks
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:56 -04:00
Anna Schumaker 98f97b723a library: Update test 4
I made sure it's working and updated the expected output.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:56 -04:00
Anna Schumaker a50d8f6e0a database: Allow templated keys to the database index
This allows me to have a std::pair<> as a key if needed.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:56 -04:00
Anna Schumaker eaafaeb7d4 library: Updates for new database design
I need a templated primary key system to group together albums with
years.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:56 -04:00
Anna Schumaker 99718ade43 filter: Update filter test for Index class removal
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:56 -04:00
Anna Schumaker 23d0b008e5 group: Updates for Index class removal
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:56 -04:00
Anna Schumaker 97d889531a index: Remove the index class
This patch updates the design so indexes are built upon databases using
a special IndexEntry.  I also updated the tests/index/ test to match
the new system, but I have not updated filter or group tests yet.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:56 -04:00
Anna Schumaker f0533ef663 database: Make all databases unique
I require entries to have a "primary key" that is stored in a map to
make it easy to find database rows by key.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:56 -04:00
Anna Schumaker c2bc99ad9b design: Design out the index class
I made a few modifications to the database, and introduced an
"IndexEntry" database type to do the exact same thing :)

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:56 -04:00
Anna Schumaker 3a47fc1549 Prefs: Remove preferences design
I think I can get by without this now ...

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:56 -04:00
Anna Schumaker 91dac2e6b9 Design: Various updates
Add more to the Library, Playlist and Audio design to match how I expect
the GUI to use the backend.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:56 -04:00
Anna Schumaker 4fc09978dc library: Lookup a song by id
If the id is valid, I fill out a song structure and return true.
If the id is invalid, I return false.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:55 -04:00
Anna Schumaker e314248f10 library: Find tags for each track
This is each song's track number, play count, and anything else specific
to a single file.  After updating, save all the changed databases.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:55 -04:00
Anna Schumaker 846810fa2f library: Clean up database entry creation
Passing the TagLib :: Tag pointer is much easier and cuts down on extra
arguments to each constructor.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:55 -04:00
Anna Schumaker 3f943aa1d6 library: Find album and genre tags
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:55 -04:00
Anna Schumaker 10fd3292fd library: Scan a directory
I don't build up a complete set of databases yet, but I do create the
Artist name database to use later.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:55 -04:00
Anna Schumaker 81429b0229 library: Add support for saving and restoring the library
Eventually these functions may have to become idle tasks, but for now I
write to disk whenever the library_db is changed and then read from disk
by calling the init() function.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:55 -04:00
Anna Schumaker 9ddbaf0b97 library: Implement basic path management
I can add and remove root-level directories from the library database.
I do not save the database when modified, and I don't yet run an update
on all the files.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:55 -04:00
Anna Schumaker fc3b5db59e database: Fix multiple issues
- Check if we are finding the "last" iterator in an empty database
- Better print() descriptions
- Print test return codes that aren't 0 to help find segfaults

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:55 -04:00
Anna Schumaker 8ccbad20cc database: Mark rows valid when inserted
It doesn't make sense to need to set this value outside of the database
code like I had been doing.  So when a new row is inserted mark it as
valid right away.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:55 -04:00
Anna Schumaker 6d94e78d23 database: Add a function for clearing databases
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:55 -04:00
Anna Schumaker 0d84f92d2a design: Fix up formatting
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:54 -04:00
Anna Schumaker 37d4085d27 filter: Use the index print functions
This cuts out some code that doesn't need to be duplicated.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:54 -04:00
Anna Schumaker 629cbeb2e9 index: Add a print() function
This function is used in debug mode to print the current status of the
index.  I also created a print_keys() function to only list the keys.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:54 -04:00
Anna Schumaker 79d592ed64 database: Add a function for printing
Other tests may need to print out a database.  To make this easier I've
added a print() function to the base database class.  This function will
only exist when CONFIG.TEST == True, so don't use it outside of testing!

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:54 -04:00
Anna Schumaker 38f97fb85b lib: Improve dependency resolution
Rather than doing everything in tedious if blocks written in any order,
I instead resolve dependencies using a much simpler loop.  At the moment
each module only depends on a single other module, so this will have to
be extended if I ever need multiple-dependency resolution.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:54 -04:00
Anna Schumaker 1f9ff4ae2d config: Simplify setting up initial environment
Rather than setting up all variables twice, just call reset() to
initialize everything.  *BONUS* Reset can be used to initialize the
value of CONFIG.TEST!

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:54 -04:00
Anna Schumaker 9880e98d0d tests: Improve removing old test data
I was using my own cpp file to remove old test data to start with a
clean slate.  I've decided it's easier to just remove the files before
running tests if they exist.

I also use this patch to update the test design and add an idea for the
future.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:54 -04:00
Anna Schumaker 31ea73b0d9 file: Rewrite file test
For some reason I turned the file test into three separate files. All
other tests were in a single source file, so I updated file tests to
match.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:54 -04:00
Anna Schumaker 1482f5bcc8 print: Rename test from basic/ to print/
"basic" doesn't really fit the description for what I'm testing here.  I
was expecting to do a series of unrelated tests, but all I'm really
doing it testing the print function.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:54 -04:00
Anna Schumaker dd92ee853f database: Add a way for databases to have unique keys
The library will need databases that have unique values (such as the
artist or album tables).  This patch adds support for that in my
existing database code.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:54 -04:00
Anna Schumaker b176a48c6c library: Add fake library generating script
I assign tags to the 1, 10, 60, and 600 second long ogg files as they
are copied to the new library directory.  This is much faster than
generating sound files on the fly, but it makes this commit 2.5MB in
size...

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:54 -04:00
Anna Schumaker 6a29066ac7 Update design.txt
To include changes to:
- Idle queue
- Library
- Playlist

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:53 -04:00
Anna Schumaker f417b48df8 idle: Add an idle queue
The idle queue is used to schedule tasks ... later.  This code was
mostly adoted from a reference TDD experiment by Josh Larson
(themutatedshrimp@gmail.com).  Thanks Josh!

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:53 -04:00
Anna Schumaker 5f30a71c55 group: Add good output
Don't clutter the testing step with output unless it's wrong output.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:53 -04:00
Anna Schumaker f7d95707d6 design: Update design.txt
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:53 -04:00
Anna Schumaker 7b7414c755 group: Implement basic groups support
I only handle the "All Music", "Library" and "Banned" groups at the
moment but I'll eventually add in more features (in future versions).

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:53 -04:00
Anna Schumaker c5f6716144 filter: Store good filter output
Now I don't need to see the entire test output when tests are run.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:53 -04:00
Anna Schumaker 755785799b index: Make sure we can index into keys that don't exist
This should just return a set of size 0.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:53 -04:00
Anna Schumaker c72ffeb9b9 design: Start thinking about the GUI
I still have some back-end work to do first, but I should start thinking
out what users will see.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:53 -04:00
Anna Schumaker 54f9263170 design: Update design.txt
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:53 -04:00
Anna Schumaker 2b15048777 filter: Implement text filtering
Because every programming project needs a test case centered around
Discworld quotes ...

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:53 -04:00
Anna Schumaker 379a96fe13 index: Add in save and load functionality
Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:53 -04:00
Anna Schumaker be0d3f3da4 index: Implement most of the index
I have everything except for save() and load() written.  My unittest is
fairly comprehensive and tests everything implemented so far, so with
any luck putting in save() and load() features will go quickly.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:53 -04:00
Anna Schumaker f124501c39 database: Add tests for databases without a filepath
These databases should not be saved to disk, since the user hasn't given
a valid filepath.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:53 -04:00
Anna Schumaker 412964bcf4 file: Update tests to check for empty filepaths
And make sure files follow the design by return false when opening an
invalid file.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:52 -04:00
Anna Schumaker 8ef1e2f8e6 design: Update design
- Save recent database changes
- Move the idle queue after the database
- Put file class definition notation
- Update the todo list

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:52 -04:00
Anna Schumaker 13313482d4 database: Make read() and write() functions for database entries
I had planned on using the stream operator for my database class but
this created some crazy compiler error that I was having difficulty
figuring out.  I decided to take the easy route for now and instead
create read() and write() functions that do exactly the same thing.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:52 -04:00
Anna Schumaker a5891a3338 database: Implement quick removal of items
Items will be marked "invalid" rather than directly removed from the
database.  This make it easier, since I won't need to reassign IDs to
every database item after the removed one.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:52 -04:00
Anna Schumaker 50a7c3dae6 database: Add funcions for database iteration
A database may have invalid rows.  If this is the case, then the next()
function needs to return the id of the next valid row.  I'm aware that
this could get horribly inefficient on large DBs with many invalid rows.
I don't expect people to delete large chunks of music all at once, but a
defragment tool is on my "todo" list for a future Ocarina version.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:52 -04:00
Anna Schumaker b3f5363445 database: Implement insert() and size()
I don't have the DatabaseEntry base class yet, but I will soon!

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:52 -04:00
Anna Schumaker f7a3eec35c file: Do not open files with an empty filepath
Instead mark them as invalid to keep from opening a directory instead of
a file.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:52 -04:00
Anna Schumaker fee08b1f94 database: Begin database code
I've been excited about this!  I think it'll be a better design than
what I had for Ocarina 5.x.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:52 -04:00
Anna Schumaker 857598dea7 design: Revisit the database design
Update the style and make sure everything still makes sense when reading
it.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:52 -04:00
Anna Schumaker 1cfd9588f9 design: Update idle queue design
I need a way to return the progress of the idle queue and to indicate
when it is out of tasks so idle threads can stop running.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:52 -04:00
Bryan Schumaker b248300d01 design: Move audio section
I want it listed last so I can select songs from a library or playlist
to play.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:52 -04:00
Bryan Schumaker 8c4e515145 Update copyright info
What's the point in continuing to commit as Bryan?  I'd rather commit as
me :)

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:52 -04:00
Bryan Schumaker f76021be99 tests: Remove the debug output file
I changed print to compile in the dprint() function when the testing
flag is enabled.  This allows tests to have the same output regardless
of debugging status.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
2014-04-06 19:56:52 -04:00
Bryan Schumaker a190047648 design: Add unit test library documentation
This will make it easier to keep track of what functions are available.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:52 -04:00
Bryan Schumaker 0ed8e48668 tests: Various improvements
- Don't be verbose when removing files.
- Reverse diff order so output makes more sense.
- Only strip whitespace from the end of lines.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:52 -04:00
Bryan Schumaker 328c6f70e8 file: Implement reading and writing
- Inherit from fstream to gain access to << and >> operators.
- Make the file version accessable to the outside world.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:52 -04:00
Bryan Schumaker ecd56831f6 file: Open and close files
- Support OPEN_READ and OPEN_WRITE
- Update the design to accomidate for error checking
- Add lib/test.cpp containing basic functions that can be used for
  testing

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:52 -04:00
Bryan Schumaker e0a32c10ac lib: Add basic file class
The class resolves the path to the ocarina directory based on the file
hint provided.  NOTE: compile-debug.good and compile.good resolve paths
to my home directory.  Other users will need to change the values for
the test to pass.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:52 -04:00
Bryan Schumaker 307bc88cb6 design: Update file design
I'm starting to implement file access.  I've reread the design and
updated a few things to make it easier to test.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:52 -04:00
Bryan Schumaker 72c7261ac8 design: Sort potential nodes by name
This will give some better stability to the design document, since
entries won't shift around based on python memory locations.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:52 -04:00
Bryan Schumaker c65e0bdb2a build: Change CONFIG_* variables into a class
The class is in charge of resetting fields at will, and will be able to
maintain everything easier than if I were to do it by hand.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:52 -04:00
Bryan Schumaker 13a0d25e8f build: Only create a single build environment
I was using a debug and a release environment for programs, that way
both versions of tests could be checked.  Instead, it'll be simpler to
only use a single environment and then control debug information using
CONFIG_DEBUG.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:51 -04:00
Bryan Schumaker e13b4afa60 design: Break doc into pieces
Each component has its own text file.  I merge everything together with
simple dependency resolution so I can figure out implementation order
easier.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:51 -04:00
Bryan Schumaker b5d3a663e0 print: Print the Ocarina version to a file
The basic/print.cpp test will write version information to a file using
both dprint() and print().

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:51 -04:00
Bryan Schumaker 7c67d062df build: Make it easier to change command line macros
I store release and debug options in a list so that env.Replace() can be
used to set, modify, and restore values.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:51 -04:00
Bryan Schumaker cf7f1f726f build: Rename config variables
I'm giving them a CONFIG_ prefix.  I also made version.h a real file
that uses a config variable.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:51 -04:00
Bryan Schumaker 38c074d898 build: Improve aliasing for tests
scons tests - Compile all tests
scons tests/basic - Compile basic tests
scons tests/basic/print - Compile text printing test

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:51 -04:00
Bryan Schumaker d8c8ea1bbf Design: Put in idle queue information
This is needed for scheduling files to load later.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:51 -04:00
Bryan Schumaker f75ba5a2b8 tests: Add a basic test
This test checks for the version.h file and then compiles it with and
without debugging enabled.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:51 -04:00
Bryan Schumaker 101648dc0a Remove old include files
I'm going to replace them with new files for Ocarina 6.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:51 -04:00
Bryan Schumaker 15df2ed075 Remove newgui
I'm not going to use this code anymore.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:51 -04:00
Bryan Schumaker 04d4aca772 Design: Add version and printing info
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:51 -04:00
Bryan Schumaker 0b2fc03f19 design: Rework playlists, add filtering
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:51 -04:00
Bryan Schumaker b786b44a49 design: Add in gstreamer thoughts
Because a music player should be able to play music :)

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:51 -04:00
Bryan Schumaker 310c9ad395 Design: Create a preferences namespace
This will be used to store various values for the user.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:51 -04:00
Bryan Schumaker 5312853b86 Design: Create a File class
This class will manage save files so paths don't need to be resolved in
multiple places.  I'll also use it for reading and writing with version
information.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:51 -04:00
Bryan Schumaker fc40a9f77f Design: Update groups
Groups now use an index to manage their data.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:51 -04:00
Bryan Schumaker 5a7fcdb305 Design: Create an index class
This will be used for groups, both stored and temporary.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:51 -04:00
Bryan Schumaker 08b0513578 Improve on file format text
I think it's cleaner now.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:51 -04:00
Bryan Schumaker 59f08cfc51 Design: Update library information
I decided to put the library into a namespace to keep the code clean.  I
also added an update algorithm and made minor naming changes.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:51 -04:00
Bryan Schumaker 2ea1ea8d26 Database design
I've decided to make my own "database" tailored for things I need to do.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:51 -04:00
Bryan Schumaker 80e00dd914 Design: Rethink groups and add in future ideas
I renamed "tags" to "groups" to avoid confusion with ID3 tags.  I also
thought out a better plan for eventually implementing user defined tags
so that I can build up to them with testing along the way.  With any
luck, I won't overwhelm myself with features =).

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:51 -04:00
Bryan Schumaker 2b145f2dab Update design
I remembered that I don't like SQL, so managing my own library database
is probably better.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:51 -04:00
Bryan Schumaker b7ee8a0f78 design: Work on playlist design
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:51 -04:00
Bryan Schumaker e4fa2155b9 Start a design document for Ocarina 6
Up until now I've just been coding whatever I feel like without thinking
about it too much.  This time I'm actually going to come up with an
ocarina design and then implement it according to the document.  The doc
can then act as a reference for how and why things are done for future
work.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:51 -04:00
Bryan Schumaker 7dc88a1e46 newgui: Capture key presses on the window
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:51 -04:00
Bryan Schumaker 3c60dbdbae newgui: Set a window title and icon
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:51 -04:00
Bryan Schumaker 5eb24ee04f newgui: Load the gtk builder file
Right now it's just a toplevel window.  I also added a script for
launching the new gui without needing to manually set the environment
variable.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:50 -04:00
Bryan Schumaker f6cb19145d libsaria: Remove app name from init data
I only have one application so there is no point in having a way to
create multiple application directories.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:50 -04:00
Bryan Schumaker 14432e216d newgui: Create and display a window
Nothing to complicated yet.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:50 -04:00
Bryan Schumaker 78e9c744fd newgui: Start rewriting the gui
The plan is to port everything to gtkmm since using the C functions is
beginning to get annoying.  Compile the new code using `scons newgui`
for now.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:50 -04:00
Bryan Schumaker e4d73fee48 libsaria: Rename IdleTask::run_task()
I think that just calling it run() is better.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:50 -04:00
Bryan Schumaker 9c72e56261 libsaria: Remove idle::do_task()
It's a 2 line function that was used in only one place.  Time to remove
it and simplify the surrounding code.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:50 -04:00
Bryan Schumaker 2f2c9cdf68 libsaria: Move idle.cpp to libsaria/
The idle queue code is all one file now, so it can exist directly in libsaria/

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:50 -04:00
Bryan Schumaker 5bc357be18 libsaria: Remove operator[] for strings
Public member variables is easier.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:50 -04:00
Bryan Schumaker d79eefc8b2 libsaria: Remove operator[] for uint values
Public access to variables is easier.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:50 -04:00
Bryan Schumaker 29718ceb12 libsaria: Remove operator[] for int values
Public access to these variables is easier.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:50 -04:00
Bryan Schumaker 56dd54f114 libsaria: Remove operator[] for Track.banned
Public access to this variable is simpler and probably more efficient.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:50 -04:00
Bryan Schumaker aaf1205078 libsaria: Make some track variables public
This should be easier than making a bunch of getters or setters.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:50 -04:00
Bryan Schumaker 05bbad5444 libsaria: Resizing a vector invalidates pointers
I was keeping a vector of objects, and then pass pointers to these
objects around everywhere.  HOWEVER, when vectors are resized they
allocate new memory and copy things over invalidating iterators and
pointers to the original objects.  This can cause memory corruption
issues when I try to use a pointer to an object that no longer exists.

The simple solution?  Allocate tracks dynamically and then store the
pointer in the library path.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:50 -04:00
Bryan Schumaker c094f9791f libsaria: Set correct library version
Otherwise we'll only read the first 124-ish songs and then stop...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:50 -04:00
Bryan Schumaker 9043183807 libsaria: Remove old idle task stuff
I handle the idle task stuff inside the idle layer, hiding it from
everything else.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:50 -04:00
Bryan Schumaker 1ac51775c3 libsaria: Remove ReadTask
I replaced it with the generic idle task I just created.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:50 -04:00
Bryan Schumaker 5244fe9605 libsaria: Begin work on a new generic idle task
I want to remove the various idle task types that have built up and
replace everything with a single idle type.  I also want the idle layer
to be the only place new tasks are allocated.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:50 -04:00
Bryan Schumaker b6e0d6dd58 libsaria: Remove my custom linked list class
Now that I'm using vectors for everything I don't need to maintain my
own class.  Nothing uses it now, so it can be safely removed.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:50 -04:00
Bryan Schumaker 36e9995bb9 libsaria: Use vectors to store the track list
For each library path, I replace the linked list with a vector allowing
me to easily index into the list to find tracks.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:50 -04:00
Bryan Schumaker 592a924881 libsaria: Change the path_list to a vector
For easier lookups.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:50 -04:00
Bryan Schumaker 8f7a610d6d libsaria: Remove DataState optimization
It made sense at the time, but I'm not convinced the added complexity is
actually worth it.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:50 -04:00
Bryan Schumaker b7a21789b6 libsaria: Pass around more const strings
This allows me to pass them by reference, it should be a bit more
efficient.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:50 -04:00
Bryan Schumaker 0b9beac1c3 ocarina: Include bash completion script as part of build
I can't believe I forgot this...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2014-04-06 19:56:49 -04:00
Bryan Schumaker 8f10d75fac Ocarina 5.11.1
- Pass escaped URIs to gstreamer.
- Fix `scons release` for bugfix releases.
2012-12-06 19:36:21 -05:00
Bryan Schumaker fa812ece74 Correct `scons release` for bugfix releases
This corrects the package build to look for a tarbal named
"ocarina-5.11.1.tar.gz" instead of "ocarina-5.11.tar.gz"

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-12-06 19:35:54 -05:00
Bryan Schumaker 9370ef34a1 libsaria: Escape filepaths passed to gstreamer
Otherwise songs might error out part way through playing and skip to
something else.  It doesn't make sense and I wish I knew why :(

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-12-06 19:28:43 -05:00
Bryan Schumaker b2226d926e Ocarina 5.11 2012-11-22 10:14:34 -05:00
Bryan Schumaker a4b154765f libsaria: Send a PLAYLIST_CHANGED notification when loading
To tell the UI what gui settings need to be changed.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-11-22 09:50:06 -05:00
Bryan Schumaker 98934ff42d libsaria: Move the rest of the deck code over
I also clean up the garbage collect code a bit.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-11-18 12:27:14 -05:00
Bryan Schumaker acb0334122 libsaria: Move deck::next() to deck.cpp
And extra variables / functions needed by next().

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-11-18 12:03:26 -05:00
Bryan Schumaker 3a486082af libsaria: Move recent playlist to the new deck file
I also created a new playlist flag for unique playlists so I don't need
to handle this elsewhere.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-11-18 11:45:10 -05:00
Bryan Schumaker b091df8ec4 libsaria: Load playlists to a new playlist_deck vector
The vector should be simpler than a linked list for tracking playlists.
I also changed reading playlists to use a function in the playlist class
rather than a function outside of the playlist.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-11-18 11:15:18 -05:00
Bryan Schumaker 27b2e386f0 libsaria: Begin a new deck.cpp file
I'm going to gradually move this out of the playlist/ directory since it
doesn't really belong there.  I also plan on cleaning up / rewriting
much of the code as I go along.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-11-18 10:20:31 -05:00
Bryan Schumaker fa09d53d70 libsaria: Remove my custom List class from the idle queue
I plan on removing this class in favor STL classes.  I probably
shouldn't have even tried to implement this myself...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-11-18 09:53:43 -05:00
Bryan Schumaker 57bf98972d libsaria: Simplify finding audio position and duration
I don't need the extra static function calls since they're only called
once.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-11-11 15:26:57 -05:00
Bryan Schumaker e16b70fd81 libsaria: Make audio variables static
Everything is in a single file...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-11-11 14:46:29 -05:00
Bryan Schumaker 9122568d8a libsaria: Remove audio::durstr()
Nothing used it anymore, so it can be removed.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-11-11 14:34:29 -05:00
Bryan Schumaker ab002e0a7f libsaria: Move audio.cpp to the libsaria directory
All the code is in a single file now so a subdirectory is unnecessary.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-11-11 14:31:30 -05:00
Bryan Schumaker 56f15b4c44 libsaria: Fold most audio code into a single file
This puts everything together and should help me remove the
subdirectory.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-11-11 14:30:30 -05:00
Bryan Schumaker 7557acc239 libsaria: Strip out old gstreamer code
Most of this was commented out and hasn't been used in almost a year.
The new gstreamer code doesn't have the property probe feature anymore,
so I can't reimplement my old alsa code.  I'll drop it for now and
figure it out later (after cleaning up this other code).

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-11-11 14:19:36 -05:00
Bryan Schumaker 83f8b1e543 libsaria: Don't use random if playlist size == 1
This could cause a floating point exception when I mod-by-zero...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-11-11 14:03:53 -05:00
Bryan Schumaker 1205a94aa7 ocarina: Adjust scroling with j and k
When scrolling I think it's important to show a few rows that are coming
up next so users know they can stop scrolling and not need to reverse.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-11-08 08:11:19 -05:00
Bryan Schumaker 5e456ad64c libsaria: Tune random next()
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-11-08 08:10:17 -05:00
Bryan Schumaker beb9019057 libsaria: Switch to gstreamer 1.0
Gstreamer 1.0 has been out for a while and replaces gstreamer 0.10.
Let's make sure we use the most recent version going forward.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-11-08 08:09:05 -05:00
Bryan Schumaker 33c80788b8 libsaria: Rewrite playlist filtering
I used to use my own inverted index implementation, which makes sense if
I'm searching all songs for a specific match.  Instead, GTK was visiting
each track and asking "does this song match?" and this requires a
different implementation.  So rather than make an index, instead I have
each track generate substrings for its tags and then I compare filter
text against the substring set.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-11-04 09:17:22 -05:00
Bryan Schumaker f65416ed2c libsaria: Clean up playlist header file
There was an undefined function and an unused protected section.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-11-03 23:14:36 -04:00
Bryan Schumaker e1930b0c88 libsaria: Create functions for checking and setting flags
I also replace a few PLAYLIST_* notifications with a generic
PLAYLIST_CHANGED notification for when small changes occur.  I think
that using set_flag() and check_flag() will make code cleaner and easier
to maintain.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-11-03 22:58:26 -04:00
Bryan Schumaker 0744aaad45 libsaria: Send track updated notifications after sorting
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-11-03 22:11:29 -04:00
Bryan Schumaker 671dd7eb3a libsaria: Remove PLAYLIST_SIZE notification
Instead, the UI should change the size during PLAYLIST_ADD and
PLAYLIST_RM.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-11-03 21:58:53 -04:00
Bryan Schumaker a6fa805a53 libsaria: Move next() into playlist.cpp
I don't want to keep one function in a file by itself.  Instead, let's
just move it into the main playlist file.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-11-03 21:48:29 -04:00
Bryan Schumaker 1e23389b51 libsaria: Remove old playlist.h
Nothing uses this file anymore, so it can be safely removed.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-11-03 21:46:51 -04:00
Bryan Schumaker e116025754 libsaria: Fix playlist bulk insert
My "insert while sorted" code was getting complicated, and didn't send
all the notifications to the UI (only the first ~1200 songs were
displayed).  This patch both simplifies the code and produces the right
answer without a noticable performance penalty.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-11-03 21:43:52 -04:00
Bryan Schumaker d345d3211f libsaria: Remove the old remove_track_it() function
I can make this simplier by simply passing the index into the vector,
rather than needing to calculate the iterator and pass the index.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-11-03 17:03:16 -04:00
Bryan Schumaker 52c09ddb12 libsaria: Don't track playlist length
There is no reason to track this on my own, iterating over all tracks
and calculating it on the fly is easier and basically unnoticable.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-11-03 15:59:54 -04:00
Bryan Schumaker d9e343895c libsaria: Clean up picking the next song from a playlist
I don't need to iterate through a linked list to find the track anymore.
Instead, I can access tracks directly using an index.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-11-03 15:36:09 -04:00
Bryan Schumaker cf8ded7d5d libsaria: Remove name field from playlists
I know what playlists are library, recent and banned.  All others are
just named "Playlist" so there is no need to set up a name variable.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-11-03 15:34:13 -04:00
Bryan Schumaker b98373c0fa libsaria: Convert Playlist class to use a vector
Vectors are more straightforward than linked lists and they should allow
me to clean up the code a lot.  For now I just put in the straight
conversion, I'll clean things up in future patches.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-11-02 23:00:20 -04:00
Bryan Schumaker c67222ab95 libsaria: Remove remaining PlaylistRenderer code
I didn't realize this was still around.  It should be removed since I
switched to a notification system instead of using the renderer.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-11-02 21:43:32 -04:00
Bryan Schumaker 0a4e4d9085 libsaria: Use [] to access track string properties
This finishes the job I started in the last commit.  Once again, I use
an enum of string properties to determine the right field to return.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-10-31 17:42:57 -04:00
Bryan Schumaker a606830f7b libsaria: Use [] to access track properties (not string)
Rathen than using a bunch of get_PROPERTY_NAME() functions, I think it's
cleaner to use dictionary-like indexing to access properties.  This
patch converts most track access functions, but I haven't gotten around
to strings yet.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-10-31 17:29:12 -04:00
Bryan Schumaker 21313e9b52 ocarina: Add a sort button
I also respond to the PLAYLIST_SORTED notification so we do the right
thing when loading a playlist during startup.  I don't put the sort
button on the library, recent list or banned list because I don't think
these lists should ever be sorted.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-17 08:18:13 -04:00
Bryan Schumaker 9933b31353 libsaria: Sort the playlist when setting PL_SORT
Otherwise the flag seems to have no effect until new songs are added.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-17 08:16:59 -04:00
Bryan Schumaker d785b91c46 ocarina: Add a random button to playlists
I reused my old dice png from several releases ago.  This implements the
"switch a playlist from set to queue and back again" feature that I
wanted.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-16 10:34:46 -04:00
Bryan Schumaker 848faa2bc6 libsaria: Move library random into a preference variable
Rather than hardcode this as a flag, if I set this through the
preferences code users can change the value.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-16 10:28:56 -04:00
Bryan Schumaker bf5b8a3bdd libsaria: Remove PlaylistType in favor of flags
Flags let me manually set properties after the playlist has been
created, rather than needing to decide upfront with no way of converting
to something else.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-14 20:25:09 -04:00
Bryan Schumaker a730eaa2cc libsaria: Remove other playlist types
They were nice for queue vs set, but I'd rather just reintroduce the
random button.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-14 16:55:02 -04:00
Bryan Schumaker 64b5b78a42 libsaria: Move the next() function into the Playlist class
I plan on removing the extra playlist classes to simplify code a bit, so
this function needs to be implemented for everything.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-14 16:38:33 -04:00
Bryan Schumaker 0600556ca4 libsaria: Replace add_track() and friends
I created simpler functions using the push_front() / push_back() names
that stl uses.  If we're a set-type playlist, then call the
insert_sorted function instead.  I also remove unnecessary bulk-inserts
of a single track.  Packing and unpacking a list each time seems stupid.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-14 16:22:50 -04:00
Bryan Schumaker a8f18478fa libsaria: Turn recent playlist into a MRU list
Basically, don't list duplicates.  If a song on the list is added again,
instead I move it to the top of the list.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-14 13:31:59 -04:00
Bryan Schumaker fc7a27c99f ocarina: Change the ban button to my old thumbs up / thumbs down image
These images still work, and banning songs is the reason that I found
them in the first place!

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-13 22:47:33 -04:00
Bryan Schumaker 31339bed2f ocarina: Add in bash command completion
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-13 22:47:33 -04:00
Bryan Schumaker 8a08967a48 Simplify remote commands
- Read a command from the pipe, rather than reading a file with a
  command in it.
- Use a single ocarina script for all commands, rather than several two
  line scripts.
- Change ocarina.bin to point to ocarina instead of ocarina-player for
  convenience.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-13 22:47:31 -04:00
Bryan Schumaker 4bf66921df Improve build scripts
The build system hadn't been touched in a while, so it needed some
cleaning up.  I moved ocarina-specific files into the ocarina/ directory
and use the ocarina/Sconscript to set up build commands.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-13 22:14:50 -04:00
Bryan Schumaker 11b421dfbb Remove old screenshot directory and image
THese are screenshots from 2010 and the early Ocarina 4.x days, so
they're somewhat out of date...  I also remove a crude ocarina icon that
I'm surprised is still around.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-13 19:42:08 -04:00
Bryan Schumaker 0d2191da13 libsaria: Remove path/
This was old code that had been replaced by fs.cpp months ago.  I must
have forgotten about removing the rest of it...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-12 08:27:06 -04:00
Bryan Schumaker 258875bdb8 libsaria: Move header files out of include/libsaria/
Ocarina no longer has a header file subdirectory so there is no reason
to have a libsaria subdirectory anymore.  Putting header files directly
in the include/ directory is a bit simpler.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-12 08:15:31 -04:00
Bryan Schumaker 267d6084d1 Begin Ocarina 5.11 2012-09-12 07:59:07 -04:00
Bryan Schumaker d59402b6b8 Ocarina 5.10 2012-09-10 08:05:04 -04:00
Bryan Schumaker 97fbd569e9 ocarina: Show and hide the recent and banned lists
Users may not always want to see them, and now I don't have an empty
"settings" tab.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-09 13:44:01 -04:00
Bryan Schumaker a9d875e05e libsaria: Better prefs::init() function
The preference may be set to zero by the user but default to a non-zero
value.  This can cause frustration on both the user and developer ends.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-09 13:42:05 -04:00
Bryan Schumaker 83e3763083 libsaria: Remove songs from the library playlist when they are reaped
It's useful to keep the UI in sync with the backend...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-09 12:58:41 -04:00
Bryan Schumaker 4d764eeb00 libsaria: Add tracks to the lib_playlist when scanning
I was trying to add an empty list, rather than track items.  This caused
the library count to increase (on the library path tab), but the library
playlist was never given track pointers so you had to restart ocarina to
see songs.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-09 12:48:12 -04:00
Bryan Schumaker 3df9d153f6 ocarina: Reenable the named pipe
I eventually want to use a unix socket so I can get bidirectional
access.  For now, I'll just reuse the old code.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-09 10:54:50 -04:00
Bryan Schumaker 42c6bdff0e ocarina: Created add-to-playlist menu items
For people who don't like keyboard shortcuts...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-08 10:09:57 -04:00
Bryan Schumaker 55cfdc5dba ocarina: Add a playlist right-click menu
Used to create new playlists, exactly the same as the menu in Ocarina
5.9.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-08 09:28:28 -04:00
Bryan Schumaker 5be817167b ocarina: Return index of searched track
And not the index of the current iterator.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-06 12:02:15 -04:00
Bryan Schumaker 442b6ffa50 ocarina: Change default window dimentions to (900, 600)
The 8:6 ratio looked ok, but 9:6 removes scrollbars with my current
font settings.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-06 11:59:08 -04:00
Bryan Schumaker 96ace25ffe ocarina: Respond to j and k even if treeviews aren't focused
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-06 11:52:31 -04:00
Bryan Schumaker 3acbbb048e ocarina: Focus the window when changing tabs
This prevents the entry widget from gaining focus when switching tabs.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-05 09:32:46 -04:00
Bryan Schumaker 11b685aeb0 libsaria: Remove playlist renderer
I have notifications to handle everything the renderer used to do, and
I've removed it from the UI side.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-05 09:22:43 -04:00
Bryan Schumaker 68aa523ba8 ocarina: Delete dynamically allocated playlist widgets
Plug the memory leak.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-05 09:18:46 -04:00
Bryan Schumaker 097b157c10 ocarina: Pass a playlist to set_length_label()
current_widgets() works based on the current tab number, and the
"switch-page" signal is triggered BEFORE the current page is updated in
the GtkNotebook structure.  This means that I was actually setting the
length based on the previous tab, and not the new one.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-05 09:15:58 -04:00
Bryan Schumaker 5f1fb2290a ocarina: Remove old playlist code
ocarina/playlist/ was the last subdirectory remaining in the ocarina
code, and I can finally remove it.  Thank you GtkBuilder!  At this
point, there is only one ocarina header file, so I move it to the main
ocarina directory.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-05 09:13:47 -04:00
Bryan Schumaker ef55c2f44a ocarina: Check if 0 songs were added to a playlist
If nothing was selected then we should tell the window to change tabs
instead.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-04 10:49:36 -04:00
Bryan Schumaker 7d4977aab8 ocarina: Delete selected songs from playlists
If the current playlist is the library or banned list, I toggle the
banned state.  Otherwise, I remove them from the current playlist.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-04 10:48:48 -04:00
Bryan Schumaker ba9ecd258b ocarina: Pass key presses directly to the playlist
This lets me remove the "if treeview is focused" special cases that keep
popping up in the window keypress handler.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-04 10:17:57 -04:00
Bryan Schumaker 88ea380f9c ocarina: Activate treeview rows when pressing enter
I already use "Return" for focusing the treeview from the main window or
from the filter entry.  If the treeview is already focused, I have it
begin playing whatever song is under the cursor.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-04 09:30:20 -04:00
Bryan Schumaker 50b4198001 Add a PLAYLIST_DISABLE notification
Disabled playlists are ignored when picking the next song.  I grey-out
the widgets on the UI when this notification is received.  I keep
filtering enabled this time (the entry was disabled too in Ocarina 5.9)

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-04 09:21:02 -04:00
Bryan Schumaker 3bb8053ea2 Add a close button to temporary playlists
I put it on the tab page this time, instead of in the tab label.  I
don't want wide tab labels, so I should eventually come up with a way of
closing playlists without having to change tabs.  Maybe a right-click
menu?

I also noticed that the libsaria delete_playlist() code didn't work, so
I simplified it a bit.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-03 13:34:06 -04:00
Bryan Schumaker e57b2891e6 ocarina: Clean out some unused playlist code
And comment out things I want to keep as reference so that things
compile.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-03 12:40:02 -04:00
Bryan Schumaker c46671b1fb Create a PLAYLIST_GOTO notification
To move the cursor to the current song.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-03 12:14:54 -04:00
Bryan Schumaker 9fb1d05376 Remove PLAYLIST_FILTER notification
It's easier to refilter automatically after setting the filter text,
rather than going through a bunch of function pointers to change the filter.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-03 11:02:46 -04:00
Bryan Schumaker 0290ea8710 ocarina: Bugfix the j and k keys a bit
Don't try to navigate when there are no visible tree views...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-03 10:33:27 -04:00
Bryan Schumaker 04b4967275 ocarina: Filter entries respond to the enter key
I use it to focus the treeview, basically the same thing the window
keypress handler does.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-03 10:09:47 -04:00
Bryan Schumaker ee7d9fa8ff ocarina: Remove old window.cpp code
It was commented out and unused.  I also commented out the "Unhandled
key: " message to keep from filling up terminal screens when treeviews
respond to a keypress.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-03 10:08:45 -04:00
Bryan Schumaker ab2ba772fe ocarina: Use j and k for treeview navigation
This makes me even more vim-like!

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-03 09:59:29 -04:00
Bryan Schumaker 9b996a7bb1 ocarina: Store window height in ocarina.window.h
Width was a typo...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-03 09:55:38 -04:00
Bryan Schumaker df79e67f12 ocarina: Add songs to currently created playlists
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-03 09:24:18 -04:00
Bryan Schumaker 992539798b ocarina: Unselect rows when pressing the Escape key
The first time Escape is pressed, rows are unselected.  The second time
Escape is pressed, the toplevel window is selected.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-03 09:07:41 -04:00
Bryan Schumaker 9365881cb4 Reorder playlists
The user can drag-and-drop tabs to change their order in the libsaria
playlist deck.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-02 23:39:08 -04:00
Bryan Schumaker b125fa2595 ocarina: Store PlaylistTabs in a variable
This way I don't need to keep calling get_widget() and then casting to a
notebook.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-02 13:38:54 -04:00
Bryan Schumaker 5bce295251 Add a PLAYLIST_DELETE notification
Triggered when a playlist is garbage collected so the UI can remove the
tab.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-02 13:35:48 -04:00
Bryan Schumaker 95d8d83fa0 ocarina: Don't track currently focused entry
It's easier to check the widgets on the current page.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-02 13:06:23 -04:00
Bryan Schumaker 84ff25b3be ocarina: Add new playlists to front and back
I was waiting until I could renumber and rearrage tabs to do this.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-02 13:06:23 -04:00
Bryan Schumaker 26e818cc21 Send a PLAYLIST_RENUMBER notification
I do this when playlists are renumbered, I also move tabs around to
match their new numbers.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-02 13:06:18 -04:00
Bryan Schumaker d27a1fb7ba ocarina: Implement switch-to-page-n keyboard shortcut
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-02 12:20:43 -04:00
Bryan Schumaker 5c09db59a6 Create dynamic playlist tabs
Instead of using a "on_new_playlist()" function, I now use the
notification system to tell the gui that a new playlist has been
created.  For now I just put it on the front of the tab list.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-02 12:09:01 -04:00
Bryan Schumaker 370f6a6832 ocarina: Programmatically create tabs
Dynamic playlists are going to need to run the same code to generate
playlist tabs as the static tabs.  Since I don't know how to use
GtkBuilder fragments, instead I write the code for generating each page.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-02 11:11:20 -04:00
Bryan Schumaker 10cdc5248a ocarina: Move some playlist setup to playlist.cpp
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-01 12:35:56 -04:00
Bryan Schumaker fc5fe427a7 ocarina: Disable treeview searching
I have filtering to perform searches, so this gtk feature can be
disabled.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-01 12:21:13 -04:00
Bryan Schumaker 5a4b9df2b2 ocarina: Split playlist.cpp into two files
One for managing the notebook tabs (tabs.cpp) and one for managing a
specific playlist page (playlist.cpp).

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-01 12:21:11 -04:00
Bryan Schumaker e6c44bf1a9 ocarina: Respond to "Return" as a shortcut
I think it'll be useful to change focus to the current treeview through
a shortcut.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-01 10:37:08 -04:00
Bryan Schumaker 694bcb83d7 ocarina: Removed dead code from window.cpp
Most of this was already commented out, but I also took the time to
figure out what header files are no longer needed.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-01 10:28:04 -04:00
Bryan Schumaker 0d5941d72f ocarina: Only print out unhandled keys
I'll know if a shortcut key is pressed, so I only want to print out
unhandled keys so I know their names.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-01 10:25:42 -04:00
Bryan Schumaker 5a9f4f4bca ocarina: Add shortcuts for switching directly to a playlist
Since I don't have dynamic playlists re-implemented yet, I just swtch
between the library, recent, and banned playlists.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-01 10:18:46 -04:00
Bryan Schumaker be67f81782 ocarina: Respond to "slash" keypress
This allows easier access to the filter entry, since clicking it is too
slow.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-01 10:04:52 -04:00
Bryan Schumaker a2e0375ac9 ocarina: add a current_widgets() function
I use this to find the set of widgets associated with the current
playlist page.  This also makes current_playlist() easy, since I can
just return the playlist from the widgets struct.  I also moved these
functions to the top of the file so the filter entries can eventually
set focus when "slash" is pressed.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-01 10:01:10 -04:00
Bryan Schumaker 55431421bf ocarina: Reenable some keyboard shortcuts
I have to track if a filter-text entry has focus to do this properly,
otherwise using a shortcut key while searching a playlist will trigger
that shortcut.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-09-01 09:48:11 -04:00
Bryan Schumaker c026686a1b ocarina: Store maximization and size of window
Re-enable and clean up the code I used to have.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-08-31 10:30:25 -04:00
Bryan Schumaker fc46bea1d1 ocarina: Use a shorter timeout for progress bar updating
I'm only using this function for updating the progress bar now, so it
doesn't need a faster response time.  I can drop CPU usage a little bit
by adding a longer delay between updates, without really noticing the
difference.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-08-31 09:18:42 -04:00
Bryan Schumaker ad3cbdebff ocarina: Move playlist tabs setup to playlist.cpp
This was in body/playlist.cpp, but I eventually plan on removing this
file so the code I'm using from there needs to be moved somewhere else.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-08-30 13:58:46 -04:00
Bryan Schumaker a985ff70a9 Create a PLAYLIST_UPDATE notification
This notification is sent when a track in the playlist is updated, such
as when the play count is incremented.  I also remove the
track_updated() functions from the library renderer and ocarina::Playlist.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-08-30 10:44:48 -04:00
Bryan Schumaker e8fd94cdeb ocarina: Clear out old ocarina::Playlist code
This class is slowly going away, and these functions have already been
reimplemented using my GtkBuilder interface.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-08-30 09:29:53 -04:00
Bryan Schumaker 69687ac6c6 libsaria: Remove obsolete renderer functions
Dynamic playlists are disabled right now, so I'm making use of this time
to clear out old code.  This patch removes library renderer functions
that have already been reimplemented.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-08-30 09:28:07 -04:00
Bryan Schumaker e6d9d2a906 ocarina: Remove more obsolete code
Some of this involved commenting out dead code that I want to use for
reference later.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-08-30 09:16:08 -04:00
Bryan Schumaker 9801e9335b Create an IDLE_ADD notification
Used for setting up g_idle_add().  Without this, banning songs will save
but unbanning them won't.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-08-29 10:30:56 -04:00
Bryan Schumaker e9f8c34e5a Create a PLAYLIST_RM notification
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-08-29 10:30:54 -04:00
Bryan Schumaker 7483aa3c4f ocarina: Set length label when tabs are changed
My old code was doing this by looking for widgets getting mapped or
unmapped.  This was stupid, so now I'm using the GtkNotebook switch-page
signal.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-08-29 10:29:41 -04:00
Bryan Schumaker ead70aef7d ocarina: Don't make playlist filters visible through get_widget()
Instead, I implement a new struct for grouping together the important
widgets of a playlist tab.  I should be able to re-use this structure
for dynamic playlists.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-08-29 00:10:29 -04:00
Bryan Schumaker ae39628b01 ocarina: Implement the banned playlist using GtkBuilder
I don't have a way to ban songs using GtkBuilder yet... that's coming,
but for now I'll just assume it works :)

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-08-26 21:34:40 -04:00
Bryan Schumaker 3ed02e221e ocarina: Create a GtkBuilder tab for the recent playlist
I also remove the old code for showing the recent playlist.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-08-26 21:23:51 -04:00
Bryan Schumaker b138c24e6d ocarina: Remove old library tab
I've re-implemented everything using GtkBuilder, so now I don't need the
ocarina::Playlist for the library.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-08-26 15:17:37 -04:00
Bryan Schumaker b8f2ffdf48 Add a LIBRARY_FILTER notification
I also enable filtering on the new library tab.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-08-26 10:27:40 -04:00
Bryan Schumaker b2e2404741 ocarina: Play songs when double clicking rows
I copied this function from playlist/treeview.cpp since it seemed to be
working well.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-08-26 09:31:38 -04:00
Bryan Schumaker 8583ac01d9 Add a PLAYLIST_SIZE notification
Used to notify the UI that the playlist size has changed.  Other options
include: Set the size automatically when responding to PLAYLIST_ADD (and
evenutally "PLAYLIST_RM")

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-08-25 16:15:47 -04:00
Bryan Schumaker 9b6665030a Create a new Library playlist tab
This tab is appended at the end of the notebook, so it looks as if there
are two Library tabs.  I'm going to use notifications and GtkBuilder on
the new tab to remove the PlaylistRenderer and to hopefully make adding
new features easier.  Right now only inserting tracks into the
LibraryPlist works, and I eventually want to remove the LibraryPlist
liststore in favor of a custom treemodel.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-08-24 08:35:25 -04:00
Bryan Schumaker fc40dd535c libsaria: Create notifications for autopause
- Send one when the pause type changes
- Send another when the pause count changes

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-08-22 08:04:21 -04:00
Bryan Schumaker 00111fc87b libsaria: Notifications for play and pause events
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-08-21 18:19:27 -04:00
Bryan Schumaker 9f7d861b77 libsaria: Remove library::Driver
I initially made this class so that multiple front ends could be used at
once and all receive the same notifications.  I see now that this was a
stupid idea, since I only need to keep one list of the library.  My
notify() function does the same stuff without the need for a driver
list.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-08-21 17:55:27 -04:00
Bryan Schumaker 3c87b9f852 libsaria: Pass an argument for notifications
Any void * will do, or even NULL!  Try to keep notify.h up-to-date with
what argument is passed and please don't send out the same notification
with multiple argument types.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-08-21 07:56:45 -04:00
Bryan Schumaker db8be5659c libsaria: Add in a simple notification system
Right now it only notifies that an event happened.  I think I should
eventually pass in an additional argument related to the event that
happened.  This will allow me to send out notifications for preferences
or library paths changing.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-08-20 08:26:38 -04:00
Bryan Schumaker 0402930098 ocarina: Remove old body/ files
I don't need these files now that I have GtkBuilder to help with the UI.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-08-19 09:13:56 -04:00
Bryan Schumaker 34f43cc96e ocarina: Use get_object() for connecting signals
The library treeview uses a cell renderer that needs the "toggled"
signal.  Since this isn't a widget, I've been seeing a gtk warning when
I get_widget() tries to use the GTK_WIDGET() macro on it.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-08-19 09:03:17 -04:00
Bryan Schumaker 56148e58fe ocarina: Add back the "ban track" button
I moved it to the GtkNotebook action-area for the playlist tabs since I
ran out of room in the "Now Playing" section.  I made the widgets
accessable through my get_widget() function, but it would be nice to
figure out how to add them in GtkBuilder.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-08-19 08:51:40 -04:00
Bryan Schumaker 2221bca25e ocarina: Create a FileChooser dialog
I use this to select songs anywhere in the filesystem, not necessarily
in the library.  I also renamed LibraryPathChooser to DirectoryChooser.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-08-17 08:08:30 -04:00
Bryan Schumaker 22694e1bfe ocarina: Remove old library.cpp
I've re-implemented everything here with GtkBuilder, so this file is now
obsolete.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-08-13 08:21:11 -04:00
Bryan Schumaker 01d8eb15d8 ocarina: Add keyboard shortcuts to the library treeview
Delete deletes the selected library path, plus opens the chooser to add
a new path.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-08-13 08:18:13 -04:00
Bryan Schumaker 448acf1181 ocarina: Look for toggled signals from the CellRendererToggle
There is some other problem with updating the renderer, but I'm more
concerned with working on the gui and moving on to other stuff.  I'll
fix it later...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-08-10 08:24:29 -04:00
Bryan Schumaker 5d2631d19a ocarina: Implement the "Add Library" button
To add new paths to the library.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-08-09 08:29:41 -04:00
Bryan Schumaker 97a7edce41 ocarina: Add an update_all() button
Click to update all library paths.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-08-08 08:22:33 -04:00
Bryan Schumaker 34dd1a1088 ocarina: Show paths in the library
Clicking them doesn't do anything yet, and the buttons are
non-functional as well.  But paths are displayed as they're configured!

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-08-07 19:29:18 -04:00
Bryan Schumaker aebcfaab45 ocarina: Re-enable automatic pause
I modified the code slightly from what I used to have.  The biggest
difference is changing the counter will always enable automatic pausing,
so I no longer need the extra click to enable this feature.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-08-05 09:26:47 -04:00
Bryan Schumaker 761842869e ocarina: Show and hide the idle bar
I check the size of the idle queue during the timeout poll and then
enable the progress bar.  When the queue size reaches zero I hide the
bar again.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-08-04 13:31:47 -04:00
Bryan Schumaker fdecd7bbdf ocarina: Get the progress bar working again
This was easy, just copy over the old code to status.cpp.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-08-04 11:57:31 -04:00
Bryan Schumaker 4a764fcc8d ocarina: Remove old controls code
This has already been reimplemented in gtk builder.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-08-03 08:09:03 -04:00
Bryan Schumaker 54d1ff991d ocarina: Set the length label
The length label is part of the gtk builder description.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-08-03 08:00:08 -04:00
Bryan Schumaker 5a1b8555db ocarina: Clean out old gtk and button code
Now that I'm using gtk builder I don't need gtk convenience functions.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-08-03 07:52:08 -04:00
Bryan Schumaker 22e64d64ca ocarina: Connect signals to buttons
And also
- Show / hide the play and pause buttons
- Remove the scrollbar from the now playing display

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-08-02 08:34:46 -04:00
Bryan Schumaker 90355962e4 ocarina: Initialize playlists during startup
I plan on replacing the playlist code eventually, but for now I want to
see how everything looks.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-08-01 08:19:31 -04:00
Bryan Schumaker a11613d3ad ocarina: Add a notebook for playlist tabs
I'll eventually fill this in with playlist data.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-08-01 08:08:54 -04:00
Bryan Schumaker 56f082142a ocarina: Add more widgets to the UI
I added a notebook for AutoPause and a few other tabs.  Widgets still
don't do anything.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-07-31 08:25:56 -04:00
Bryan Schumaker 40bcff7063 ocarina: Add control buttons to the UI
These buttons don't do anything yet.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-07-30 08:26:57 -04:00
Bryan Schumaker 9eb181d263 ocarina: Add in the slider and position / duration labels
Only the duration label changes, I don't do anything with the others
yet.  I'll work on it later (once I get the rest of the UI converted
over).

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-07-30 07:59:27 -04:00
Bryan Schumaker bb56dc4d2a ocarina: Remove idle_add() from the ocarina namespace
It's only used in ocarina.cpp, and it's already static there.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-07-29 16:09:20 -04:00
Bryan Schumaker ff0f4a2c66 ocarina: Add back Title / Artist / Album labels
Using GtkBuilder now...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-07-29 16:04:22 -04:00
Bryan Schumaker 037577850f ocarina: Add the timeout poll back
I want to create the now playing widgets next, so this is needed now.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-07-29 15:19:55 -04:00
Bryan Schumaker 693692766d ocarina: Change window default size
It needed to be bigger.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-07-29 15:13:59 -04:00
Bryan Schumaker 4585d90a32 ocarina: Remove window.h and lots of gtk shortcuts
The shortcuts were hiding more than they probably should have, and I
didn't have much using them.  The only function in window.h that I'm
going to use is init_window(), so I'll just declare it in ocarina.h.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-07-29 15:11:36 -04:00
Bryan Schumaker 1ddcb9f2fc ocarina: Initialize the window from window.cpp
Eventually this will support all the same features of the old ocarina
window...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-07-29 15:01:20 -04:00
Bryan Schumaker 681aa4b611 libsaria: Remove flags from initdata
I wasn't doing anything with these, so they're just getting in the way
and increasing complexity.  This change also allows me to remove the
"enabled" variable from the idle queue.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-07-29 14:31:35 -04:00
Bryan Schumaker 59b79b6575 ocarina: Begin switching to GtkBuilder for the UI
I feel that hand-written UI code is slowing me down, so I'm going to
switch to using glade / GtkBuilder to manage the UI as much as possible.
So far, I create, show, and destroy a window.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-07-29 11:27:50 -04:00
Bryan Schumaker bfb00ec812 libsaria: Remove the remove_tracks() function from playlists
It doesn't make sense to keep it around anymore since I have the
single-track removal function.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-07-01 12:02:11 -04:00
Bryan Schumaker 94cbcd9a5d libsaria: Give playlists a remove_track() function
This makes more sense than pushing a single track into a list and then
iterating over the single item...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-07-01 11:38:50 -04:00
Bryan Schumaker 1ba1c72e3f libsaria: Use a flags variable for initdata
I was using multiple boolean fields, but I think it'll be easier to set
up a single bit-flag field instead.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-07-01 11:24:06 -04:00
Bryan Schumaker aed5a023b3 libsaria: Remove second library path list
I kept around the old list while I was converting everything over to the
new list.  Now that I support all the needed features, I can remove the
old variable.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-07-01 11:24:02 -04:00
Bryan Schumaker a7d1f57403 libsaria: Switch the update code to use the new list
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-07-01 09:59:48 -04:00
Bryan Schumaker 250a8b9bfe libsaria: Rename List::last() -> List::end()
To better match C++ iterators.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-06-30 12:08:04 -04:00
Bryan Schumaker e0074525f3 libsaria: Convert the idle queue to use the new list class
- The erase() function returns the previous item
- Implement a push_front() function
- Implement a pop_front() function

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-06-30 11:59:32 -04:00
Bryan Schumaker e2242359d4 libsaria: Create iterators for lists
Not really C++ iterators, but close enough.  I can get the first and
last values values to use in for loops, I also made a next() function
for list items.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-06-30 11:28:12 -04:00
Bryan Schumaker 743caa85e6 libsaria: Add tracks to new library lists too
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-06-16 14:59:59 -04:00
Bryan Schumaker 28eaba41e0 libsaria: Use find_item() for updating library paths
I need to check if the file is already in the library.  I also made a
note for how this check could be done faster using a tree.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-06-16 14:51:47 -04:00
Bryan Schumaker 065feedee2 libsaria: Save tracks using for_each_item()
It's simpler than custom writing my own for each loop...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-06-16 14:51:47 -04:00
Bryan Schumaker bd8cdee041 libsaria: Implement a find_item() for lists
This function takes a function pointer argument that should return
"true" if the current item is the item we're looking for and "false"
otherwise.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-06-16 14:51:45 -04:00
Bryan Schumaker 8b56659b1c libsaria: Created a list for_each_item()
Useful for accessing each item in the list sequentially without having
to write a lot of loops.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-06-16 14:04:55 -04:00
Bryan Schumaker 311e404af9 libsaria: Give Lists a size()
Return the "count" variable and hope we don't have more than
MAX_UNSIGNED_INT objects in the list...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-06-16 13:37:38 -04:00
Bryan Schumaker bf0e340a53 libsaria: Rename ListNode -> ListItem
I like ListItem better.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-06-14 17:48:44 -04:00
Bryan Schumaker 34c13bc93e libsaria: Add items to a List
I free the memory in the destructor, too!  Be careful, though, the copy
constructor isn't actually a copy constructor.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-06-14 17:18:22 -04:00
Bryan Schumaker da776eeebf libsaria: Initialize list objects
I point the list head towards itself.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-06-14 08:11:16 -04:00
Bryan Schumaker 4aac603b85 libsaria: Begin a custom List class
I'm going to gradually replace the stl list with my own implementation.
This should make everything more efficient and I won't have to deal with
those pesky iterators.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-06-13 21:34:45 -04:00
Bryan Schumaker 14fe5661a5 libsaria: Rename List -> Stack
I want to recycle the "class List" name, so I need to free it up from
the playlist code.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-06-13 21:34:44 -04:00
Bryan Schumaker d12c5bac75 Begin Ocarina 5.10 2012-06-13 21:34:44 -04:00
Bryan Schumaker a3e149e7c0 Ocarina 5.9 2012-06-02 13:21:22 -04:00
Bryan Schumaker 7390c65d63 scripts: Move ocarina -> %APP
It'll try to run a command passed through the shell, if the command
can't be found it'll run %APP-player.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-06-02 13:21:22 -04:00
Bryan Schumaker 7816dea1cf build: Improve PKGBUILD.tmpl
Simpler package function and use $MAKEFLAGS.  There is no longer a need
for DESTDIR or POSTFIX in the Sconstruct file anymore, either.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-06-02 13:21:21 -04:00
Bryan Schumaker f64bf65b37 build: Generate the PKGBUILD file during `scons release`
This is better than needing to update it manually...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-06-02 12:42:05 -04:00
Bryan Schumaker faadd138c4 build: Turn off debugging
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-06-02 12:19:45 -04:00
Bryan Schumaker 7cc5cded9f libsaria: Directly set version in version.h
Rather than building it up as part of a function call

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-06-02 12:16:34 -04:00
Bryan Schumaker 698ed1508a build: Remove bin/ and lib/ as part of scons clean
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-06-02 12:06:10 -04:00
Bryan Schumaker 304e8005f1 build: Remove lib/ and bin/ during a scons -c
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-06-02 11:53:32 -04:00
Bryan Schumaker e4a3b8902f build: Improve install target and create uninstall target
Install files in bin and lib.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-06-02 11:50:32 -04:00
Bryan Schumaker 3d9f21837e build: Alias "ocarina" to the entire ocarina project
Otherwise it'll build just the ocarina subdirectory, which isn't useful
if I ever have multiple projects using libsaria.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-06-02 10:47:45 -04:00
Bryan Schumaker 80cf0bb28e ocarina: Use files in the lib directory
I copy images and other files to lib/ocarina/ during the build to make
installing easier.  The lib directory should always be relative to the
bin (executable) path, so I can easily find the lib path based on
executable path (/proc/self/exe).

I can also use this to find bugs in the buld process, such as adding a
file to the images/ directory but forgetting to add it as an install
target.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-06-02 10:41:04 -04:00
Bryan Schumaker dcaeb8cbd1 build: Copy images to lib/%APP/ during build
From here, I can copy the entire directory when I choose to install.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-06-02 10:17:22 -04:00
Bryan Schumaker e23ecd4bfb Build: make a directory using application name
The app_directory() function sets the config.application variable, then
calls the Sconscript file in that directory.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-06-02 09:41:46 -04:00
Bryan Schumaker 0ffd1ad4d6 Ocarina 5.9-rc 2012-06-01 08:05:14 -04:00
Bryan Schumaker fbcc660bd6 build: Create a configuration script
Users set values here to be used by the build system.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-28 11:34:37 -04:00
Bryan Schumaker 0dfb02c612 libsaria: Added a "toggle" command
This toggles between play and pause states.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-28 11:07:05 -04:00
Bryan Schumaker 794580b4d0 libsaria: Add "stop" command
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-28 11:02:54 -04:00
Bryan Schumaker 949e635651 scripts: Remove old write-pipe command
I've replaced this with a function call

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-28 10:59:09 -04:00
Bryan Schumaker e632ff1012 libsaria: Added "next" and "prev" commands
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-28 10:55:49 -04:00
Bryan Schumaker 838b2b3d8f libsaria: Recognize a "pause" command
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-28 10:51:14 -04:00
Bryan Schumaker bba2989866 scripts: Create functions file in lib/ocarina/
Makes it easier to install and keeps functions separate from the ocarina
commands.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-28 10:47:27 -04:00
Bryan Schumaker de5cdc1cbc build: Use "C++" instead of "CXX" for building
I don't like the look of "CXX" as much.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-28 10:29:17 -04:00
Bryan Schumaker d6dff5290f scripts: Create an %APP-play for sending play commands
I'm currently using the "ocarina" script as a functions file, but this
will change eventually.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-27 23:16:56 -04:00
Bryan Schumaker 62c3ef2684 build: Create ocarina.bin as a symlink to ocarina-player
I want to add in more ocarina-* commands, so the first step is making
the player its own command.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-27 17:37:25 -04:00
Bryan Schumaker 30375bbdff build: Compile libsaria using an Sconscript file
To extract libsaria-related stuff from the main build script.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-27 10:40:19 -04:00
Bryan Schumaker cc32587917 build: Create an ocarina Sconscript file
This file will set up building the ocarina/ subdirectory.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-27 10:36:45 -04:00
Bryan Schumaker 5f5f23bf9e Build: Create version.h using an Sconscript file
This lets me pull code out of the generic Sconstruct, so it can't be
bad!  I also removed the test directory since I never made unit tests.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-27 10:23:47 -04:00
Bryan Schumaker 3d722f364d Honor banned tracks when enabling a library path
Before this I was always putting them into the Library playlist.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-26 19:47:30 -04:00
Bryan Schumaker 4afce6300c Turn off library paths
I set the "visible" field to "false" and then remove each track from the
library playlist.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-23 07:48:10 -04:00
Bryan Schumaker f5181c50b1 libsaria: Fix deck::prev()
Having tracks add themselves to the recent playlist means that it also
adds itself when going backwards through the playlist, resetting the
cur iterator and causing the same 2 songs to be played.  To get around
this, I gave tracks a new load_unlisted() function to load without
adding themselves to the recently played list.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-19 20:48:25 -04:00
Bryan Schumaker ce6782558d libsaria: Bugfix Track playlist list
I was sometimes trying to remove a playlist from an invalid pointer.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-19 20:32:08 -04:00
Bryan Schumaker 057bce8809 Show last played date on each playlist tab
I like to know when I last listened to a song.

Signed-off-by: Bryan Schumaker <bjchuma@gmail.com>
2012-05-19 20:09:21 -04:00
Bryan Schumaker ca9f3e6cf9 Show the play count in the playlist renderer
I created a new renderer function for updating tracks when they change.
Using this, I can show the new playcount of tracks as it is incremented.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-19 19:47:11 -04:00
Bryan Schumaker 61769f74fd libsaria: Keep a pointer to each playlist a Track is on
Useful for removing them later without having to check every playlist.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-19 19:01:55 -04:00
Bryan Schumaker e874345596 ocarina: Ban and unban songs using delete key
Banning: Use the delete key on selected tracks from the library tab.
Unbanning: Use the delete key on selected tracks from the banned tab.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-19 18:48:08 -04:00
Bryan Schumaker 01b5eeb10f ocarina: Make "add to playlist" menu items
These menu items add tracks to a specific playlist instead of creating a
new one.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-19 18:35:05 -04:00
Bryan Schumaker 77225d4d9f libsaria: Define MAX_PLAYLISTS in a header file
So applications can use this value too.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-19 18:34:30 -04:00
Bryan Schumaker 0e6632ce45 ocarina: Use yes / no images for banning songs
I think this makes more sense than using the GTK_STOCK_DIALOG_ERROR for
both states.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-18 12:17:45 -04:00
Bryan Schumaker dea787d576 ocarina: Disable tab label text when playlists are disabled
To make it more obvious which playlists are disabled when you are on
other tabs.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-18 12:11:19 -04:00
Bryan Schumaker d74d008223 ocarina: Change disable playlist button image
I do this whenever the playlist disabled flag changes.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-18 12:05:03 -04:00
Bryan Schumaker 706f07b6f7 ocarina: Disable playlist widgets with a playlist
To emphasize that the playlist has been disabled.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-18 11:57:28 -04:00
Bryan Schumaker 973b5d3d31 Save playlist disabled status to file
This allows me to restore it when restarting ocarina.  I also need to
notify the renderer that the playlist status has changed so I can change
the button state.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-18 11:51:52 -04:00
Bryan Schumaker 35d71efe58 Disable temporary playlists
When a playlist is disabled I won't pick songs from it until the user
re-enables it.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-18 11:25:51 -04:00
Bryan Schumaker f6cdcae79c ocarina: Create a make_toggle_button_data() function
Used to pass extra data to the toggle function.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-18 11:24:38 -04:00
Bryan Schumaker 01e63da4f7 ocarina: Don't show playlist tabs immediately
Instead, I want to show them when they have tracks added to them.  This
keeps the banned tab from being shown and then hidden right away during
startup.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-18 10:46:38 -04:00
Bryan Schumaker 376fe67115 ocarina: Bugfix the ban button
- Use g_signal_connect() when creating toggle buttons
- Only set the banned state on a track if it has changed

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-18 10:39:26 -04:00
Bryan Schumaker ed33881a25 ocarina: Created a shortcut for switching to the banned list
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-17 13:31:02 -04:00
Bryan Schumaker bd171423a6 ocarina: Hide empty playlists
If the playlist size == 0, then we don't need to show it.  This hides
the banned list when it doesn't contain any songs.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-17 13:28:55 -04:00
Bryan Schumaker ed5574f612 libsaria: Start banned songs on the banned playlist
Instead of putting them on the library playlist.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-17 13:21:26 -04:00
Bryan Schumaker 4718bf77f3 Change playlists when the ban button is pressed
I remove the track from the library playlist and add it to the banned
list.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-17 13:15:36 -04:00
Bryan Schumaker bb7a662f92 Ban songs in the library
Right now, this just toggles the "banned" field in the Track class and
then skips to the next track.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-17 13:00:03 -04:00
Bryan Schumaker e8e8589614 libsaria: Add a new field to the Track class
I plan on using this to track if the user has banned a track or not.
This patch introduces the new field and handles the library version
upgrade.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-17 12:30:11 -04:00
Bryan Schumaker ea7b66ae6d libsaria: Read file from pipe
Scripts should write commands to a temporary file and then write the
path to that file to the application pipe.  I can then write results of
the command to this file before exiting.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-17 11:51:36 -04:00
Bryan Schumaker a7570cc80a ocarina: Tell gtk to look for data coming in over the pipe
This gives me a chance to read it without needing to poll for changes.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-15 11:33:29 -04:00
Bryan Schumaker 8f1de2745e libsaria: Create functions for opening and closing pipes
I'm going to use the pipe with shell scripts for remote-controlling
ocarina (possibly through a web interface).

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-15 11:23:47 -04:00
Bryan Schumaker 463cef95dd libsaria: Create an initdata struct for initializing
Passing individual variables through works for a small number of
variables, but passing a struct makes it easier to add new arguments.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-15 11:06:43 -04:00
Bryan Schumaker d0f6996403 libsaria: Remove the list_recent field from tracks
I think it's easier to check if the track has an associated library
path.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-15 10:49:56 -04:00
Bryan Schumaker d7166f3cab libsaria: Track the last played date
When we mark a song as played we should also mark that it was last
played today.  With this, I think I'm finally using all my library path
fields!

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-15 10:44:25 -04:00
Bryan Schumaker 34cd70fa39 libsaria: Track play count
I've had a library field for this for a while, but I haven't been using
it.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-15 10:29:26 -04:00
Bryan Schumaker 36bd2c2b66 Reorder playlists in the playlist deck
This allows me to change playback order without having to delete old
playlists and make new ones.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-14 11:21:10 -04:00
Bryan Schumaker 874f999adf ocarina: Close button modifications
- Set relief to none
- Remove the inner-border to make the button smaller

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-14 10:30:23 -04:00
Bryan Schumaker 2dd1e362d1 Created a "delete playlist" button
On the libsaria side, I created a function for finding and deleting a
playlist pointer.  On the ocarina side, I added a button to each
playlist tab to remove the tab.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-13 13:48:22 -04:00
Bryan Schumaker d03e38ffbb ocarina: Add a make_button_data() function
Used for passing extra data through the button clicked callback.  I also
use this patch to remove the extra GdkEvent argument passed to buttons,
since this argument isn't actually part of the callback...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-13 13:36:42 -04:00
Bryan Schumaker 5363cfac82 libsaria: Garbage collect the playlist deck
I do this after choosing the next song and after tracks are removed from
each playlist.  This allows me to remove playlists as they empty.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-13 12:09:39 -04:00
Bryan Schumaker 8309c4a606 libsaria: Remove undefined function
I used in a while ago, but it's been removed (but not from the header file).

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-13 11:35:39 -04:00
Bryan Schumaker 4fe9e667f7 libsaria: Almost always add track to the recent list
Before I was only adding tracks that were picked through the
deck::next() function.  Now I have the track add itself to the recent
list (except when I'm playing an outside track).

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-13 11:26:23 -04:00
Bryan Schumaker 3b5af7b865 libsaria: Remove tracks from index
Basically the same way they are inserted, only call a "remove" function.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-13 11:18:40 -04:00
Bryan Schumaker c3ba90f900 libsaria: Tell tracks if they should play when loaded
This should set the gst pipeline to the correct state when the song is
loaded, rather than pausing after telling it to play.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-13 11:07:00 -04:00
Bryan Schumaker 7dab47783b libsaria: Remove unused find_nth_playlist() function
I improve get_playlist() instead

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-13 10:49:40 -04:00
Bryan Schumaker 7f52d81d12 libsaria: Don't store the library in the playlist deck
This makes some of the deck code easier, since I don't need to check for
static playlists anymore.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-13 10:46:32 -04:00
Bryan Schumaker 5b86536af3 Begin Ocarina 5.9 2012-05-13 10:46:17 -04:00
Bryan Schumaker 243a885713 Update PKGBUILD for 5.8
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-12 08:06:27 -04:00
Bryan Schumaker cf85c0231d Ocarina 5.8 2012-05-12 08:06:02 -04:00
Bryan Schumaker 574e1062fa libsaria: Use lstat for listing directories
Now I work on JFS in addition to other filesystems...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-11 17:52:48 -04:00
Bryan Schumaker c3bb6119e5 libsaria: More next() tuning
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-07 08:11:11 -04:00
Bryan Schumaker c0fdcb4d93 libsaria: Improve playlist iterator handling
To prevent segfaults

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-07 08:09:45 -04:00
Bryan Schumaker b04aaf3815 libsaria: Restore last song on startup
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-05-07 08:08:23 -04:00
Bryan Schumaker a8c6aabff7 libsaria: Return new current index from rm_index()
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-14 11:36:29 -04:00
Bryan Schumaker c2c13b2cbc libsaria: Create a single add_tracks() function
Derived classes need to implement a do_add_tracks() function instead so
I have a single place to notify the renderer and save the playlist.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-14 11:16:15 -04:00
Bryan Schumaker 18e0daeb17 ocarina: Remove more commented out and disabled code
- The old header functions
- The old callback header file
- The old shortcut registering system
- The old main() code

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-13 08:22:44 -04:00
Bryan Schumaker 3b705515c2 ocarina: Remove old songlist code
I've been wanting to do this for a long time.  I don't think I need it
anymore, so it can all be safely removed.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-13 08:19:20 -04:00
Bryan Schumaker 45c839c04a libsaria: Improve random_next()
Limiting rand to plist.size() * (3 / 4) kept causing songs at the end of
the range to get selected.  This caused a backwards-scrolling effect as
songs were played.  Instead, I want to pick from the next half of the
list to create a forward-scrolling effect.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-13 08:08:07 -04:00
Bryan Schumaker 570374f53d libsaria: Go to new current iterator when picking next
The new "cur" iterator points to a valid song, so I might as well scroll
close to it.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-13 08:06:36 -04:00
Bryan Schumaker 0cdd5eff0d libsaria: Remove diff reject file
Where did this come from?

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-13 08:05:40 -04:00
Bryan Schumaker 3287cde11e ocarina: Find selected indicies
Used for removing tracks from temporary playlists.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-13 08:05:01 -04:00
Bryan Schumaker 99757c47f9 libsaria: Remove tracks by index
Because otherwise removing a track will remove all duplicates, too.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-13 08:03:46 -04:00
Bryan Schumaker 900cac7e45 ocarina: Improve right click menu
I can now create new playlists at either the front or back of the
playlist deck.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-12 08:06:39 -04:00
Bryan Schumaker 97427af922 Create new playlists in front
The "S" or "Q" shortcut will create a new playlist on the front of the
deck, "s" or "q" creates a shortcut on the back of the deck.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-10 08:04:29 -04:00
Bryan Schumaker 898865293d libsaria: Change deck::push() to deck::push_back()
I'm going to create a push_front() function too, so renaming it makes
sense.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-10 07:57:14 -04:00
Bryan Schumaker 4c33ba82ec ocarina: Find keypad numbers
I needed to strip out the "KP_" at the beginning.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-09 08:07:35 -04:00
Bryan Schumaker 6f69392e5f ocarina: Use "N" for going to previous track
This matches the vim keybinding, which explains why I kept trying to use
it instead of "p"...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-09 08:02:16 -04:00
Bryan Schumaker b2c17bd54a libsaria: Create a get_playlist() function
I don't want to keep creating functions for doing things to playlists.
Instead, I'd rather just get the playlist directly.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-09 08:00:12 -04:00
Bryan Schumaker 851aa10ae1 libsaria: Create generic function for reading numbered directories
I create directories with numbered files for the library and playlist,
this patch creates generic code for reading them during startup.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:20 -04:00
Bryan Schumaker 261316fb5f libsaria: Clean out header files
Remove things that aren't being used anymore.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:20 -04:00
Bryan Schumaker f487a08ac1 libsaria: Remove commented out code
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:20 -04:00
Bryan Schumaker 0d05e14724 libsaria: Reload playlists on startup
I do this in another idle task, I also had to give the library a
function to find tracks based on (libid, trackid).

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:20 -04:00
Bryan Schumaker 60d2e4fcd8 libsaria: Save temporary playlists
I do this whenever the playlist changes (tracks added, removed or
playlist renumbered).  When playlists are deleted I remove the file.  I
also remove the file when new_number < cur_number.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:20 -04:00
Bryan Schumaker 3f030872ba libsaria: Remove old controls.cpp file
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:20 -04:00
Bryan Schumaker da49c68e82 libsaria: Remove old index header
Not needed anymore.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:20 -04:00
Bryan Schumaker 3caea974fe ocarina: Refilter the playlist
I don't change what can play as a result, but at least I can find songs
again!

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:20 -04:00
Bryan Schumaker 235ac70033 libsaria: Move filter code
From index.cpp to filter.cpp.  I also added in an "is_visible()"
function for testing visibility of tracks.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:20 -04:00
Bryan Schumaker 7820b28534 libsaria: Search the index
And notify the renderer to update

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:20 -04:00
Bryan Schumaker 556aad3344 libsaria: Introduce bare Index class
Right now I just add and remove songs from the index as they are added
and removed from the playlist.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:20 -04:00
Bryan Schumaker 2fb2f97a43 libsaria: Fix compile errors
g++ must have gotten updated...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:20 -04:00
Bryan Schumaker 8869b2aaed ocarina: Use pause_count
This allows me to say "pause in N songs" instead of limiting it pausing
only after the next song.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:19 -04:00
Bryan Schumaker dc57109d9e libsaria: Give access to pause_count
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:19 -04:00
Bryan Schumaker 9d271740aa ocarina: Added automatic pause controls
Right now I just pause after the current song, but I eventually plan on
adding controls to pause after N songs.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:19 -04:00
Bryan Schumaker 2cdfbde9be libsaria: Implement pause after N tracks
I keep a counter that is decremented after every call to next().  When
it reaches zero, pause after loading the next song.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:19 -04:00
Bryan Schumaker cb29bcba48 libsaria: Remove unused library file
I've re-implemented everything in this file, so it's time to remove it.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:19 -04:00
Bryan Schumaker 3772bf78fa libsaria: Re-order code in update.cpp
Keep class functions with the class that uses them.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:19 -04:00
Bryan Schumaker d6b8044ad3 ocarina: Hit "Delete" to remove tracks from a specific playlist
Yay keyboard shortcuts!

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:19 -04:00
Bryan Schumaker 31ab70b37d libsaria: Remove tracks from a specific playlist
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:19 -04:00
Bryan Schumaker b6cf10bf61 ocarina: Update library path when row is activated
This can either be a double-click or pressing "enter" on a selected row.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:19 -04:00
Bryan Schumaker 659a2208b8 libsaria: Remove files that no longer exist
I scan a library path, do an lstat() and remove the files that can't be
found.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:19 -04:00
Bryan Schumaker a1819dd5f9 libsaria: Only add new files during a library scan
I simply check if the file is already in the library before tagging it.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:19 -04:00
Bryan Schumaker 537dc3a22d ocarina: Support removing library paths
Use the "Delete" key for now.  I also added in using the plus key to add
new paths.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:19 -04:00
Bryan Schumaker 6e97f04e85 libsaria: Remove library paths
- Delete the library file
- Remove tracks from each playlist
- Notify the renderer that tracks have been removed
- Notify library drivers that the path has been removed
- Remove the path from the list

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:19 -04:00
Bryan Schumaker 97fcff5c18 ocarina: Smaller progress bar
I learned how to set custom gtk_rc styles to configure the idle task
progress bar.  Now that it's smaller, I also moved it to the very bottom
of the window.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:19 -04:00
Bryan Schumaker a33e1e6d8d ocarina: Use the playlist number
- Create new notebook page at number
- Show number to left of label

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:19 -04:00
Bryan Schumaker bc800057e0 libsaria: Expand on numbered playlists
- Renumber when new playlists are either added or removed
- Finding nth playlist is much easier now
- Insert new playlists right before the library

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:19 -04:00
Bryan Schumaker 4e046beb20 libsaria: Introduce playlist numbers
To track where in the deck they are.  Displaying and modifying them
comes next...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:19 -04:00
Bryan Schumaker 5194130db4 libsaria: Rename playlist stack to playlist deck
I'm going to make it less stack-ish because I was getting confused.
Turns out people don't think people have a hard time thinking about song
order starting from the end... :-(

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:19 -04:00
Bryan Schumaker 6f3397c1a4 ocarina: Remove old code from window.cpp
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:19 -04:00
Bryan Schumaker 72522aab56 ocarina: Make playlist notebook tabs scrollable
If the user shrinks the window, the scroll arrows will appear for
navigation.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:19 -04:00
Bryan Schumaker b977832f3c ocarina: Use g_signal_connect() for the window
I was using connect_after(), but somewhere along the line the space bar
was getting lost.  Instead, I only connect the number keys using
g_signal_connect_after() so treeview shortcuts continue to work.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:19 -04:00
Bryan Schumaker 14c35e5810 ocarina: Set current duration using new format function
This gives me the correct answer right away.  I also re-set the time
whenever a new playlist is created to keep the new tab from changing the
time.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:19 -04:00
Bryan Schumaker c5fe4546e2 libsaria: Format a duration (in seconds)
I turn it into a string "W days, X hours, Y minutes, Z seconds"

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:19 -04:00
Bryan Schumaker fcc48dbccb ocarina: Show the length of the currently visible playlist
I should eventually format this better...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:19 -04:00
Bryan Schumaker e0ebe4c97f libsaria: Track the length of playlists
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:18 -04:00
Bryan Schumaker 026b17a6a5 ocarina: Treeview keypresses
To add songs to already-created playlists.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:18 -04:00
Bryan Schumaker c6bf52a516 libsaria: Find nth playlist
Gives access to a specific playlist on the stack.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:18 -04:00
Bryan Schumaker d23469dfa7 ocarina: Added toggle_play() shortcut
Spacebar!

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:18 -04:00
Bryan Schumaker 6ae25ccdcb libsaria: Created a toggle_play() function
Switches between playing and paused.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:18 -04:00
Bryan Schumaker f67cecef0e ocarina: Add some keyboard shortcuts
0 - 9: Switch to playlist N
L / l: Switch to library
R / r: Switch to recent songs
N / n: Play next song
P / p: Play previous song
Escape: Give main window focus

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:18 -04:00
Bryan Schumaker 691f74ee10 libsaria: Return nth renderer
Useful for switching to a specific list in the UI

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:18 -04:00
Bryan Schumaker c953ce6fd4 libsaria: Use () instead of [] for playlist names
I think it looks better in the UI

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:18 -04:00
Bryan Schumaker 6214136ee3 ocarina: Tab label improvements
- Respond to the renamed() callback
- Right-align / justify labels

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:18 -04:00
Bryan Schumaker a91713dbfd libsaria: Set max_playlists to 10
This allows the UI to use the number keys as shortcuts...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:18 -04:00
Bryan Schumaker 2ae050fe47 libsaria: Automatically rename playlists when added or removed
The one on the top is always numbered "0"

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:18 -04:00
Bryan Schumaker 5a272ef62e libsaria: Playlists know their own type
Useful for dynamically renaming them (see next patch).

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:18 -04:00
Bryan Schumaker 3cbeb85828 ocarina: Don't scroll if (index < number of visible rows)
This prevents a possible slow down / infinite loop (I never actually let
it finish)

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:18 -04:00
Bryan Schumaker ee2191fc4f libsaria: Scroll playlist when iterator is reset
This allows me to scroll the recent tracks list back to the beginning.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:18 -04:00
Bryan Schumaker 319d68e8d2 ocarina: Scroll to current song
Only on non-draining playlists when that playlist selects a song.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:18 -04:00
Bryan Schumaker acef058afa libsaria: Tell playlist renderers to goto a specific index
I want to use this to scroll the library list when a new song is picked.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:18 -04:00
Bryan Schumaker 5f7e5890c8 libsaria: Library shouldn't drain
I wonder how this got changed...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:18 -04:00
Bryan Schumaker 4116cd3ed2 ocarina: Show recent songs playlist
I also needed to add in a change to focus the library by default.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:18 -04:00
Bryan Schumaker 3b3beb4625 libsaria: Track recent songs using a playlist
This way people can see what has played recently and directly select
from a list.  Generic playlist classes are awesome!

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:18 -04:00
Bryan Schumaker e5b91a5de9 libsaria: Remove commented out playlist code
I don't think I need any of it anymore.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:18 -04:00
Bryan Schumaker 7b527bc4e3 ocarina: Move progress bar and control buttons
I moved it above the "ribbon" to match what I had in 5.7

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:18 -04:00
Bryan Schumaker 5dc215d69a libsaria: Created Queue playlist class
This was much easier using inheritance...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:18 -04:00
Bryan Schumaker 3f665712a1 Remove empty playlists when picking next song
Hopefully with fewer problems than 5.7 had...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:18 -04:00
Bryan Schumaker 15aabfcff0 Create new playlists on the stack
- Only works for new sets
- Set a callback function when created
- Add a right-click menu to the ocarina treeview
- Remove songs from playlist when picking next song

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:18 -04:00
Bryan Schumaker 78787d9cf5 libsaria: Play songs from outside the library
Pass in a file path and play!  I even created a button as a notebook
action widget.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:18 -04:00
Bryan Schumaker 297f81213d ocarina: Provide an open file button
To play random songs from the filesystem.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:17 -04:00
Bryan Schumaker cb663075bd ocarina: Remove old button generating code and old footer
I now only have a single instance of the control buttons, so the old
code can be removed now.  The footer has been completely replaced by now.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:17 -04:00
Bryan Schumaker 2f26e5b869 libsaria: Remove old callback framework
I'm not using it anymore, so it can be removed.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:17 -04:00
Bryan Schumaker db3a9f8b02 libsaria: Clean out header files
I removed a lot of commented out code that won't be needed anymore.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:17 -04:00
Bryan Schumaker d6eb7ebb35 libsaria: Remove LibPath class
I'm using a simple struct for this now (see library.h).

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:17 -04:00
Bryan Schumaker c5a84807be libsaria: Remove InFile and OutFile classes
I do this all through either appdir or Read / Write tasks

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:17 -04:00
Bryan Schumaker 47fadb8113 libsaria: Remove IOTask
I have separate read and write tasks now

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:17 -04:00
Bryan Schumaker 4ef59da4dd libsaria: Remove more dead library code
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:17 -04:00
Bryan Schumaker fad3019d83 libsaria: Reload a saved library
And add tracks to the library playlist.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:17 -04:00
Bryan Schumaker d0a1b9fdf8 libsaria: Save library
- Change WriteTask() to take an extra void pointer argument
- Pass library path pointer through WriteTask
- Store tracks to file named after library id.
- Remove newline from tags

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:17 -04:00
Bryan Schumaker ab687a49bc libsaria: Create library and track counters
I plan on using (library, track) ids as a way of storing playlists.  I
made both counters unsigned ints, since I'm willing to bet that people
won't have 4,294,967,295 songs or library paths...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:17 -04:00
Bryan Schumaker 41dac97711 libsaria: Remove old library files
I was keeping them for reference, but I don't need them anymore.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:17 -04:00
Bryan Schumaker ac3964de01 libsaria: Randomly pick next song from library
I'll eventually allow more playlists to be stacked, but for now picking
from the library is easy.  I may eventually add in a way to pick
sequentially from a set.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:17 -04:00
Bryan Schumaker 07c365fcc0 libsaria: Add library playlist to to stack
I do this during library::init()

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:17 -04:00
Bryan Schumaker 3d7082e6f9 libsaria: Remove some old audio code
Not needed anymore with recent changes.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:17 -04:00
Bryan Schumaker 6bae34e487 libsaria: Added stopping
pause() and seek_to(0).  I also added a button in Ocarina.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:17 -04:00
Bryan Schumaker 0061e0bec6 Ocarina: Seek using progress bar
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:17 -04:00
Bryan Schumaker 595806ec0f libsaria: Reenabled seeking
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:17 -04:00
Bryan Schumaker d6d455ab7f ocarina: Update slider as track plays
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:17 -04:00
Bryan Schumaker 70ef389aab libsaria: Find audio position and duration
Used for update a slider in the UI.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:17 -04:00
Bryan Schumaker 53425485d6 libsaria: Preserve the current playback state when changing tracks
This makes something new play when we want it to...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:17 -04:00
Bryan Schumaker 4f68e6b26d ocarina: Show and hide the play / pause buttons
Based on the current gstreamer state.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:17 -04:00
Bryan Schumaker fe76a8d30a libsaria: Add play(), pause() and get_state() functions
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:17 -04:00
Bryan Schumaker e3c44146ff ocarina: Show information on the currently playing track
I update it using the main timeout loop, but only if the current track
pointer has changed.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:17 -04:00
Bryan Schumaker f1bbbbcc5c libsaria: Play a track using Track::play_now()
It loads and begins playback.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:17 -04:00
Bryan Schumaker 5163447638 libsaria: Remove most audio code
It'll be re-added as I review it all.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:16 -04:00
Bryan Schumaker a0d509cdff ocarina: Look for double clicking treeview rows
I now have direct access to the track that was selected, so I created a
dummy function to play it (to be filled in soon).

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:16 -04:00
Bryan Schumaker 570b483b9b ocarina: Set playlist tab label justify
I like the centered look better.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:16 -04:00
Bryan Schumaker 9464e0d33d ocarina: Watch for insert() operations in the Playlist
And update the GtkListStore when we see these calls.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:16 -04:00
Bryan Schumaker 6bb3cd38a4 libsaria: Notify playlist renderers when new tracks are added
For sets, I keep a sorted list and merge-sort the new songs.  I also
created insert_prepare() and insert_done() functions to tell the UI that
we are about to insert (this gives me a chance to call the
freeze_child_notify() and thaw_child_notify() in GTK).

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:16 -04:00
Bryan Schumaker 50f2f99074 ocarina: Created treeview and liststore
Track information will be stored in these structures.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:16 -04:00
Bryan Schumaker abac8883c3 libsaria: Give playlists a name
Right now this must be set when a new playlist is constructed.  I can
eventually change this to use a default name based on what type of
playlist has been created.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:16 -04:00
Bryan Schumaker cdd2fe1af5 Add a playlist renderer
The renderer doesn't actually render anything yet, but it is statically
defined in ocarina/playlist.cpp and it will eventually display the
library.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:16 -04:00
Bryan Schumaker b1eb47006d libsaria: Move the renderer into the playlist namespace
This makes more sense to me conceptually than having a class called
PlaylistRenderer.  I also commented out a lot of code, so the renderer
doesn't do anything right now.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:16 -04:00
Bryan Schumaker 59789ebc85 ocarina: Begin to set up for playlist code
I'm going to re-implement my old SongList class as a PlaylistRenderer,
so for now I create a new directory and a new header file.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:16 -04:00
Bryan Schumaker 6d709e3a18 libsaria: Add sorted songs to the Set playlist
I sort the subset of tracks to be added, and then use insertion sort to
add them to the playlist object.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:16 -04:00
Bryan Schumaker cfc50cf745 libsaria: Added Set playlist type
I think inheritance is easier than passing a bunch of flags and then
deciding what to do.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:16 -04:00
Bryan Schumaker 29cb7f7a47 libsaria: Create a static playlist for the library
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:16 -04:00
Bryan Schumaker dfb5c09260 libsaria: Remove most of the playlist class
I'm going to clean it up too, so I've removed everything for now to
slowly re-add later.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:16 -04:00
Bryan Schumaker 01d4819d15 libsaria: Add fields for play count and last played date
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:16 -04:00
Bryan Schumaker c38eaccf3a libsaria: Find audio information, too
Length, bitrate and various other fields.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:16 -04:00
Bryan Schumaker 97a0bb7260 libsaria: Find song file tags
I don't pull out the audio properties yet, but I do find artist, album,
title and everything else that I can.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:16 -04:00
Bryan Schumaker 011db26d92 libsaria: Pass library path to Track()
This will eventually be used to determine if the track is visible based
on library path visibility.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:16 -04:00
Bryan Schumaker b0c76f4b11 Notify when library paths have been updated
This gives the UI a chance to set the new path or new size.  I also
updated Ocarina to show the library path size in its liststore row.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:16 -04:00
Bryan Schumaker 8f666fe10c libsaria: Add new tracks to library paths during update
Right now the Track added is empty, but I'll fill it in soon enough.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:16 -04:00
Bryan Schumaker a944869093 libsaria: Clean out the Track class for re-implementation
This also removed the other `typedef sid_t` left in the header file.
I'll re-add in functions and variables as I need them, and hopefully
keep things working more efficiently.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:16 -04:00
Bryan Schumaker d77b06f267 libsaria: Remove sid_t type
I was using the sid_t to lookups for tracks and library paths.  I think
I can simplify things by storing pointers in the UI rather than using
id numbers.  This will give me direct access to whatever it is I want to
manipulate.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:16 -04:00
Bryan Schumaker 230a31a5a7 libsaria: Divide scan file list into smaller chunks
Each chunk is given to a new ScanTask to process.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:16 -04:00
Bryan Schumaker f5462da461 Find files to add to the library
I created a new "list_dir()" function to recursively list directory
contents.  I plan on using this to find songs to add to the library, but
it could also be modified to read playlists and library paths in the
appdir.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:16 -04:00
Bryan Schumaker 2c830af7fa Create a progress bar for idle tasks
Whenever a task is queued, I increment a counter.  When it is run, I
increment a different counter.  This allows me to track the idle queue
completion percentage.  I also created a progress bar for Ocarina to
display in the toes of the footer.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:15 -04:00
Bryan Schumaker 03d35fee77 libsaria: Only use the library::Driver for notifications
This allows other tools to be written to modify the library of a
currently running program without having to create a library driver
instance.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:15 -04:00
Bryan Schumaker a029a30d3a ocarina: Track more library information
I may need to look up library paths by ID, so I added library id as a
liststore field.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:15 -04:00
Bryan Schumaker e1b410845d ocarina: Set child propertys for GtkNotebook
The set_tab_packing() function is deprecated, so I might as well just
use the real way to do this...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:15 -04:00
Bryan Schumaker 032caad800 ocarina: Poll for idle queue tasks
I'm going to need a polling loop for the progress bar.  I might as well
only create one poll() function that is used to do everything...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:15 -04:00
Bryan Schumaker 30e2003a27 libsaria: Find library id from inode number
I want to eventually use this to create a library file for each library
path.  The "visible" field will be used to enable and disable different
paths during run time.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:15 -04:00
Bryan Schumaker 0a8600fd01 ocarina: Added placehold for controls
So I know what will eventually go there.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:15 -04:00
Bryan Schumaker a0b9c16178 ocarina: Use treeview to show library paths
My old settings page was basically doing this already, but in a slightly
more complicated way...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:15 -04:00
Bryan Schumaker ca161d3340 ocarina: Decrese the tab border
This makes tab labels smaller!

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:15 -04:00
Bryan Schumaker ecd9a28add ocarina: Return FALSE from the configure event
This tells gtk to continue processing the signal and actually redraw the
window...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:15 -04:00
Bryan Schumaker 4448ba7ce1 libsaria: Turn the library::Renderer into a library::Driver
This will provide a 2-way notification system, rather than just going
from libsaria to the UI.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:15 -04:00
Bryan Schumaker 111e8f2c3b libsaria: Created a library::Renderer class
The UI should inherit from this class to create a driver used to control
the library.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:15 -04:00
Bryan Schumaker ae9074103a libsaria: Create new LibraryPaths
The UI calls the library::add_path() function to create a new
LibraryPath structure to be managed by the library.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:15 -04:00
Bryan Schumaker 7c8ef5508e libsaria: Comment out most of the library
I want to gradually re-add everything and clean it up as I go along.  To
help with this, I comment out the old code so I can use it as a
reference while writing new code.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:15 -04:00
Bryan Schumaker e2cac7fda0 ocarina: Remove text from library buttons
Instead, I show the same information using tooltips.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:15 -04:00
Bryan Schumaker 06e613d901 ocarina: Don't assume scrolled windows for footer pages
This made the footer too big, in my opinion.  I have some other ideas
for how to fix it, though.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:15 -04:00
Bryan Schumaker 81da1743a5 ocarina: Add footer pages to scrolled windows
This will allow them to scroll if they get too big.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:15 -04:00
Bryan Schumaker 8f43bf62e4 ocarina: Created footer tabs
I'm going to use a ribbon-ish interface for the footer and work the
settings pages in with the now playing widgets to make things easier to
find.  Right now, I created everything with placeholders.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:15 -04:00
Bryan Schumaker 3d11ea47ba ocarina: Create default content for the window
I'm not using a notebook as the main widget anymore.  I'm also setting
the content directly, rather than getting the widget from the body code
and setting it in the window code.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:15 -04:00
Bryan Schumaker c0df8f2e2b libsaria: Take idle callback func during libsaria init
This allows me to enable the idle queue if the function pointer is not
NULL.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:15 -04:00
Bryan Schumaker ca35bfd46f ocarina: Track the window's maximized state
I need to do some hacky things if the maximization changes.  First, I
need to track the old (w, h) values and restore them in the preferences
since the configure-event will resize the window before the maximize
signal is given.  Next, I need to ignore the next configure event since
it'll overwrite the preferences with the size of the window when it was
maximized.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:15 -04:00
Bryan Schumaker 5c618de4df ocarina: Capture window resizing
I store the new size of the window in the preferences and use it the
next time ocarina starts up.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:15 -04:00
Bryan Schumaker 292d237561 libsaria: Idle queue cleanups
To make the code easier to follow and maintain.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:15 -04:00
Bryan Schumaker 84582ae9d8 libsaria: load preferences from disk during startup
This is one of the first things that happens when initializing libsaria.
This also allows me to remove the remaining commented out code from the
preferences file.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:15 -04:00
Bryan Schumaker 06412afeed libsaria: Save preferences in idle task after they change
I made a WriteTask class to use for saving files.  This allows me to
create a file in the appdir and write out the new preferences if they've
changed.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:14 -04:00
Bryan Schumaker a0da654fc6 ocarina: Resize window to match preference
I initialize the window size preferences to (800, 600) and then resize
the window to match.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:14 -04:00
Bryan Schumaker 3c19e4a3d9 ocarina: set window title and icon
I do this from the window init function using default values, rather
than pass it as a parameter to the init function.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:14 -04:00
Bryan Schumaker 698d449c34 vers_str() needs to be static inline
Otherwise we could possibly have multiple definitions of it.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:14 -04:00
Bryan Schumaker 5817effdde ocarina: Fix up include files and begin new window code
I combined the ocarina.h and gtk.h header files into one single file.  I
also began writing new window managing code under a window namespace for
code separation.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:14 -04:00
Bryan Schumaker 95cc9d272f libsaria: Begin appdir code
I'm going to replace my old path lookup code with something designed
around accessing files in a pre-set directory.  I'm also moving back to
putting files in the home diretory, rather than the XDG_CONFIG directory.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:14 -04:00
Bryan Schumaker 02740d1feb libsaria: Remove initflags and comment out init() functions
Instead, I pass a string with the name of the application being run.
This will be used to have separate applications using libsaria.

This commit also comments out most of the libsaria and ocarina init
functions until I can revise and clean up everything.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:14 -04:00
Bryan Schumaker 9aeae532d3 Ocarina: Set path prefix better
The string class already has functions for what I need, so I might as
well use them...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:14 -04:00
Bryan Schumaker 933fc308e6 libsaria: Variables in version.h should be static
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:14 -04:00
Bryan Schumaker d764489e89 libsaria: Create init flags
I eventually plan on creating more cpp binaries that link with libsaria
for pipe actions and other things.  It's helpful to only initialize the
parts of libsaria that I intend to use.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:01:14 -04:00
Bryan Schumaker af2d4833fa Begin Ocarina 5.8 2012-04-07 10:01:14 -04:00
Bryan Schumaker db00eb0908 libsaria: Include missing header file
This was needed for unlink()

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-04-07 10:00:05 -04:00
Bryan Schumaker 696da607ba Ocarina 5.7-rc 2012-03-06 08:12:51 -05:00
Bryan Schumaker 37bcb47de2 libsaria: Check the top of the stack through a function
The UI shortcuts may remove songs from the queue with no way of
notifying the stack layer.  The UI should call the stack_top_pop()
function to check if the top playlist is empty and ready for removal.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-03-05 08:23:00 -05:00
Bryan Schumaker ed3254813c libsaria: Playlist tells renderer where to insert tracks
Now renderers don't need to track this on their own, and renderers will
update as tracks are added.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-03-05 07:47:55 -05:00
Bryan Schumaker 3c423e986a libsaria: Load playlists on startup
I removed this in a previous patch by accident, but I fixed it now.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-03-04 10:29:39 -05:00
Bryan Schumaker 981b64a635 libsaira: Pass a flag if renderers should be deleted
Not all renderers are created dynamically, so I made a way of telling
the playlist system if renderers should be deleted.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-03-04 10:13:44 -05:00
Bryan Schumaker dd5e73a2ba libsaria: Delete playlists and renderers when popped
This allows dynamic memory to be freed when we are done using it.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-03-04 10:02:03 -05:00
Bryan Schumaker 83897633ce Dynamically allocate queue playlists
I only allow one queue instance right now, but this allows me to remove
the queue directory since it is no longer needed.  I also removed the
QUEUE_REFRESH callback since all this is handled through the libsaria
playlist code.  All that's left is reloading saved playlists on startup.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-03-03 14:19:33 -05:00
Bryan Schumaker d7725d9068 ocarina: Allocate SongLists when they are needed
Right now it's just for a single queue, but I should be able to expand
this once I enable more stacking in the backend.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-03-02 08:09:35 -05:00
Bryan Schumaker c23c4a2740 ocarina: Add tabs from Songlist init()
If Songlists manage this, then I can have them remove their pages
through on_playlist_empty().

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-28 08:16:25 -05:00
Bryan Schumaker ef62f5d2b0 libsaria: Alert the PlaylistRenderer when the playlist becomes empty
This allows for bookkeeping and other cleanup (schedule playlist
removal, remove from UI, and so on).

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-28 08:16:23 -05:00
Bryan Schumaker d41c64c798 ocarina: Remove the Page class
This patch does two things.  First, I remove the Page class and let each
notebook page manage itself.  Second, I created functions to add the
header and footer to a GtkWidget and then prepend the page in the
notebook (so it adds pages as if it was a stack).

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-27 11:31:33 -05:00
Bryan Schumaker b7e1c2c631 libsaria: Create a Playlist stack
My goal is to eventually pick songs from whatever is on top of the
playlist stack.  Right now, only the library is added and no songs are
picked.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-25 17:21:19 -05:00
Bryan Schumaker 8d50e63df2 libsaria: Remove refresh() after picking next queued song
Unfortunately, this doesn't hide the queue when empty anymore.  I
probably won't see this behavior again until I create the stack.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-25 14:04:31 -05:00
Bryan Schumaker e03dfb33b8 libsaria: Remove indices from the queue
This replaces the "remove id" ability and replaces it with a "remove
index" ability.  Removing an index will remove the correct song in the
case that the same song has been added multiple times.  I also modified
the UI to remove rows at a specific index.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-25 13:50:56 -05:00
Bryan Schumaker 6637a82573 ocarina: Remove the SongListFuncs struct
I can get everything I need using playlists and renderers, so I can
safely remove this bit of code (I never really liked it anyway...).  I
have to keep around the queue::size() function for a little bit longer,
since choosing the next song still uses it.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-25 10:52:35 -05:00
Bryan Schumaker f7d7589882 libsaria: Remove library and queue iterator functions
I don't need these now that I have playlist renderers, so I might as
well rip out the code while I'm thinking about it.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-25 10:11:26 -05:00
Bryan Schumaker 4ebfd8a33b libsaria: Use a tighter loop to fill in the playlist
Rather than exposing iterator functions, I now have a function to walk
the playlist and call the renderer insert() function for each track.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-25 10:04:19 -05:00
Bryan Schumaker 055f349cd1 libsaria: Playlist knows about the renderer
I plan on using this to fill in each playlist instead of using my
current iterator system.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-25 09:50:35 -05:00
Bryan Schumaker f795af5d6c libsaria: Created a playlist renderer
This class will be given a Playlist and will be in charge of calling
Playlist functions.  I eventually plan on expanding this to allow the
playlist to call renderer functions instead of using my current callback
system.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-25 09:45:27 -05:00
Bryan Schumaker d8b6f5b0a0 libsaria: Queue size uses apparent_size()
I don't have filtering enabled right now, but I may change my mind in
the future.  Might as well prepare now...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-24 09:44:37 -05:00
Bryan Schumaker 4ee79d8385 libsaria: Always load the library first
Other playlists need this, so it makes sense to queue this up first.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-24 09:36:14 -05:00
Bryan Schumaker 3472aec5bf libsaria: Save idl_task to filename
This was hardcoded to "queue.q"

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-24 09:35:44 -05:00
Bryan Schumaker 98573bf3a9 libsaria: Create a function for reloading a playlist
I don't think I'll need this once I implement dynamic, stackable
playlists, but for now I need a way of scheduling the idle task.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-24 09:34:18 -05:00
Bryan Schumaker f3abd0cbc6 libsaria: Fix sequential_next()
the while(true) created a state where the loop never ended.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-24 09:26:25 -05:00
Bryan Schumaker aaeb4d8fba libsaria: Replace SaveTask and LoadTask
I put in a generic IOTask function.  I'm sure this could eventually be
expanded to open and pass the appropriate stream to functions using this
task.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-23 09:57:52 -05:00
Bryan Schumaker a9abe28d84 libsaria: Don't choose a random song if none are visible
This lead to a floating point exception and crashed Ocarina.  Oops...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-23 09:31:10 -05:00
Bryan Schumaker b5339f8688 libsaria: Remove the library/list subdirectory
I moved all the functions into a single file and bumped that file up one
directory.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-23 09:26:02 -05:00
Bryan Schumaker 8a52471c95 libsaria: Remove the old library track list
I've completely replaced it with a Playlist now.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-23 09:17:54 -05:00
Bryan Schumaker b46a4e38ac libsaria: Check random preference in some cases
If both PL_RANDOM and PL_SEQUENTIAL are enabled, then I want to check
the random preference to determine what to do.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-23 09:15:04 -05:00
Bryan Schumaker d902de95cc libsaria: Pick a random song from the playlist
I do this if PL_RANDOM is set before checking PL_SEQUENTIAL.  I still
need to respond to the case that both flags are set...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-22 10:10:17 -05:00
Bryan Schumaker d075773682 libsaria: Give playlists an apparent_size() function
This will return the number of visible songs, instead of the number of
songs in the playlist.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-22 10:03:40 -05:00
Bryan Schumaker 9980f53f63 libsaria: Iterate past invisible songs when choosing next
If the PL_FILTER flag is enabled, then we skip songs that aren't
currenly visible.
2012-02-21 10:05:45 -05:00
Bryan Schumaker c8ad4371d6 libsaria: Added playlist flags and improved next()
The improved next() function will increment the current iterator to the
next visible song.  If no songs are visible, then it moves to the next
song on the list.  The PL_DRAIN flags is then checked, and if draining
is enabled then the current track is removed from the list before
returning.

This patch also switches over the library sequential next function to
use the lib_playlist version.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-21 09:47:23 -05:00
Bryan Schumaker 8b9457a8d0 libsaria: Remove library::find_filepath()
I can do this easier with library::lookup() since this avoids having to
loop on the entire track_list.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-20 10:02:56 -05:00
Bryan Schumaker cc224376fa libsaria: Replace library::get_info()
get_info() performed a loop over all library paths and over each track
in each path to find the requested sid_t.  I now keep a map sid_t ->
Track * to make finding the track easier and faster.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-20 09:44:57 -05:00
Bryan Schumaker 8069144e87 libsaria: Get library size from the library playlist
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-20 09:22:47 -05:00
Bryan Schumaker 8af182fac9 libsaria: Change playlists to a list of Track pointers
This allows more direct access to each item in the list.  It also speeds
up sorting, since I don't need to keep looking up the same tracks over
and over again in the library.

Siged-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-19 17:58:23 -05:00
Bryan Schumaker 7b6ecfdd99 libsaria: Sort the Playlist
I do this whenever the sort() function is called.  I eventually want a
more automatic way of doing this, so I expect the function won't exist
for long.
2012-02-19 17:47:29 -05:00
Bryan Schumaker f352952924 libsaria: Add and remove individual tracks to a playlist
I can easily get the sid_t out of the Track pointer, so I might as well
allow this for now...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-19 17:37:04 -05:00
Bryan Schumaker e52e6ae3b0 libsaria: Don't require filename when creating a Playlist
A Playlist created without a filename will sever be loaded or saved.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-19 17:28:13 -05:00
Bryan Schumaker 7a272e35f5 libsaria: Create load and save functions in the Playlist
These create and schedule idle tasks that perform the actual loading or
saving.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-19 17:17:26 -05:00
Bryan Schumaker 2813481dff libsaria: Remove old queue code
With Playlists this code is no longer needed.  I'll remove more of this
code once I've updated the UI.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-19 17:17:26 -05:00
Bryan Schumaker 57c8fcf030 libsaria: Save a playlist whenever it changes
With this change, my old queue code no longer saves itself.  Instead, it
only sends out QUEUE_REFRESH notifications.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-19 17:17:25 -05:00
Bryan Schumaker 00274a836f libsaria: SaveTasks take an extra argument
I want to pass a Playlist through to save a changing playlist.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-19 17:17:25 -05:00
Bryan Schumaker 83e3fa4b24 libsaria: Pick next song from the Playlist
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-19 17:17:25 -05:00
Bryan Schumaker 95aa5802cd libsaria: Remove ids from a playlist
Note that this follows the broken implementation used by the queue.  It
will remove all ids with the given values rather than the ones at a
specifix index.  This will be fixed later when I update the UI to make
it Playlist-aware.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-19 17:17:25 -05:00
Bryan Schumaker 7aca058254 libsaria: Give Playlists a size() function
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-19 17:17:25 -05:00
Bryan Schumaker 6866200e42 libsaria: Implement playlist iterators
I replace the old queue iterator functions with calls to the queue
playlist object that way I don't need to modify the UI.  This creates a
common iterator that can be used by all playlists.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-19 17:17:25 -05:00
Bryan Schumaker 356f6c0465 libsaria: Add ids to the queue playlist
I could read the queue file, but that doesn't help me add new songs...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-19 17:17:25 -05:00
Bryan Schumaker 2fa54e76ac libsaria: Create a parallel queue as a Playlist
My goal is to slowly phase in use of a Playlist class.  This patch
begins this effort by creating the Playlist class and changing the queue
code to load queue.q as a playlist in addition to the queue's hardcoded
list.

Signed-off-by: Bryan Schumake <bjschuma@gmail.com>
2012-02-19 17:17:25 -05:00
Bryan Schumaker c452af1ce7 libsaria: LoadTasks take an extra argument
I want to pass a playlist argument through during playlist construction,
so I changed the LoadTask to handle it.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-19 17:17:25 -05:00
Bryan Schumaker 7a355d1434 libsaria: Remove the SourceModel class
Nothing has used it in a few months, so it can safely be removed.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-19 17:17:25 -05:00
Bryan Schumaker 1470b908c2 libsaria: Remove dir.cpp.orig
Where did this file ever come from?

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-19 17:17:25 -05:00
Bryan Schumaker 1933689d4f Added copyright lines to everything
I probably should have done this earlier... oh well

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-19 17:17:24 -05:00
Bryan Schumaker e49a9bd114 Begin Ocarina 5.7 2012-02-19 17:17:24 -05:00
Bryan Schumaker 454f83ef9b Ocarina 5.6.2 2012-02-19 17:16:48 -05:00
Bryan Schumaker c3ed28250c libsaria: Return the correct saria directory
My environment variables were set in a way that the path
/home/bjschuma/~/.config/saria-debug was being returned as the working
directory.  Obviously this is wrong, so I changed the function to make
better use of default values when finding the directory.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-19 17:14:44 -05:00
Bryan Schumaker f51013c97c Ocarina 5.6.1 2012-02-17 22:18:17 -05:00
Bryan Schumaker ed0ace5366 build: Configure scripts to use the correct lib directory
When installing through the PKGBUILD, a non-blank DESTDIR is used and
the ocarina-* scripts are configured to use the package directory rather
than the installed directory.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-17 22:06:45 -05:00
Bryan Schumaker f6fd7915c9 Ocarina 5.6 2012-02-17 08:27:12 -05:00
Bryan Schumaker 98a2dc316a libsaria: Free alsa value array
I don't want to be leaking memory...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-11 12:57:22 -05:00
Bryan Schumaker 01bd48d6cc libsaria: Call add_alsa() during startup
Rather than resetting the preference, it's easier to call the add_alsa()
function if the preference is set.  This also cuts down on startup
warnings!

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-11 12:57:22 -05:00
Bryan Schumaker bec76743da libsaria: Call gst_quit()
This gives gstreamer a chance to free anything it's created.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-11 12:57:22 -05:00
Bryan Schumaker defa6185c2 Ocarina 5.6-rc
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-11 12:57:20 -05:00
Bryan Schumaker 5d687176e8 tests: Began creating test programs
I want these to help check for memory leaks and other problems.  Maybe
one day I can run them through Jenkins!

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-09 08:22:40 -05:00
Bryan Schumaker 9e322433d5 libsaria: Set about-to-finish from ALSA
I've found that without ALSA enabled, the about-to-finish will hang.  To
solve this, I only enable it when ALSA is enabled.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-09 08:04:52 -05:00
Bryan Schumaker 46ae66634e Ocarina: Check for a current alsa device before setting
Otherwise we set a C++ string to NULL and it throws an exception...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-09 08:04:01 -05:00
Bryan Schumaker 9ead002ab8 ocarina: Add stop as a pipe action
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-09 08:03:54 -05:00
Bryan Schumaker 234626ea81 ocarina: Escape tooltip text
GTK was printing a warning whenever a non-escaped string was hovered
over.  The tooltip was also empty.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-08 08:24:07 -05:00
Bryan Schumaker cefbf36415 ocarina: Free strings created by g_markup_escape_text()
This function returns a newly allocated string, so I can't set it
directly to a C++ string since this will leak memory.  Instead, I need
to keep the char* pointer around to free it.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-08 08:19:48 -05:00
Bryan Schumaker dce461656f scons: Install multiple scripts
Each script acts as an ocarina sub-command, and each write through the
ocarina-write-pipe script.  Note that these scripts cannot be run
directly, and need to run through a processor in the Sconstruct file to
set the correct paths.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-08 08:11:14 -05:00
Bryan Schumaker 152e7009d8 scons: Create a ocarina-debug launcher
My Sconstruct now supports installing a debug build to
/usr/lib/ocarina-debug and launching through ocarina-debug.  This should
allow me to test pipe related scripts
2012-02-08 08:11:14 -05:00
Bryan Schumaker a1672b83c4 scripts: Remove makepipe
This is now handled by libsaria

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-08 08:11:14 -05:00
Bryan Schumaker 280baa7572 libsaria: Allow different UIs to use a different pipe
The UI now passes in a string to use as the filename.  In addition, I
store the filename and remove it when the application is closed.  If the
pipe already exists, then I return the path without creating a new one.

Pipes will only be removed by the application that creates them.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-08 08:11:13 -05:00
Bryan Schumaker 0aa8b950a9 ocarina: Scroll to saved song
I save the song before refreshing the library so I can scroll back to
it.  This way the user isn't interrupted too much...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-08 08:11:13 -05:00
Bryan Schumaker 362a0697c9 ocarina: Scroll to a songid instead of a Track
I want to store the currently selected row and go back there after a
refresh or a filter.  This allows me to find the current songid and
scroll back to it later.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-08 08:11:13 -05:00
Bryan Schumaker bc0be6d831 ocarina: Set column visibility through function
I eventually want to be able to choose what columns are shown, so I need
them added to the treeview but now shown.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-08 08:11:13 -05:00
Bryan Schumaker a3c8128bbe ocarina: Add a tooltip column to the liststore
The tooltip is the filepath of the selected track.  This should help me
figure out what some non-tagged tracks are...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-08 08:11:13 -05:00
Bryan Schumaker f72447decc ocarina: New column registering framework
I keep one array instead of two, and I store more information for each
array entry.  I can then find the size of the array for the number of
columns, and I can add new columns without having to modify the allay,
treestore and liststore.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-08 08:11:13 -05:00
Bryan Schumaker 8623779210 libsaria: Reduce library refreshes during update
The library only needs to refresh if new tracks were found, so don't do
anything if nothing new has been added.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-08 08:11:13 -05:00
Bryan Schumaker 6fd4d01e37 ocarina: Each page gets its own custom header
I eventually only want the library page to have this header, but setting
this up allows me to remove the "switched page" logic that may (or may
not) have been causing problems.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-08 08:11:13 -05:00
Bryan Schumaker 551ae682b5 ocarina: Provide a UI for using ALSA
You can either turn it on or off, and then you can select an output
device from a dropdown list.

Signed-off-by: Bryan Schumaker <bjschuma@netapp.com>
2012-02-08 08:11:13 -05:00
Bryan Schumaker 01288e1a86 Libsaria: Make alsa controls its own thing
I created a new preference for "Using ALSA" that people can set if they
want to use extra alsa features.  This should allow the UI to provide a
dropdown list of outputs that users can select.  Once a UI is in place,
users can play music either on their computer speakers or pipe it out to
their blu ray players (or other device).

Signed-off-by: Bryan Schumaker <bjschuma@netapp.com>
2012-02-08 08:11:13 -05:00
Bryan Schumaker 56f0e801f5 ocarina: Give each page its own footer
After listening to a long queue, I noticed that there were problems
re-realizing widgets after moving the footer to a different page (the
header might have the same problem?).  I decided to fix this issue by
creating a new footer instance for each notebook page.

If I do the same thing for the page header then I can get rid of the
"move this widget from page X to page Y" logic AND allow pages to use
their own custom header AND allow for separate library and queue
filters.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-08 08:11:13 -05:00
Bryan Schumaker 41467524db ocarina: Listen for text written to a named pipe
If the text is "play", "pause", or "next" then I call the appropriate
libsaria function.  I eventually plan on adding more commands so bash
can act as a generic remote control, but for now this is a good start!

To use:  `echo play > ~/.config/saria[-debug]/saria.pipe` after creating
the fifo (see scripts/makepipe).

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-08 08:11:13 -05:00
Bryan Schumaker 82b9974448 libsaria: Get the path to the pipe file
This will either return the full path to the file or an empty string if
no pipe has been created.
2012-02-08 08:11:13 -05:00
Bryan Schumaker e1c527c6e7 Add a script to create a pipe
I should eventually work this into the main ocarina script somehow, but
probably not until I get generic commands going.  `ocarina openpipe`
should do...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-08 08:11:13 -05:00
Bryan Schumaker 4c36e0b7e2 ocarina: Don't set progress bar to a value greater than pipeline
duration

This can happen because of gapless playback in the gstreamer pipeline.
It fails a gstreamer assertion, so I need to look out for it.
2012-02-08 08:11:13 -05:00
Bryan Schumaker b2f72df146 libsaria: Don't notify_audio_changed() in main loop
I have a hard time remembering how this works, so instead I leave it up
to the UI to determine how to handle this event running from multiple
threads.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-08 08:11:13 -05:00
Bryan Schumaker 1f02fa3d9c ocarina: Force callbacks onto the main thread
Gstreamer uses multiple threads, and doing gtk calls outside the main
thread can lead to X11 errors.  I get around this by creating a new
signal to respond to by the main loop.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-08 08:11:13 -05:00
Bryan Schumaker 747ba85fbb libsaria: Never return negative duration
A negative duration doesn't make sense, so return 0 instead.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-08 08:11:13 -05:00
Bryan Schumaker e7e1bb352a libsaria: Remove OutFile print statement
It was triggering too often during a library update, so I removed it.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-08 08:11:13 -05:00
Bryan Schumaker c7abfb6496 libsaria: Save queue in a background task
We can easily do this a little bit later to improve performance.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-08 08:11:13 -05:00
Bryan Schumaker 4b9fde453b Ocarina: Clean up the settings page
The new code is a bit simpler, and it correctly fills in the list of
library paths during startup (I still have no idea why this didn't
happen with the old code).

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-08 08:11:13 -05:00
Bryan Schumaker 808927da45 libsaria: Export size of a library path to the UI
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-08 08:11:13 -05:00
Bryan Schumaker a0b7718ee7 ocarina: Don't lock gdk when doing an idle_add call
idle_add needs the gdk lock, so it can't already be held when entering.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-08 08:11:13 -05:00
Bryan Schumaker 1daa12ee81 libsaria: Create a library path iterator
This makes it easier to loop over all the library paths without needing
to know anything about implementation.  I modified the update functions
to use the new way, so it should be ready for use by the UI.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-08 08:11:13 -05:00
Bryan Schumaker 12b193cc80 libsaria: Move LibraryPath to a global header
I am going to expose this class to the UI so it can directly access
information (size, path, ...).

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-08 08:11:12 -05:00
Bryan Schumaker d6c48ca177 libsaria: Add the library path to the libsaria namespace
I want to move it to a global header file, so it needs to be added to
the libsaria namespace.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-08 08:11:12 -05:00
Bryan Schumaker 3d511a1f19 libsaria: Remove old callback framework
I moved ocarina over to the new system, so the old one can go away now
since it isn't thread safe and nothing uses it anymore.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-08 08:11:12 -05:00
Bryan Schumaker 6b6b2814c3 ocarina: Created thread-safe ocarina callbacks
I use the gdk threading functions to change my gtk code.  This should
create fewer UI inconsistencies whenever anything changes, and it should
also allow me to trigger TRACK_LOADED from a new gstreamer thread.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-08 08:11:12 -05:00
Bryan Schumaker 7150e8bdee libsaria: Prepare for a single callback handler function
Rather than keeping a map of function pointers, I want the UI to
register a single function that takes a callback_t as an argument.  From
there, the UI can decide the best way to handle callback lookups (such
as grabbing a lock before changing anything).  At the very least, a
switch statement or array lookup should be faster than searching a map.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-08 08:11:12 -05:00
Bryan Schumaker 12f6723111 Begin work on Ocarina 5.6 2012-02-08 08:11:12 -05:00
Josh Larson 0d63656df8 Fixed bug with unset environment variable.
When either HOME or XDG_CONFIG_HOME are unset getenv() can return NULL.
C++ strings don't like being set to NULL, so we need to check for this
case.

Bryan: Edited Sconstruct and commit message.

Signed-off-by: Josh Larson <theMutatedShrimp@gmail.com>
Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-08 08:10:19 -05:00
Bryan Schumaker fe7bf9e445 libsaria: Check if a song exists before loading it
This could lead to a segmentation fault if we don't do it...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-07 22:25:13 -05:00
Bryan Schumaker 51e5887971 libsaria: Rename the index rand() function
I found it was calling itself over and over again, rather than calling
the stdlib rand().  This wasn't the desired behavior...

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-02-07 08:47:24 -05:00
Bryan Schumaker d00ed2ebdc Update PKGBUILD for the new release
I have been doing this as part of the release process, but it's slightly
easier to do it as a commit after.  I was having too much trouble
keeping the hash correct in the last few months.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
2012-01-23 08:21:26 -05:00
Bryan Schumaker 4f0671e4a7 Ocarina 5.5 2012-01-23 08:04:39 -05:00
Bryan Schumaker e11df95c1b Ocarina 5.5-rc 2012-01-04 08:28:07 -05:00
Bryan Schumaker 3e458e2d9f libsaria: Validate library before adding new songs
If a file has been moved to another location in the same library root
the new location won't be added since it'll have the same inode number.
The track would then be removed during the library validation step.  I
switch the order for correctness.
2012-01-04 08:22:21 -05:00
Bryan Schumaker b503536d57 libsaria: Fix iterator initializer bug
It was being initialized with '==' instead of '=', so the for loop was
always causing a segmentation fault.  This was caused by commit
180707a6c2

Author: Bryan Schumaker <bjschuma@gmail.com>
Date:   Thu Dec 29 22:08:53 2011 -0500

	libsaria: Remove redundant code

	Nothing needs to call this function anymore.  I also cleaned
	up the header file a bit.
2011-12-31 11:19:31 -05:00
Bryan Schumaker e21f0e251c libsaria: LibraryPath()s load their own directory
It makes more sense to set this variable directly from the save file
rather than read it in and pass it as an argument.
2011-12-31 11:13:36 -05:00
Bryan Schumaker 41ec0b68e0 libsaria: Validate library tracks after updating
I check two things during this step:

1) Does the file still exist?
2) Does the file have the same inode number?

If the answer to either of these is "no", then the track is removed from
the library.
2011-12-31 10:48:05 -05:00
Bryan Schumaker d4ac6a870f ocarina: Remove from queue keybinding
Select some tracks and press delete.
2011-12-30 23:32:07 -05:00
Bryan Schumaker 58800be19a ocarina: Create a remove from queue menu item
Now I can remove things from the queue if I change my mind!
2011-12-30 23:27:45 -05:00
Bryan Schumaker 3fa1331303 libsaria: Remove ids from the queue
In case the user changes their mind...
2011-12-30 23:27:15 -05:00
Bryan Schumaker 425c7421ed libsaria: Switch to using a list for the queue
A deque won't allow me to remove elements from anywhere in the queue, so
using a linked list is a better choice.
2011-12-30 23:15:07 -05:00
Bryan Schumaker d655739b77 libsaria: Save queue to disk
This will restore the queue the next time ocarina is started up.
2011-12-30 20:26:36 -05:00
Bryan Schumaker 8a0922c4a1 libsaria: Generic LoadFile() task
This was specific to the library namespace, but I think it makes more
sense to exist as a global class definition that can be reused by
others.
2011-12-30 20:22:47 -05:00
Bryan Schumaker 11e82cccf1 libsaria: Save queue to disk
I save when IDs are added and when a next track is chosen.
2011-12-30 20:02:24 -05:00
Bryan Schumaker 30c45f608f ocarina: Modifications for the new current_track() function
Without this patch ocarina/ won't compile...
2011-12-30 19:48:04 -05:00
Bryan Schumaker 4dac0fe096 libsaria: New current_track() function
Instead of taking a callback function,  I instead find a pointer to the
current track and return this to the caller.
2011-12-30 19:47:13 -05:00
Bryan Schumaker 0ef8e44207 libsaria: Remove unused variable from Track() 2011-12-30 19:46:54 -05:00
Bryan Schumaker 94a17a32a4 ocarina: Play file after loading
Somewhere along the line I lost the call to play() when a non-library
track is loaded from the harddrive.
2011-12-30 19:45:27 -05:00
Bryan Schumaker a44ecbb795 libsaria: Remove old readdir() function
It's not used anymore...
2011-12-30 19:15:03 -05:00
Bryan Schumaker ab0e459298 libsaria: Change track cleanup process
Tracks only need to be unlisted from the library list when they are
manually removed by the user.  Trying to do this during shutdown lead do
a segfault because the library's file_list had already been removed when
I tried to access it.
2011-12-30 16:42:04 -05:00
Bryan Schumaker 2a9900c1e5 libsaria: Tracks remove themselves from the list
This is mostly for when a library path is removed from the list.  Tracks
all remove themselves when destroyed, and then the library can be
refreshed.
2011-12-30 16:05:35 -05:00
Bryan Schumaker 26979eb6a9 libsaria: Track()s add themselves to the index and library
When one is created, it adds itself to the library and index.  Up next:
removing themselves when they are destroyed.
2011-12-30 15:57:14 -05:00
Bryan Schumaker 6b7c3f3d50 libsaria: Use dynamic memory for library tracks
This allows me to create only one Track() instance for each song in the
library.  Before this, a Track() was being created and then copied when
adding new songs to the library.  I thought this was wasteful, so now
each song is only created once.
2011-12-30 15:50:21 -05:00
Bryan Schumaker ff4fcbf809 libsaria: Clean up path scanning code
I have an easier time figuring out what's going on now.
2011-12-30 15:03:45 -05:00
Bryan Schumaker 180707a6c2 libsaria: Remove redundant code
Nothing needs to call this function anymore.  I also cleaned up the
header file a bit.
2011-12-29 22:08:53 -05:00
Bryan Schumaker bdf359e008 libsaria: Remove path.cpp file
I moved these functions into the main library.cpp file
2011-12-29 21:54:51 -05:00
Bryan Schumaker 8e8eec3556 libsaria: Move update_path() function
Now it's in the library.cpp file.
2011-12-29 21:42:07 -05:00
Bryan Schumaker dbeb2981d4 libsaria: Move update code to path subdir
This keeps it all together and makes editing the library less confusing.
2011-12-29 21:12:27 -05:00
Bryan Schumaker ad989fdcd7 libsaria: Move more LibraryPath() code to the subdirectory 2011-12-29 21:02:24 -05:00
Bryan Schumaker df7e677bf2 libsaria: Remove unused LibraryPath function
I don't need to get the list of tracks anymore, now that my for_each
function has been removed.
2011-12-29 20:46:01 -05:00
Bryan Schumaker d74efc6022 libsaria: Remove barely used size function from LibraryPath
It was used internally once and externally once (to print out the
current size).  It can easily be removed to clean things up.
2011-12-29 20:43:46 -05:00
Bryan Schumaker 995a372a6e libsaria: Library code can access the path_list directly
This makes more sense than using an accessor function.  Nothing outside
the library can use this variable, so there shouldn't be other problems.
2011-12-29 20:37:05 -05:00
Bryan Schumaker fe8a293377 libsaria: Move library's LoadTask() to file.cpp
This is the only place it's used, so it makes sense to define it there.
2011-12-29 20:31:54 -05:00
Bryan Schumaker 9da577daa0 libsaria: Begin moving LibraryPath class to subdirectory
I think it'll be easier to work with if it is self-contained in a
subdirectory.  Otherwise it's too mixed in with the library code to be
maintainable.
2011-12-29 20:27:04 -05:00
Bryan Schumaker 8b78203fc7 ocarina: Fix compile error
I forgot to remove the for_each() function from the library code.
2011-12-29 20:21:03 -05:00
Bryan Schumaker 63140fb6a0 libsaria: Remove queue for_each
It's been replaced with iterator functions.
2011-12-29 16:25:34 -05:00
Bryan Schumaker 02f8dbc6b8 ocarina: Fill queue using iterator functions
I don't need the old for_each method anymore, either.  I remove it using
this patch.
2011-12-29 16:24:54 -05:00
Bryan Schumaker fe8c1cd580 libsaria: Create iterator functions for the queue 2011-12-29 16:24:33 -05:00
Bryan Schumaker 3749b56bfd libsaria: Remove old list file
I've completely replaced it with my new list now.
2011-12-29 15:47:11 -05:00
Bryan Schumaker ec2aadbc2d libsaria: Move get_info() function to new list 2011-12-29 15:43:17 -05:00
Bryan Schumaker fb0084c275 libsaria: Remove old play_id() function
Nothing uses it anymore
2011-12-29 15:35:06 -05:00
Bryan Schumaker 17e4f3f2ca ocarina: Use new playid() function 2011-12-29 15:33:48 -05:00
Bryan Schumaker 8049a7a9fd libsaria: Select songid using libsaria controls.cpp
I do this in the upper level namespace, rather than doing it in the
library, to make use of the play_filepath() function that I already have
written.
2011-12-29 15:32:15 -05:00
Bryan Schumaker c1cc33877c libsaria: Find filepath from songid using new list 2011-12-29 15:30:30 -05:00
Bryan Schumaker 7b78f18e52 libsaria: Remove next() from the queue
I don't need it anymore.
2011-12-29 15:10:00 -05:00
Bryan Schumaker bcc34ef4b0 libsaria: Choose next song from the new list
I removed the old list functions while I was at it.  I also changed the
next() function in the controls.cpp file to work with filepaths so the
library and queue won't have to load the chosen file themselves.
2011-12-29 15:06:12 -05:00
Bryan Schumaker 942c518394 libsaria: Remove for_each() from library
I don't need it anymore.
2011-12-29 14:20:53 -05:00
Bryan Schumaker fea84b90ac libsaria: Move list size function
It now exists with my new playlist code, since I'm phasing out the old
code.
2011-12-29 12:28:00 -05:00
Bryan Schumaker 5dcfac8be2 ocarina: Use the iterators to fill the library list
I keep the old way around for the queue until I can change that, too.
2011-12-29 12:09:35 -05:00
Bryan Schumaker 2fd41ff4d7 libsaria: Create iterator functions for the library
I use these to fill in the UI list for the library.  I think this will
be easier to use (and cleaner) than passing a function pointer to a
for_each loop.
2011-12-29 12:08:32 -05:00
Bryan Schumaker 0fa608c90f libsaria: Sort the new playlist after reading
Otherwise it won't be useful...
2011-12-28 23:04:41 -05:00
Bryan Schumaker 2effa26b32 libsaria: Began new playlist namespace
It'll exist in parallel to the current list for now.  I'll remove the
old one once the new one has all the same features.
2011-12-28 22:25:55 -05:00
Bryan Schumaker 336f188686 libsaria: Sort list using comparison operator
It makes sense to define a function for sorting tracks as part of the
track class, rather than having to implement it externally.
2011-12-28 22:03:43 -05:00
Bryan Schumaker 1e5628d059 libsaria: Find lowercase tags when creating a track
This avoids several lookups during list sorting, so initial startup
should be a little bit faster now.
2011-12-28 17:40:11 -05:00
Bryan Schumaker a3130a7da5 libsaria: Cache lowercase strings, too
This is useful for sorting the library when filling in the list, since I
do many comparisons with the same artists and albums.  This beats having
to lowercase them every time!
2011-12-28 11:00:08 -05:00
Bryan Schumaker 8e4b3dfbfe libsaria: Don't track cache misses
Each cache miss will add a new word to either the format cache or the
substring cache.  I can look at the size of the caches to determine the
number of misses rather than keep track of this with a new variable.
2011-12-28 10:23:17 -05:00
Bryan Schumaker 147a212809 libsaria: Format to a set of words
I don't care about the order of words for indexing, and I don't need
duplicates either.  Formatting to a unique set of words should make
things a little faster.
2011-12-28 10:15:08 -05:00
Bryan Schumaker abfd67cc84 libsaria: Refresh index while scanning
This keeps the index up-to-date with the library.  Tracks are indexed as
they are scanned, then the current filter string is run through the
index again to update it.
2011-12-27 23:02:09 -05:00
Bryan Schumaker 26a18f331e libsaria: Remove old index code
It has been replaced with my new index.
2011-12-27 22:42:50 -05:00
Bryan Schumaker 1d3baa79d5 libsaria: Implement index::rand()
Needed to get a random song from the index when filtered.
2011-12-27 22:41:54 -05:00
Bryan Schumaker 5bf0a26584 ocarina: Filter using the new index
This is why I made it...
2011-12-27 22:31:52 -05:00
Bryan Schumaker 83488dfa06 libsaria: Add filtering to the new index
Otherwise it's useless.  I search all three indexes and use the union of
those results to determine what is visible.
2011-12-27 22:30:38 -05:00
Bryan Schumaker 9c749e4ade libsaria: Began new index
Right now I just add songs to it and cache substrings for each word.  I
also print out stats during libsaria shutdown.
2011-12-27 19:42:46 -05:00
Bryan Schumaker 52a3e73023 libsaria: Print format_cache stats
I wanted to know how often there were cache hits and misses, so I print
out these stats on shutdown.
2011-12-27 19:42:27 -05:00
Bryan Schumaker 664ad0dad2 libsaria: Cache words generated from strings
I now look up a list of words from a map (if it exists), rather than
having to iterate over the same string potentially many times.
2011-12-27 18:48:57 -05:00
Bryan Schumaker 6eaa8f944c ocarina: Changes for the TrackTag() class removal 2011-12-26 12:14:35 -05:00
Bryan Schumaker a74cea2e71 libsaria: Remove old TrackTag() class
It was basically a layer of misdirection that made it harder to use
Tracks.  The Track() class now does everything that the TrackTag() one
did.
2011-12-26 12:14:25 -05:00
Bryan Schumaker 11e3d77dca ocarina: Remove references to ino_t
sid_t is more obvious that it's a song id.
2011-12-25 23:30:28 -05:00
Bryan Schumaker 5f20899b14 libsaria: Remove references to ino_t
I want to use sid_t instead.  It's more obvious what it's used for.
2011-12-25 23:29:35 -05:00
Bryan Schumaker f047c72521 Ocarina: sid_t changes
Use the "get_songid()" function rather than "get_inode()"
2011-12-25 23:07:58 -05:00
Bryan Schumaker e4f7fde197 Create a typedef for song ids
Passing around an inode number doesn't tell people what the inode is
used for.  Typedefing it to a song id is more helpful.
2011-12-25 23:07:58 -05:00
Bryan Schumaker da118b2281 libsaria: Switch to the new OutFile() class
The new class is more convenient to work with since it's the output
stream with my save protocol built in.  I should have done this earlier!
2011-12-25 22:34:12 -05:00
Bryan Schumaker 5877d3ac4a libsaria: Created a new OutFile() class
Similar to how I created a new InFile() class.  The new one can be used
directly as a stream, only it has my save file protocol stuff built in.
2011-12-25 22:21:11 -05:00
Bryan Schumaker 6794ce15e5 libsaria: Return ifstream reference from operator>>
This allows me to chain calls to the same stream, cleaning up the code.
2011-12-25 22:20:04 -05:00
Bryan Schumaker d39536d7d0 libsaria: Completely replace old InFile() class
My InFile2() class is clearer and simpler, so I've replaced InFile()
with it.
2011-12-25 21:24:02 -05:00
Bryan Schumaker 5e308202a0 libsaria: Create a new way to save files
I inherit from the ifstream class, so I can override the insertion
operator for string handling.  I can then use templates to save
everything else.
2011-12-25 21:16:09 -05:00
Bryan Schumaker 603a76964b libsaria: Store current audio volume
This allows me to restore the volume on startup.
2011-12-23 22:04:24 -05:00
Bryan Schumaker f7d7d5e038 libsaria: Add floats as preferenc type
Now I can store floating point numbers in addition to booleans.
2011-12-23 22:03:31 -05:00
Bryan Schumaker 8dfbb8915b libsaria: Check for current file before attempting state change
Without this, pressing "play" on an empty library will cause an error.
The recovery code will then try to pick a new song, and fail (since
there are no tracks to choose from).  It will then try to play, cause an
error and repeat forever.
2011-12-23 21:18:45 -05:00
Bryan Schumaker 1dc9df80e1 libsaria: Cleanup audio progress code 2011-12-23 21:14:14 -05:00
Bryan Schumaker 0e983e4043 libsaria: Implement gapless playback
I need to get the next file out of the library or queue without changing
it immediately.  I then queue it up in the gstreamer pipeline so it will
play automatically when the current track finishes.
2011-12-23 20:48:37 -05:00
Bryan Schumaker 2783b8d995 libsaria: Improved audio file loading
I look for an audio-changed signal and push this to the message bus.  I
then use the message to send out the TRACK_LOADED callback to the UI.
This should be even more useful for gapless playback.
2011-12-23 20:46:02 -05:00
Bryan Schumaker 5e20a26dbf ocarina: Set duration on every refresh
The progress bar should stay in sync now.  I got annoyed that it never
did when pausing after the current track.
2011-12-23 20:38:00 -05:00
Bryan Schumaker 7711b354cb libsaria: Create a durstr() function
Call this to get a string representation of the pipeline's current
duration.
2011-12-23 20:31:07 -05:00
Bryan Schumaker e509d4e723 libsaria: Added comments
I'll be able to figure out these functions easier the next time I see
them.
2011-12-23 16:04:28 -05:00
Bryan Schumaker 04a64ca015 libsaria: Use a load_file() function
All this function does is load a file.  Nothing else.  I think this will
be useful for using about-to-finish.
2011-12-23 16:03:10 -05:00
Bryan Schumaker f8f5f87e54 libsaria: Remove the get_player() function
I declared the variables in the local header file for use by the audio
layer.  I think this will make things a bit more efficient.
2011-12-23 15:49:56 -05:00
Bryan Schumaker 2458061cf3 ocarina: Use new controls for shortcuts
Fewer things to implement in the UI!
2011-12-23 15:49:10 -05:00
Bryan Schumaker 3944e691a5 libsaria: New controls
I added functions for rewinding, fast forwarding, and toggling play /
pause.  This should make it easier on the UI.
2011-12-23 15:48:08 -05:00
Bryan Schumaker e2ee610439 ocarina: Move to the new print() function 2011-12-18 15:07:44 -05:00
Bryan Schumaker df1e1a0a9a libsaria: Replace the old print() function
I now use a wrapper around printf() that can be disabled when debugging
is off.
2011-12-18 15:07:01 -05:00
Bryan Schumaker f1fa96eab9 Begin Ocarina 5.5
I'm planning on libsaria code cleanups and performance enhancements
for this release.
2011-12-18 15:04:48 -05:00
Bryan Schumaker 3c919ba7ca Ocarina 5.4 2011-12-17 10:07:57 -05:00
Bryan Schumaker 983ce59efb ocarina: Added keyboard shortcuts
Now I don't need to click in the GUI to do things.  I never realized how
much I missed these until now.
2011-12-17 09:44:24 -05:00
Bryan Schumaker 81e7662c7e libsaria: Track current gstreamer state
I use this to tell the GUI if music is currently playing or not.
2011-12-17 09:44:24 -05:00
Bryan Schumaker b75deae1a2 ocarina: Move pause after menu item
I now put it at the end of the menu since I want to queue songs more
often.
2011-12-17 09:44:20 -05:00
Bryan Schumaker 7f125061f6 ocarina: Don't filter the queue
It was only getting filtered when new songs were added to it and never
unfiltered.  This was somewhat confusing for me, and not very useful
since the only visible songs were the last ones added.  I fixed this by
creating an init option to enable filtering on songlists.
2011-12-17 09:44:16 -05:00
Bryan Schumaker a10fd2f5a0 libsaria: Print size of queue
I needed this for debugging, so I'll leave it there.
2011-12-17 09:44:11 -05:00
Bryan Schumaker 01b6df4f47 ocarina: Scroll treeview to current song
I do this whenever the current song changes.
2011-12-12 08:35:11 -05:00
Bryan Schumaker 64aff6a849 ocarina: Added a "Pause after current track" menu item
Unlike my old version, this menu item is a check box that shows the user
the current 'pause after' state.  This should be more useful and less
frustrating / confusing now.
2011-12-11 21:05:04 -05:00
Bryan Schumaker 5c6d7903a8 libsaria: Pause after current song
What if you want to leave and a good song starts playing?  This solves
the problem by loading the next song, but not playing it so the user can
go away and listen to it when they come back.
2011-12-11 21:03:09 -05:00
Bryan Schumaker 304b581274 libsaria: Check if $HOME is part of $XDG_CONFIG_HOME
On one machine it is, on another it isn't.  This should be a solution
that works for everybody.
2011-12-11 20:26:39 -05:00
Bryan Schumaker 83867dba2c libsaria: Reindex on library refresh
This should allow me to filter while the library is scanning.
2011-12-11 20:25:53 -05:00
Bryan Schumaker e987eaa3a4 ocarina: Hide queue when empty
This was something that I did in 4.x, and I like the feature.  Who wants
to see an empty notebook page?
2011-12-11 17:56:24 -05:00
Bryan Schumaker e983d69322 libsaria: Chose next songs from the queue
If there are songs in the queue, I pick from there.  Otherwise, I pick
from the library.
2011-12-11 16:25:24 -05:00
Bryan Schumaker 0f3e5d5963 ocarina: Fill in the queue
The library passes in its selected songs and then the queue responds to
the QUEUE_REFRESH callback to fill in the list.
2011-12-11 16:18:47 -05:00
Bryan Schumaker 6ef54e07c5 libsaria: Add songs to the queue
It takes a list of song ids and adds them to a deque.  The UI can then
iterate over each ID and query the size.
2011-12-11 16:16:02 -05:00
Bryan Schumaker 9739bdc76a libsaria: Library get_info() returns TrackTag
I simplify the function by removing the function pointer call and
letting callers deal with the TrackTag pointer it now returns.
2011-12-11 16:14:53 -05:00
Bryan Schumaker 56eee0ae22 libsaria: Added queue
I do this as a double-ended queue so I can remove songs anywhere I want
(and hopefully re-order them later, too).
2011-12-11 15:46:58 -05:00
Bryan Schumaker 9a9fc87f92 ocarina: Properly respond to a right click
I had a test function, but it wasn't being called.  I connected the
widget to the activate signal and improved the function to list the rows
that are currently selected.
2011-12-11 15:46:54 -05:00
Bryan Schumaker 74ab92ea6f ocarina: Get list of selected IDs from the songlist 2011-12-11 15:46:50 -05:00
Bryan Schumaker 781dedfe13 ocarina: Added a queue page
Eventually it will show the list of queued songs.  For now I just add an
unused page.
2011-12-11 15:46:47 -05:00
Bryan Schumaker 57bf72c4e5 libsaria: Get utf8 encoded strings from taglib
This should cut down on the number of pango errors that I see when
filing in lists.
2011-12-11 15:46:44 -05:00
Bryan Schumaker 0b4d9c25eb libsaria: Use absolute paths for saria dirs
I noticed that new save files weren't being created.  I now use the HOME
environment variable to construct an absolute path to write files to.
2011-12-11 15:46:40 -05:00
Bryan Schumaker a14cedc942 libsaria: Choose songs after filtering
Songs are only picked from the set of visible songs after filtering.
2011-12-11 15:46:35 -05:00
Bryan Schumaker f0decd07d6 libsaria: Load library through an idle task
This allows me to draw the UI first and load the library once that has
finished.  This should make Ocarina feel more responsive.
2011-11-13 13:44:45 -05:00
Bryan Schumaker ffbaff27ec libsaria: Change the number of tracks indexed at once
I was doing 50, but I think I can handle 100.  I also defined a constant
at the top of the file to make it easier to change this value again in
the future.
2011-11-13 12:43:02 -05:00
Bryan Schumaker 6e033513c0 libsaria: Refilter during indexing
I trigger a REFILTER callback after each IndexTask is processed to keep
the UI up to date with the current index.
2011-11-13 12:40:42 -05:00
Bryan Schumaker f7bd0d873f ocarina: Move some buttons to the header
I think these buttons work better in the page header, rather than in the
footer with the controls.
2011-11-13 12:34:57 -05:00
Bryan Schumaker 364b3a7c65 ocarina: Set label text after filtering
Set it to the current number of visible songs.
2011-11-13 12:22:02 -05:00
Bryan Schumaker b36def4c08 libsaria: Change library size when filtered
I return the number of visible songs, so if the user has entered a
filter string then I return the size of the results set.  If we're not
filtered then I return the size of the playlist.
2011-11-13 12:21:00 -05:00
Bryan Schumaker 5512d46e4e ocarina: Filter the song list
Users enter text and non-matching songs are removed from the songlist
view (they do come back when the text is removed)
2011-11-13 12:05:52 -05:00
Bryan Schumaker fa498f379c libsaria: Added an is_visible() function
This will return true if the given inode is visible.
2011-11-13 12:05:03 -05:00
Bryan Schumaker 75cb804756 libsaria: Added a REFILTER callback
This will be called to inform the UI that the filter text has changed.
2011-11-13 11:33:12 -05:00
Bryan Schumaker 824f589ff2 libsaria: Perform filtering
I use an in-place set intersection to find a set of songs that match the
search terms.
2011-11-13 11:29:41 -05:00
Bryan Schumaker 048313c681 ocarina: Added filter entry 2011-11-13 10:49:05 -05:00
Bryan Schumaker 1c0084b2e9 libsaria: Created a generic format_text() function
This is used by the track tags for creating word lists.  I also use the
function to format filter search text.
2011-11-13 10:47:55 -05:00
Bryan Schumaker 1c5b230434 ocarina: Add a GtkEntry for filtering 2011-11-13 10:33:16 -05:00
Bryan Schumaker 8ae21bfe58 ocarina: Added basic header
It's a label declaring itself to be a header.  This allows me to make
sure that page switching functions work before I get too far.
2011-11-13 10:03:47 -05:00
Bryan Schumaker d5df6e134b libsaria: Build the substring index
This is an index of every substring in the (artist, album, title) tags
of the library.  This should be easier to work with than regular
expression based filtering since I don't need to compare every key with
every search term.
2011-11-13 09:48:50 -05:00
Bryan Schumaker 7fc4e22795 libsaria: Call a dummy index function for each TrackTag
This function takes an inode and word list.  Soon it will add each
substring to an index.
2011-11-12 19:31:42 -05:00
Bryan Schumaker fc50ceb34f libsaria: Format each tag as it is read in
I lowercase everything, strip out some characters, and create a linked
list of each word for each tag.
2011-11-12 19:21:41 -05:00
Bryan Schumaker 86e40cefcb ocarina: Turn on idle tasks during startup
This allows indexing to run right away, rather than waiting for other
idle tasks to be added.
2011-11-12 14:27:28 -05:00
Bryan Schumaker ef36c58e96 libsaria: Create an IdleTask for indexing the library
Right now this will only be triggered when the library is loaded from
disk.  Once I get farther I can easily create a function to index a
track as it is added to the library (so I won't need to reindex
everything during this case)
2011-11-12 14:25:32 -05:00
Bryan Schumaker eab73ffb39 Begin work on Ocarina 5.4 2011-11-12 14:03:13 -05:00
Bryan Schumaker cad03257eb Created a PKGBUILD
Now I can submit ocarina to the AUR!  I also updated the .gitattributes
file so the PKGBUILD doesn't get included in the tarball.
2011-11-11 08:12:40 -05:00
Bryan Schumaker a9b4147df8 build: Updated Sconstruct
A few fixes before releasing 5.3
2011-11-11 08:07:58 -05:00
Bryan Schumaker 82cb17c1cb build: Added support for DESTDIR
I'll need this for my PKGBUILD
2011-11-10 17:31:27 -05:00
Bryan Schumaker 41f1c01752 build: Don't generate include/version.h all the time
Installing, cleaning and archiving don't need to create the version.h
file, so instead I'll add it as a build step for ocarina.
2011-11-09 23:17:59 -05:00
Bryan Schumaker 863bce3482 Update .gitignore
Ignore tarballs
2011-11-09 23:04:36 -05:00
Bryan Schumaker 624d9a9e74 build: Added a `scons archive` command
This will create an ocarina tarball for the current release.
2011-11-09 23:04:16 -05:00
Bryan Schumaker 42d4fd4bd1 Update attributes file
Maybe now it'll work a bit better...
2011-11-09 22:47:45 -05:00
Bryan Schumaker 36cfd0af48 ocarina: Remove old random image
I haven't use the 20-sided die image in almost a year...
2011-11-09 22:47:14 -05:00
Bryan Schumaker 2aa79126ec Added .gitattributes file
I want to be able to ignore the screenshots directory when generating an
archive.
2011-11-09 22:43:23 -05:00
Bryan Schumaker 958020f270 libsaria: Check stream status before reading
If we are unable to open the preferences file we shouldn't try to read
from it.  This led to a segmentation fault when compiled in release
mode, but for some reason it worked when compiled in debug mode?
2011-11-09 17:28:19 -05:00
Bryan Schumaker 1d704a3ac0 Ocarina 5.3-rc1 2011-11-09 17:28:09 -05:00
Bryan Schumaker 6f96a1d135 build: Generate ocarina.sh during instatll
I was doing this whenever the Command() class was constructed, instead I
only want to do this when it's run.
2011-11-09 08:34:08 -05:00
Bryan Schumaker 026bf0c010 libsaria: Only load song if string is not empty
It's stupid to try loading an empty string.
2011-11-09 08:33:40 -05:00
Bryan Schumaker ab3c89d5e6 Added license
I wanted something simple, so after some google searching I decided to
go with a "plain language" version of the GLP v2.  This means I can
understand it, since it's not written in lawyerspeak.
2011-11-09 08:31:36 -05:00
Bryan Schumaker db70dd8fe6 build: Don't cd when running the binary
Relative paths should keep working now.
2011-11-08 08:21:56 -05:00
Bryan Schumaker 66f70249ad ocarina: Load images using the full path
relative paths can't be trusted once the program has been installed.  To
get around this, I assume that the install directory has been configured
correctly and then point to images located in the subdirectory next to
the executable.
2011-11-08 08:20:21 -05:00
Bryan Schumaker 11d92eef89 libsaria: Add a debugging message
Helpful for knowing what path the audio subsystem is attempting to load.
2011-11-08 08:19:47 -05:00
Bryan Schumaker 8aebd278f2 build: Create an install target
This copies files into /usr/lib/ocarina and then creates
/usr/bin/ocarina to run the program.
2011-11-07 23:42:59 -05:00
Bryan Schumaker 3fe03734a1 ocarina: Pack tag labels into a scrolled window
I don't like the main window resizing, so we allow the users to scroll
if the tags take up too much space.
2011-11-07 19:43:09 -05:00
Bryan Schumaker 30246df924 ocarina: Improved label setting function
I created a single function to escape the text and set it in the label.
I don't know why I didn't do this from the beginning!
2011-11-07 19:22:46 -05:00
Bryan Schumaker 5ae5174536 ocarina: Left justify tag labels
I like this look better than the centered look.
2011-11-07 19:06:49 -05:00
Bryan Schumaker 258ebbc081 libsaria: Choose the next song based on the random setting
If random is enabled, I choose a random song from the list.  If random
is disabled I choose the next song sequentially.
2011-11-07 18:33:15 -05:00
Bryan Schumaker e409c2317f ocarina: Added a random button
Random hasn't been implemented in libsaria yet, but I can still create
the button to test preferences.  The random button should set itself to
the value store in the preferences file.
2011-11-07 08:32:01 -05:00
Bryan Schumaker b6f21d5705 libsaria: Added preferences
Right now I only store boolean values, but I think I've coded this in a
way to make adding new values easy.
2011-11-07 08:30:53 -05:00
Bryan Schumaker 0f2d682216 ocarina: Split buttons over two rows
The single row was getting somewhat long, so I split them up.
2011-11-06 20:33:47 -05:00
Bryan Schumaker 913b9f8630 ocarina: Seek to different parts of the song by clicking
Button 1 seeks by 10 seconds either forward or backward, button 2 seeks
to an absolute position.  I initally wanted to switch the behavior of
these two buttons, but for now I'll just have to get used to the GTK
defaults.
2011-11-06 20:26:11 -05:00
Bryan Schumaker c1332133a9 libsaria: Change meaning of audio::seek_to()
It used to seek to a percentage of the pipeline, but now is seeks to an
absolute position in nanoseconds.
2011-11-06 20:25:13 -05:00
Bryan Schumaker 6b58311e9e libsaria: Call next() at the end of the stream
It's nice to pick another song after the end of the current one.
2011-11-06 19:44:16 -05:00
Bryan Schumaker fffb9875ac ocarina: Add a next() button
Users press this button to choose the next song.
2011-11-06 19:18:03 -05:00
Bryan Schumaker e908f46c21 libsaria: Implement a next() function
This will pick the next song from the library to play.
2011-11-06 19:17:15 -05:00
Bryan Schumaker 9379a2cf33 libsaria: Better track comparision function
I sort by artist / album / track, so I need to check each of these
fields in order.  It would be nice if I could expand numbers into words
for some tags (3 Doors Down, Matchbox 20 and so on), but I'm happy with
what I have right now.
2011-11-06 15:44:45 -05:00
Bryan Schumaker 858fa1821f libsaria: Turn the play_list into a list of pointers
Pointers to a TrackTag structure are easier to pass around than the
TrackTag structure, so this should speed up sorting.  Also it removes
duplicated memory between the LibraryPaths and the play_list.
2011-11-06 13:57:09 -05:00
Bryan Schumaker 095ade27ad libsaria: Sort play_list by artist
Right now I do a basic string comparison.  I should eventually format
the strings to remove punctuation and use the same case.
2011-11-06 13:49:20 -05:00
Bryan Schumaker 4f2c75499f libsaria: Clean up LibraryPath class
I moved around some code and removed undefined functions
2011-11-06 13:39:14 -05:00
Bryan Schumaker 922c9e86ef libsaria: Get info from play_list
It's easier with everything in one single list.
2011-11-06 13:36:11 -05:00
Bryan Schumaker 5ae5a349de libsaria: Play tracks from the play_list
Rather than finding the id in the LibraryPath lists, I instead find it
in the play_list list and store an iterator to this track.
2011-11-06 13:15:48 -05:00
Bryan Schumaker b3cb20dd5d libsaria: Properly set the inode for each track tag
I was setting local variables rather than the TrackTag variable.  No
wonder things didn't work
2011-11-06 13:09:59 -05:00
Bryan Schumaker 5b2e0c7b82 libsaria: Fill a SourceModel from the play_list
Looping over a single list is really easy and straightforward!
2011-11-06 12:44:14 -05:00
Bryan Schumaker cdcaaeb8c8 libsaria: Report the library size as the play_list size
This is simpler than looping over all library paths and adding up their
individual sizes.
2011-11-06 12:39:13 -05:00
Bryan Schumaker 637ea47a60 libsaria: Insert all tracks into one giant list
This puts everything in one place for easy use (I hope)
2011-11-06 12:34:41 -05:00
Bryan Schumaker b55ac22866 libsaria: Introduce a rebuild_list() function
I am going to create a play list in memory based on the state of the
library.  To do this, I first need a way to trigger construction of a
list.
2011-11-06 12:16:54 -05:00
Bryan Schumaker 7507955018 libsaria: Fix bug in updating library
I was readding all tracks to the new linked list, rather than checking
if the track existed first.  This has been fixed.
2011-11-06 12:11:31 -05:00
Bryan Schumaker b5c8efc6d5 libsaria: Move LibraryPath functions to path.cpp
This is really what path.cpp is all about.
2011-11-06 11:50:16 -05:00
Bryan Schumaker d23c1c72f0 libsaria: Move library update code to new file
Putting it all in path.cpp along with other LibraryPath functions was
getting confusing.  I'd rather just have it all in a new file for
simplicity.
2011-11-06 11:47:26 -05:00
Bryan Schumaker 297c0637ea libsaria: Rename path list accessor functions
I added these functions into the library namespace so I can remove the
"_library_" part of the function names.
2011-11-06 11:36:12 -05:00
Bryan Schumaker d678a5c170 libsaria: Move library path constructor
This constructor creates a library path from a file, so it makes sense
to store it in file.cpp instead of path.cpp.
2011-11-06 11:29:38 -05:00
Bryan Schumaker 6d7828b946 libsaria: Store library path as a linked list of track tags
Lookup by id will be slighly slower, but now I will have one list for
each path that can be merged together and sorted to represent the
library.  This sounds like a good tradeoff to me, especially since I can
store an iterator to the current track when deciding what to play next.
This will give me much faster access to song for the current track.
2011-11-06 11:16:46 -05:00
Bryan Schumaker 9c0e61b42d libsaria: Create track tags with an inode
I need to store the inode somewhere if I want to use a linked list to
store LibraryPath data.  I currently have a map <ino_t, TrackTag>, so
the obvious choice is to store the inode in the TrackTag structure.
2011-11-06 10:54:45 -05:00
Bryan Schumaker 8609b9a6a7 libsaria: Use a linked list of library paths
I was using a map, but the map required duplicating the library path
everywhere.  Except for removing a path, I don't ever need to look up a
specific path by name, so why bother optimizing this case?  Iterating
over a linked list should be more efficient (and easier to comprehend)
2011-11-06 10:43:35 -05:00
Bryan Schumaker 6930c1ccf3 Ocarina: Add a test menu item
The label for the menu reads "test", but it doesn't do anything yet.
2011-11-04 08:25:51 -04:00
Bryan Schumaker 481c2b4832 ocarina: Initialize songlist with a list of menu items
These items will be used to create a right click menu.
2011-11-03 08:32:32 -04:00
Bryan Schumaker dfa3d06142 ocarina: Respond to right click events
Right now I just print out some text, but eventually I'll be drawing in
a menu.
2011-11-03 08:23:25 -04:00
Bryan Schumaker 9f6320ce18 libsaria: Return empty string when no song loaded
I was returning "0:00", but I think an empty string looks better.
2011-11-02 08:25:17 -04:00
Bryan Schumaker 1018b0bc5b ocarina: Show the current audio position
This probably isn't a final placement of the widget, but for now drawing
in the widget is a good improvement.
2011-11-02 08:21:01 -04:00
Bryan Schumaker 0a216c38ce libsaria: Return the current audio position as a string
This returns it in mm:ss format for easy use by the UI
2011-11-02 08:20:26 -04:00
Bryan Schumaker 9236dcbb50 ocarina: Show length of song next to progress bar
This makes it easy to tell the total length of the current song.
2011-11-02 08:11:04 -04:00
Bryan Schumaker 90bc64131d ocarina: Individual functions for setting tag labels
I switched over to using pango <span> tags to set font properties to
make the text larger.  I decided that the title will be bigger than
artist and album, so I can't have one generic function for setting the
label properties.  Instead, I divided it up into one function for each
label.
2011-11-01 23:16:04 -04:00
Bryan Schumaker 0db7c0cf6b ocarina: Move the progress bar
I put it above the current song display and taking up the full width of
the window.  I think a big progress bar is more useful than a small one.
2011-11-01 22:48:35 -04:00
Bryan Schumaker c75d832934 libsaria: Give the audio separate position() and duration() functions
The UI can use these functions to set up an accurate progress bar based
on the number of nanoseconds each returns.
2011-11-01 22:47:04 -04:00
Bryan Schumaker 0eff7df5c4 ocarina: Add a progress bar 2011-10-29 17:24:21 -04:00
Bryan Schumaker 8987dddade libsaria: Added a get_progress() function to the audio namespace
This function is used to access how far into the song the current audio
position is.  The value is returned as a percentage of the total length
for easy use by the UI.
2011-10-29 17:23:25 -04:00
Bryan Schumaker 0da84e8151 libsaria: Find tags for songs not in the library
I always want to find tags if it's possible.  Since I already have a way
to find the tags, it's fairly simple to tag a random file and pass the
result back to the UI.
2011-10-29 16:26:26 -04:00
Bryan Schumaker 049f91e514 libsaria: Return default track values in error case
If we can't find the inode, I return some default values to the UI to
keep it happy (and clear out the information from the previous song).
2011-10-29 16:18:15 -04:00
Bryan Schumaker c894815dad ocarina: Add the library list to the ocarina namespace 2011-10-29 15:55:48 -04:00
Bryan Schumaker 0b1684620d ocarina: Add the chooser to the ocarina namespace
This removes some ocarina_*() functions
2011-10-29 15:52:03 -04:00
Bryan Schumaker 7c79aab787 ocarina: Create initial namespace
Namespaces make code easier to follow, and remove the need to mangle the
beginning of function names by using ocarina_*() or libsaria_*().  In
other words: "namespaces are one honking good idea.  Let's have more of
them!"
2011-10-29 15:47:00 -04:00
Bryan Schumaker 6b12cff613 ocarina: Clean up library.cpp a bit
I reordered the functions and removed the unnecessary declaration from
the top of the file.
2011-10-29 15:35:30 -04:00
Bryan Schumaker c727aaa526 ocarina: Fill a songlist by inheriting from a SourceModel
The SourceModel declares an insert() function that is called when
filling the list.  I have defined this function in a way that the list
will be filled in through repeated calls to insert()
2011-10-29 15:19:56 -04:00
Bryan Schumaker 136f12bc7c libsaria: Created a SourceModel class
The source model class is used to more tightly control how songs are
inserted into the UI.  I provide an insert() function that the library's
for_each() function can take advantage of.  This allows me to directly
insert songs into the UI rather than having to use a static function as
the "middle man"
2011-10-29 15:19:45 -04:00
Bryan Schumaker e5bd2471b0 ocarina: Rearrange the now playing panel
I want controls to be on the same level as the artist / album / title
labels.  This will be more compact, and it won't waste a lot of empty
space above the labels and next to the controls.
2011-10-29 04:46:42 -04:00
Bryan Schumaker fc4f311971 ocarina: Added a "now playing" panel
This is just an initial implementation, so it's not very good right now.
It does give all the information, though.  That's a plus.  I also set
the artist / album / playlist whenever a SONG_LOADED callback is given.
2011-10-28 17:22:51 -04:00
Bryan Schumaker 9d22d6b278 ocarina: Split footer into multiple files
This should help keep things organized
2011-10-28 17:06:18 -04:00
Bryan Schumaker 39f74eb6b4 libsaria: Various cleanups
- Pass inodes by reference
- Change some namespace code formatting to match later code
2011-10-28 17:02:46 -04:00
Bryan Schumaker a975fcc2cc libsaria: Added a current_track() function
This function will generate a Track object based on the current file
stored by the audio.  I then pass this object to to provided function so
the UI can be updated.
2011-10-28 15:33:17 -04:00
Bryan Schumaker 9997e6ffa6 libsaria: Added TRACK_LOADED callback
This is triggered whenever a new track is loaded.
2011-10-28 14:37:18 -04:00
Bryan Schumaker 66a3ca63e6 ocarina: Add a separator to the footer
I think the separator looks better, and helps to show where the songlist
ends and the footer begins.
2011-10-28 14:27:05 -04:00
Bryan Schumaker c06106bff8 Remove config system
It was an interesting idea, but it really wasn't being used for
anything.  I'll stop trying to copy Kbuild now...
2011-10-28 14:17:59 -04:00
Bryan Schumaker 868898ec07 Begin Ocarina 5.3 2011-10-28 14:08:44 -04:00
Bryan Schumaker 1fee8e50b3 ocarina: Move some songlist functions to a new file
This splits out more functions, and makes the songlist more maintainable
overall.
2011-10-28 13:59:53 -04:00
Bryan Schumaker 6c5412a3d5 ocarina: Move songlist init code into a new file
Doing it all in one function was messy and hard to follow.  I've broken
it into several smaller functions, so now I know what is going on.
2011-10-27 17:17:46 -04:00
Bryan Schumaker 236cf0fee5 ocarina: Move songlist.h
It really should go into the include directory.  I don't want to use
relative paths to include header files in a subdirectory... I don't know
why I even did it in the first place!
2011-10-27 16:39:27 -04:00
Bryan Schumaker ab9b76a0b4 ocarina: Switch to new idle::run_task() function
Part of my rewrite involved moving the run_task() function to a new
namespace.  Ocarina now uses the new function.
2011-10-27 15:18:05 -04:00
Bryan Schumaker 707e7b3427 libsaria: Create an idle namespace
This cleans up the idle task code a lot, and reduces the size of
ocarina.bin to less than 1MB (with full debugging).  It probably won't
stay there long...
2011-10-27 15:18:03 -04:00
Bryan Schumaker c8dc6e1ee8 libsaria: Queue idle tasks from the task class
This is cleaner than calling an outside function since the task can
easily queue itself up.
2011-10-27 14:43:18 -04:00
Bryan Schumaker 7dce8ffedc ocarina: Switch to new audio functions
These functions have been moved to a new namespace, so the front end
needs to be updated.
2011-10-27 14:31:35 -04:00
Bryan Schumaker 90ac1ecfed libsaria: Massive audio cleanup
I removed libsaria/audio.cpp and did some namespace shuffling.  The new
code should be easier to follow and work with.
2011-10-27 14:31:30 -04:00
Bryan Schumaker 0425df6d63 ocarina: Rename tiny.cpp
I am no longer going to use the tiny / full footer scheme that I used in
Ocarina 4.x, so this file is better described as footer.cpp
2011-10-27 12:13:22 -04:00
Bryan Schumaker d3c9301628 ocarina: Access footer through get_footer() and put_footer()
I combined reference counting with the get_footer() function to make
using it easier (no manual reference counting).  put_footer() will
deallocate the widget if the reference count is 0 (this is already done
by the g_object_unref() function) so it should work in a sane way.
2011-10-27 12:08:21 -04:00
Bryan Schumaker 007a2e820d ocarina: Remove unused #include
The footer is no longer used in ocarina.cpp
2011-10-22 08:57:22 -04:00
Bryan Schumaker 155e436259 ocarina: Set window title and icon during init()
I was setting these through other function calls, but it's easier (and
cleaner) to do it all in the initial init() call.
2011-10-22 08:55:32 -04:00
Bryan Schumaker c3fd002e92 ocarina: Remove unnecessary widgets
I can now add the body tabs directly to the window, rather than packing
them in a box with other things.
2011-10-22 08:53:32 -04:00
Bryan Schumaker bc6068cbda ocarina: Move controls to the right of the window
They have been on the left for a while, but I like them better on the
right.
2011-10-21 17:55:27 -04:00
Bryan Schumaker 882f917c8f ocarina: Add a reference to the footer before moving
Calling the remove() function will destroy the footer if it has no other
references.  To prevent this, I need to call g_object_ref() add a
reference to the widget.
2011-10-21 14:51:22 -04:00
Bryan Schumaker 6467356cf6 ocarina: Cleanup path info buttons
I was using variables that I really didn't need to use...
2011-10-20 20:33:21 -04:00
Bryan Schumaker 3ff17e907c ocarina: Update library path button
One click and the single library path will be updated
2011-10-20 20:31:35 -04:00
Bryan Schumaker 4f26d9ee2d libsaria: Update single paths
Updating a single LibraryPath may sometimes be faster than updating the
entire library.
2011-10-20 20:31:09 -04:00
Bryan Schumaker b84a19cd77 ocarina: Created a "remove path" button
Clicking this button removes a path from the library
2011-10-20 20:19:51 -04:00
Bryan Schumaker 245157c6b4 libsaria: Remove paths from library
If the user no longer wishes to track a certain path, they can remove it
from the library.  Note: it is unsafe to remove a path from the library
while that path is being scanned.  This could potentially lead to a
segmentation fault.
2011-10-20 20:18:35 -04:00
Bryan Schumaker 2c12cb80aa ocarina: Move tab page content into a table
This should make it easier to add or remove headers and footers so that
I can share one widget between all pages.
2011-10-20 19:33:05 -04:00
Bryan Schumaker 83719838aa ocarina: Refresh path list when library is updated
I respond to the LIBRARY_REFRESH callback by creating new path panels to
show the updated information.
2011-10-20 18:46:54 -04:00
Bryan Schumaker 61153a0580 ocarina: Added update library button
This button will call the new library::update() function
2011-10-20 13:24:11 -04:00
Bryan Schumaker c4cdfbe4b3 libsaria: Added library::update()
This will rescan every library path and add new files to the library.
Eventually it should probably remove files that no longer exist...
2011-10-20 13:24:11 -04:00
Bryan Schumaker 60dc610195 ocarina: Display library paths
Right now I simply create a list during startup.  I still need to clear
this list and refill it whenever the library is updated.
2011-10-20 13:24:11 -04:00
Bryan Schumaker 2a6d05ebee libsaria: Fill out a struct PathInfo
This struct is used by the gui to show how large a library path is
and eventually to remove it from the library.
2011-10-20 13:24:08 -04:00
Bryan Schumaker e8341288b3 ocarina: Songlist improvements
- Function pointers for specific tasks
- Change label text
- Use libsaria namespaces
2011-10-19 10:00:01 -04:00
Bryan Schumaker 8cf3caeb27 libsaria: Added function for getting the library size
I like to show this on the library tab so I know how many songs are
currently in the library.
2011-10-19 09:58:30 -04:00
Bryan Schumaker a508b7ff72 libsaria: Rip out old library
The code was a bit messy and didn't make use of namespaces very well.
By converting to a set of functions (instead of a class) I can use
each function as a function pointer if I want to.  I am also able to
remove libsaria/library.cpp since this was just a set of wrapper
functions to the old static class functions.
2011-10-18 10:02:55 -04:00
Bryan Schumaker 1b18069b77 ocarina: remove unnecessary add_callback() function
It only called the register_callback() function, so there is no point in
keeping it around.
2011-10-02 11:07:36 -04:00
Bryan Schumaker ef7d9d0fe2 Bump minor version number
I'm no longer working on 5.1, so might as well change this
2011-10-02 10:53:52 -04:00
Bryan Schumaker c8daf92af4 libsaria: Save to XDG_CONFIG_HOME
I plan on storing all my preferences there rather than creating my own
save directory.  This will keep things consistent with other
applications the user may have.
2011-10-02 10:52:23 -04:00
Bryan Schumaker 1996b54065 ocarina: Update to new libsaria namespace
The old functions are no longer defined, so this patch updates to the
new functions.
2011-10-01 13:27:43 -04:00
Bryan Schumaker cea236a757 libsaria: Introduce libsaria namespace
Now I don't need to define everything as libsaria_some_func(), instead
these functions will exist in the libsaria namespace.
2011-10-01 13:27:31 -04:00
Bryan Schumaker 165a359655 ocarina: Fill library on startup
Once the library has been loaded we can display it to users.
2011-10-01 12:52:05 -04:00
Bryan Schumaker 1a7b8a5ae9 libsaria: Load a saved library
No point in saving a library if I can't make use of the save file later.
2011-09-30 08:12:26 -04:00
Bryan Schumaker 1d1ecc8d8c libsaria: Save the library scan results
I write each track to a file that will be read in on startup (once those
changes are committed)
2011-09-27 08:23:49 -04:00
Bryan Schumaker 517faceb99 libsaria: Add tasks to the front and back of the queue
Queueing a task to run immediately can be useful, especially if it's
something like saving data as part of a "checkpoint"
2011-09-27 08:22:24 -04:00
Bryan Schumaker a97da1dd05 libsaria: Create the saria dir on startup
This is either ~/.saria or ~/.saria-debug, depending on if we're running
a debug build or not.
2011-09-22 08:21:57 -04:00
Bryan Schumaker 250964a351 ocarina: Freeze and thaw during a clear
This should speed up clearing the list, too.
2011-09-21 08:21:45 -04:00
Bryan Schumaker ce2f9f02f8 ocarina: Freeze and thaw the liststore while filling
This causes fewer refreshes of the liststore and speeds up filling it
in.
2011-09-21 08:12:56 -04:00
Bryan Schumaker 284176fb5c ocarina: Play a song when a row is double-clicked
This is a natural way for the user to play a specific song.
2011-09-20 08:35:24 -04:00
Bryan Schumaker 2017e8a2f1 libsaria: Play tracks based on inode number
This allows the UI to pass in an inode returned by the track list used
to set up the display.
2011-09-20 08:34:02 -04:00
Bryan Schumaker 309cda851f ocarina: Insert songs in the songlist
I created an insert() function that will fill in the list and display
all the songs.
2011-09-19 19:48:37 -04:00
Bryan Schumaker 0326b9c7e4 libsaria: Add accessor functions for Track and Tag classes
I need to get at these variables to add them to a list in the UI
2011-09-19 19:47:31 -04:00
Bryan Schumaker 7bf6f48488 ocarina: Display treeview columns
Columns are displayed with the names of attributes that will be listed.
2011-09-18 19:19:20 -04:00
Bryan Schumaker 1c944d3156 ocarina: Get list of library tracks
This will be used to fill in a gtk listview sometime soon
2011-09-18 18:07:59 -04:00
Bryan Schumaker 884a0331e2 ocarina: Listen for correct callback 2011-09-18 18:07:40 -04:00
Bryan Schumaker 6dfe4de57b libsaria: Create a list of all tracks in a library
This list will eventually be used to fill in a gtk listview, but for now
I gather all the information in one place.
2011-09-18 18:06:54 -04:00
Bryan Schumaker 170e700746 ocarina: Listen for LIBRARY_REFRESH callback
I eventually want to add songs to the songlist, but for now it is enough
to wait for this callback.
2011-09-18 17:27:12 -04:00
Bryan Schumaker 69beb10d6b libsaria: Added LIBRARY_REFRESH callback
This callback is triggered during a library update to tell the UI that a
new version of the library is available.
2011-09-18 17:25:57 -04:00
Bryan Schumaker 3a5a41f53f ocarina: Added bare songlist and a library tab
Eventually the songlist class will list all songs in the library.  For
now, I just create an empty window and add it to the main tabs.
2011-09-18 14:43:46 -04:00
Bryan Schumaker 18ebac3937 Bump minor version number
I've been working on Ocarina-5.1 for a while, so I might as well
reflect that in the code.
2011-09-18 12:45:54 -04:00
Bryan Schumaker 7aff13f382 libsaria: Add tags to the library
I add each scanned track to the library for use later.
2011-09-18 12:20:59 -04:00
Bryan Schumaker a685023bcb libsaria: Convert length into a string
I format it into mm:ss format for UIs to display.
2011-09-18 11:39:18 -04:00
Bryan Schumaker 3255b045f0 libsaria: Find audio properties of each scanned song
This gives me the length, bitrate, sample rate and number of channels.
2011-09-18 11:23:44 -04:00
Bryan Schumaker 333a3a4b04 libsaria: Tag files to add to the library
I collect the artist / album / title / ... tags and add them to a class.
2011-09-17 14:16:06 -04:00
Bryan Schumaker 65c04585a3 ocarina: Print out the correct version
I should print out the value returned by vers_str(), rather than
hardcoding in "5.0"
2011-09-17 13:51:45 -04:00
Bryan Schumaker 0f38005bdb ocarina: Use new print functions
This mostly involved switching each print() to a println()
2011-09-17 13:50:37 -04:00
Bryan Schumaker 2c2e058b49 libsaria: Use new print functions
This mostly involved switching each print() to a println() to end the
line.
2011-09-17 13:50:13 -04:00
Bryan Schumaker ef5da936b4 libsaria: New print functions
I added a print(int) function to print out integer values.  I also
created println() functions for strings and ints.
2011-09-17 13:48:09 -04:00
Bryan Schumaker 1abdd945ae libsaria: Create scan tasks for each subdirectory
I want to recursively scan each directory for music files.
2011-09-17 12:56:39 -04:00
Bryan Schumaker 5167c6f012 libsaria: Read a directory into two vectors
I separate out directories and files so they can be processed
differenty.
2011-09-17 12:27:20 -04:00
Bryan Schumaker dfdb38be27 ocarina: Don't always run the idle task
I register the idle task when there are events in the idle queue and I
remove the idle task once those events have been processed.  This should
cut down on CPU usage when nothing is happening.
2011-09-13 17:35:21 -04:00
Bryan Schumaker 59fbd0c696 libsaria: Notify UI when the idle queue size has changed
When the first task is queued, I trigger a callback so the UI can start
processing when idle.  I return the size of the queue from both
run_task() and queue_task() so the UI knows when to stop processing
callbacks.
2011-09-13 17:27:46 -04:00
Bryan Schumaker e94ca6b9d6 libsaria: Rename UpdateTask to ScanTask
I feel that ScanTask is a better name
2011-09-13 08:04:59 -04:00
Bryan Schumaker b84b7b415d libsaria: Remove .swo files
They shouldn't have been added in the first place...
2011-09-13 08:04:25 -04:00
Bryan Schumaker 6cd4cbdba8 ocarina: Call the add_library() function
This function will add a new path to the library map and then scan it,
adding music files to the library.
2011-09-12 14:18:30 -04:00
Bryan Schumaker b43fcc4b05 libsaria: Queue an idle task to update the library
I don't actually perform a library update at this point, but I do create
a new task and add it to the update queue.  When the run_task() function
is called, the task is removed from the queue and deleted.
2011-09-12 14:18:23 -04:00
Bryan Schumaker c0a80623f5 libsaria: Created new idle.h
This exposes the libsaria_idle_task() function to the UI.
2011-09-12 11:31:58 -04:00
Bryan Schumaker 7840f491a1 libsaria: Move idle header files to idle directory 2011-09-12 11:27:58 -04:00
Bryan Schumaker 8a83b57010 libsaria: Create a new include/libsaria/audio.h
This file contains the audio init function.
2011-09-12 11:20:12 -04:00
Bryan Schumaker 679bf41cc1 libsaria: Move include/audio.h to the audio directory
The audio class can easily be defined in a file located in the audio/
directory.  This frees up the audio.h name for a UI-facing include file.
2011-09-12 11:14:23 -04:00
Bryan Schumaker d3b8020bbe libsaria: Remove libsaria class
I replaced the class functions with simple functions that exist in
multiple files.  I think things will be easier to work with now.
2011-09-12 11:08:56 -04:00
Bryan Schumaker dbce5c244a libsaria: Move idle trigger to new file
I think the idle code will be easier to manage if it is in its own file.
2011-09-12 10:38:27 -04:00
Bryan Schumaker c3eb748f44 libsaria: Move idle object out of libsaria class
This helps me prepare to remove the libsaria class.
2011-09-12 10:30:22 -04:00
Bryan Schumaker 33fe24fc64 Remove callbacks from libsaria class
These can easily exist as its own set of functions, and I want to remove
the libsaria class in the future.
2011-09-10 13:46:09 -04:00
Bryan Schumaker a660d5a34a ocarina: Register an idle function
This function will call the libsaria_idle_task() function to process the
next idle task.
2011-09-10 11:22:57 -04:00
Bryan Schumaker 84c0f7fe21 libsaria: Create an idle driver and idle task
Right now both classes are empty, but eventually I will add in support
for creating new idle tasks and for removing tasks from the idle queue.
2011-09-10 11:22:03 -04:00
Bryan Schumaker 36212af3a4 ocarina: Don't do anything if chooser result is blank
If we don't have a filepath to scan or play then we shouldn't do
anything with the path.
2011-09-10 10:49:51 -04:00
Bryan Schumaker 705ca61e6a ocarina: Select a directory to scan
This directory will eventually be scanned and added to the library.
Right now I just print it to the screen.
2011-09-10 10:45:52 -04:00
Bryan Schumaker 13244b880c ocarina: Make a generic chooser function
I want a function that can be used to select either a file or a
directory.
2011-09-10 10:41:47 -04:00
Bryan Schumaker 9df15e944c ocarina: Add a text button for library scanning
A text button will use a slightly larger image to make it easier to see.
This also gives me an opportunity to add some help text to describe what
the button does.
2011-09-10 10:30:25 -04:00
Bryan Schumaker 95ebff8b6e ocarina: Make generic button-building functions
I want to have buttons with text in addition to images.  To help with
this, I created some functions that should help with that.
2011-09-10 10:07:48 -04:00
Bryan Schumaker 62b86f5136 ocarina: Add a settings tab for library management
Right now I just add an empty vbox to the page.  I eventually want to
show information about each library path.
2011-09-10 09:42:34 -04:00
Bryan Schumaker b8f977cc35 ocarina: Add a switch for tab label expanding
Pass in true to cause the tab label to expand and fill up the entire
space, false if the label should not expand.
2011-09-09 08:27:58 -04:00
Bryan Schumaker 2110319176 ocarina: Resize window
I resized the window to 800 x 600, and then changed the main tabs to
fill up the entire space.
2011-09-09 08:23:43 -04:00
Bryan Schumaker 976637f88b ocarina: Add settings tab
Eventually this tab will be used for configuring everything.  Right now
it's an empty page.
2011-09-09 08:14:07 -04:00
Bryan Schumaker c3b82c401f ocarina: Created tabs for the main window
Most things are going to be displayed in a gtk notebook.  This patch
creates that notebook.
2011-09-07 08:25:52 -04:00
Bryan Schumaker 7b48c3311d ocarina: Rename gui/ to ocarina/
I think ocarina/ is a better name for this directory, and now that I've
named the executable "ocarina.bin" I can do this again.  I also added
functions for creating a page footer with the basic controls.
2011-09-07 08:12:02 -04:00
Bryan Schumaker a097e751b2 ocarina: Remove custom icon size from button constructor
All buttons are the same size, so there is no point in requesting the
size for each button.
2011-09-06 07:57:06 -04:00
Bryan Schumaker 39a8f861c7 ocarina: Added a fast-forward button
Clicking it advances the song by 5 seconds
2011-09-03 23:15:30 -04:00
Bryan Schumaker bd6aea830b libsaria: Fix finding audio duration
I needed to pass in a value for the format argument...
2011-09-03 23:09:31 -04:00
Bryan Schumaker c2c3a1eea9 ocarina: Added a rewind button
Pressing the rewind button rewinds the song by 5 seconds.
2011-09-03 23:06:13 -04:00
Bryan Schumaker ded2c559af libsaria: Fix up the audio seek() function
It now seeks forward or backward through a song by dt seconds.
2011-09-03 23:03:31 -04:00
Bryan Schumaker 77a7f84110 libsaria: Created a seek_to() function
This function will seek to an absolute percentage of a song, rather than
by some displaced amount.
2011-09-03 22:32:12 -04:00
Bryan Schumaker 4b3b1babbc libsaria: Add progress file
This will include code for seeking and getting the current position in
the song.  Right now I just have a function for resetting the position
to the beginning of the song.
2011-09-03 21:55:42 -04:00
Bryan Schumaker 937fbc1111 Move volume helper functions
I moved these to a volume.h file to keep them separate from controls.
2011-09-03 21:31:21 -04:00
Bryan Schumaker ef3e18ba25 ocarina: Use the new libsaria convenience functions
When libsaria changes, I won't have to recompile as much (in theory)
2011-09-03 21:10:41 -04:00
Bryan Schumaker e10a8e97f4 libsaria: Create convenience functions for libsaria
Now I won't have to keep using libsaria_get() to access parts of
libsaria.  This should also cut down on the number of things that need
to be recompiled when libsaria is changed...
2011-09-03 21:07:52 -04:00
Bryan Schumaker 7cdd6b1664 ocarina: Set volume button to current audio levels
When the button is created, it should be set to the current volume of
the gstreamer pipeline.  If I don't do this, the icon will default to a
"muted" status.
2011-09-03 10:25:53 -04:00
Bryan Schumaker ceddd240ca libsaria: Added a get_volume() function
I use this function to get the current volume levels.  I added and extra
variable to the Audio class to track what the current volume is.
2011-09-03 10:24:34 -04:00
Bryan Schumaker 5a8cafa4d8 libsaria: Add a VOLUME callback
This will be triggered whenever the volume changes through the libsaria
class.
2011-09-03 10:08:54 -04:00
Bryan Schumaker ef2b716047 ocarina: Change volume when volume slider changed
I pass along the new value to libsaria to set in the gstreamer pipeline.
2011-09-03 09:49:53 -04:00
Bryan Schumaker f354a305ae libsaria: Change volume function
I introduced a function for directly setting the new volume level.  It
does not allow changing by some value.
2011-09-03 09:49:09 -04:00
Bryan Schumaker cfc86bd891 Added callback.h
This should have been added a long time ago, but my include/ocarina
directory was being ignored by git...
2011-09-03 09:14:03 -04:00
Bryan Schumaker ad066238ac Change final program name
I change it from ocarina to ocarina.bin so that my .gitignore rules
work.
2011-09-03 09:13:38 -04:00
Bryan Schumaker 6137ec8a83 ocarina: Added volume button
This button will eventually be used to control the libsaria volume.  It
doesn't do anything useful yet.
2011-09-02 08:26:44 -04:00
Bryan Schumaker f49b5e1d6d gui: Move stop button
It's in the controls.cpp file with the play and pause button code.
2011-08-31 08:29:02 -04:00
Bryan Schumaker f6ac48219e ocarina: Move pause button code
I moved it from the generic button.cpp file to the controls.cpp file to
keep everything together.  I also changed the button list to use the new
show / hide functions.
2011-08-31 08:26:40 -04:00
Bryan Schumaker bd907ecfe0 ocarina: Remove show_play_buttons() and hide_play_buttons()
I replaced these functions with a generic show_button_list() and
hide_button_list() functions.
2011-08-31 08:20:45 -04:00
Bryan Schumaker 8234e4072b ocarina: Move play button to new file
I moved all the button code into a new subdirectory.  From there, I
moved the play button code into a file named controls.cpp.  This should
help clean up button code.
2011-08-30 08:26:23 -04:00
Bryan Schumaker 7e9b2f9380 Switch from make to scons
Scons will track changes to my include/ directory better than make will.
I also have an easier time understanding the Sconstruct file than I did
with Makefiles.
2011-08-28 11:10:58 -04:00
Bryan Schumaker ac03eed3f5 ocarina: Show and hide play and pause buttons
I hide the play button when music is playing and show it when music has
been stopped.  I hide the pause button when music is not playing and
show it when music has been stopped.  This can give the effect of one
button replacing the other.
2011-08-27 13:38:01 -04:00
Bryan Schumaker 31c777dc8a libsaria: Remove old function declarations
I replaced these functions with a self-contained class.  I don't need to
keep these around anymore.
2011-08-27 12:43:49 -04:00
Bryan Schumaker feaa34b8db libsaria: Remove audio check_state() function
It was empty because I decided to go along a different route.
2011-08-27 12:40:10 -04:00
Bryan Schumaker 0075c01991 ocarina: Added initial callbacks
These functions will be triggered when the libsaria play or pause
functions are called.  Right now they just print out a message, but I
plan on doing more.
2011-08-27 12:36:41 -04:00
Bryan Schumaker bf1d423b2f libsaria: Don't auto-load songs passed on startup
I would rather have the front end program load the song rather than
assuming that everything should be loaded right away.  This also gives
front end programs a chance to register callbacks before loading.
2011-08-27 12:35:28 -04:00
Bryan Schumaker 2888e741e8 libsaria: Added callback framework
I have created generic functions for registering and triggering
callbacks.  New callbacks can be added by creating a new constant in the
callback_t enum.
2011-08-27 12:34:19 -04:00
Bryan Schumaker 5dea1ae42a libsaria: Audio return values when changing state
play() and pause() now return true or false base on if the state change
request succeeds or fails.  This can be used later to determine if a
callback should be triggered.
2011-08-27 12:32:06 -04:00
Bryan Schumaker 11f972aee4 ocarina: Load a file through the gui
I call the new libsaria load function with a file selected through the
gui.
2011-08-23 08:29:46 -04:00
Bryan Schumaker 1831046685 libsaria: Created a load() function
Calling this function will load a song.
2011-08-23 08:28:35 -04:00
Bryan Schumaker 20756aac14 Created an open button
Clicking the button will open a file chooser to select a file to play.
2011-08-23 08:26:23 -04:00
Bryan Schumaker 7d3769a1a2 ocarina: Clean up button code
I didn't like using macros...
2011-08-23 07:53:25 -04:00
Bryan Schumaker b23d912f64 ocarina: Added a stop button
This calls the Libsaria stop function
2011-08-22 08:29:23 -04:00
Bryan Schumaker 6e47ec49df libsaria: Added a stop function
I stop playback, and seek to the beginning.  I do this as to different
function calls in the Libsaria class so callbacks will still trigger
(once they have been implemented).
2011-08-22 08:27:34 -04:00
Bryan Schumaker edc46f9ced ocarina: Smaller window
I only have two buttons.  I don't need to take up an 800 x 600 window
yet.
2011-08-21 19:28:54 -04:00
Bryan Schumaker 3e2f374bf8 libsaria: created Audio() class
This class will be used to control gstreamer functions.  So far, it can
load a song, play, and pause.
2011-08-21 19:24:33 -04:00
Bryan Schumaker c716f62aaa ocarina: Use new play and pause functions
Eventually the global functions are going away, so I convert to using
the functions as part of the Libsaria instance.
2011-08-21 18:11:17 -04:00
Bryan Schumaker ec2c848a90 Libsaria class can play and pause music
Eventually the class will contain an audio instance, so there won't be a
global play or pause function anymore.
2011-08-21 18:10:18 -04:00
Bryan Schumaker 0173f97fba Call libsaria_quit()
This should free up any memory currently in use.
2011-08-21 15:46:00 -04:00
Bryan Schumaker dd5ad9e87d Began Libsaria() class
This class will act as an interface for the Ocarina front-end.
2011-08-21 15:45:15 -04:00
Bryan Schumaker b939fa12a4 Print function only prints if debugging is enabled
I want to keep actual output to a minimum when running a release
version.
2011-08-21 15:27:59 -04:00
Bryan Schumaker bf3d41f8d2 Set window icon
Just to my basic ocarina image for now.
2011-08-21 15:19:56 -04:00
Bryan Schumaker b802b31d42 Set window title
I set the title based on the current version, but I do this through a
function to make it easier to change later.
2011-08-21 15:15:40 -04:00
Bryan Schumaker 9c0a00dd48 Created version.h
This is an auto-generated file that provides a way to get the current
version.
2011-08-21 15:14:49 -04:00
Bryan Schumaker ae5b3a358e Play and pause buttons work
They play and pause music...
2011-08-20 12:12:53 -04:00
Bryan Schumaker 8c49544efd Created helper for connecting signals
This should make connecting signals easier, since I don't need to use
any conversion macros.
2011-08-20 11:47:26 -04:00
Bryan Schumaker 1413a31aa7 Create wrapper function for gtk_container_add()
I don't want to have to keep typing out the conversion macros, so this
function puts them all in one place.
2011-08-20 11:36:29 -04:00
Bryan Schumaker d75227b6af Added a wrapper function for gtk_box_pack_start()
This will call the conversion macros for packing items into a box.
2011-08-20 11:32:20 -04:00
Bryan Schumaker 467cedf828 Added a pause button
I just put in next to the play button for now.
2011-08-20 11:17:01 -04:00
Bryan Schumaker 0f5303503c Improve play button creation
I made a function to create a play button.  I suspect that
pre-configured buttons will be easier to use than having to build them
up every time.
2011-08-20 11:08:42 -04:00
Bryan Schumaker 4b7762c589 Update Makefile
Now it should compile linking against gtk and gstreamer
2011-08-18 08:26:51 -04:00
Bryan Schumaker 7efcfddcde Add a button to the window
The button doesn't do anything yet, but I may eventually modify it for
playing and pausing music.
2011-08-18 08:20:56 -04:00
Bryan Schumaker 53d8718053 Open a window and play a song
I start ocarina with a file.  I play the song right away, and open a
window so that gtk_main() can quit when closed.
2011-08-15 07:53:25 -04:00
Bryan Schumaker c0ace6fed6 Basic initializiation code
I print some messages to the screen and I have a makefile to compile
libsaria and gui code.
2011-08-14 11:35:37 -04:00
Bryan Schumaker b8e8f7179c Remove Ocarina 4 files
Get them out of the way to begin work on Ocarina 5
2011-08-14 10:46:22 -04:00
246 changed files with 16543 additions and 4609 deletions

10
.gitattributes vendored Normal file
View File

@ -0,0 +1,10 @@
tests/ export-ignore
Doxyfile export-ignore
.gitattributes export-ignore
.gitignore export-ignore
DESIGN export-ignore
GOALS export-ignore
PKGBUILD export-ignore
TODO export-ignore

25
.gitignore vendored
View File

@ -1,3 +1,22 @@
*.pyc
*.swp
ocarina.py
*.o
*.sw*
*.out
*.glade~
*.ui~
share/ocarina/#*
bin/
.sconsign.dblite
*.patch
*.tar.gz
*.gcov
*.gcda
*.gcno
core.*
.debug
CMakeCache.txt
CMakeFiles
Makefile
cmake_install.cmake
install_manifest.txt
CTestTestfile.cmake
Testing/

14
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,14 @@
stages:
- build
- test
build:
stage: build
script:
- cmake -DCONFIG_DEBUG=ON && make
test:
stage: test
script:
- cmake -DCONFIG_TESTING_VERBOSE=ON -DCONFIG_TESTING_GUI=OFF && make tests

148
CHANGELOG Normal file
View File

@ -0,0 +1,148 @@
6.5.0:
- Add a switch to disable GUI tests
- Don't save and restore the "Last Played" tracks column width
- Save databases if they have been upgraded
- Don't duplicate tracks in the library after a defrag
- Remove "Add New ..." menubutton and replace with Add Library Path button
- Various UI tweaks
- Fix showing the first playlist in the list
- Fix memory leaks in core/
- Fix theme parsing errors
- Fix crash while reading 6.4.x playlists
6.5.0-rc:
- Convert to CMake/CTest
- Save current track in settings database
- Add "Queued Tracks" playlist
- Add support for changing current playlist
- Hide empty playlists
- Save current position in playlists
- Set file version from Ocarina minor version
- Add support for defragmenting tag databases on startup
- Add user created playlists
- Add support for changing volume
- Remove Repeat button
- Various UI improvements
- Add command line options
6.4.20:
- Enable idle processing when tracks are played to update dynamic playlists
6.4.20-rc:
- Use a single GtkTreeModelFilter instance for displaying tracks
- Use a single GuiQueueModel instance for displaying tracks
- Reduce use of database entry index accesses
- Reduce the size of the track tag
6.4.19:
- Fix memory corruption when adding new library playlists
- Use Enter key to accept new library paths
- Remove deleted tracks from artist playlists
- File chooser selects user's music directory
- Remove deleted tracks from artist playlists
6.4.19-rc:
- Allow filtering specific fields
- Replace filtering with a token matching system
- Clean up system playlist code
6.4.18:
- Load each artist playlist in a separate idle task
- UI spacing improvements
6.4.18-rc:
- Remove stack widget from UI
- Add Library Path playlists
- Add Artist playlists
6.4.17:
- Fix memory leak in __playlist_name()
- Remember search text when changing displayed playlist
6.4.17-rc:
- Filter can use GHashTables directly
- Filter can store track pointers instead of indexes
- Remove unused set and index classes
- Convert Collection into a playlist
- Convert History into a playlist
6.4.16:
- Let tests run without fetching album art
- Don't try to read data from nonexistant playlists
- Show hidden folders when selecting new images
- Add preview widget to album art chooser dialog
- Fix blurry album art
- Reduce time spent polling for album art
- Split album art code into a new file
- Fix PKGBUILD dependencies
6.4.16-rc:
- Implement generic playlist layer
- Implement separate queues for each playlist, including dynamic playlists
- Remove core/containers/queue
6.4.15:
- Add idle progress as a tooltip.
- Initialize track labels with the correct initial size
- Initialize album part with the correct size
- Gui spacing updates
6.4.15-rc:
- Write data files to a temporary file first, then rename
- Add support for writing files to the user's XDG_USER_CACHE_DIR
- Add idle tasks that run in a new thread
- Fetch album art
6.4.14:
- GtkPaned spacing improvements
6.4.14-rc:
- Load files and databases using the idle queue
- Switch over to using the glib g_random_int_range() function
- Improve track average play count calculation
6.4.13:
- Enable bolding the current track in the GtkTreeView
- Enable GtkTreeView fixed-height mode
- Fix bug where temporary queues don't save
- Fix bug where a queue is not selected on startup
- Fix bugs related to scrolling on track change
6.4.13-rc:
- Rewrite GtkTreeView code
- Save and Restore treeview column widths
- Only have a single GtkTreeView instance
- Finish conversion of Ocarina to C
6.4.12:
- Don't reenable tempqueues when restarting
- Control automatic pausing with a GtkComboBox
- Move current position slider into the top section
- Update tooltips on various buttons
- Various UI tweaks
- Swap position of random/repeat and favorite/hide buttons
6.4.12-rc:
- Rewrite our custom GtkTreeModel and add tests
- Move shuffle and repeat buttons into the sidebar
6.4.11:
- Remove stop button
- Move collection enabled checkboxes into a right click menu
- Various UI tweaks (Thanks to Colin Fulton for helping here)
6.4.11-rc:
- Convert window code to C
- Convert collection gui code to C
- Convert playlist gui code to C
- Add sidebar and hide notebook tabs
6.4.10:
- Block audio accelerator keys if a GtkEntry widget has focus
- Various UI tweaks
- Add changelog
6.4.10-rc:
- Add generic settings functions
- Convert code using GTK+ builder to C
- Convert audio code to C

84
CMakeLists.txt Normal file
View File

@ -0,0 +1,84 @@
cmake_minimum_required(VERSION 3.4)
project(Ocarina)
# Various options for users
option(CONFIG_DEBUG "Compile with debugging symbols" OFF)
option(CONFIG_TESTING_VERBOSE "Enable verbose output when running tests" OFF)
option(CONFIG_TESTING_GUI "Enable running GUI tests (requires an X server)" ON)
option(CONFIG_TESTING_ARTWORK "Enable album artwork fetching tests" ON)
# Configure settings
set(CONFIG_MAJOR 6)
set(CONFIG_MINOR 5)
set(CONFIG_MICRO 10)
set(CONFIG_RC ON)
set(CONFIG_VERSION "${CONFIG_MAJOR}.${CONFIG_MINOR}.${CONFIG_MICRO}")
if (CONFIG_RC)
set(CONFIG_VERSION "${CONFIG_VERSION}-rc")
endif()
set(DEBUG_OPTIONS -Wall -Werror -g -DCONFIG_DEBUG)
if (CONFIG_DEBUG)
add_definitions(${DEBUG_OPTIONS})
set(CONFIG_VERSION "${CONFIG_VERSION}-debug")
endif()
find_package(Git)
if (GIT_FOUND AND IS_DIRECTORY .git/)
configure_file(.git/HEAD .git/HEAD COPYONLY)
execute_process(COMMAND ${GIT_EXECUTABLE} describe --abbrev=0
COMMAND xargs ${GIT_EXECUTABLE} diff --quiet
RESULT_VARIABLE HAS_CHANGED)
if (HAS_CHANGED AND CONFIG_RC)
set(CONFIG_VERSION "${CONFIG_VERSION}+")
endif()
endif()
add_definitions(-DCONFIG_VERSION=\"${CONFIG_VERSION}\")
add_definitions(-DCONFIG_MAJOR=${CONFIG_MAJOR})
add_definitions(-DCONFIG_MINOR=${CONFIG_MINOR})
find_package(PkgConfig REQUIRED)
function(use_module name module)
pkg_check_modules(${name} REQUIRED ${module})
include_directories(${${name}_INCLUDE_DIRS})
add_definitions(${${name}_CFLAGS} ${${name}_CFLAGS_OTHERS})
link_libraries(${${name}_LIBRARIES} ${${name}_LDFLAGS})
endfunction()
use_module(GTK gtk+-3.0)
use_module(GMODULE gmodule-export-2.0)
use_module(GST gstreamer-1.0)
use_module(TAGLIB taglib_c)
use_module(CAA libcoverart)
use_module(MB5 libmusicbrainz5)
# Tell compiler where to find header and source files
include_directories(include)
file(GLOB_RECURSE core "core/*.c")
file(GLOB_RECURSE gui "gui/*.c")
# Configure executable
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY bin/)
add_executable(ocarina ${core} ${gui})
# Configure install targets
install(TARGETS ocarina DESTINATION /usr/bin/)
install(DIRECTORY share/ DESTINATION /usr/share/)
# Configure release target
set(CONFIG_RELEASE ocarina-${CONFIG_VERSION})
add_custom_target(release COMMAND git archive -v --prefix=${CONFIG_RELEASE}/ -o ${CONFIG_RELEASE}.tar.gz HEAD)
# Set up unit tests
set(CMAKE_TEST_COMMAND ctest --output-on-failure)
if (CONFIG_TESTING_VERBOSE)
set(CMAKE_TEST_COMMAND ctest -V)
endif()
if (IS_DIRECTORY tests/)
enable_testing()
add_custom_target(tests COMMAND ${CMAKE_TEST_COMMAND})
add_subdirectory(tests/)
endif()

1
CTestCustom.cmake Normal file
View File

@ -0,0 +1 @@
set(CTEST_CUSTOM_PRE_TEST "rm -rf $ENV{HOME}/.local/share/ocarina-test $ENV{HOME}/.cache/ocarina-test")

339
LICENSE Normal file
View File

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View File

@ -1,24 +0,0 @@
all: ocarina.py
./ocarina.py
ocarina.py:
sh scripts/makebin.sh
clean:
rm `find . | grep .pyc`
rm ocarina.py
install:
cd /opt/ && git clone git://lavos.homelinux.com/ocarina.git
cd /opt/ocarina && make ocarina.py
cd /usr/bin && ln -sf /opt/ocarina/bin/ocarina .
uninstall:
rm -rIf /opt/ocarina
rm -f /usr/bin/ocarina
update:
cd /opt/ocarina && make clean
cd /opt/ocarina && git pull
cd /opt/ocarina && make ocarina.py

28
PKGBUILD Normal file
View File

@ -0,0 +1,28 @@
# Maintainer: Anna Schumaker <anna@nowheycreamery.com>
pkgname=ocarina
pkgver=6.5.9
pkgrel=1
pkgdesc="A simple GTK+ and GStreamer based music player."
url="http://www.nowheycreamery.com/"
arch=('x86_64' 'i686' 'armv7h')
license=('GPL2')
depends=('gtk3>=3.22' 'gstreamer' 'gst-plugins-base' 'taglib' 'libmusicbrainz5' 'libcoverart')
optdepends=('gst-plugins-good' 'gst-plugins-bad' 'gst-plugins-ugly')
makedepends=('cmake')
conflicts=()
replaces=()
backup=()
source=("http://nowheycreamery.com/wp-content/ocarina/${pkgname}-${pkgver}.tar.gz")
sha1sums=('')
build() {
cd "${srcdir}/${pkgname}-${pkgver}"
cmake .
make $MAKEFLAGS
}
package() {
cd "${srcdir}/${pkgname}-${pkgver}"
mkdir -p ${pkgdir}/usr
cp -r bin/ share/ ${pkgdir}/usr/
}

53
README.md Normal file
View File

@ -0,0 +1,53 @@
# Ocarina 6.5
Ocarina is a simple GTK+ and GStreamer based music player written to let you listen to your music without getting in the way.
### Git
Ocarina is tracked with Git, and can be cloned from the following sources:
* http://git.nowheycreamery.com/anna/ocarina.git
* git://git.nowheycreamery.com/anna/ocarina.git
##### Branches
* [master]
* The most recent release. This branch does not change frequently.
* [next]
* Changes that will be included in the next release. This branch is for testing and bugfixing.
### Building
Ocarina uses `cmake`to control the build process. After cloning the code, run `cmake .` to generate the Makefile. Compile using `make`
##### CMake Options
Ocarina supports the following options, which can be passed to `cmake` through `cmake -D<option>=<ON|OFF>`. For example, `cmake -DCONFIG_DEBUG=ON` would enable debugging.
* CONFIG_DEBUG
* Compile with debugging symbols enabled
* CONFIG_TESTING_VERBOSE
* Enable extra output when running unit tests
* CONFIG_TESTING_GUI
* Enable running GUI unit tests
* CONFIG_TESTING_ARTWORK
* Enable unit tests that fetch album artwork
### Running
Once compiled, Ocarina can be run by invoking `bin/ocarina` on the command line.
##### Runtime options
The following options can be passed to Ocarina during startup
* -h, --help
* Print help message and exit
* -n, --next
* Tell a running Ocarina instance to play the next track
* - P, --pause
* Tell a running Ocarina instance to pause playback
* -p, --play
* Tell a running Ocarina instance to start playback
* -N, --previous
* Tell a running Ocarina instance to play the previous track
* -t, --toggle
* Tell a paused Ocarina instance to begin playback, or tell a playing Ocarina instance to pause.
* -v, --version
* Print Ocarina version and exit
### Installing
Running `make install` will install Ocarina for use by all users. There is currently no "uninstall" option.
### Testing
Running `make tests` will compile and run the Ocarina unit tests. See the CMake Options section above for additional testing options.

40
TODO Normal file
View File

@ -0,0 +1,40 @@
Future work:
I want to set reasonable expectations for Ocarina 6 so that I don't
have to spend a large amount of time coding before releasing something
to the wild. This section will be a list of features that I want, but
should be deferred to a future release so basic support can be coded.
- Fix track durations:
Some tracks in my library are tagged with the wrong duration,
so fix them as they are played.
- Track tag editor:
Make a pop-up window for editing the tags of a track. Be sure
to update the library information and the on-disk file.
- Copy a song group to a different directory:
This can be useful for keeping an external device (like an
Android phone) updated with the music you want to listen to.
Complications: I have an mp3 mirror of all my music, and I
want the mp3s to be synced. Perhaps track mirrors in Ocarina?
- Mirror directory:
I rip music to .flac, but keep an mp3 mirror directory to sync
to other computers and phones. An Ocarina tool to manage a
COMPLETE library mirror might be a good idea so I no longer
need to manage it externally. This can still be done with a
script, a cron job, and maybe a "mirror this track" option in
the library? Perhaps create a mirror group?
- AirPlay / remote audio support
- Replaygain support
External script to calculate values?
Calculate value after first playback?
Store in library :: Track structure
- "About" dialog
- Ports:
- OSX
- Windows
- Android

View File

@ -1,2 +0,0 @@
#!/bin/bash
cd /opt/ocarina && `which python2` ocarina.py $*

344
core/audio.c Normal file
View File

@ -0,0 +1,344 @@
/*
* Copyright 2013 (c) Anna Schumaker.
*/
#include <core/audio.h>
#include <core/idle.h>
#include <core/playlist.h>
#include <core/settings.h>
#define LOAD_PLAYING (1 << 0) /* Begin playback after loading */
#define LOAD_HISTORY (1 << 1) /* Add the track to the history */
#define LOAD_DEFAULT (LOAD_PLAYING | LOAD_HISTORY)
static const char *SETTINGS_TRACK = "core.audio.cur";
static const char *SETTINGS_VOLUME = "core.audio.volume";
static struct file audio_file = FILE_INIT_DATA("", "cur_track", 0);
static struct track *audio_track = NULL;
static int audio_pause_count = -1;
static GstElement *audio_pipeline = NULL;
static GstElement *audio_source = NULL;
static GstElement *audio_decoder = NULL;
static GstElement *audio_converter = NULL;
static GstElement *audio_volume = NULL;
static GstElement *audio_sink = NULL;
static guint audio_bus_id = 0;
static struct audio_callbacks *audio_cb = NULL;
static bool __audio_change_state(GstState state)
{
if (audio_cur_state() == state)
return false;
return gst_element_set_state(audio_pipeline, state) != GST_STATE_CHANGE_FAILURE;
}
static struct track *__audio_load(struct track *track, unsigned int flags)
{
struct track *prev = audio_track;
gchar *path;
if (!track)
return NULL;
audio_track = track;
path = track_path(track);
if (audio_cur_state() != GST_STATE_NULL)
gst_element_set_state(audio_pipeline, GST_STATE_READY);
g_object_set(G_OBJECT(audio_source), "location", path, NULL);
gst_element_set_state(audio_pipeline, flags & LOAD_PLAYING ?
GST_STATE_PLAYING : GST_STATE_PAUSED);
playlist_played(prev);
if (prev && TRACK_IS_EXTERNAL(prev))
track_free_external(prev);
playlist_selected(track);
if (flags & LOAD_HISTORY && !TRACK_IS_EXTERNAL(track))
playlist_add(playlist_lookup(PL_SYSTEM, "History"), track);
if (audio_cb)
audio_cb->audio_cb_load(track);
audio_save();
g_free(path);
return track;
}
static void __audio_pad_added(GstElement *element, GstPad *pad, gpointer data)
{
GstPad *sink = gst_element_get_static_pad(audio_decoder, "sink");
gst_element_link(element, audio_converter);
gst_pad_link(pad, sink);
gst_object_unref(sink);
}
static gboolean __audio_message(GstBus *bus, GstMessage *message, gpointer data)
{
GstObject *source = GST_OBJECT(GST_MESSAGE_SRC(message));
gchar *debug = NULL;
GError *error = NULL;
GstState old, state, next;
unsigned int load_flags = LOAD_DEFAULT;
switch (GST_MESSAGE_TYPE(message)) {
case GST_MESSAGE_ERROR:
gst_message_parse_error(message, &error, &debug);
g_printerr("ERROR from element %s: %s\n",
GST_OBJECT_NAME(source), error->message);
g_printerr("DEBUG details: %s\n", debug ? debug : "none");
g_error_free(error);
g_free(debug);
if (audio_cur_state() != GST_STATE_PLAYING)
load_flags = LOAD_HISTORY;
__audio_load(playlist_next(), load_flags);
break;
case GST_MESSAGE_EOS:
track_played(audio_track);
if (audio_pause_count >= 0) {
audio_pause_after(audio_pause_count - 1);
if (audio_pause_count == -1)
load_flags = LOAD_HISTORY;
}
__audio_load(playlist_next(), load_flags);
break;
case GST_MESSAGE_STATE_CHANGED:
if (!audio_cb || source != GST_OBJECT(audio_pipeline))
break;
gst_message_parse_state_changed(message, &old, &state, &next);
if (state == GST_STATE_PLAYING || state == GST_STATE_PAUSED) {
if (next == GST_STATE_VOID_PENDING)
audio_cb->audio_cb_state_change(state);
}
default:
break;
}
return true;
}
static bool __audio_init_idle(void *data)
{
unsigned int track;
if (settings_has(SETTINGS_TRACK)) {
track = settings_get(SETTINGS_TRACK);
__audio_load(track_get(track), LOAD_HISTORY);
} else if (file_open(&audio_file, OPEN_READ)) {
track = file_readu(&audio_file);
file_close(&audio_file);
file_remove(&audio_file);
__audio_load(track_get(track), LOAD_HISTORY);
}
return true;
}
void audio_init(int *argc, char ***argv, struct audio_callbacks *callbacks)
{
unsigned int volume = 100;
GstBus *bus;
gst_init(argc, argv);
audio_cb = callbacks;
audio_pipeline = gst_pipeline_new("pipeline");
audio_source = gst_element_factory_make("filesrc", "source");
audio_decoder = gst_element_factory_make("decodebin", "decoder");
audio_converter = gst_element_factory_make("audioconvert", "converter");
audio_volume = gst_element_factory_make("volume", "volume");
audio_sink = gst_element_factory_make("autoaudiosink", "sink");
bus = gst_pipeline_get_bus(GST_PIPELINE(audio_pipeline));
audio_bus_id = gst_bus_add_watch(bus, __audio_message, NULL);
gst_bin_add_many(GST_BIN(audio_pipeline), audio_source, audio_decoder,
audio_converter, audio_volume,
audio_sink, NULL);
gst_element_link(audio_source, audio_decoder);
gst_element_link_many(audio_converter, audio_volume, audio_sink, NULL);
g_signal_connect(audio_decoder, "pad-added", G_CALLBACK(__audio_pad_added), NULL);
gst_object_unref(bus);
if (settings_has(SETTINGS_VOLUME))
volume = settings_get(SETTINGS_VOLUME);
audio_set_volume(volume);
idle_schedule(IDLE_SYNC, __audio_init_idle, NULL);
}
void audio_deinit()
{
gst_element_set_state(audio_pipeline, GST_STATE_NULL);
gst_object_unref(GST_ELEMENT(audio_pipeline));
g_source_remove(audio_bus_id);
audio_pipeline = NULL;
audio_source = NULL;
audio_decoder = NULL;
audio_converter = NULL;
audio_volume = NULL;
audio_sink = NULL;
audio_track = NULL;
gst_deinit();
}
void audio_save()
{
if (audio_track && !TRACK_IS_EXTERNAL(audio_track))
settings_set(SETTINGS_TRACK, track_index(audio_track));
}
bool audio_load(struct track *track)
{
if (track == audio_track)
return false;
return __audio_load(track, LOAD_DEFAULT) != NULL;
}
bool audio_load_filepath(const gchar *filepath)
{
struct track *track;
if (!filepath)
return false;
track = track_lookup(filepath);
if (!track)
track = track_alloc_external(filepath);
return audio_load(track);
}
struct track *audio_cur_track()
{
return audio_track;
}
GstState audio_cur_state()
{
GstState cur = GST_STATE_NULL;
if (audio_pipeline)
gst_element_get_state(audio_pipeline,
&cur, NULL,
GST_CLOCK_TIME_NONE);
return cur;
}
void audio_set_volume(unsigned int volume)
{
gdouble vol;
if (volume > 100)
volume = 100;
vol = (gdouble)volume / 100;
settings_set(SETTINGS_VOLUME, volume);
g_object_set(G_OBJECT(audio_volume), "volume", vol, NULL);
}
unsigned int audio_get_volume()
{
gdouble volume;
g_object_get(G_OBJECT(audio_volume), "volume", &volume, NULL);
return volume * 100;
}
bool audio_play()
{
if (!audio_track)
return false;
return __audio_change_state(GST_STATE_PLAYING);
}
bool audio_pause()
{
if (!audio_track)
return false;
return __audio_change_state(GST_STATE_PAUSED);
}
bool audio_seek(gint64 offset)
{
if (!audio_track)
return false;
return gst_element_seek_simple(audio_pipeline,
GST_FORMAT_TIME,
GST_SEEK_FLAG_FLUSH,
offset);
}
gint64 audio_position()
{
gint64 position;
if (gst_element_query_position(audio_pipeline,
GST_FORMAT_TIME,
&position))
return position;
return 0;
}
gint64 audio_duration()
{
gint64 duration;
if (gst_element_query_duration(audio_pipeline,
GST_FORMAT_TIME,
&duration))
return duration;
if (audio_track)
return audio_track->tr_length * GST_SECOND;
return 0;
}
struct track *audio_next()
{
return __audio_load(playlist_next(), LOAD_DEFAULT);
}
struct track *audio_prev()
{
return __audio_load(playlist_prev(), LOAD_PLAYING);
}
bool audio_pause_after(int n)
{
if (n >= -1 && n != audio_pause_count) {
audio_pause_count = n;
if (audio_cb)
audio_cb->audio_cb_config_pause(audio_pause_count);
return true;
}
return false;
}
int audio_get_pause_count(void)
{
return audio_pause_count;
}
#ifdef CONFIG_TESTING
void test_audio_eos()
{
GstMessage *message = gst_message_new_eos(GST_OBJECT(audio_pipeline));
__audio_message(NULL, message, NULL);
gst_message_unref(message);
}
void test_audio_error(GError *error, gchar *debug)
{
GstMessage *message = gst_message_new_error(
GST_OBJECT(audio_pipeline), error, debug);
__audio_message(NULL, message, NULL);
gst_message_unref(message);
}
GstElement *test_audio_pipeline()
{
return audio_pipeline;
}
#endif /* CONFIG_TESTING */

34
core/core.c Normal file
View File

@ -0,0 +1,34 @@
/*
* Copyright 2014 (c) Anna Schumaker.
*/
#include <core/core.h>
static bool core_defragment(void *data)
{
if (tags_defragment()) {
playlist_save();
audio_save();
}
return true;
}
void core_init(int *argc, char ***argv, struct playlist_callbacks *playlist_cb,
struct audio_callbacks *audio_cb, enum idle_sync_t idle_sync)
{
idle_init(idle_sync);
settings_init();
tags_init();
playlist_init(playlist_cb);
audio_init(argc, argv, audio_cb);
idle_schedule(IDLE_SYNC, core_defragment, NULL);
}
void core_deinit()
{
audio_deinit();
playlist_deinit();
tags_deinit();
settings_deinit();
idle_deinit();
}

232
core/database.c Normal file
View File

@ -0,0 +1,232 @@
/*
* Copyright 2013 (c) Anna Schumaker.
*/
#include <core/database.h>
#include <core/idle.h>
#define DB_ENTRY_AT(db, index) \
(struct db_entry *)g_ptr_array_index(db->db_entries, index)
static void __dbe_free(struct database *db, struct db_entry *dbe)
{
if (dbe) {
g_hash_table_remove(db->db_keys, dbe->dbe_key);
g_free(dbe->dbe_key);
g_ptr_array_index(db->db_entries, dbe->dbe_index) = NULL;
db->db_ops->dbe_free(dbe);
db->db_size--;
}
}
static struct db_entry *__dbe_next(const struct database *db, unsigned int index)
{
if (!db->db_entries)
return NULL;
for (; index < db->db_entries->len; index++) {
if (DB_ENTRY_AT(db, index))
return DB_ENTRY_AT(db, index);
}
return NULL;
}
static struct db_entry *__dbe_read(struct database *db, unsigned int index)
{
struct db_entry *dbe = NULL;
if (file_readd(&db->db_file))
dbe = db->db_ops->dbe_read(&db->db_file, index);
g_ptr_array_index(db->db_entries, index) = dbe;
return dbe;
}
static void __dbe_setup(struct database *db, unsigned int index)
{
struct db_entry *dbe = DB_ENTRY_AT(db, index);
if (dbe) {
dbe->dbe_index = index;
dbe->dbe_key = db->db_ops->dbe_key(dbe);
g_hash_table_insert(db->db_keys, dbe->dbe_key, dbe);
db->db_size++;
}
}
static void __dbe_write(struct database *db, struct db_entry *dbe)
{
if (dbe) {
file_writef(&db->db_file, "%u ", true);
db->db_ops->dbe_write(&db->db_file, dbe);
} else
file_writef(&db->db_file, "%u", false);
file_writef(&db->db_file, "\n");
}
void db_init(struct database *db, const char *filepath, bool autosave,
const struct db_ops *ops, unsigned int fmin)
{
db->db_ops = ops;
db->db_size = 0;
db->db_autosave = autosave;
db->db_entries = g_ptr_array_new();
db->db_keys = g_hash_table_new(g_str_hash, g_str_equal);
file_init_data(&db->db_file, "", filepath, fmin);
}
void db_deinit(struct database *db)
{
struct db_entry *dbe, *next;
db_for_each(dbe, next, db)
__dbe_free(db, dbe);
g_ptr_array_free(db->db_entries, true);
g_hash_table_destroy(db->db_keys);
db->db_entries = NULL;
db->db_keys = NULL;
}
void db_save(struct database *db)
{
if (file_open(&db->db_file, OPEN_WRITE) == false)
return;
file_writef(&db->db_file, "%u\n", db_actual_size(db));
for (unsigned int i = 0; i < db_actual_size(db); i++)
__dbe_write(db, DB_ENTRY_AT(db, i));
file_close(&db->db_file);
}
void db_autosave(struct database *db)
{
if (db->db_autosave == true)
db_save(db);
}
void db_load(struct database *db)
{
unsigned int size;
bool save;
if (file_open(&db->db_file, OPEN_READ) == false)
return;
size = file_readu(&db->db_file);
g_ptr_array_set_size(db->db_entries, size);
for (unsigned int i = 0; i < size; i++) {
if (__dbe_read(db, i))
__dbe_setup(db, i);
}
save = file_version(&db->db_file) != OCARINA_MINOR_VERSION;
file_close(&db->db_file);
if (save)
db_autosave(db);
}
struct db_entry *db_insert(struct database *db, const gchar *key)
{
struct db_entry *item = NULL;
if (key)
item = db->db_ops->dbe_alloc(key, db_actual_size(db));
if (item) {
g_ptr_array_add(db->db_entries, item);
__dbe_setup(db, db_actual_size(db) - 1);
db_autosave(db);
}
return item;
}
void db_remove(struct database *db, struct db_entry *item)
{
if (item == NULL)
return;
if (db_at(db, item->dbe_index) != item)
return;
__dbe_free(db, item);
db_autosave(db);
}
bool db_defrag(struct database *db)
{
struct db_entry *dbe;
unsigned int i, cur;
if (db->db_size == db_actual_size(db))
return false;
for (cur = 0, i = 1; cur < db->db_size; cur++) {
if (DB_ENTRY_AT(db, cur))
continue;
while (i <= cur || !DB_ENTRY_AT(db, i))
i++;
dbe = DB_ENTRY_AT(db, i);
g_ptr_array_index(db->db_entries, i) = NULL;
g_ptr_array_index(db->db_entries, cur) = dbe;
dbe->dbe_index = cur;
}
g_ptr_array_set_size(db->db_entries, db->db_size);
db_autosave(db);
return true;
}
void db_rekey(struct database *db, struct db_entry *dbe)
{
if (dbe == NULL)
return;
g_hash_table_remove(db->db_keys, dbe->dbe_key);
g_free(dbe->dbe_key);
dbe->dbe_key = db->db_ops->dbe_key(dbe);
g_hash_table_insert(db->db_keys, dbe->dbe_key, dbe);
}
unsigned int db_actual_size(const struct database *db)
{
if (db->db_entries)
return db->db_entries->len;
return 0;
}
struct db_entry *db_first(const struct database *db)
{
return __dbe_next(db, 0);
}
struct db_entry *db_next(const struct database *db, struct db_entry *ent)
{
if (ent)
return __dbe_next(db, ent->dbe_index + 1);
return NULL;
}
struct db_entry *db_at(const struct database *db, unsigned int index)
{
if (index >= db_actual_size(db))
return NULL;
return DB_ENTRY_AT(db, index);
}
struct db_entry *db_get(struct database *db, const gchar *key)
{
return (struct db_entry *)g_hash_table_lookup(db->db_keys, key);
}
struct db_entry *db_find(struct database *db, const gchar *key)
{
struct db_entry *dbe = db_get(db, key);
if (dbe)
return dbe;
return db_insert(db, key);
}

68
core/date.c Normal file
View File

@ -0,0 +1,68 @@
/*
* Copyright 2015 (c) Anna Schumaker.
*/
#include <core/date.h>
#include <core/string.h>
#include <endian.h>
#include <time.h>
void date_set(struct date *date, unsigned int year,
unsigned int month, unsigned int day)
{
if (date) {
date->d_year = year;
date->d_month = month;
date->d_day = day;
}
}
void date_today(struct date *date)
{
time_t rawtime = time(NULL);
struct tm *now = localtime(&rawtime);
date_set(date, now->tm_year + 1900, now->tm_mon + 1, now->tm_mday);
}
void date_read(struct file *f, struct date *date)
{
date->d_year = file_readu(f);
date->d_month = file_readu(f);
date->d_day = file_readu(f);
}
void date_read_stamp(struct file *f, struct date *date)
{
date->d_stamp = be32toh(file_readu(f));
}
void date_write(struct file *f, struct date *date)
{
file_writef(f, "%u %u %u", date->d_year, date->d_month, date->d_day);
}
void date_write_stamp(struct file *f, struct date *date)
{
file_writef(f, "%u", htobe32(date->d_stamp));
}
gchar *date_string(const struct date *date)
{
struct tm tm = {
.tm_year = date->d_year - 1900,
.tm_mon = date->d_month - 1,
.tm_mday = date->d_day,
};
return string_tm2str(&tm);
}
int date_compare(const struct date *lhs, const struct date *rhs)
{
int ret = lhs->d_year - rhs->d_year;
if (ret != 0)
return ret;
ret = lhs->d_month - rhs->d_month;
if (ret != 0)
return ret;
return lhs->d_day - rhs->d_day;
}

279
core/file.c Normal file
View File

@ -0,0 +1,279 @@
/*
* Copyright 2013 (c) Anna Schumaker.
*/
#include <core/file.h>
#include <core/string.h>
#include <core/version.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#define REPORT_ERROR(fname, error) \
g_printerr("%s (%s:%d): %s: %s\n", __func__, __FILE__, __LINE__, fname, error)
#define REPORT_ERRNO(fname) REPORT_ERROR(fname, strerror(errno))
static void __file_init_common(struct file *file, const gchar *subdir,
const gchar *name, unsigned int min,
const gchar *(*user_dir)(void))
{
file->f_file = NULL;
file->f_name = name;
file->f_subdir = subdir;
file->f_mode = CLOSED;
file->f_version = OCARINA_MINOR_VERSION;
file->f_prev = 0;
file->f_min = min;
file->f_user_dir = user_dir;
}
static bool __file_open(struct file *file, enum open_mode mode)
{
gchar *cmode, *path;
if (mode == OPEN_READ || mode == OPEN_READ_BINARY) {
cmode = "r";
path = file_path(file);
} else {
cmode = "w";
path = file_write_path(file);
}
file->f_file = g_fopen(path, cmode);
if (!file->f_file)
REPORT_ERRNO(path);
g_free(path);
return file->f_file != NULL;
}
static bool __file_mkdir(struct file *file)
{
gchar *dir = g_build_filename(file->f_user_dir(), OCARINA_NAME,
file->f_subdir, NULL);
int ret = g_mkdir_with_parents(dir, 0755);
if (ret != 0)
REPORT_ERRNO(dir);
g_free(dir);
return ret == 0;
}
static bool __file_can_write(struct file *file)
{
gchar *path = file_path(file);
bool ret = true;
if (g_access(path, F_OK) == 0 && g_access(path, W_OK) < 0)
ret = false;
g_free(path);
return ret;
}
void file_init_data(struct file *file, const gchar *subdir,
const gchar *name, unsigned int min)
{
__file_init_common(file, subdir, name, min, g_get_user_data_dir);
}
void file_init_cache(struct file *file, const gchar *subdir, const gchar *name)
{
__file_init_common(file, subdir, name, 0, g_get_user_cache_dir);
}
gchar *file_path(struct file *file)
{
if (string_length(file->f_name) == 0)
return g_strdup("");
return g_build_filename(file->f_user_dir(), OCARINA_NAME,
file->f_subdir, file->f_name, NULL);
}
gchar *file_write_path(struct file *file)
{
gchar *tmp, *res;
if (string_length(file->f_name) == 0)
return g_strdup("");
tmp = g_strdup_printf(".%s.tmp", file->f_name);
res = g_build_filename(file->f_user_dir(), OCARINA_NAME,
file->f_subdir, tmp, NULL);
g_free(tmp);
return res;
}
const unsigned int file_version(struct file *file)
{
if (file->f_file && (file->f_mode == OPEN_READ))
return file->f_prev;
return file->f_version;
}
bool file_exists(struct file *file)
{
gchar *path = file_path(file);
bool ret = g_file_test(path, G_FILE_TEST_EXISTS);
g_free(path);
return ret;
}
static bool __file_open_read(struct file *file, enum open_mode mode)
{
if (!file_exists(file))
return false;
if (!__file_open(file, mode))
return false;
file->f_mode = mode;
if (mode == OPEN_READ_BINARY)
return true;
file->f_prev = file_readu(file);
if (file->f_prev < file->f_min) {
REPORT_ERROR(file->f_name, "File too old to be upgraded.");
file_close(file);
exit(1);
}
if (file->f_prev > file->f_version) {
REPORT_ERROR(file->f_name, "File too new to be opened.");
file_close(file);
exit(1);
}
return true;
}
static bool __file_open_write(struct file *file, enum open_mode mode)
{
if (!__file_mkdir(file))
return false;
if (!__file_can_write(file))
return false;
if (!__file_open(file, OPEN_WRITE))
return false;
file->f_mode = mode;
if (mode == OPEN_WRITE_BINARY)
return true;
return file_writef(file, "%d\n", file->f_version) > 0;
}
bool file_open(struct file *file, enum open_mode mode)
{
if ((string_length(file->f_name) == 0) || (file->f_file != NULL))
return false;
if (mode == CLOSED)
return false;
if (mode == OPEN_READ || mode == OPEN_READ_BINARY)
return __file_open_read(file, mode);
return __file_open_write(file, mode);
}
void file_close(struct file *file)
{
gchar *path = file_path(file);
gchar *tmp = file_write_path(file);
if (file->f_file) {
fclose(file->f_file);
if (file->f_mode == OPEN_WRITE || file->f_mode == OPEN_WRITE_BINARY)
g_rename(tmp, path);
}
file->f_file = NULL;
file->f_mode = CLOSED;
g_free(path);
g_free(tmp);
}
gchar *file_readw(struct file *file)
{
gchar *s;
return fscanf(file->f_file, "%ms%*c", &s) ? s : g_strdup("");
}
gchar *file_readl(struct file *file)
{
gchar *s = NULL;
size_t len = 0;
return getline(&s, &len, file->f_file) ? g_strchomp(s) : g_strdup("");
}
unsigned int file_readu(struct file *file)
{
unsigned int u;
return fscanf(file->f_file, "%u%*c", &u) ? u : 0;
}
int file_writef(struct file *file, const char *fmt, ...)
{
va_list argp;
int ret;
va_start(argp, fmt);
ret = g_vfprintf(file->f_file, fmt, argp);
va_end(argp);
if (ret < 0)
REPORT_ERRNO(file->f_name);
return ret;
}
gchar *file_read(struct file *file)
{
int fd = fileno(file->f_file);
struct stat st;
gchar *buf;
if (fstat(fd, &st) < 0)
return NULL;
buf = g_malloc0(st.st_size + 1);
if (fread(buf, st.st_size, 1, file->f_file) == 1)
return buf;
g_free(buf);
return NULL;
}
int file_write(struct file *file, const void *data, size_t len)
{
if (fwrite(data, len, 1, file->f_file) == 1)
return len;
return -1;
}
bool file_import(struct file *file, const gchar *srcpath)
{
gchar *contents = NULL;
gsize length = 0;
if (!file->f_file || !srcpath)
return false;
if (!g_file_get_contents(srcpath, &contents, &length, NULL))
return false;
file_write(file, contents, length);
return true;
}
bool file_remove(struct file *file)
{
gchar *path, *dir;
int ret = -1;
if (!file->f_file) {
path = file_path(file);
ret = g_unlink(path);
dir = g_path_get_dirname(path);
if (string_length(file->f_subdir) > 0)
g_rmdir(dir);
g_free(path);
g_free(dir);
}
return ret == 0;
}

111
core/idle.c Normal file
View File

@ -0,0 +1,111 @@
/*
* Copyright 2013 (c) Anna Schumaker.
*/
#include <core/idle.h>
#include <glib.h>
struct idle_task {
bool (*idle_func)(void *);
void *idle_data;
};
static GThreadPool *idle_pool = NULL;
static GQueue idle_queue = G_QUEUE_INIT;
static enum idle_sync_t idle_mode = IDLE_SYNC;
static unsigned int queued = 0;
static unsigned int serviced = 0;
void __idle_free_task(struct idle_task *task)
{
g_free(task);
g_atomic_int_inc(&serviced);
}
bool __idle_run_task(struct idle_task *task)
{
bool finished = task->idle_func(task->idle_data);
if (finished)
__idle_free_task(task);
return finished;
}
void __idle_thread(gpointer task, gpointer data)
{
if (!__idle_run_task(task))
g_thread_pool_push(idle_pool, task, NULL);
}
void idle_init(enum idle_sync_t sync)
{
idle_mode = sync;
}
void idle_deinit()
{
struct idle_task *task;
while (!g_queue_is_empty(&idle_queue)) {
task = g_queue_pop_head(&idle_queue);
g_free(task);
}
if (idle_pool) {
g_thread_pool_free(idle_pool, true, true);
idle_pool = NULL;
}
queued = 0;
serviced = 0;
}
void idle_schedule(enum idle_sync_t sync, bool (*func)(void *), void *data)
{
struct idle_task *task;
if (sync == IDLE_ASYNC && idle_mode == IDLE_SYNC)
return;
task = g_malloc(sizeof(struct idle_task));
task->idle_func = func;
task->idle_data = data;
if (sync == IDLE_SYNC)
g_queue_push_tail(&idle_queue, task);
else {
if (!idle_pool)
idle_pool = g_thread_pool_new(__idle_thread, NULL, 1,
false, NULL);
g_thread_pool_push(idle_pool, task, NULL);
}
g_atomic_int_inc(&queued);
}
bool idle_run_task()
{
struct idle_task *task;
if (!g_queue_is_empty(&idle_queue)) {
task = g_queue_pop_head(&idle_queue);
if (!__idle_run_task(task))
g_queue_push_tail(&idle_queue, task);
}
if (g_atomic_int_get(&queued) != g_atomic_int_get(&serviced))
return true;
queued = 0;
serviced = 0;
return false;
}
float idle_progress()
{
if (g_atomic_int_get(&serviced) == 0 &&
g_atomic_int_get(&queued) == 0)
return 1.0;
return (float)g_atomic_int_get(&serviced) / (float)queued;
}

236
core/playlist.c Normal file
View File

@ -0,0 +1,236 @@
/*
* Copyright 2013 (c) Anna Schumaker.
*/
#include <core/playlist.h>
#include <core/settings.h>
#include <core/string.h>
static const gchar *SETTINGS_CUR_TYPE = "core.playlist.cur.type";
static const gchar *SETTINGS_CUR_ID = "core.playlist.cur.id";
static const gchar *SETTINGS_PREV_TYPE = "core.playlist.prev.type";
static const gchar *SETTINGS_PREV_ID = "core.playlist.prev.id";
static struct playlist *current = NULL;
static struct playlist *previous = NULL;
struct playlist_type *playlist_types[] = {
[PL_SYSTEM] = &pl_system,
[PL_ARTIST] = &pl_artist,
[PL_LIBRARY] = &pl_library,
[PL_USER] = &pl_user,
};
static struct playlist *__playlist_saved(const gchar *s_type, const gchar *s_id)
{
unsigned int type, id;
if (!settings_has(s_type) || !settings_has(s_id))
return NULL;
type = settings_get(s_type);
id = settings_get(s_id);
return playlist_types[type]->pl_get(id);
}
void playlist_init(struct playlist_callbacks *cb)
{
playlist_generic_set_callbacks(cb);
pl_system_init();
pl_artist_init();
pl_user_init();
pl_library_init();
current = __playlist_saved(SETTINGS_CUR_TYPE, SETTINGS_CUR_ID);
previous = __playlist_saved(SETTINGS_PREV_TYPE, SETTINGS_PREV_ID);
if (!current)
current = playlist_lookup(PL_SYSTEM, "Collection");
}
void playlist_deinit()
{
pl_system_deinit();
pl_artist_deinit();
pl_user_deinit();
pl_library_deinit();
}
void playlist_save()
{
unsigned int i;
for (i = 0; i < PL_MAX_TYPE; i++)
playlist_types[i]->pl_save();
}
void playlist_played(struct track *track)
{
unsigned int i;
if (track && !TRACK_IS_EXTERNAL(track)) {
for (i = 0; i < PL_MAX_TYPE; i++)
playlist_types[i]->pl_played(track);
}
}
void playlist_selected(struct track *track)
{
unsigned int i;
if (track && !TRACK_IS_EXTERNAL(track)) {
for (i = 0; i < PL_MAX_TYPE; i++)
playlist_types[i]->pl_selected(track);
if (playlist_size(current) == 0)
playlist_select(previous);
}
}
struct playlist *playlist_new(enum playlist_type_t type, const gchar *name)
{
if (type < PL_MAX_TYPE && playlist_types[type]->pl_new)
return playlist_types[type]->pl_new(name);
return NULL;
}
bool playlist_delete(struct playlist *playlist)
{
enum playlist_type_t type;
bool ret;
if (!playlist || !playlist->pl_ops->pl_delete)
return false;
type = playlist->pl_type;
ret = playlist->pl_ops->pl_delete(playlist);
if (ret)
playlist_types[type]->pl_save();
return ret;
}
struct playlist *playlist_lookup(enum playlist_type_t type, const gchar *name)
{
if (type >= PL_MAX_TYPE)
return NULL;
return playlist_types[type]->pl_lookup(name);
}
struct playlist *playlist_get(enum playlist_type_t type, unsigned int id)
{
if (type >= PL_MAX_TYPE)
return NULL;
return playlist_types[type]->pl_get(id);
}
struct playlist *playlist_current(void)
{
return current;
}
bool playlist_select(struct playlist *playlist)
{
if (!playlist || (playlist == current))
return false;
if (!playlist->pl_ops->pl_can_select)
return false;
if (!playlist->pl_ops->pl_can_select(playlist))
return false;
previous = current;
current = playlist;
settings_set(SETTINGS_CUR_TYPE, current->pl_type);
settings_set(SETTINGS_CUR_ID, current->pl_id);
if (previous) {
settings_set(SETTINGS_PREV_TYPE, previous->pl_type);
settings_set(SETTINGS_PREV_ID, previous->pl_id);
}
return true;
}
struct track *playlist_next(void)
{
struct track *track = playlist_generic_next(current);
if (track && current->pl_type < PL_MAX_TYPE)
playlist_types[current->pl_type]->pl_save();
return track;
}
struct track *playlist_prev(void)
{
return playlist_generic_next(playlist_lookup(PL_SYSTEM, "History"));
}
bool playlist_add(struct playlist *playlist, struct track *track)
{
bool ret;
if (!track || !playlist || !playlist->pl_ops->pl_add)
return false;
ret = playlist->pl_ops->pl_add(playlist, track);
if (ret && playlist->pl_type < PL_MAX_TYPE)
playlist_types[playlist->pl_type]->pl_save();
if (playlist == playlist_lookup(PL_SYSTEM, "Queued Tracks"))
playlist_select(playlist);
return ret;
}
bool playlist_remove(struct playlist *playlist, struct track *track)
{
bool ret;
if (!track || !playlist || !playlist->pl_ops->pl_remove)
return false;
ret = playlist->pl_ops->pl_remove(playlist, track);
if (ret && playlist->pl_type < PL_MAX_TYPE)
playlist_types[playlist->pl_type]->pl_save();
return ret;
}
void playlist_set_random(struct playlist *playlist, bool enabled)
{
if (playlist && playlist->pl_ops->pl_set_random) {
playlist->pl_ops->pl_set_random(playlist, enabled);
if (playlist->pl_type < PL_MAX_TYPE)
playlist_types[playlist->pl_type]->pl_save();
}
}
bool playlist_sort(struct playlist *playlist, enum compare_t sort)
{
if (!playlist || !playlist->pl_ops->pl_sort)
return false;
playlist->pl_ops->pl_sort(playlist, sort);
if (playlist->pl_type < PL_MAX_TYPE)
playlist_types[playlist->pl_type]->pl_save();
return g_slist_length(playlist->pl_sort) > 0;
}
bool playlist_rearrange(struct playlist *playlist, unsigned int old_pos,
unsigned int new_pos)
{
bool ret;
if (!playlist || !playlist->pl_ops->pl_rearrange)
return false;
ret = playlist->pl_ops->pl_rearrange(playlist, old_pos, new_pos);
if (ret && playlist->pl_type < PL_MAX_TYPE)
playlist_types[playlist->pl_type]->pl_save();
return ret;
}
void playlist_set_search(struct playlist *playlist, const gchar *text)
{
gchar **tokens = NULL;
if (!playlist)
return;
if (playlist->pl_search)
g_strfreev(playlist->pl_search);
if (strlen(text) > 0)
tokens = g_str_tokenize_and_fold(text, NULL, NULL);
playlist->pl_search = tokens;
}

157
core/playlists/artist.c Normal file
View File

@ -0,0 +1,157 @@
/*
* Copyright 2016 (c) Anna Schumaker.
*/
#include <core/idle.h>
#include <core/playlists/artist.h>
#include <core/string.h>
static struct file artist_file = FILE_INIT_DATA("", "playlist.artist", 0);
static struct playlist_ops pl_artist_ops = {
.pl_can_select = playlist_generic_can_select,
.pl_set_random = playlist_generic_set_random,
.pl_sort = playlist_generic_sort,
.pl_rearrange = playlist_generic_rearrange,
};
static struct playlist *__artist_pl_alloc(struct artist *artist)
{
return playlist_generic_alloc(artist->ar_name, PL_ARTIST,
artist_index(artist), &pl_artist_ops,
3, COMPARE_YEAR, COMPARE_ALBUM, COMPARE_TRACK);
}
static bool __artist_pl_add(void *data)
{
struct playlist *playlist = (struct playlist *)data;
struct artist *artist = artist_lookup(playlist->pl_name);
struct db_entry *dbe, *next;
db_for_each(dbe, next, track_db_get()) {
if (TRACK(dbe)->tr_album->al_artist == artist)
playlist_generic_add_front(playlist, TRACK(dbe));
}
playlist_generic_resort(playlist);
return true;
}
static struct playlist *__artist_pl_lookup(const gchar *name)
{
struct artist *artist = artist_lookup(name);
return artist ? artist->ar_playlist : NULL;
}
static bool __artist_pl_load(void *data)
{
struct playlist *playlist;
unsigned int i, n;
gchar *name;
if (!file_open(&artist_file, OPEN_READ))
return true;
n = file_readu(&artist_file);
for (i = 0; i < n; i++) {
name = file_readl(&artist_file);
playlist = __artist_pl_lookup(name);
if (playlist)
playlist_generic_load(playlist, &artist_file,
PL_SAVE_METADATA);
g_free(name);
}
file_close(&artist_file);
return true;
}
static void pl_artist_save(void)
{
struct db_entry *dbe, *next;
struct playlist *playlist;
if (!file_open(&artist_file, OPEN_WRITE))
return;
file_writef(&artist_file, "%u\n", artist_db_get()->db_size);
db_for_each(dbe, next, artist_db_get()) {
playlist = ARTIST(dbe)->ar_playlist;
file_writef(&artist_file, "%s\n", playlist->pl_name);
playlist_generic_save(playlist, &artist_file, PL_SAVE_METADATA);
}
file_close(&artist_file);
}
static struct playlist *pl_artist_lookup(const gchar *name)
{
return __artist_pl_lookup(name);
}
static struct playlist *pl_artist_get(unsigned int id)
{
struct artist *artist = artist_get(id);
return artist ? artist->ar_playlist : NULL;
}
static void pl_artist_played(struct track *track)
{
struct artist *artist = track->tr_album->al_artist;
playlist_generic_update(artist->ar_playlist, track);
}
struct playlist_type pl_artist = {
.pl_save = pl_artist_save,
.pl_lookup = pl_artist_lookup,
.pl_get = pl_artist_get,
.pl_played = pl_artist_played,
.pl_selected = pl_artist_played,
};
void pl_artist_init(void)
{
struct db_entry *dbe, *next;
struct playlist *playlist;
db_for_each(dbe, next, artist_db_get()) {
playlist = __artist_pl_alloc(ARTIST(dbe));
ARTIST(dbe)->ar_playlist = playlist;
idle_schedule(IDLE_SYNC, __artist_pl_add, playlist);
}
idle_schedule(IDLE_SYNC, __artist_pl_load, NULL);
}
void pl_artist_deinit()
{
struct db_entry *dbe, *next;
db_for_each(dbe, next, artist_db_get()) {
playlist_generic_free(ARTIST(dbe)->ar_playlist);
ARTIST(dbe)->ar_playlist = NULL;
}
}
void pl_artist_new_track(struct track *track)
{
struct artist *artist = track->tr_album->al_artist;
struct playlist *playlist = (struct playlist *)artist->ar_playlist;
if (!playlist) {
playlist = __artist_pl_alloc(artist);
artist->ar_playlist = playlist;
}
playlist_generic_add(playlist, track);
}
void pl_artist_delete_track(struct track *track)
{
struct artist *artist = track->tr_album->al_artist;
playlist_generic_remove(artist->ar_playlist, track);
}

313
core/playlists/generic.c Normal file
View File

@ -0,0 +1,313 @@
/*
* Copyright 2016 (c) Anna Schumaker.
*/
#include <core/idle.h>
#include <core/playlists/generic.h>
#include <stdlib.h>
static struct playlist_callbacks *callbacks = NULL;
static int __playlist_generic_find_sort(gconstpointer a, gconstpointer b)
{
return abs(GPOINTER_TO_INT(a)) - abs(GPOINTER_TO_INT(b));
}
static int __playlist_generic_less_than(gconstpointer a, gconstpointer b,
gpointer data)
{
struct track *lhs = (struct track *)a;
struct track *rhs = (struct track *)b;
GSList *cur = ((struct playlist *)data)->pl_sort;
int res, field;
while (cur) {
field = GPOINTER_TO_INT(cur->data);
res = track_compare(lhs, rhs, abs(field));
if (res != 0)
break;
cur = g_slist_next(cur);
};
return (field > 0) ? res : -res;
}
void playlist_generic_set_callbacks(struct playlist_callbacks *cb)
{
callbacks = cb;
}
static void __playlist_generic_vinit(struct playlist *playlist,
unsigned int nargs, va_list argp)
{
unsigned int i;
if (!playlist)
return;
g_queue_init(&playlist->pl_tracks);
playlist->pl_length = 0;
playlist->pl_random = false;
playlist->pl_current = NULL;
playlist->pl_sort = NULL;
playlist->pl_search = NULL;
for (i = 0; i < nargs; i++)
playlist_generic_sort(playlist, va_arg(argp, unsigned int));
}
void playlist_generic_init(struct playlist *playlist, unsigned int nargs, ...)
{
va_list argp;
va_start(argp, nargs);
__playlist_generic_vinit(playlist, nargs, argp);
va_end(argp);
}
void playlist_generic_deinit(struct playlist *playlist)
{
if (playlist) {
playlist_generic_clear(playlist);
playlist_clear_sort(playlist);
g_strfreev(playlist->pl_search);
playlist->pl_search = NULL;
playlist->pl_length = 0;
}
}
struct playlist *playlist_generic_alloc(gchar *name, enum playlist_type_t type,
unsigned int id, struct playlist_ops *ops,
unsigned int nargs, ...)
{
struct playlist *playlist = g_malloc(sizeof(struct playlist));
va_list argp;
playlist->pl_name = name;
playlist->pl_type = type;
playlist->pl_id = id;
playlist->pl_ops = ops;
va_start(argp, nargs);
__playlist_generic_vinit(playlist, nargs, argp);
if (callbacks)
callbacks->pl_cb_alloc(playlist);
va_end(argp);
return playlist;
}
void playlist_generic_free(struct playlist *playlist)
{
if (playlist) {
playlist_generic_deinit(playlist);
g_free(playlist);
}
}
void playlist_generic_save(struct playlist *playlist, struct file *file,
unsigned int flags)
{
playlist_iter it;
GSList *sort;
int field;
if (!playlist)
return;
if (flags & PL_SAVE_ITER)
file_writef(file, "%u ", playlist_current_index(playlist));
if (flags & PL_SAVE_FLAGS) {
sort = playlist->pl_sort;
file_writef(file, "%u ", playlist->pl_random ? PL_RANDOM : 0);
file_writef(file, "%u", g_slist_length(sort));
while (sort) {
field = GPOINTER_TO_INT(sort->data);
file_writef(file, " %u %d", abs(field) - 1, field > 0);
sort = g_slist_next(sort);
}
file_writef(file, "\n");
}
if (flags & PL_SAVE_TRACKS) {
file_writef(file, "%u", playlist_size(playlist));
playlist_for_each(playlist, it)
file_writef(file, " %u",
track_index(playlist_iter_track(it)));
file_writef(file, "\n");
}
}
void playlist_generic_load(struct playlist *playlist, struct file *file,
unsigned int flags)
{
unsigned int f, n, i, t, it = 0;
int field, ascending;
if (!playlist)
return;
if (flags & PL_SAVE_ITER)
it = file_readu(file);
if (flags & PL_SAVE_FLAGS) {
f = file_readu(file);
n = file_readu(file);
playlist_clear_sort(playlist);
for (i = 0; i < n; i++) {
field = file_readu(file) + 1;
ascending = file_readd(file);
if (!ascending)
field = -field;
playlist->pl_sort = g_slist_append(playlist->pl_sort,
GINT_TO_POINTER(field));
}
playlist_generic_resort(playlist);
}
if (flags & PL_SAVE_TRACKS) {
n = file_readu(file);
for (i = 0; i < n; i++) {
t = file_readu(file);
playlist_generic_add(playlist, track_get(t));
}
}
playlist_generic_set_random(playlist, f == PL_RANDOM);
playlist_current_set(playlist, it);
}
bool playlist_generic_can_select(struct playlist *playlist)
{
return playlist_size(playlist) > 0;
}
void playlist_generic_clear(struct playlist *playlist)
{
unsigned int n;
if (!playlist)
return;
n = playlist_size(playlist);
g_queue_clear(&playlist->pl_tracks);
playlist->pl_length = 0;
playlist->pl_current = NULL;
if (callbacks)
callbacks->pl_cb_removed(playlist, NULL, n);
}
bool playlist_generic_add(struct playlist *playlist, struct track *track)
{
if (!playlist || !track || playlist_has(playlist, track))
return false;
playlist->pl_length += track->tr_length;
if (playlist->pl_sort) {
g_queue_insert_sorted(&playlist->pl_tracks, track,
__playlist_generic_less_than, playlist);
} else
g_queue_push_tail(&playlist->pl_tracks, track);
if (callbacks)
callbacks->pl_cb_added(playlist, track);
return true;
}
bool playlist_generic_add_front(struct playlist *playlist, struct track *track)
{
if (!playlist || !track)
return false;
playlist->pl_length += track->tr_length;
g_queue_push_head(&playlist->pl_tracks, track);
if (callbacks)
callbacks->pl_cb_added(playlist, track);
return true;
}
bool playlist_generic_remove(struct playlist *playlist, struct track *track)
{
unsigned int count;
if (!playlist || !track)
return false;
while (playlist_current_track(playlist) == track)
playlist_current_previous(playlist);
count = g_queue_remove_all(&playlist->pl_tracks, track);
playlist->pl_length -= (count * track->tr_length);
if (callbacks)
callbacks->pl_cb_removed(playlist, track, count);
return count > 0;
}
void playlist_generic_update(struct playlist *playlist, struct track *track)
{
if (playlist && callbacks)
callbacks->pl_cb_updated(playlist, track);
}
void playlist_generic_set_random(struct playlist *playlist, bool enabled)
{
playlist->pl_random = enabled;
}
void playlist_generic_sort(struct playlist *playlist, enum compare_t field)
{
gpointer sort = GINT_TO_POINTER(field);
GSList *found = g_slist_find_custom(playlist->pl_sort, sort,
__playlist_generic_find_sort);
if (found)
found->data = GINT_TO_POINTER(-field);
else
playlist->pl_sort = g_slist_append(playlist->pl_sort, sort);
playlist_generic_resort(playlist);
}
void playlist_generic_resort(struct playlist *playlist)
{
if (!playlist || !playlist->pl_sort)
return;
g_queue_sort(&playlist->pl_tracks, __playlist_generic_less_than, playlist);
playlist_generic_update(playlist, NULL);
}
bool playlist_generic_rearrange(struct playlist *playlist, unsigned int old_pos,
unsigned int new_pos)
{
GList *nth;
if (old_pos == new_pos || old_pos >= playlist_size(playlist) ||
new_pos > playlist_size(playlist))
return false;
playlist_clear_sort(playlist);
nth = g_queue_pop_nth_link(&playlist->pl_tracks, old_pos);
g_queue_push_nth_link(&playlist->pl_tracks, new_pos, nth);
playlist_generic_update(playlist, NULL);
return true;
}
struct track *playlist_generic_next(struct playlist *playlist)
{
unsigned int pos, size = playlist_size(playlist);
if (size == 0)
return NULL;
else if (playlist->pl_random) {
pos = playlist_current_index(playlist);
pos += g_random_int_range(1, size);
playlist_current_set(playlist, pos % size);
} else if (!playlist_current_next(playlist))
playlist_current_set(playlist, 0);
return playlist_current_track(playlist);
}

277
core/playlists/library.c Normal file
View File

@ -0,0 +1,277 @@
/*
* Copyright 2016 (c) Anna Schumaker.
*/
#include <core/idle.h>
#include <core/playlists/artist.h>
#include <core/playlists/library.h>
#include <core/playlists/system.h>
#include <core/playlists/user.h>
#include <unistd.h>
struct scan_data {
struct library *sd_library;
gchar *sd_path;
};
static bool __lib_pl_scan_dir(void *);
static struct file lib_file = FILE_INIT_DATA("", "playlist.library", 0);
static struct playlist_ops pl_library_ops;
static struct playlist *__lib_pl_alloc(struct library *library)
{
return playlist_generic_alloc(library->li_path, PL_LIBRARY,
library_index(library), &pl_library_ops,
4, COMPARE_ARTIST, COMPARE_YEAR,
COMPARE_ALBUM, COMPARE_TRACK);
}
static bool __lib_pl_add(void *data)
{
struct playlist *playlist = (struct playlist *)data;
struct library *library = library_lookup(playlist->pl_name);
struct db_entry *dbe, *next;
db_for_each(dbe, next, track_db_get()) {
if (TRACK(dbe)->tr_library == library)
playlist_generic_add_front(playlist, TRACK(dbe));
}
playlist_generic_resort(playlist);
return true;
}
static struct playlist *__lib_pl_lookup(const gchar *name)
{
struct library *library = library_lookup(name);
return library ? library->li_playlist : NULL;
}
static bool __lib_pl_load(void *data)
{
struct playlist *playlist;
unsigned int i, n;
gchar *name;
if (!file_open(&lib_file, OPEN_READ))
return true;
n = file_readu(&lib_file);
for (i = 0; i < n; i++) {
name = file_readl(&lib_file);
playlist = __lib_pl_lookup(name);
if (playlist)
playlist_generic_load(playlist, &lib_file,
PL_SAVE_METADATA);
g_free(name);
}
file_close(&lib_file);
return true;
}
static void __lib_pl_scan_dir_idle(struct library *library, const gchar *path)
{
struct scan_data *scan = g_malloc(sizeof(struct scan_data));
scan->sd_library = library;
scan->sd_path = g_strdup(path);
/* scan data is freed by __lib_pl_scan_dir() */
idle_schedule(IDLE_SYNC, __lib_pl_scan_dir, scan);
}
static void __lib_pl_read_path(struct scan_data *scan, const gchar *name)
{
gchar *path = g_build_filename(scan->sd_path, name, NULL);
struct playlist *playlist = scan->sd_library->li_playlist;
struct track *track;
if (g_file_test(path, G_FILE_TEST_IS_DIR))
__lib_pl_scan_dir_idle(scan->sd_library, path);
else {
track = track_add(scan->sd_library, path);
if (track) {
playlist_generic_add(playlist, track);
pl_system_new_track(track);
pl_artist_new_track(track);
}
}
g_free(path);
}
static bool __lib_pl_scan_dir(void *data)
{
struct scan_data *scan = (struct scan_data *)data;
const gchar *name;
GDir *dir;
dir = g_dir_open(scan->sd_path, 0, NULL);
if (!dir)
goto out;
name = g_dir_read_name(dir);
while (name != NULL) {
__lib_pl_read_path(scan, name);
name = g_dir_read_name(dir);
}
g_dir_close(dir);
track_db_commit();
out:
/* Allocated by __lib_pl_scan_dir_idle() */
g_free(scan->sd_path);
g_free(scan);
return true;
}
static bool __lib_pl_update(void *data)
{
struct playlist *playlist = (struct playlist *)data;
struct library *library = library_lookup(playlist->pl_name);
struct db_entry *dbe, *next;
gchar *path;
db_for_each(dbe, next, track_db_get()) {
if (TRACK(dbe)->tr_library != library)
continue;
path = track_path(TRACK(dbe));
if (g_access(path, F_OK) < 0) {
pl_system_delete_track(TRACK(dbe));
pl_artist_delete_track(TRACK(dbe));
playlist_generic_remove(playlist, TRACK(dbe));
track_remove(TRACK(dbe));
}
g_free(path);
}
track_db_commit();
__lib_pl_scan_dir_idle(library, library->li_path);
return true;
}
static bool pl_library_delete(struct playlist *playlist)
{
struct library *library = library_lookup(playlist->pl_name);
playlist_iter it;
if (!library)
return false;
playlist_for_each(playlist, it) {
pl_system_delete_track(playlist_iter_track(it));
pl_artist_delete_track(playlist_iter_track(it));
pl_user_delete_track(playlist_iter_track(it));
}
playlist_generic_free(playlist);
track_remove_all(library);
library_remove(library);
return true;
}
static struct playlist_ops pl_library_ops = {
.pl_can_select = playlist_generic_can_select,
.pl_delete = pl_library_delete,
.pl_set_random = playlist_generic_set_random,
.pl_sort = playlist_generic_sort,
.pl_rearrange = playlist_generic_rearrange,
};
static void pl_library_save(void)
{
struct db_entry *dbe, *next;
struct playlist *playlist;
if (!file_open(&lib_file, OPEN_WRITE))
return;
file_writef(&lib_file, "%u\n", library_db_get()->db_size);
db_for_each(dbe, next, library_db_get()) {
playlist = LIBRARY(dbe)->li_playlist;
file_writef(&lib_file, "%s\n", playlist->pl_name);
playlist_generic_save(playlist, &lib_file, PL_SAVE_METADATA);
}
file_close(&lib_file);
}
static struct playlist *pl_library_lookup(const gchar *name)
{
return __lib_pl_lookup(name);
}
static struct playlist *pl_library_get(unsigned int id)
{
struct library *library = LIBRARY(db_at(library_db_get(), id));
return library ? library->li_playlist : NULL;
}
static struct playlist *pl_library_new(const gchar *name)
{
struct library *library;
if (__lib_pl_lookup(name) || !g_file_test(name, G_FILE_TEST_IS_DIR))
return NULL;
library = library_find(name);
library->li_playlist = __lib_pl_alloc(library);
__lib_pl_scan_dir_idle(library, name);
return library->li_playlist;
}
static void pl_library_played(struct track *track)
{
struct library *library = track->tr_library;
playlist_generic_update(library->li_playlist, track);
}
struct playlist_type pl_library = {
.pl_save = pl_library_save,
.pl_lookup = pl_library_lookup,
.pl_get = pl_library_get,
.pl_new = pl_library_new,
.pl_played = pl_library_played,
.pl_selected = pl_library_played,
};
void pl_library_init(void)
{
struct db_entry *dbe, *next;
struct playlist *playlist;
db_for_each(dbe, next, library_db_get()) {
playlist = __lib_pl_alloc(LIBRARY(dbe));
LIBRARY(dbe)->li_playlist = playlist;
idle_schedule(IDLE_SYNC, __lib_pl_add, playlist);
idle_schedule(IDLE_SYNC, __lib_pl_update, playlist);
}
idle_schedule(IDLE_SYNC, __lib_pl_load, NULL);
}
void pl_library_deinit()
{
struct db_entry *dbe, *next;
db_for_each(dbe, next, library_db_get()) {
playlist_generic_free(LIBRARY(dbe)->li_playlist);
LIBRARY(dbe)->li_playlist = NULL;
}
}
void pl_library_update(struct playlist *playlist)
{
idle_schedule(IDLE_SYNC, __lib_pl_update, playlist);
}

454
core/playlists/system.c Normal file
View File

@ -0,0 +1,454 @@
/*
* Copyright 2016 (c) Anna Schumaker.
*/
#include <core/idle.h>
#include <core/playlists/system.h>
#include <core/string.h>
static struct playlist *pl_system_lookup(const gchar *);
static struct playlist *pl_system_get(unsigned int);
static void pl_system_save();
static struct file sys_file = FILE_INIT_DATA("", "playlist.db", 0);
static struct file sys_deck_f = FILE_INIT_DATA("", "deck", 1);
static struct file sys_collection_f = FILE_INIT_DATA("", "library.q", 0);
static struct file sys_pl_file = FILE_INIT_DATA("", "playlist.system", 0);
/*
* Generic system playlist operations.
*/
static bool sys_pl_delete_clear(struct playlist *playlist)
{
playlist_generic_clear(playlist);
pl_system_save();
return false;
}
static bool sys_pl_update_check(struct playlist *playlist, struct track *track)
{
switch (playlist->pl_id) {
case SYS_PL_UNPLAYED:
return track->tr_count == 0;
case SYS_PL_LEAST_PLAYED:
return track->tr_count <= track_db_average_plays() &&
track->tr_count > 0;
case SYS_PL_MOST_PLAYED:
return track->tr_count > track_db_average_plays();
}
return true;
}
static bool sys_pl_update_func(void *data)
{
struct playlist *playlist = (struct playlist *)data;
struct db_entry *dbe, *next;
db_for_each(dbe, next, track_db_get()) {
struct track *track = TRACK(dbe);
if (!sys_pl_update_check(playlist, track))
playlist_generic_remove(playlist, track);
else if (!playlist_has(pl_system_get(SYS_PL_HIDDEN), track) &&
!playlist_has(playlist, track))
playlist_generic_add_front(playlist, track);
}
playlist_generic_resort(playlist);
return true;
}
static void sys_pl_update(struct playlist *playlist)
{
switch (playlist->pl_id) {
case SYS_PL_COLLECTION:
case SYS_PL_UNPLAYED:
case SYS_PL_LEAST_PLAYED:
case SYS_PL_MOST_PLAYED:
idle_schedule(IDLE_SYNC, sys_pl_update_func, playlist);
default:
break;
}
}
/*
* Favorite tracks playlist operations.
*/
static struct playlist_ops favorites_ops = {
.pl_add = playlist_generic_add,
.pl_can_select = playlist_generic_can_select,
.pl_delete = sys_pl_delete_clear,
.pl_remove = playlist_generic_remove,
.pl_set_random = playlist_generic_set_random,
.pl_sort = playlist_generic_sort,
.pl_rearrange = playlist_generic_rearrange,
};
/*
* Hidden tracks playlist operations.
*/
static bool sys_pl_hidden_add(struct playlist *playlist, struct track *track)
{
bool ret = playlist_generic_add(pl_system_get(SYS_PL_HIDDEN), track);
playlist_generic_remove(pl_system_get(SYS_PL_COLLECTION), track);
playlist_generic_remove(pl_system_get(SYS_PL_UNPLAYED), track);
playlist_generic_remove(pl_system_get(SYS_PL_MOST_PLAYED), track);
playlist_generic_remove(pl_system_get(SYS_PL_LEAST_PLAYED), track);
return ret;
}
static bool sys_pl_hidden_remove(struct playlist *playlist, struct track *track)
{
bool ret = playlist_generic_remove(playlist, track);
unsigned int average = track_db_average_plays();
unsigned int add_id = SYS_PL_LEAST_PLAYED;
add_id = (track->tr_count == 0) ? SYS_PL_UNPLAYED : add_id;
add_id = (track->tr_count > average) ? SYS_PL_MOST_PLAYED : add_id;
playlist_generic_add(pl_system_get(SYS_PL_COLLECTION), track);
playlist_generic_add(pl_system_get(add_id), track);
return ret;
}
static bool sys_pl_hidden_clear(struct playlist *playlist)
{
struct track *track;
while (playlist_size(playlist) > 0) {
track = playlist_at(playlist, 0);
sys_pl_hidden_remove(playlist, track);
}
pl_system_save();
return false;
}
static struct playlist_ops hidden_ops = {
.pl_add = sys_pl_hidden_add,
.pl_can_select = playlist_generic_can_select,
.pl_delete = sys_pl_hidden_clear,
.pl_remove = sys_pl_hidden_remove,
.pl_set_random = playlist_generic_set_random,
.pl_sort = playlist_generic_sort,
.pl_rearrange = playlist_generic_rearrange,
};
/*
* Queued tracks playlist operations.
*/
static bool sys_pl_queued_load()
{
struct playlist *playlist = pl_system_get(SYS_PL_QUEUED);
unsigned int num, i, flags = 0;
if (!file_open(&sys_deck_f, OPEN_READ))
return true;
num = file_readu(&sys_deck_f);
for (i = 0; i < num; i++) {
flags = file_readu(&sys_deck_f);
flags &= PL_RANDOM;
if (i == 0)
playlist_generic_set_random(playlist,
flags == PL_RANDOM);
playlist_generic_load(playlist, &sys_deck_f, PL_SAVE_TRACKS);
}
file_close(&sys_deck_f);
file_remove(&sys_deck_f);
return true;
}
static bool sys_pl_queued_delete(struct playlist *playlist)
{
playlist_generic_set_random(playlist, false);
playlist_clear_sort(playlist);
return sys_pl_delete_clear(playlist);
}
static bool sys_pl_queued_remove(struct playlist *playlist, struct track *track)
{
bool ret = playlist_generic_remove(playlist, track);
if (playlist_size(playlist) == 0)
sys_pl_queued_delete(playlist);
return ret;
}
static struct playlist_ops queued_ops = {
.pl_add = playlist_generic_add,
.pl_can_select = playlist_generic_can_select,
.pl_delete = sys_pl_queued_delete,
.pl_remove = sys_pl_queued_remove,
.pl_set_random = playlist_generic_set_random,
.pl_sort = playlist_generic_sort,
.pl_rearrange = playlist_generic_rearrange,
};
/*
* Collection playlist operations.
*/
static bool sys_pl_collection_load()
{
struct playlist *playlist = pl_system_get(SYS_PL_COLLECTION);
if (file_open(&sys_collection_f, OPEN_READ)) {
playlist_generic_load(playlist, &sys_collection_f, PL_SAVE_FLAGS);
file_close(&sys_collection_f);
file_remove(&sys_collection_f);
}
return true;
}
static struct playlist_ops collection_ops = {
.pl_can_select = playlist_generic_can_select,
.pl_remove = sys_pl_hidden_add,
.pl_set_random = playlist_generic_set_random,
.pl_sort = playlist_generic_sort,
.pl_rearrange = playlist_generic_rearrange,
};
/*
* History playlist operations.
*/
static bool sys_pl_history_add(struct playlist *playlist, struct track *track)
{
playlist_generic_add_front(playlist, track);
playlist_current_set(playlist, 0);
return true;
}
static struct playlist_ops history_ops = {
.pl_add = sys_pl_history_add,
};
/*
* Unplayed, Most Played, and Least Played tracks playlist operations.
*/
static struct playlist_ops dynamic_ops = {
.pl_can_select = playlist_generic_can_select,
.pl_set_random = playlist_generic_set_random,
.pl_sort = playlist_generic_sort,
.pl_rearrange = playlist_generic_rearrange,
};
#define SYS_PLAYLIST(id, name, ops) \
[id] = DEFINE_PLAYLIST(PL_SYSTEM, name, id, ops)
static struct playlist sys_playlists[SYS_PL_NUM_PLAYLISTS] = {
SYS_PLAYLIST(SYS_PL_FAVORITES, "Favorites", &favorites_ops),
SYS_PLAYLIST(SYS_PL_HIDDEN, "Hidden", &hidden_ops),
SYS_PLAYLIST(SYS_PL_QUEUED, "Queued Tracks", &queued_ops),
SYS_PLAYLIST(SYS_PL_COLLECTION, "Collection", &collection_ops),
SYS_PLAYLIST(SYS_PL_HISTORY, "History", &history_ops),
SYS_PLAYLIST(SYS_PL_UNPLAYED, "Unplayed", &dynamic_ops),
SYS_PLAYLIST(SYS_PL_MOST_PLAYED, "Most Played", &dynamic_ops),
SYS_PLAYLIST(SYS_PL_LEAST_PLAYED, "Least Played", &dynamic_ops),
};
static bool __sys_pl_update_save()
{
pl_system_save();
return true;
}
static bool __sys_pl_load()
{
struct playlist *playlist;
unsigned int i, n;
gchar *name;
if (!file_open(&sys_file, OPEN_READ))
return true;
n = file_readu(&sys_file);
for (i = 0; i < n; i++) {
file_readu(&sys_file);
name = file_readl(&sys_file);
if (string_match(name, "Banned")) {
g_free(name);
name = g_strdup("Hidden");
}
playlist = pl_system_lookup(name);
g_free(name);
if (playlist)
playlist_generic_load(playlist, &sys_file, PL_SAVE_TRACKS);
}
file_close(&sys_file);
file_remove(&sys_file);
return true;
}
static bool __sys_pl_load_new()
{
struct playlist *playlist;
unsigned int i, n, load;
gchar *name;
if (!file_open(&sys_pl_file, OPEN_READ)) {
__sys_pl_load();
sys_pl_collection_load();
sys_pl_queued_load();
__sys_pl_update_save();
return true;
}
n = file_readu(&sys_pl_file);
for (i = 0; i < n; i++) {
load = PL_SAVE_METADATA;
name = file_readl(&sys_pl_file);
if (string_match(name, "Banned")) {
g_free(name);
name = g_strdup("Hidden");
}
playlist = pl_system_lookup(name);
g_free(name);
switch (i) {
case SYS_PL_FAVORITES:
case SYS_PL_HIDDEN:
case SYS_PL_QUEUED:
load = PL_SAVE_ALL;
}
playlist_generic_load(playlist, &sys_pl_file, load);
}
file_close(&sys_pl_file);
return true;
}
static void pl_system_save(void)
{
struct playlist *playlist;
unsigned int i, save;
if (!file_open(&sys_pl_file, OPEN_WRITE))
return;
file_writef(&sys_pl_file, "%u\n", SYS_PL_NUM_PLAYLISTS);
for (i = 0; i < SYS_PL_NUM_PLAYLISTS; i++) {
save = PL_SAVE_METADATA;
playlist = pl_system_get(i);
switch (i) {
case SYS_PL_FAVORITES:
case SYS_PL_HIDDEN:
case SYS_PL_QUEUED:
save = PL_SAVE_ALL;
}
file_writef(&sys_pl_file, "%s\n", playlist->pl_name);
playlist_generic_save(playlist, &sys_pl_file, save);
}
file_close(&sys_pl_file);
}
static struct playlist *pl_system_lookup(const gchar *name)
{
unsigned int i;
for (i = 0; i < SYS_PL_NUM_PLAYLISTS; i++) {
if (string_match(name, pl_system_get(i)->pl_name))
return pl_system_get(i);
}
return NULL;
}
static struct playlist *pl_system_get(unsigned int id)
{
return (id < SYS_PL_NUM_PLAYLISTS) ? &sys_playlists[id] : NULL;
}
static void pl_system_played(struct track *track)
{
unsigned int i;
for (i = 0; i < SYS_PL_NUM_PLAYLISTS; i++)
playlist_generic_update(pl_system_get(i), track);
sys_pl_update(pl_system_lookup("Unplayed"));
sys_pl_update(pl_system_lookup("Most Played"));
sys_pl_update(pl_system_lookup("Least Played"));
}
static void pl_system_selected(struct track *track)
{
unsigned int i;
sys_pl_queued_remove(pl_system_get(SYS_PL_QUEUED), track);
for (i = 0; i < SYS_PL_NUM_PLAYLISTS; i++)
playlist_generic_update(pl_system_get(i), track);
}
struct playlist_type pl_system = {
.pl_save = pl_system_save,
.pl_lookup = pl_system_lookup,
.pl_get = pl_system_get,
.pl_played = pl_system_played,
.pl_selected = pl_system_selected,
};
void pl_system_init(void)
{
struct playlist *playlist;
unsigned int i;
idle_schedule(IDLE_SYNC, __sys_pl_load_new, NULL);
for (i = 0; i < SYS_PL_NUM_PLAYLISTS; i++) {
playlist = pl_system_get(i);
switch (i) {
case SYS_PL_QUEUED:
case SYS_PL_HISTORY:
playlist_generic_init(playlist, 0);
break;
case SYS_PL_COLLECTION:
case SYS_PL_UNPLAYED:
case SYS_PL_MOST_PLAYED:
case SYS_PL_LEAST_PLAYED:
sys_pl_update(playlist);
case SYS_PL_FAVORITES:
case SYS_PL_HIDDEN:
playlist_generic_init(playlist, 4, COMPARE_ARTIST,
COMPARE_YEAR, COMPARE_ALBUM, COMPARE_TRACK);
break;
}
}
}
void pl_system_deinit()
{
for (unsigned int i = 0; i < SYS_PL_NUM_PLAYLISTS; i++)
playlist_generic_deinit(pl_system_get(i));
}
void pl_system_new_track(struct track *track)
{
playlist_generic_add(pl_system_lookup("Collection"), track);
playlist_generic_add(pl_system_lookup("Unplayed"), track);
}
void pl_system_delete_track(struct track *track)
{
for (unsigned int i = 0; i < SYS_PL_NUM_PLAYLISTS; i++)
playlist_generic_remove(pl_system_get(i), track);
}

178
core/playlists/user.c Normal file
View File

@ -0,0 +1,178 @@
/*
* Copyright 2016 (c) Anna Schumaker.
*/
#include <core/playlists/user.h>
static struct database user_db;
static struct playlist_ops user_ops;
static struct user_playlist *__user_db_alloc(gchar *name, unsigned int index)
{
struct user_playlist *playlist = g_malloc(sizeof(struct user_playlist));
dbe_init(&playlist->pl_dbe, playlist);
playlist->pl_playlist.pl_name = name;
playlist->pl_playlist.pl_type = PL_USER;
playlist->pl_playlist.pl_id = index;
playlist->pl_playlist.pl_ops = &user_ops;
playlist_generic_init(&playlist->pl_playlist, 0);
return playlist;
}
static struct db_entry *user_db_alloc(const gchar *name, unsigned int index)
{
return &__user_db_alloc(g_strdup(name), index)->pl_dbe;
}
static void user_db_free(struct db_entry *dbe)
{
playlist_generic_deinit(&USER_PLAYLIST(dbe)->pl_playlist);
g_free(USER_PLAYLIST(dbe)->pl_playlist.pl_name);
g_free(USER_PLAYLIST(dbe));
}
static gchar *user_db_key(struct db_entry *dbe)
{
return g_strdup(USER_PLAYLIST(dbe)->pl_playlist.pl_name);
}
static struct db_entry *user_db_read(struct file *file, unsigned int index)
{
gchar *name = file_readl(file);
struct user_playlist *playlist = __user_db_alloc(name, index);
playlist_generic_load(&playlist->pl_playlist, file, PL_SAVE_ALL);
return &playlist->pl_dbe;
}
static void user_db_write(struct file *file, struct db_entry *dbe)
{
struct playlist *playlist = &USER_PLAYLIST(dbe)->pl_playlist;
file_writef(file, "%s\n", playlist->pl_name);
playlist_generic_save(playlist, file, PL_SAVE_ALL);
}
static const struct db_ops user_db_ops = {
.dbe_alloc = user_db_alloc,
.dbe_free = user_db_free,
.dbe_key = user_db_key,
.dbe_read = user_db_read,
.dbe_write = user_db_write,
};
static bool pl_user_delete(struct playlist *playlist)
{
struct db_entry *dbe = db_get(&user_db, playlist->pl_name);
if (dbe) {
db_remove(&user_db, dbe);
db_defrag(&user_db);
}
return dbe != NULL;
}
static struct playlist_ops user_ops = {
.pl_add = playlist_generic_add,
.pl_can_select = playlist_generic_can_select,
.pl_delete = pl_user_delete,
.pl_remove = playlist_generic_remove,
.pl_set_random = playlist_generic_set_random,
.pl_sort = playlist_generic_sort,
.pl_rearrange = playlist_generic_rearrange,
};
static void pl_user_save(void)
{
db_save(&user_db);
}
static struct playlist *pl_user_lookup(const gchar *name)
{
struct db_entry *dbe = db_get(&user_db, name);
return dbe ? &USER_PLAYLIST(dbe)->pl_playlist : NULL;
}
static struct playlist *pl_user_get(unsigned int id)
{
struct db_entry *dbe = db_at(&user_db, id);
return dbe ? &USER_PLAYLIST(dbe)->pl_playlist : NULL;
}
static struct playlist *pl_user_new(const gchar *name)
{
struct db_entry *dbe;
if (db_get(&user_db, name))
return NULL;
dbe = db_insert(&user_db, name);
return dbe ? &USER_PLAYLIST(dbe)->pl_playlist : NULL;
}
static void pl_user_played(struct track *track)
{
struct db_entry *dbe, *next;
db_for_each(dbe, next, &user_db)
playlist_generic_update(&USER_PLAYLIST(dbe)->pl_playlist, track);
}
struct playlist_type pl_user = {
.pl_save = pl_user_save,
.pl_lookup = pl_user_lookup,
.pl_get = pl_user_get,
.pl_new = pl_user_new,
.pl_played = pl_user_played,
.pl_selected = pl_user_played,
};
void pl_user_init(void)
{
db_init(&user_db, "playlist.user", true, &user_db_ops, 0);
db_load(&user_db);
}
void pl_user_deinit()
{
db_deinit(&user_db);
}
struct database *pl_user_db_get()
{
return &user_db;
}
void pl_user_delete_track(struct track *track)
{
struct db_entry *dbe, *next;
struct playlist *playlist;
db_for_each(dbe, next, &user_db) {
playlist = &USER_PLAYLIST(dbe)->pl_playlist;
playlist_generic_remove(playlist, track);
}
}
bool pl_user_rename(struct playlist *playlist, const gchar *name)
{
struct db_entry *dbe;
if (!playlist || db_get(&user_db, name))
return false;
dbe = db_get(&user_db, playlist->pl_name);
if (!dbe)
return false;
g_free(playlist->pl_name);
playlist->pl_name = g_strdup(name);
db_rekey(&user_db, dbe);
pl_user_save();
return true;
}

86
core/settings.c Normal file
View File

@ -0,0 +1,86 @@
/*
* Copyright 2015 (c) Anna Schumaker.
*/
#include <core/file.h>
#include <core/settings.h>
static GHashTable *gui_settings = NULL;
static struct file gui_settings_file = FILE_INIT_DATA("", "settings", 0);
static void __settings_save_item(gpointer key, gpointer value, gpointer data)
{
file_writef(&gui_settings_file, "%s %u\n", (const gchar *)key,
GPOINTER_TO_UINT(value));
}
static void __settings_save()
{
file_open(&gui_settings_file, OPEN_WRITE);
file_writef(&gui_settings_file, "%u\n", g_hash_table_size(gui_settings));
g_hash_table_foreach(gui_settings, __settings_save_item, NULL);
file_close(&gui_settings_file);
}
static void __settings_read()
{
unsigned int num, i, value;
gchar *key;
num = file_readu(&gui_settings_file);
for (i = 0; i < num; i++) {
key = file_readw(&gui_settings_file);
value = file_readu(&gui_settings_file);
g_hash_table_insert(gui_settings, key, GUINT_TO_POINTER(value));
}
}
void settings_init()
{
gui_settings = g_hash_table_new_full(g_str_hash, g_str_equal,
g_free, NULL);
if (file_open(&gui_settings_file, OPEN_READ))
__settings_read();
file_close(&gui_settings_file);
}
void settings_deinit()
{
g_hash_table_destroy(gui_settings);
gui_settings = NULL;
}
void settings_set(const gchar *key, unsigned int value)
{
if (gui_settings && key) {
g_hash_table_replace(gui_settings, g_strdup(key),
GUINT_TO_POINTER(value));
__settings_save();
}
}
unsigned int settings_get(const gchar *key)
{
if (gui_settings && key)
return GPOINTER_TO_UINT(g_hash_table_lookup(gui_settings, key));
return 0;
}
bool settings_has(const gchar *key)
{
if (gui_settings && key)
return g_hash_table_contains(gui_settings, key);
return false;
}
#ifdef CONFIG_TESTING
GHashTable *test_get_settings()
{
return gui_settings;
}
#endif /* CONFIG_TESTING */

105
core/string.c Normal file
View File

@ -0,0 +1,105 @@
/*
* Copyright 2015 (c) Anna Schumaker.
*/
#include <core/string.h>
#define O_SECONDS (1)
#define O_MINUTES (60)
#define O_HOURS (60 * O_MINUTES)
#define O_DAYS (24 * O_HOURS)
static unsigned int factor[4] = { O_DAYS, O_HOURS, O_MINUTES, O_SECONDS };
static const char *field[4] = { "day", "hour", "minute", "second" };
gchar *string_sec2str(unsigned int sec)
{
return g_strdup_printf("%u:%02u", sec / 60, sec % 60);
}
gchar *string_sec2str_long(unsigned int sec)
{
gchar *tmp;
unsigned int val;
gchar *res = g_strdup("");
for (unsigned int i = 0; i < 4; i++) {
val = sec / factor[i];
sec %= factor[i];
if (val == 0)
continue;
tmp = g_strdup_printf("%s%u %s%s%s", res, val, field[i],
(val > 1) ? "s" : "",
(sec > 0) ? ", " : "");
g_free(res);
res = tmp;
}
return res;
}
gchar *string_tm2str(struct tm *tm)
{
gchar *buf = g_malloc(20 * sizeof(gchar));
strftime(buf, 20, "%Ex", tm);
return buf;
}
int string_compare_tokens(gchar **lhs, gchar **rhs)
{
unsigned int i, cmp;
if (!lhs[0] && rhs[0])
return 1;
if (lhs[0] && !rhs[0])
return -1;
for (i = 0; lhs[i]; i++) {
if (!rhs[i])
break;
cmp = g_utf8_collate(lhs[i], rhs[i]);
if (cmp != 0)
return cmp;
}
if (lhs[i])
return 1;
if (rhs[i])
return -1;
return 0;
}
bool string_match_token(const gchar *prefix, gchar **tokens)
{
unsigned int i;
for (i = 0; tokens[i]; i++) {
if (g_str_has_prefix(tokens[i], prefix))
return true;
}
return false;
}
bool string_is_subdir(const gchar *a, const gchar *b)
{
gchar **parent = b ? g_strsplit(b, "/", -1) : NULL;
gchar **child = a ? g_strsplit(a, "/", -1) : NULL;
bool subdir = true;
int i;
if (!parent || !child)
return false;
for (i = 0; parent[i]; i++) {
if (!child[i] || g_utf8_collate(parent[i], child[i]) != 0) {
subdir = false;
break;
}
}
g_strfreev(parent);
g_strfreev(child);
return subdir;
}

406
core/tags/album.c Normal file
View File

@ -0,0 +1,406 @@
/*
* Copyright 2014 (c) Anna Schumaker.
*/
#include <core/idle.h>
#include <core/string.h>
#include <core/version.h>
#include <core/tags/album.h>
#include <core/tags/genre.h>
#include <coverart/caa_c.h>
#include <musicbrainz5/mb5_c.h>
#ifdef CONFIG_TESTING
#define OCARINA_AGENT "ocarina-test"
#else
#define OCARINA_AGENT OCARINA_NAME
#endif
#define ALBUM_DB_MIN 0 /* Ocarina 6.0 */
static struct database album_db;
static bool album_db_upgraded = false;
struct album_cache_file {
struct file ac_file;
gchar *ac_subdir;
gchar *ac_name;
};
struct album_cache_file *__album_alloc_file(struct album *al)
{
struct album_cache_file *ret = g_malloc(sizeof(struct album_cache_file));
gchar *name = g_uri_escape_string(al->al_name, " ", true);
ret->ac_subdir = g_strdup_printf("%d", al->al_year);
ret->ac_name = g_strdup_printf("%s.jpg", name);
file_init_cache(&ret->ac_file, ret->ac_subdir, ret->ac_name);
g_free(name);
return ret;
}
static inline void __album_free_file(struct album_cache_file *acf)
{
g_free(acf->ac_subdir);
g_free(acf->ac_name);
g_free(acf);
}
static bool __album_fetch_cover(struct album *album, gchar *releaseid)
{
struct album_cache_file *file;
CaaImageData image;
CaaCoverArt *caa;
gchar error[256];
caa = caa_coverart_new(OCARINA_AGENT);
if (!caa)
return false;
image = caa_coverart_fetch_front(caa, releaseid);
if (!image) {
caa_coverart_get_lasterrormessage(caa, error, sizeof(error));
g_printf("Cover Art Archive: %s\n", error);
goto out;
}
file = __album_alloc_file(album);
if (file_open(&file->ac_file, OPEN_WRITE_BINARY)) {
file_write(&file->ac_file, caa_imagedata_data(image),
caa_imagedata_size(image));
file_close(&file->ac_file);
}
__album_free_file(file);
caa_imagedata_delete(image);
out:
caa_coverart_delete(caa);
return album_artwork_exists(album);
}
static bool __album_foreach_fetch(struct album *album, Mb5Metadata metadata)
{
Mb5ReleaseList list = mb5_metadata_get_releaselist(metadata);
gchar releaseid[40];
Mb5Release release;
unsigned int i;
for (i = 0; i < mb5_release_list_size(list); i++) {
release = mb5_release_list_item(list, i);
if (!release)
break;
mb5_release_get_id(release, releaseid, sizeof(releaseid));
if (__album_fetch_cover(album, releaseid))
return true;
}
return false;
}
static bool __album_run_query(struct album *album, gchar *term1,
gchar *term2, gchar *term3)
{
gchar *param, *query = "query";
Mb5Metadata data = NULL;
unsigned int code;
gchar error[256];
bool ret = false;
Mb5Query *mb5;
param = g_strjoin(" AND ", term1, term2, term3, NULL);
do {
mb5 = mb5_query_new(OCARINA_AGENT, NULL, 0);
if (!mb5)
break;
data = mb5_query_query(mb5, "release", "", "", 1, &query, &param);
code = mb5_query_get_lasthttpcode(mb5);
if (mb5_query_get_lastresult(mb5) != 0) {
mb5_query_get_lasterrormessage(mb5, error, sizeof(error));
g_printf("MusicBrainz: %s\n", error);
}
mb5_query_delete(mb5);
} while (code == 503);
if (data) {
ret = __album_foreach_fetch(album, data);
mb5_metadata_delete(data);
}
g_free(param);
return ret;
}
static bool __album_query_artist(struct album *album, struct artist *al_artist,
gchar *lower)
{
gchar *release, *artist, *year;
bool found = false;
if (!al_artist || !string_length(al_artist->ar_name) ||
strcmp(al_artist->ar_tokens[0], "various") == 0)
return false;
release = g_strdup_printf("release:\"%s\"~", lower);
artist = g_strdup_printf("artist:\"%s\"~", al_artist->ar_name);
year = g_strdup_printf("date:%d*", album->al_year);
if (album->al_year > 0)
found = __album_run_query(album, release, artist, year);
if (!found)
found = __album_run_query(album, release, artist, NULL);
if (!found && album->al_year > 0)
found = __album_run_query(album, lower, artist, year);
if (!found)
found = __album_run_query(album, lower, artist, NULL);
g_free(release);
g_free(artist);
g_free(year);
return found;
}
static bool __album_fetch_artwork(struct album *album)
{
gchar *lower;
if (album_artwork_exists(album))
return true;
if (string_length(album->al_name) == 0)
return true;
lower = g_strjoinv(" ", album->al_tokens);
if (!__album_query_artist(album, album->al_artist, lower))
__album_run_query(album, lower, NULL, NULL);
g_free(lower);
return true;
}
static gchar *__album_key(struct artist *artist, struct genre *genre,
const gchar *name, unsigned int year)
{
if (!artist || !genre)
return g_strdup_printf("%u/%s", year, name);
return g_strdup_printf("%u/%u/%u/%s", artist_index(artist),
genre_index(genre), year, name);
}
static struct album *__album_alloc(struct artist *artist, struct genre *genre,
gchar *name, unsigned int year)
{
struct album *album = g_malloc(sizeof(struct album));
dbe_init(&album->al_dbe, album);
album->al_year = year;
album->al_name = name;
album->al_tokens = g_str_tokenize_and_fold(name, NULL, &album->al_alts);
album->al_artist = artist;
album->al_genre = genre;
if (!album_artwork_exists(album) && artist && genre)
idle_schedule(IDLE_ASYNC, IDLE_FUNC(__album_fetch_artwork), album);
return album;
}
static struct db_entry *__album_alloc_v0(const gchar *key)
{
unsigned int year;
gchar *name;
if (sscanf(key, "%u/%m[^\n]", &year, &name) == 1)
name = g_strdup("");
return &__album_alloc(NULL, NULL, name, year)->al_dbe;
}
static struct db_entry *album_alloc(const gchar *key, unsigned int index)
{
unsigned int artist_id, genre_id, year, n;
gchar *name;
n = sscanf(key, "%u/%u/%u/%m[^\n]", &artist_id, &genre_id, &year, &name);
if (n == 1)
return __album_alloc_v0(key);
else if (n == 3)
name = g_strdup("");
return &__album_alloc(artist_get(artist_id), genre_get(genre_id),
name, year)->al_dbe;
}
static void album_free(struct db_entry *dbe)
{
g_free(ALBUM(dbe)->al_name);
g_strfreev(ALBUM(dbe)->al_tokens);
g_strfreev(ALBUM(dbe)->al_alts);
g_free(ALBUM(dbe));
}
static gchar *album_key(struct db_entry *dbe)
{
return __album_key(ALBUM(dbe)->al_artist, ALBUM(dbe)->al_genre,
ALBUM(dbe)->al_name, ALBUM(dbe)->al_year);
}
static struct album *__album_parse_v0(gchar *line)
{
unsigned int year;
gchar *name;
if (sscanf(line, "%u %m[^\n]", &year, &name) == 1)
name = g_strdup("");
return __album_alloc(NULL, NULL, name, year);
}
static struct db_entry *album_read(struct file *file, unsigned int index)
{
unsigned int year, artist_id, genre_id, n;
struct album *album;
gchar *line, *name;
line = file_readl(file);
if (file_version(file) == 0) {
album = __album_parse_v0(line);
album_db_upgraded = true;
goto out;
}
n = sscanf(line, "%u %u %u %m[^\n]", &artist_id, &genre_id, &year, &name);
if (n == 3)
name = g_strdup("");
album = __album_alloc(artist_get(artist_id),
genre_get(genre_id), name, year);
out:
g_free(line);
return &album->al_dbe;
}
static void album_write(struct file *file, struct db_entry *dbe)
{
struct album *album = ALBUM(dbe);
struct artist *artist = album->al_artist;
struct genre *genre = album->al_genre;
file_writef(file, "%u %u %u %s", artist ? artist_index(artist) : 0,
genre ? genre_index(genre) : 0,
album->al_year, album->al_name);
}
static const struct db_ops album_ops = {
.dbe_alloc = album_alloc,
.dbe_free = album_free,
.dbe_key = album_key,
.dbe_read = album_read,
.dbe_write = album_write,
};
void album_db_init()
{
db_init(&album_db, "album.db", true, &album_ops, ALBUM_DB_MIN);
db_load(&album_db);
}
void album_db_deinit()
{
db_deinit(&album_db);
}
bool album_db_defrag()
{
return db_defrag(&album_db);
}
bool album_db_upgrade_done()
{
struct db_entry *dbe, *next;
if (album_db_upgraded == false)
return false;
db_for_each(dbe, next, &album_db) {
if (!ALBUM(dbe)->al_artist && !ALBUM(dbe)->al_genre)
db_remove(&album_db, dbe);
}
return true;
}
struct album *album_find(struct artist *artist, struct genre *genre,
const gchar *name, unsigned int year)
{
gchar *key = __album_key(artist, genre, name, year);
struct album *album = ALBUM(db_find(&album_db, key));
g_free(key);
return album;
}
struct album *album_get(const unsigned int index)
{
return ALBUM(db_at(&album_db, index));
}
int album_compare(struct album *lhs, struct album *rhs)
{
return string_compare_tokens(lhs->al_tokens, rhs->al_tokens);
}
int album_compare_year(struct album *lhs, struct album *rhs)
{
if (lhs->al_year - rhs->al_year == 0)
return album_compare(lhs, rhs);
return lhs->al_year - rhs->al_year;
}
bool album_match_token(struct album *album, const gchar *string)
{
return string_match_token(string, album->al_tokens) ||
string_match_token(string, album->al_alts);
}
bool album_artwork_exists(struct album *album)
{
struct album_cache_file *file;
bool ret;
file = __album_alloc_file(album);
ret = file_exists(&file->ac_file);
__album_free_file(file);
return ret;
}
gchar *album_artwork_path(struct album *album)
{
struct album_cache_file *file;
gchar *ret = NULL;
file = __album_alloc_file(album);
if (file_exists(&file->ac_file))
ret = file_path(&file->ac_file);
__album_free_file(file);
return ret;
}
bool album_artwork_import(struct album *album, gchar *path)
{
struct album_cache_file *file;
bool ret = false;
file = __album_alloc_file(album);
if (path && file_open(&file->ac_file, OPEN_WRITE_BINARY)) {
ret = file_import(&file->ac_file, path);
file_close(&file->ac_file);
}
__album_free_file(file);
return ret;
}
#ifdef CONFIG_TESTING
const struct db_ops *test_album_ops() { return &album_ops; }
#endif /* CONFIG_TESTING */

103
core/tags/artist.c Normal file
View File

@ -0,0 +1,103 @@
/*
* Copyright 2014 (c) Anna Schumaker.
*/
#include <core/string.h>
#include <core/tags/artist.h>
static struct database artist_db;
static struct artist *__artist_alloc(gchar *name)
{
struct artist *artist = g_malloc(sizeof(struct artist));
dbe_init(&artist->ar_dbe, artist);
artist->ar_name = name;
artist->ar_tokens = g_str_tokenize_and_fold(name, NULL, &artist->ar_alts);
artist->ar_playlist = NULL;
return artist;
}
static struct db_entry *artist_alloc(const gchar *name, unsigned int index)
{
return &__artist_alloc(g_strdup(name))->ar_dbe;
}
static void artist_free(struct db_entry *dbe)
{
g_strfreev(ARTIST(dbe)->ar_tokens);
g_strfreev(ARTIST(dbe)->ar_alts);
g_free(ARTIST(dbe));
}
static gchar *artist_key(struct db_entry *dbe)
{
return ARTIST(dbe)->ar_name;
}
struct db_entry *artist_read(struct file *file, unsigned int index)
{
return &__artist_alloc(file_readl(file))->ar_dbe;
}
static void artist_write(struct file *file, struct db_entry *dbe)
{
file_writef(file, "%s", ARTIST(dbe)->ar_name);
}
static const struct db_ops artist_ops = {
.dbe_alloc = artist_alloc,
.dbe_free = artist_free,
.dbe_key = artist_key,
.dbe_read = artist_read,
.dbe_write = artist_write,
};
void artist_db_init()
{
db_init(&artist_db, "artist.db", true, &artist_ops, 0);
db_load(&artist_db);
}
void artist_db_deinit()
{
db_deinit(&artist_db);
}
const struct database *artist_db_get()
{
return &artist_db;
}
struct artist *artist_find(const gchar *name)
{
return ARTIST(db_find(&artist_db, name));
}
struct artist *artist_lookup(const gchar *name)
{
return ARTIST(db_get(&artist_db, name));
}
struct artist *artist_get(const unsigned int index)
{
return ARTIST(db_at(&artist_db, index));
}
int artist_compare(struct artist *lhs, struct artist *rhs)
{
return string_compare_tokens(lhs->ar_tokens, rhs->ar_tokens);
}
bool artist_match_token(struct artist *artist, const gchar *string)
{
return string_match_token(string, artist->ar_tokens) ||
string_match_token(string, artist->ar_alts);
}
#ifdef CONFIG_TESTING
const struct db_ops *test_artist_ops() { return &artist_ops; }
#endif /* CONFIG_TESTING */

92
core/tags/genre.c Normal file
View File

@ -0,0 +1,92 @@
/*
* Copyright 2014 (c) Anna Schumaker.
*/
#include <core/string.h>
#include <core/tags/genre.h>
static struct database genre_db;
static struct genre *__genre_alloc(gchar *name)
{
struct genre *genre = g_malloc(sizeof(struct genre));
dbe_init(&genre->ge_dbe, genre);
genre->ge_name = name;
genre->ge_tokens = g_str_tokenize_and_fold(name, NULL, &genre->ge_alts);
return genre;
}
static struct db_entry *genre_alloc(const gchar *name, unsigned int index)
{
return &__genre_alloc(g_strdup(name))->ge_dbe;
}
static void genre_free(struct db_entry *dbe)
{
g_strfreev(GENRE(dbe)->ge_tokens);
g_strfreev(GENRE(dbe)->ge_alts);
g_free(GENRE(dbe));
}
static gchar *genre_key(struct db_entry *dbe)
{
return GENRE(dbe)->ge_name;
}
static struct db_entry *genre_read(struct file *file, unsigned int index)
{
return &__genre_alloc(file_readl(file))->ge_dbe;
}
static void genre_write(struct file *file, struct db_entry *dbe)
{
file_writef(file, "%s", GENRE(dbe)->ge_name);
}
static const struct db_ops genre_ops = {
.dbe_alloc = genre_alloc,
.dbe_free = genre_free,
.dbe_key = genre_key,
.dbe_read = genre_read,
.dbe_write = genre_write,
};
void genre_db_init()
{
db_init(&genre_db, "genre.db", true, &genre_ops, 0);
db_load(&genre_db);
}
void genre_db_deinit()
{
db_deinit(&genre_db);
}
struct genre *genre_find(const gchar *name)
{
return GENRE(db_find(&genre_db, name));
}
struct genre *genre_get(const unsigned int index)
{
return GENRE(db_at(&genre_db, index));
}
int genre_compare(struct genre *lhs, struct genre *rhs)
{
return string_compare_tokens(lhs->ge_tokens, rhs->ge_tokens);
}
bool genre_match_token(struct genre *genre, const gchar *string)
{
return string_match_token(string, genre->ge_tokens) ||
string_match_token(string, genre->ge_alts);
}
#ifdef CONFIG_TESTING
const struct db_ops *test_genre_ops() { return &genre_ops; }
#endif /* CONFIG_TESTING */

122
core/tags/library.c Normal file
View File

@ -0,0 +1,122 @@
/*
* Copyright 2014 (c) Anna Schumaker.
*/
#include <core/string.h>
#include <core/tags/library.h>
#define LIBRARY_DB_MIN 0 /* Ocarina 6.0 */
static struct database library_db;
static struct library *__library_alloc(gchar *path)
{
struct library *library = g_malloc(sizeof(struct library));
dbe_init(&library->li_dbe, library);
library->li_path = path;
library->li_playlist = NULL;
return library;
}
static struct db_entry *library_alloc(const gchar *path, unsigned int index)
{
return &__library_alloc(g_strdup(path))->li_dbe;
}
static void library_free(struct db_entry *dbe)
{
g_free(LIBRARY(dbe));
}
static gchar *library_key(struct db_entry *dbe)
{
return LIBRARY(dbe)->li_path;
}
static struct db_entry *library_read(struct file *file, unsigned int index)
{
gchar *path;
/* Old "enabled" flag */
if (file_version(file) == 0)
file_readd(file);
path = file_readl(file);
return &__library_alloc(path)->li_dbe;
}
static void library_write(struct file *file, struct db_entry *dbe)
{
file_writef(file, "%s", LIBRARY(dbe)->li_path);
}
static const struct db_ops library_ops = {
.dbe_alloc = library_alloc,
.dbe_free = library_free,
.dbe_key = library_key,
.dbe_read = library_read,
.dbe_write = library_write,
};
void library_db_init()
{
db_init(&library_db, "library.db", true, &library_ops, LIBRARY_DB_MIN);
db_load(&library_db);
}
void library_db_deinit()
{
db_deinit(&library_db);
}
bool library_db_defrag()
{
return db_defrag(&library_db);
}
const struct database *library_db_get()
{
return &library_db;
}
struct library *library_find(const gchar *path)
{
struct library *library = library_lookup(path);
if (library)
return library;
return LIBRARY(db_insert(&library_db, path));
}
struct library *library_lookup(const gchar *path)
{
struct db_entry *dbe, *next;
db_for_each(dbe, next, &library_db) {
if (string_is_subdir(path, LIBRARY(dbe)->li_path))
return LIBRARY(dbe);
}
return NULL;
}
struct library *library_get(const unsigned int index)
{
return LIBRARY(db_at(&library_db, index));
}
void library_remove(struct library *library)
{
if (library)
db_remove(&library_db, &library->li_dbe);
}
gchar *library_file(struct library *library, const gchar *path)
{
return g_strdup_printf("%s/%s", library->li_path, path);
}
#ifdef CONFIG_TESTING
const struct db_ops *test_library_ops() { return &library_ops; }
#endif /* CONFIG_TESTING */

50
core/tags/tags.c Normal file
View File

@ -0,0 +1,50 @@
/*
* Copyright 2014 (c) Anna Schumaker.
*/
#include <core/idle.h>
#include <core/tags/album.h>
#include <core/tags/artist.h>
#include <core/tags/genre.h>
#include <core/tags/library.h>
#include <core/tags/tags.h>
#include <core/tags/track.h>
static bool tags_upgrade_done(void *data)
{
if (album_db_upgrade_done())
track_db_commit();
return true;
}
void tags_init()
{
artist_db_init();
genre_db_init();
album_db_init();
library_db_init();
track_db_init();
idle_schedule(IDLE_SYNC, tags_upgrade_done, NULL);
}
void tags_deinit()
{
track_db_deinit();
library_db_deinit();
genre_db_deinit();
album_db_deinit();
artist_db_deinit();
}
bool tags_defragment(void *data)
{
bool album = album_db_defrag();
bool library = library_db_defrag();
bool track = track_db_defrag();
if (library)
track_db_rekey();
if (album || library || track)
track_db_commit();
return track;
}

399
core/tags/track.c Normal file
View File

@ -0,0 +1,399 @@
/*
* Copyright 2014 (c) Anna Schumaker.
*/
#include <core/string.h>
#include <core/tags/track.h>
#include <glib.h>
#include <taglib/tag_c.h>
#define TRACK_DB_MIN 0 /* Ocarina 6.0 */
static struct database track_db;
static unsigned int unplayed_count = 0;
static unsigned int play_count = 0;
static gchar *__track_key(struct library *library, gchar *path)
{
gchar *res;
if (library)
res = g_strdup_printf("%u/%s", library_index(library), path);
else
res = g_strdup("");
g_free(path);
return res;
}
static gchar *__track_path(struct track *track)
{
gchar *path;
sscanf(track->tr_path, "%*u/%m[^\n]", &path);
return path;
}
static struct track *__track_alloc()
{
struct track *track = g_malloc(sizeof(struct track));
dbe_init(&track->tr_dbe, track);
return track;
}
static struct track *__track_alloc_filepath(const gchar *filepath)
{
TagLib_File *file = taglib_file_new(filepath);
const TagLib_AudioProperties *audio;
struct track *track = NULL;
struct artist *artist;
struct genre *genre;
TagLib_Tag *tag;
if (!file || !taglib_file_is_valid(file)) {
g_printerr("WARNING: Could not read tags for: %s\n", filepath);
return NULL;
}
track = __track_alloc();
tag = taglib_file_tag(file);
audio = taglib_file_audioproperties(file);
artist = artist_find(taglib_tag_artist(tag));
genre = genre_find(taglib_tag_genre(tag));
track->tr_album = album_find(artist, genre, taglib_tag_album(tag),
taglib_tag_year(tag));
track->tr_count = 0;
track->tr_length = taglib_audioproperties_length(audio);
track->tr_track = taglib_tag_track(tag);
date_set(&track->tr_date, 0, 0, 0);
track->tr_title = g_strdup(taglib_tag_title(tag));
track->tr_tokens = g_str_tokenize_and_fold(track->tr_title, NULL,
&track->tr_alts);
taglib_tag_free_strings();
taglib_file_free(file);
return track;
}
static void __track_free(struct track *track)
{
g_strfreev(track->tr_tokens);
g_strfreev(track->tr_alts);
g_free(track->tr_title);
g_free(track);
}
struct db_entry *track_alloc(const gchar *key, unsigned int index)
{
struct library *library;
char *fullpath, *path;
struct track *track;
unsigned int lib_id;
sscanf(key, "%u/%m[^\n]", &lib_id, &path);
library = library_get(lib_id);
fullpath = library_file(library, path);
track = __track_alloc_filepath(fullpath);
if (track) {
track->tr_library = library;
track->tr_path = g_strdup(key);
unplayed_count++;
}
g_free(path);
g_free(fullpath);
return track ? &track->tr_dbe : NULL;
}
static void track_free(struct db_entry *dbe)
{
struct track *track = TRACK(dbe);
play_count -= track->tr_count;
if (track->tr_count == 0)
unplayed_count--;
__track_free(track);
}
static gchar *track_key(struct db_entry *dbe)
{
return TRACK(dbe)->tr_path;
}
static void track_read_v0(struct file *file, struct track *track)
{
struct artist *artist = artist_get(file_readu(file));
struct album *album = album_get( file_readu(file));
struct genre *genre = genre_get( file_readu(file));
track->tr_track = file_readhu(file);
date_read(file, &track->tr_date);
if (album->al_artist != artist || album->al_genre != genre)
album = album_find(artist, genre, album->al_name, album->al_year);
track->tr_album = album;
}
static struct db_entry *track_read(struct file *file, unsigned int index)
{
struct track *track = __track_alloc();
track->tr_library = library_get(file_readu(file));
if (file_version(file) == 0)
track_read_v0(file, track);
else {
track->tr_album = album_get(file_readu(file));
track->tr_track = file_readhu(file);
date_read_stamp(file, &track->tr_date);
}
track->tr_count = file_readhu(file);
track->tr_length = file_readhu(file);
play_count += track->tr_count;
if (track->tr_count == 0)
unplayed_count++;
track->tr_title = file_readl(file);
track->tr_tokens = g_str_tokenize_and_fold(track->tr_title, NULL,
&track->tr_alts);
track->tr_path = __track_key(track->tr_library, file_readl(file));
return &track->tr_dbe;
}
static void track_write(struct file *file, struct db_entry *dbe)
{
struct track *track = TRACK(dbe);
gchar *path = __track_path(track);
file_writef(file, "%u %u %hu ", library_index(track->tr_library),
album_index(track->tr_album),
track->tr_track);
date_write_stamp(file, &track->tr_date);
file_writef(file, " %hu %hu %s\n%s", track->tr_count,
track->tr_length,
track->tr_title,
path);
g_free(path);
}
static const struct db_ops track_ops = {
.dbe_alloc = track_alloc,
.dbe_free = track_free,
.dbe_key = track_key,
.dbe_read = track_read,
.dbe_write = track_write,
};
void track_db_init()
{
db_init(&track_db, "track.db", false, &track_ops, TRACK_DB_MIN);
db_load(&track_db);
}
void track_db_deinit()
{
db_deinit(&track_db);
}
void track_db_commit()
{
db_save(&track_db);
}
bool track_db_defrag()
{
return db_defrag(&track_db);
}
void track_db_rekey()
{
struct db_entry *dbe, *next;
struct track *track;
unsigned int lib;
gchar *path;
db_for_each(dbe, next, &track_db) {
track = TRACK(dbe);
sscanf(track->tr_path, "%u/%m[^\n]", &lib, &path);
if (lib != library_index(track->tr_library)) {
track->tr_path = __track_key(track->tr_library, path);
db_rekey(&track_db, dbe);
} else
g_free(path);
}
}
const struct database *track_db_get()
{
return &track_db;
}
unsigned int track_db_count_unplayed()
{
return unplayed_count;
}
unsigned int track_db_count_plays()
{
return play_count;
}
unsigned int track_db_average_plays()
{
if (unplayed_count == track_db.db_size)
return 0;
return play_count / (track_db.db_size - unplayed_count);
}
struct track *track_alloc_external(const gchar *filepath)
{
struct track *track = __track_alloc_filepath(filepath);
if (track) {
track->tr_library = NULL;
track->tr_path = g_strdup(filepath);
}
return track;
}
void track_free_external(struct track *track)
{
if (TRACK_IS_EXTERNAL(track)) {
g_free(track->tr_path);
__track_free(track);
}
}
struct track *track_add(struct library *library, const gchar *filepath)
{
unsigned int offset = strlen(library->li_path) + 1;
gchar *key = __track_key(library, g_strdup(filepath + offset));
struct track *track = NULL;
if (!db_get(&track_db, key))
track = TRACK(db_insert(&track_db, key));
g_free(key);
return track;
}
void track_remove(struct track *track)
{
db_remove(&track_db, &track->tr_dbe);
}
void track_remove_all(struct library *library)
{
struct db_entry *it, *next;
db_for_each(it, next, &track_db) {
if (TRACK(it)->tr_library == library)
db_remove(&track_db, it);
}
track_db_commit();
}
struct track *track_get(const unsigned int index)
{
return TRACK(db_at(&track_db, index));
}
struct track *track_lookup(const gchar *filepath)
{
struct library *library = library_lookup(filepath);
unsigned int offset;
struct track *track;
gchar *key;
if (!library)
return NULL;
offset = strlen(library->li_path) + 1;
key = __track_key(library, g_strdup(filepath + offset));
track = TRACK(db_get(&track_db, key));
g_free(key);
return track;
}
int track_compare(struct track *lhs, struct track *rhs, enum compare_t compare)
{
switch (compare) {
case COMPARE_ARTIST:
return artist_compare(lhs->tr_album->al_artist,
rhs->tr_album->al_artist);
case COMPARE_ALBUM:
return album_compare(lhs->tr_album, rhs->tr_album);
case COMPARE_COUNT:
return lhs->tr_count - rhs->tr_count;
case COMPARE_GENRE:
return genre_compare(lhs->tr_album->al_genre,
rhs->tr_album->al_genre);
case COMPARE_LENGTH:
return lhs->tr_length - rhs->tr_length;
case COMPARE_PLAYED:
return date_compare(&lhs->tr_date, &rhs->tr_date);
case COMPARE_TITLE:
return string_compare_tokens(lhs->tr_tokens, rhs->tr_tokens);
case COMPARE_TRACK:
return lhs->tr_track - rhs->tr_track;
case COMPARE_YEAR:
return album_compare_year(lhs->tr_album, rhs->tr_album);
}
return 0; /* We should never get here. */
}
bool track_match_token(struct track *track, const gchar *token)
{
return string_match_token(token, track->tr_tokens) ||
string_match_token(token, track->tr_alts);
}
gchar *track_path(struct track *track)
{
gchar *path, *res;
if (track->tr_library) {
path = __track_path(track);
res = library_file(track->tr_library, path);
g_free(path);
return res;
}
return g_strdup(track->tr_path);
}
void track_played(struct track *track)
{
if (TRACK_IS_EXTERNAL(track))
return;
if (track->tr_count == 0)
unplayed_count--;
track->tr_count++;
play_count++;
date_today(&track->tr_date);
track_db_commit();
}
gchar *track_last_play(struct track *track)
{
if (track->tr_count > 0)
return date_string(&track->tr_date);
return g_strdup("Never");
}
#ifdef CONFIG_TESTING
const struct db_ops *test_track_ops() { return &track_ops; }
#endif /* CONFIG_TESTING */

147
gui/artwork.c Normal file
View File

@ -0,0 +1,147 @@
/*
* Copyright 2016 (c) Anna Schumaker.
*/
#include <core/audio.h>
#include <gui/artwork.h>
#include <gui/window.h>
#include <glib/gi18n.h>
#define ARTWORK_PREVIEW_SIZE 150
static struct album *artwork_current = NULL;
static unsigned int artwork_timeout = 0;
static cairo_surface_t *__gui_artwork_scale(cairo_surface_t *orig, int new_h)
{
int old_h = cairo_image_surface_get_height(orig);
int old_w = cairo_image_surface_get_width(orig);
int new_w = (old_w * new_h) / old_h;
int scale = gtk_widget_get_scale_factor(GTK_WIDGET(gui_artwork()));
cairo_content_t content = cairo_surface_get_content(orig);
cairo_surface_t *scaled = cairo_surface_create_similar(orig, content,
new_w, new_h);
cairo_t *cairo = cairo_create(scaled);
cairo_scale(cairo, (double)(scale * new_w) / old_w,
(double)(scale * new_h) / old_h);
cairo_set_source_surface(cairo, orig, 0, 0);
cairo_paint(cairo);
cairo_destroy(cairo);
return scaled;
}
static cairo_surface_t *__gui_artwork_get(gchar *path, int new_h)
{
GdkPixbuf *pixbuf = path ? gdk_pixbuf_new_from_file(path, NULL) : NULL;
cairo_surface_t *surface = NULL;
cairo_surface_t *scaled = NULL;
if (!pixbuf)
return NULL;
surface = gdk_cairo_surface_create_from_pixbuf(pixbuf, 0, NULL);
if (surface) {
scaled = __gui_artwork_scale(surface, new_h);
cairo_surface_destroy(surface);
}
g_object_unref(G_OBJECT(pixbuf));
return scaled;
}
static bool __gui_artwork_set_path(GtkImage *image, gchar *path, int new_h)
{
cairo_surface_t *surface = __gui_artwork_get(path, new_h);
bool status = surface != NULL;
if (surface) {
gtk_image_set_from_surface(image, surface);
cairo_surface_destroy(surface);
} else
gtk_image_set_from_icon_name(image, "image-missing",
GTK_ICON_SIZE_DIALOG);
return status;
}
static gboolean __gui_artwork_timeout(gpointer data)
{
struct track *track = audio_cur_track();
int height = gui_builder_widget_height("artwork");
gchar *path;
bool status;
if (!track || track->tr_album == artwork_current)
return G_SOURCE_REMOVE;
path = album_artwork_path(track->tr_album);
status = __gui_artwork_set_path(gui_artwork(), path, height);
gtk_widget_set_sensitive(GTK_WIDGET(gui_artwork()), status);
artwork_current = status ? track->tr_album : NULL;
artwork_timeout = status ? artwork_timeout : 0;
g_free(path);
return status ? G_SOURCE_CONTINUE : G_SOURCE_REMOVE;
}
void __gui_artwork_update_preview(GtkFileChooser *chooser, gpointer data)
{
GtkWidget *preview = gtk_file_chooser_get_preview_widget(chooser);
gchar *path = gtk_file_chooser_get_preview_filename(chooser);
__gui_artwork_set_path(GTK_IMAGE(preview), path, ARTWORK_PREVIEW_SIZE);
g_free(path);
}
void __gui_artwork_select_cover(GtkButton *button)
{
struct track *track = audio_cur_track();
GtkWidget *preview, *dialog;
GtkFileFilter *filter;
gchar *path;
if (!track)
return;
filter = gtk_file_filter_new();
preview = gtk_image_new_from_icon_name("", GTK_ICON_SIZE_DIALOG);
dialog = gtk_file_chooser_dialog_new("Choose an image", gui_window(),
GTK_FILE_CHOOSER_ACTION_OPEN,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_Open"), GTK_RESPONSE_ACCEPT,
NULL);
gtk_file_filter_add_mime_type(filter, "image/*");
gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter);
gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(dialog), true);
gtk_file_chooser_set_preview_widget(GTK_FILE_CHOOSER(dialog), preview);
gtk_file_chooser_set_use_preview_label(GTK_FILE_CHOOSER(dialog), false);
g_signal_connect(dialog, "update-preview",
(GCallback)__gui_artwork_update_preview, NULL);
if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
path = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
gui_artwork_import(track, path);
g_free(path);
}
gtk_widget_destroy(dialog);
}
void gui_artwork_set_cover(void)
{
if (__gui_artwork_timeout(NULL) != G_SOURCE_CONTINUE)
return;
artwork_timeout = g_timeout_add(2000, __gui_artwork_timeout, NULL);
}
void gui_artwork_import(struct track *track, gchar *path)
{
album_artwork_import(track->tr_album, path);
if (track == audio_cur_track()) {
artwork_current = NULL;
gui_artwork_set_cover();
}
}

205
gui/audio.c Normal file
View File

@ -0,0 +1,205 @@
/*
* Copyright 2014 (c) Anna Schumaker.
*/
#include <core/string.h>
#include <gui/artwork.h>
#include <gui/audio.h>
#include <gui/idle.h>
#include <gui/playlist.h>
#include <gui/treeview.h>
#include <gui/window.h>
static guint audio_timeout = 0;
static guint popover_timeout = 0;
static inline void __gui_audio_set_label_markup(GtkLabel *label,
const gchar *size,
const gchar *text)
{
const gchar *fmt = "<span size='%s'>%s</span>";
gchar *markup = g_markup_printf_escaped(fmt, size, text);
gtk_label_set_markup(label, markup);
g_free(markup);
}
static void __gui_audio_load(struct track *track)
{
gchar *duration = string_sec2str(track->tr_length);
__gui_audio_set_label_markup(gui_title_tag(), "xx-large",
track->tr_title);
__gui_audio_set_label_markup(gui_album_tag(), "x-large",
track->tr_album->al_name);
__gui_audio_set_label_markup(gui_artist_tag(), "x-large",
track->tr_album->al_artist->ar_name);
__gui_audio_set_label_markup(gui_duration(), "large", duration);
__gui_audio_set_label_markup(gui_position(), "large", "0:00");
gtk_adjustment_set_upper(gui_seek(), track->tr_length);
gui_pl_system_track_loaded(track);
gui_treeview_scroll();
gui_artwork_set_cover();
gui_idle_enable();
g_free(duration);
}
static void __gui_audio_set_pause_text(int n, GstState state)
{
bool sensitive = true;
gchar *text;
if (n == -1) {
sensitive = false;
if (state == GST_STATE_PLAYING)
text = g_strdup("Keep playing");
else
text = g_strdup("Paused");
} else if (n == 0)
text = g_strdup("Pause after this track");
else if (n == 1)
text = g_strdup("Pause after next track");
else
text = g_strdup_printf("Pause after %d tracks", n);
gtk_widget_set_sensitive(GTK_WIDGET(gui_pause_down()), sensitive);
gtk_entry_set_text(gui_pause_entry(), text);
g_free(text);
}
static void __gui_audio_change_state(GstState state)
{
bool playing = (state == GST_STATE_PLAYING);
gtk_widget_set_visible(GTK_WIDGET(gui_play_button()), !playing);
gtk_widget_set_visible(GTK_WIDGET(gui_pause_button()), playing);
__gui_audio_set_pause_text(audio_get_pause_count(), state);
}
static void __gui_audio_config_pause(int n)
{
__gui_audio_set_pause_text(n, audio_cur_state());
}
struct audio_callbacks audio_cb = {
.audio_cb_load = __gui_audio_load,
.audio_cb_state_change = __gui_audio_change_state,
.audio_cb_config_pause = __gui_audio_config_pause,
};
void __gui_audio_pause(GtkButton *button, gpointer data)
{
audio_pause();
if (audio_get_pause_count() > -1) {
gtk_popover_popup(gui_pause_popover());
popover_timeout = g_timeout_add_seconds(10,
gui_audio_popover_timeout, NULL);
}
}
void __gui_audio_pause_change_text(GtkEntry *entry, gpointer data)
{
const gchar *text = gtk_entry_get_text(entry);
int n = audio_get_pause_count();
unsigned int i;
if (g_str_match_string("Keep", text, true))
n = -1;
else if (g_str_match_string("This", text, true))
n = 0;
else if (g_str_match_string("Next", text, true))
n = 1;
else {
for (i = 0; text[i] != '\0'; i++) {
if (!g_ascii_isdigit(text[i]))
continue;
if (i > 0 && text[i-1] == '-')
i -= 1;
n = g_strtod(text + i, NULL);
break;
}
}
if (!audio_pause_after(n))
__gui_audio_set_pause_text(audio_get_pause_count(), audio_cur_state());
}
void __gui_audio_pause_inc(GtkButton *button, gpointer data)
{
audio_pause_after(audio_get_pause_count() + 1);
}
void __gui_audio_pause_dec(GtkButton *button, gpointer data)
{
audio_pause_after(audio_get_pause_count() - 1);
}
void __gui_audio_pause_popover_popdown(GtkButton *button, gpointer data)
{
gtk_popover_popdown(gui_pause_popover());
#ifdef CONFIG_TESTING
gtk_widget_hide(GTK_WIDGET(gui_pause_popover()));
#endif /* CONFIG_TESTING */
g_source_remove(popover_timeout);
popover_timeout = 0;
}
void __gui_audio_pause_popover_clear(GtkButton *button, gpointer data)
{
audio_pause_after(-1);
__gui_audio_pause_popover_popdown(button, data);
}
void __gui_audio_seek(GtkRange *range, GtkScrollType type,
double value, gpointer data)
{
audio_seek(value * GST_SECOND);
}
void __gui_audio_volume_changed(GtkScaleButton *button, gdouble value,
gpointer data)
{
audio_set_volume((unsigned int)value);
}
gboolean __gui_audio_can_accel(GtkWidget *widget, guint signal_id)
{
g_signal_stop_emission_by_name(widget, "can-activate-accel");
return !GTK_IS_ENTRY(gtk_window_get_focus(gui_window())) &&
gtk_widget_is_visible(widget) &&
gtk_widget_is_sensitive(widget);
}
void gui_audio_init()
{
gtk_scale_button_set_value(gui_volume_button(), audio_get_volume());
gtk_button_set_relief(GTK_BUTTON(gui_volume_button()), GTK_RELIEF_NORMAL);
audio_timeout = g_timeout_add(500, gui_audio_timeout, NULL);
}
void gui_audio_deinit()
{
g_source_remove(audio_timeout);
if (popover_timeout > 0)
g_source_remove(popover_timeout);
}
int gui_audio_timeout(gpointer data)
{
gchar *position = string_sec2str(audio_position() / GST_SECOND);
gtk_adjustment_set_upper(gui_seek(), audio_duration() / GST_SECOND);
gtk_adjustment_set_value(gui_seek(), audio_position() / GST_SECOND);
__gui_audio_set_label_markup(gui_position(), "large", position);
g_free(position);
return G_SOURCE_CONTINUE;
}
int gui_audio_popover_timeout(gpointer data)
{
__gui_audio_pause_popover_popdown(NULL, data);
return G_SOURCE_REMOVE;
}

42
gui/builder.c Normal file
View File

@ -0,0 +1,42 @@
/*
* Copyright 2016 (c) Anna Schumaker.
*/
#include <gui/builder.h>
static GtkBuilder *gui_builder = NULL;
void gui_builder_init(const char *file)
{
gui_builder = gtk_builder_new_from_file(file);
gtk_builder_connect_signals(gui_builder, NULL);
}
void gui_builder_deinit()
{
g_object_unref(G_OBJECT(gui_builder));
gui_builder = NULL;
}
GObject *gui_builder_object(const char *name)
{
if (gui_builder)
return gtk_builder_get_object(gui_builder, name);
return NULL;
}
GtkWidget *gui_builder_widget(const char *name)
{
return GTK_WIDGET(gui_builder_object(name));
}
int gui_builder_widget_height(const char *name)
{
return gtk_widget_get_allocated_height(gui_builder_widget(name));
}
#ifdef CONFIG_TESTING
GtkBuilder *test_get_gui_builder()
{
return gui_builder;
}
#endif /* CONFIG_TESTING */

142
gui/filter.c Normal file
View File

@ -0,0 +1,142 @@
/*
* Copyright 2016 (c) Anna Schumaker.
*/
#include <core/audio.h>
#include <core/string.h>
#include <gui/filter.h>
#include <gui/model.h>
static GtkTreeModelFilter *filter_model = NULL;
static inline GtkTreePath *__gui_filter_convert_path(GtkTreePath *path)
{
return gtk_tree_model_filter_convert_path_to_child_path(filter_model,
path);
}
static inline gboolean __gui_filter_match_token(struct track *track,
const gchar *token,
unsigned int how)
{
switch (how) {
case GUI_FILTER_ALBUM:
return album_match_token(track->tr_album, token);
case GUI_FILTER_ARTIST:
return artist_match_token(track->tr_album->al_artist, token);
case GUI_FILTER_GENRE:
return genre_match_token(track->tr_album->al_genre, token);
case GUI_FILTER_TITLE:
return track_match_token(track, token);
case GUI_FILTER_DEFAULT:
return track_match_token(track, token) ||
album_match_token(track->tr_album, token) ||
artist_match_token(track->tr_album->al_artist, token) ||
genre_match_token(track->tr_album->al_genre, token);
default:
return false;
}
}
static gboolean __gui_filter_visible_func(GtkTreeModel *model,
GtkTreeIter *iter,
gpointer data)
{
unsigned int i, how = gtk_combo_box_get_active(gui_filter_how());
gchar **search = gui_model_get_playlist()->pl_search;
struct track *track;
if (!search)
return TRUE;
track = gui_model_iter_get_track(iter);
for (i = 0; search[i]; i++) {
if (!__gui_filter_match_token(track, search[i], how))
return FALSE;
}
return TRUE;
}
void __gui_filter_search_changed(GtkSearchEntry *search, gpointer data)
{
playlist_set_search(gui_model_get_playlist(),
gtk_entry_get_text(GTK_ENTRY(search)));
gtk_tree_model_filter_refilter(gui_filter_get());
}
void __gui_filter_how_changed(int n)
{
__gui_filter_search_changed(gui_filter_search(), NULL);
}
void gui_filter_init()
{
GtkTreeModel *model = GTK_TREE_MODEL(gui_model_get());
GtkTreeModel *filter = gtk_tree_model_filter_new(model, NULL);
filter_model = GTK_TREE_MODEL_FILTER(filter);
gtk_tree_model_filter_set_visible_func(filter_model,
__gui_filter_visible_func,
NULL, NULL);
}
void gui_filter_deinit()
{
g_object_unref(G_OBJECT(filter_model));
}
void gui_filter_set_playlist(struct playlist *playlist)
{
gchar **search = playlist ? (gchar **)playlist->pl_search : NULL;
gchar *text = search ? g_strjoinv(" ", search) : g_strdup("");
gui_model_set_playlist(playlist);
gtk_entry_set_text(GTK_ENTRY(gui_filter_search()), text);
g_free(text);
}
GtkTreeModelFilter *gui_filter_get()
{
return filter_model;
}
struct track *gui_filter_path_get_track(GtkTreePath *path)
{
GtkTreePath *real = __gui_filter_convert_path(path);
struct track *track = real ? gui_model_path_get_track(real) : NULL;
gtk_tree_path_free(real);
return track;
}
void gui_filter_path_load_track(GtkTreePath *path)
{
struct track *track = gui_filter_path_get_track(path);
unsigned int index = gtk_tree_path_get_indices(path)[0];
audio_load(track);
playlist_current_set(gui_model_get_playlist(), index);
}
unsigned int gui_filter_path_get_index(GtkTreePath *path)
{
GtkTreePath *real = __gui_filter_convert_path(path);
unsigned int ret = gtk_tree_path_get_indices(real)[0];
gtk_tree_path_free(real);
return ret;
}
GtkTreePath *gui_filter_path_from_index(unsigned int index)
{
GtkTreePath *real, *path;
real = gtk_tree_path_new_from_indices(index, -1);
path = gtk_tree_model_filter_convert_child_path_to_path(filter_model,
real);
gtk_tree_path_free(real);
return path;
}
void gui_filter_refilter(struct playlist *playlist)
{
if (!playlist || playlist == gui_model_get_playlist())
gtk_tree_model_filter_refilter(gui_filter_get());
}

31
gui/idle.c Normal file
View File

@ -0,0 +1,31 @@
/*
* Copyright 2016 (c) Anna Schumaker.
*/
#include <gui/idle.h>
static guint idle_id = 0;
static gboolean __on_idle(gpointer data)
{
bool more = idle_run_task();
gchar *text = g_strdup_printf("%f%%", idle_progress() * 100);
gtk_widget_set_visible(GTK_WIDGET(gui_progress_bar()), more);
gtk_progress_bar_set_fraction(gui_progress_bar(), idle_progress());
gtk_widget_set_tooltip_text(GTK_WIDGET(gui_progress_bar()), text);
g_free(text);
idle_id = more ? idle_id : 0;
return more ? G_SOURCE_CONTINUE : G_SOURCE_REMOVE;
}
void gui_idle_enable()
{
idle_id = g_idle_add(__on_idle, NULL);
}
void gui_idle_disable()
{
if (idle_id)
g_source_remove(idle_id);
}

383
gui/model.c Normal file
View File

@ -0,0 +1,383 @@
/*
* Copyright 2016 (c) Anna Schumaker.
*/
#include <core/audio.h>
#include <core/string.h>
#include <gui/builder.h>
#include <gui/model.h>
static gboolean __gui_model_iter_nth_child(GtkTreeModel *, GtkTreeIter *,
GtkTreeIter *, gint);
static struct playlist *cur_playlist = NULL;
static GObjectClass *parent_class = NULL;
static GuiModel *gui_model = NULL;
static GType gui_model_type = 0;
static GType gui_model_columns[GUI_MODEL_N_COLUMNS] = {
[GUI_MODEL_TRACK_NR] = G_TYPE_UINT,
[GUI_MODEL_TITLE] = G_TYPE_STRING,
[GUI_MODEL_LENGTH] = G_TYPE_STRING,
[GUI_MODEL_ARTIST] = G_TYPE_STRING,
[GUI_MODEL_ALBUM] = G_TYPE_STRING,
[GUI_MODEL_YEAR] = G_TYPE_UINT,
[GUI_MODEL_GENRE] = G_TYPE_STRING,
[GUI_MODEL_COUNT] = G_TYPE_UINT,
[GUI_MODEL_LAST_PLAY] = G_TYPE_STRING,
[GUI_MODEL_FILE_PATH] = G_TYPE_STRING,
[GUI_MODEL_FONT] = G_TYPE_STRING,
};
const GtkTargetEntry gui_model_drag_targets[] = {
{ GUI_DRAG_DATA, GTK_TARGET_SAME_APP, 0 },
};
const unsigned int gui_model_n_targets = G_N_ELEMENTS(gui_model_drag_targets);
static GtkTreeModelFlags __gui_model_get_flags(GtkTreeModel *model)
{
return GTK_TREE_MODEL_LIST_ONLY;
}
static gint __gui_model_get_n_columns(GtkTreeModel *model)
{
return GUI_MODEL_N_COLUMNS;
}
static GType __gui_model_get_column_type(GtkTreeModel *model, gint index)
{
g_return_val_if_fail(index >= 0, G_TYPE_INVALID);
g_return_val_if_fail(index < GUI_MODEL_N_COLUMNS, G_TYPE_INVALID);
return gui_model_columns[index];
}
static gboolean __gui_model_get_iter(GtkTreeModel *model, GtkTreeIter *iter,
GtkTreePath *path)
{
gint *indices, depth;
g_assert(path != NULL);
indices = gtk_tree_path_get_indices_with_depth(path, &depth);
g_assert(depth == 1);
return __gui_model_iter_nth_child(model, iter, NULL, indices[0]);
}
static GtkTreePath *__gui_model_get_path(GtkTreeModel *model, GtkTreeIter *iter)
{
GtkTreePath *path;
unsigned int pos;
g_return_val_if_fail(iter != NULL, FALSE);
g_return_val_if_fail(iter->user_data, FALSE);
path = gtk_tree_path_new();
pos = playlist_iter_index(cur_playlist, iter->user_data);
gtk_tree_path_append_index(path, pos);
return path;
}
static void __gui_model_get_value(GtkTreeModel *model, GtkTreeIter *iter,
gint column, GValue *value)
{
struct track *track = playlist_iter_track(iter->user_data);
gchar *str;
g_return_if_fail(iter != NULL);
g_return_if_fail(iter->user_data != NULL);
g_return_if_fail(column < GUI_MODEL_N_COLUMNS);
g_value_init(value, gui_model_columns[column]);
switch (column) {
case GUI_MODEL_TRACK_NR:
g_value_set_uint(value, track->tr_track);
break;
case GUI_MODEL_TITLE:
g_value_set_static_string(value, track->tr_title);
break;
case GUI_MODEL_LENGTH:
g_value_take_string(value, string_sec2str(track->tr_length));
break;
case GUI_MODEL_ARTIST:
g_value_set_static_string(value, track->tr_album->al_artist->ar_name);
break;
case GUI_MODEL_ALBUM:
g_value_set_static_string(value, track->tr_album->al_name);
break;
case GUI_MODEL_YEAR:
g_value_set_uint(value, track->tr_album->al_year);
break;
case GUI_MODEL_GENRE:
g_value_set_static_string(value, track->tr_album->al_genre->ge_name);
break;
case GUI_MODEL_COUNT:
g_value_set_uint(value, track->tr_count);
break;
case GUI_MODEL_LAST_PLAY:
g_value_take_string(value, track_last_play(track));
break;
case GUI_MODEL_FILE_PATH:
str = track_path(track);
g_value_take_string(value, g_markup_escape_text(str, -1));
g_free(str);
break;
case GUI_MODEL_FONT:
str = (track == audio_cur_track()) ? "bold" : "";
g_value_take_string(value, g_strdup(str));
break;
}
}
static gboolean __gui_model_iter_next(GtkTreeModel *model, GtkTreeIter *iter)
{
g_return_val_if_fail(iter != NULL, FALSE);
g_return_val_if_fail(iter->user_data, FALSE);
iter->user_data = playlist_iter_next(iter->user_data);
return iter->user_data != NULL;
}
static gboolean __gui_model_iter_children(GtkTreeModel *model, GtkTreeIter *iter,
GtkTreeIter *parent)
{
return __gui_model_iter_nth_child(model, iter, parent, 0);
}
static gboolean __gui_model_iter_has_child(GtkTreeModel *model, GtkTreeIter *iter)
{
return FALSE;
}
static gint __gui_model_iter_n_children(GtkTreeModel *model, GtkTreeIter *iter)
{
if (iter != NULL || !cur_playlist)
return 0;
return playlist_size(cur_playlist);
}
static gboolean __gui_model_iter_nth_child(GtkTreeModel *model,
GtkTreeIter *iter,
GtkTreeIter *parent,
gint n)
{
if (parent || !cur_playlist || n >= playlist_size(cur_playlist))
return FALSE;
iter->stamp = gui_model->gm_stamp;
iter->user_data = playlist_iter_get(cur_playlist, n);
return iter->user_data != NULL;
}
static gboolean __gui_model_iter_parent(GtkTreeModel *model, GtkTreeIter *iter,
GtkTreeIter *child)
{
return FALSE;
}
static gboolean __gui_model_drag_data_get(GtkTreeDragSource *drag_source,
GtkTreePath *path,
GtkSelectionData *selection_data)
{
struct gui_model_drag_data *data = g_malloc(sizeof(*data));
data->drag_row = gtk_tree_path_get_indices(path)[0];
data->drag_track = gui_model_path_get_track(path);
gtk_selection_data_set(selection_data, gdk_atom_intern(GUI_DRAG_DATA, false),
8 /* bytes */, (void *)data, sizeof(*data));
g_free(data);
return true;
}
static gboolean __gui_model_drag_data_delete(GtkTreeDragSource *drag_source,
GtkTreePath *path)
{
return true;
}
static void __gui_model_init(GuiModel *model)
{
model->gm_stamp = g_random_int();
}
static void __gui_model_finalize(GObject *object)
{
parent_class->finalize(object);
}
static void __gui_model_class_init(GuiModelClass *class)
{
GObjectClass *object_class = (GObjectClass *)class;
object_class->finalize = __gui_model_finalize;
parent_class = g_type_class_peek_parent(class);
}
static void __gui_tree_model_init(GtkTreeModelIface *iface)
{
iface->get_flags = __gui_model_get_flags;
iface->get_n_columns = __gui_model_get_n_columns;
iface->get_column_type = __gui_model_get_column_type;
iface->get_iter = __gui_model_get_iter;
iface->get_path = __gui_model_get_path;
iface->get_value = __gui_model_get_value;
iface->iter_next = __gui_model_iter_next;
iface->iter_children = __gui_model_iter_children;
iface->iter_has_child = __gui_model_iter_has_child;
iface->iter_n_children = __gui_model_iter_n_children;
iface->iter_nth_child = __gui_model_iter_nth_child;
iface->iter_parent = __gui_model_iter_parent;
}
static void __gui_drag_source_init(GtkTreeDragSourceIface *iface)
{
iface->drag_data_get = __gui_model_drag_data_get;
iface->drag_data_delete = __gui_model_drag_data_delete;
}
static const GTypeInfo gui_model_type_info = {
.class_size = sizeof(GuiModelClass),
.base_init = NULL,
.base_finalize = NULL,
.class_init = (GClassInitFunc)__gui_model_class_init,
.class_finalize = NULL,
.class_data = NULL,
.instance_size = sizeof(GuiModel),
.n_preallocs = 0,
.instance_init = (GInstanceInitFunc)__gui_model_init,
};
static const GInterfaceInfo gui_tree_model = {
.interface_init = (GInterfaceInitFunc)__gui_tree_model_init,
.interface_finalize = NULL,
.interface_data = NULL,
};
static const GInterfaceInfo gui_drag_source = {
.interface_init = (GInterfaceInitFunc)__gui_drag_source_init,
.interface_finalize = NULL,
.interface_data = NULL,
};
void gui_model_init(void)
{
gui_model_type = g_type_register_static(G_TYPE_OBJECT, "GuiModel",
&gui_model_type_info,
(GTypeFlags)0);
g_type_add_interface_static(gui_model_type, GTK_TYPE_TREE_MODEL,
&gui_tree_model);
g_type_add_interface_static(gui_model_type, GTK_TYPE_TREE_DRAG_SOURCE,
&gui_drag_source);
gui_model = g_object_new(gui_model_type, NULL);
g_assert(gui_model != NULL);
}
void gui_model_deinit(void)
{
g_object_unref(gui_model);
gui_model_type = 0;
gui_model = NULL;
cur_playlist = NULL;
}
static void __gui_model_set_runtime(void)
{
gchar *len = NULL;
if (cur_playlist)
len = string_sec2str_long(cur_playlist->pl_length);
gtk_label_set_text(gui_model_runtime(), len);
g_free(len);
}
static gboolean __gui_model_foreach_changed(GtkTreeModel *model, GtkTreePath *path,
GtkTreeIter *iter, gpointer data)
{
if (!data || data == gui_model_iter_get_track(iter))
gtk_tree_model_row_changed(model, path, iter);
return FALSE;
}
GuiModel *gui_model_get(void)
{
return gui_model;
}
GType gui_model_get_type()
{
return gui_model_type;
}
void gui_model_add(struct playlist *playlist, struct track *track)
{
GtkTreePath *path;
GtkTreeIter iter;
if (cur_playlist != playlist)
return;
path = gtk_tree_path_new_from_indices(0, -1);
__gui_model_get_iter(GTK_TREE_MODEL(gui_model), &iter, path);
gtk_tree_model_row_inserted(GTK_TREE_MODEL(gui_model), path, &iter);
gtk_tree_path_free(path);
__gui_model_set_runtime();
}
void gui_model_remove(struct playlist *playlist, struct track *track,
unsigned int n)
{
GtkTreePath *path;
unsigned int i;
if (cur_playlist != playlist)
return;
path = gtk_tree_path_new_from_indices(n - 1, -1);
for (i = 0; i < n; i++) {
gtk_tree_model_row_deleted(GTK_TREE_MODEL(gui_model), path);
gtk_tree_path_prev(path);
}
gtk_tree_path_free(path);
__gui_model_set_runtime();
}
void gui_model_update(struct playlist *playlist, struct track *track)
{
if (cur_playlist == playlist)
gtk_tree_model_foreach(GTK_TREE_MODEL(gui_model),
__gui_model_foreach_changed, track);
__gui_model_set_runtime();
}
void gui_model_set_playlist(struct playlist *playlist)
{
if (cur_playlist)
gui_model_remove(cur_playlist, NULL, playlist_size(cur_playlist));
cur_playlist = playlist;
__gui_model_set_runtime();
if (playlist && playlist_size(playlist) > 0)
gui_model_add(playlist, 0);
}
struct playlist *gui_model_get_playlist(void)
{
return cur_playlist;
}
struct track * gui_model_path_get_track(GtkTreePath *path)
{
GtkTreeIter iter;
__gui_model_get_iter(GTK_TREE_MODEL(gui_model), &iter, path);
return gui_model_iter_get_track(&iter);
}

151
gui/ocarina.c Normal file
View File

@ -0,0 +1,151 @@
/*
* Copyright 2014 (c) Anna Schumaker.
*/
#include <core/core.h>
#include <gui/audio.h>
#include <gui/builder.h>
#include <gui/filter.h>
#include <gui/idle.h>
#include <gui/model.h>
#include <gui/playlist.h>
#include <gui/sidebar.h>
#include <gui/treeview.h>
#include <gui/window.h>
#define OCARINA_FLAGS (G_APPLICATION_HANDLES_COMMAND_LINE)
static const GOptionEntry ocarina_options[] = {
{ "next", 'n', 0, G_OPTION_ARG_NONE, NULL, "Play next track", NULL },
{ "pause", 'P', 0, G_OPTION_ARG_NONE, NULL, "Pause playback", NULL },
{ "play", 'p', 0, G_OPTION_ARG_NONE, NULL, "Start playback", NULL },
{ "previous", 'N', 0, G_OPTION_ARG_NONE, NULL, "Play previous track", NULL },
{ "sync", 's', 0, G_OPTION_ARG_NONE, NULL, "Don't run background tasks", NULL },
{ "toggle", 't', 0, G_OPTION_ARG_NONE, NULL, "Toggle playback state", NULL },
{ "version", 'v', 0, G_OPTION_ARG_NONE, NULL, "Print version and exit", NULL },
{ NULL },
};
#ifndef CONFIG_DEBUG
const static gchar *OCARINA_APP = "org.gtk.ocarina";
#else
const static gchar *OCARINA_APP = "org.gtk.ocarina-debug";
#endif
static enum idle_sync_t idle_sync = IDLE_ASYNC;
static int startup_argc;
static char **startup_argv;
static gchar *find_file_path(const gchar *file)
{
gchar *path = g_strjoin("/", "share", "ocarina", file, NULL);
if (g_file_test(path, G_FILE_TEST_IS_REGULAR))
return path;
g_free(path);
return g_strjoin("/", "/usr", "share", "ocarina", file, NULL);
}
static void __ocarina_activate(GApplication *application, gpointer data)
{
gtk_application_add_window(GTK_APPLICATION(application), gui_window());
}
static int __ocarina_local_options(GApplication *application,
GVariantDict *options, gpointer data)
{
if (g_variant_dict_contains(options, "sync"))
idle_sync = IDLE_SYNC;
if (!g_variant_dict_contains(options, "version"))
return -1;
g_printf("Ocarina %s\n", get_version());
g_printf("GTK+ %u.%u.%u\n", GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION);
g_printf("%s\n", gst_version_string());
g_printf("%s, %s\n", __DATE__, __TIME__);
return 0;
}
static int __ocarina_command_line(GApplication *application,
GApplicationCommandLine *command,
gpointer data)
{
GVariantDict *options;
gchar **args;
g_application_activate(application);
args = g_application_command_line_get_arguments(command, NULL);
if (args && args[1]) {
audio_load_filepath(args[1]);
g_strfreev(args);
}
options = g_application_command_line_get_options_dict(command);
if (g_variant_dict_contains(options, "next"))
audio_next();
else if (g_variant_dict_contains(options, "pause"))
audio_pause();
else if (g_variant_dict_contains(options, "play"))
audio_play();
else if (g_variant_dict_contains(options, "previous"))
audio_prev();
else if (g_variant_dict_contains(options, "toggle")) {
if (audio_cur_state() == GST_STATE_PLAYING)
audio_pause();
else
audio_play();
}
return 0;
}
static void __ocarina_startup(GApplication *application, gpointer data)
{
gchar *ui = find_file_path("ocarina.ui");
gchar *icon = find_file_path("ocarina.png");
gui_builder_init(ui);
core_init(&startup_argc, &startup_argv, &playlist_cb, &audio_cb, idle_sync);
gui_window_init(icon);
gui_model_init();
gui_filter_init();
gui_treeview_init();
gui_sidebar_init();
gui_playlist_init();
gui_audio_init();
gui_idle_enable();
g_free(ui);
g_free(icon);
}
static void __ocarina_shutdown(GApplication *application, gpointer data)
{
gui_idle_disable();
gui_audio_deinit();
core_deinit();
gui_treeview_deinit();
gui_filter_deinit();
gui_model_deinit();
gui_window_deinit();
gui_builder_deinit();
}
int main(int argc, char **argv)
{
GtkApplication *ocarina = gtk_application_new(OCARINA_APP, OCARINA_FLAGS);
startup_argc = argc;
startup_argv = argv;
g_application_add_main_option_entries(G_APPLICATION(ocarina), ocarina_options);
g_application_add_option_group(G_APPLICATION(ocarina), gst_init_get_option_group());
g_signal_connect(G_APPLICATION(ocarina), "activate", (GCallback)__ocarina_activate, NULL);
g_signal_connect(G_APPLICATION(ocarina), "handle-local-options",
(GCallback)__ocarina_local_options, NULL);
g_signal_connect(G_APPLICATION(ocarina), "command-line", (GCallback)__ocarina_command_line, NULL);
g_signal_connect(G_APPLICATION(ocarina), "startup", (GCallback)__ocarina_startup, NULL);
g_signal_connect(G_APPLICATION(ocarina), "shutdown", (GCallback)__ocarina_shutdown, NULL);
return g_application_run(G_APPLICATION(ocarina), argc, argv);
}

259
gui/playlist.c Normal file
View File

@ -0,0 +1,259 @@
/*
* Copyright 2016 (c) Anna Schumaker.
*/
#include <core/idle.h>
#include <core/string.h>
#include <gui/filter.h>
#include <gui/model.h>
#include <gui/playlist.h>
#include <gui/treeview.h>
#include <gui/sidebar.h>
static void (*update_size[PL_MAX_TYPE])(struct playlist *) = {
[PL_SYSTEM] = gui_pl_system_update,
[PL_ARTIST] = gui_pl_artist_update,
[PL_LIBRARY] = gui_pl_library_update,
[PL_USER] = gui_pl_user_update,
};
static void (*select_playlist[PL_MAX_TYPE])(struct playlist *) = {
[PL_SYSTEM] = gui_pl_system_select,
[PL_ARTIST] = gui_pl_artist_select,
[PL_LIBRARY] = gui_pl_library_select,
[PL_USER] = gui_pl_user_select,
};
static inline void __gui_playlist_update_size(struct playlist *playlist)
{
update_size[playlist->pl_type](playlist);
}
static void __gui_playlist_alloc(struct playlist *playlist)
{
if (playlist->pl_type == PL_ARTIST)
gui_pl_artist_add(playlist);
}
static void __gui_playlist_added(struct playlist *playlist, struct track *track)
{
gui_model_add(playlist, track);
gui_filter_refilter(playlist);
__gui_playlist_update_size(playlist);
}
static void __gui_playlist_removed(struct playlist *playlist, struct track *track,
unsigned int n)
{
gui_model_remove(playlist, track, n);
__gui_playlist_update_size(playlist);
}
struct playlist_callbacks playlist_cb = {
.pl_cb_alloc = __gui_playlist_alloc,
.pl_cb_added = __gui_playlist_added,
.pl_cb_removed = __gui_playlist_removed,
.pl_cb_updated = gui_model_update,
};
static void __gui_playlist_add_selected_to(struct playlist *playlist)
{
GList *cur, *list = NULL;
struct track *track;
if (!playlist)
return;
list = gui_treeview_list_selected_tracks();
cur = g_list_first(list);
while (cur) {
track = (struct track *)cur->data;
playlist_add(playlist, track);
cur = g_list_next(cur);
}
g_list_free(list);
}
void __gui_playlist_add_favorites(GtkMenuItem *item, gpointer data)
{
__gui_playlist_add_selected_to(playlist_lookup(PL_SYSTEM, "Favorites"));
}
void __gui_playlist_add_hidden(GtkMenuItem *item, gpointer data)
{
__gui_playlist_add_selected_to(playlist_lookup(PL_SYSTEM, "Hidden"));
}
void __gui_playlist_add_user(GtkMenuItem *item, gpointer data)
{
__gui_playlist_add_selected_to(gui_pl_user_add_dialog());
}
void __gui_playlist_add_other(GtkMenuItem *item, gpointer data)
{
__gui_playlist_add_selected_to(data);
}
void __gui_playlist_add_queued(GtkMenuItem *item, gpointer data)
{
__gui_playlist_add_selected_to(playlist_lookup(PL_SYSTEM, "Queued Tracks"));
}
void __gui_playlist_delete(GtkMenuItem *item, gpointer data)
{
struct playlist *playlist = gui_model_get_playlist();
GList *cur, *list = NULL;
struct track *track;
if (!playlist)
return;
list = gui_treeview_list_selected_tracks();
cur = g_list_first(list);
while (cur) {
track = (struct track *)cur->data;
playlist_remove(playlist, track);
cur = g_list_next(cur);
}
g_list_free(list);
}
void __gui_playlist_keypress(GtkTreeView *treeview, GdkEventKey *event,
gpointer data)
{
switch (event->keyval) {
case GDK_KEY_f:
__gui_playlist_add_favorites(NULL, NULL);
break;
case GDK_KEY_h:
__gui_playlist_add_hidden(NULL, NULL);
break;
case GDK_KEY_p:
__gui_playlist_add_user(NULL, NULL);
break;
case GDK_KEY_q:
__gui_playlist_add_queued(NULL, NULL);
break;
case GDK_KEY_Delete:
__gui_playlist_delete(NULL, NULL);
default:
break;
}
}
static GtkWidget *__gui_playlist_build_submenu(void)
{
struct playlist *playlist;
GList *list = gui_pl_user_list();
GList *cur = g_list_first(list);
GtkWidget *submenu, *item;
if (!list)
return NULL;
submenu = gtk_menu_new();
while (cur) {
playlist = (struct playlist *)cur->data;
item = gtk_menu_item_new_with_label(playlist->pl_name);
gtk_menu_shell_append(GTK_MENU_SHELL(submenu), item);
g_signal_connect(item, "activate",
G_CALLBACK(__gui_playlist_add_other),
playlist);
cur = g_list_next(cur);
}
gtk_widget_show_all(submenu);
g_list_free(list);
return submenu;
}
bool __gui_playlist_button_press(GtkTreeView *treeview, GdkEventButton *event,
gpointer data)
{
GtkWidget *submenu;
if (event->button != GDK_BUTTON_SECONDARY)
return false;
submenu = __gui_playlist_build_submenu();
gtk_menu_item_set_submenu(gui_rc_add_to_other(), submenu);
gtk_widget_set_visible(GTK_WIDGET(gui_rc_add_to_other()),
submenu != NULL);
gui_treeview_select_path_at_pos(event->x, event->y);
gtk_menu_popup_at_pointer(gui_rc_menu(), (GdkEvent *)event);
return true;
}
void __gui_playlist_row_activated(GtkTreeView *treeview, GtkTreePath *path,
GtkTreeViewColumn *col, gpointer data)
{
struct playlist *prev = playlist_current();
gui_sidebar_filter_path_select(path);
__gui_playlist_update_size(prev);
__gui_playlist_update_size(playlist_current());
}
void __gui_playlist_row_collapsed(GtkTreeView *treeview, GtkTreeIter *iter,
GtkTreePath *path, gpointer data)
{
gui_sidebar_filter_row_expanded(iter, false);
}
void __gui_playlist_row_expanded(GtkTreeView *treeview, GtkTreeIter *iter,
GtkTreePath *path, gpointer data)
{
gui_sidebar_filter_row_expanded(iter, true);
}
void __gui_playlist_drag_data_received(GtkTreeView *treeview, GdkDragContext *context,
gint x, gint y, GtkSelectionData *data,
guint info, guint time, gpointer user_data)
{
struct playlist *playlist;
GtkTreeIter iter;
if (gui_sidebar_iter_from_xy(x, y, &iter))
playlist = gui_sidebar_iter_playlist(&iter);
if (!playlist)
playlist = gui_pl_user_add_dialog();
if (!playlist)
goto out;
if (playlist == playlist_lookup(PL_SYSTEM, "Collection") &&
gui_model_get_playlist() == playlist_lookup(PL_SYSTEM, "Hidden"))
__gui_playlist_delete(NULL, NULL);
else if (playlist != playlist_lookup(PL_SYSTEM, "History"))
__gui_playlist_add_selected_to(playlist);
out:
g_signal_stop_emission_by_name(treeview, "drag_data_received");
gtk_drag_finish(context, true, true, time);
}
bool __gui_playlist_init_idle()
{
struct playlist *playlist = playlist_current();
GtkTreeModel *filter = GTK_TREE_MODEL(gui_sidebar_filter());
GtkTreeIter iter;
gtk_tree_model_get_iter_first(filter, &iter);
do {
gui_sidebar_filter_set_expand(&iter);
} while (gtk_tree_model_iter_next(filter, &iter));
select_playlist[playlist->pl_type](playlist);
return true;
}
void gui_playlist_init()
{
gui_pl_system_init();
gui_pl_artist_init();
gui_pl_user_init();
gui_pl_library_init();
idle_schedule(IDLE_SYNC, __gui_playlist_init_idle, NULL);
}

70
gui/playlists/artist.c Normal file
View File

@ -0,0 +1,70 @@
/*
* Copyright 2016 (c) Anna Schumaker.
*/
#include <core/idle.h>
#include <core/playlist.h>
#include <gui/sidebar.h>
static bool __gui_pl_artist_header(GtkTreeIter *iter)
{
if (gui_sidebar_iter_first(iter))
return gui_sidebar_iter_find(iter, "Collection", PL_SYSTEM);
return false;
}
static bool __gui_pl_artist_init_idle()
{
struct db_entry *artist, *next;
struct playlist *playlist;
GtkTreeIter iter;
if (!__gui_pl_artist_header(&iter))
return false;
db_for_each(artist, next, artist_db_get()) {
playlist = ARTIST(artist)->ar_playlist;
gui_sidebar_iter_sort_child(&iter, playlist, "system-users");
}
return true;
}
void gui_pl_artist_init()
{
idle_schedule(IDLE_SYNC, __gui_pl_artist_init_idle, NULL);
}
bool gui_pl_artist_add(struct playlist *playlist)
{
GtkTreeIter iter;
if (!__gui_pl_artist_header(&iter))
return false;
gui_sidebar_iter_sort_child(&iter, playlist, "system-users");
return true;
}
void gui_pl_artist_update(struct playlist *playlist)
{
GtkTreeIter iter, child;
if (!__gui_pl_artist_header(&iter))
return;
if (!gui_sidebar_iter_down(&iter, &child))
return;
if (gui_sidebar_iter_find(&child, playlist->pl_name, playlist->pl_type))
gui_sidebar_iter_update(&child);
}
void gui_pl_artist_select(struct playlist *playlist)
{
GtkTreeIter iter, child;
if (!__gui_pl_artist_header(&iter))
return;
if (!gui_sidebar_iter_down(&iter, &child))
return;
if (gui_sidebar_iter_find(&child, playlist->pl_name, playlist->pl_type))
gui_sidebar_iter_select(&child);
}

117
gui/playlists/library.c Normal file
View File

@ -0,0 +1,117 @@
/*
* Copyright 2015 (c) Anna Schumaker.
*/
#include <core/idle.h>
#include <core/playlist.h>
#include <gui/idle.h>
#include <gui/playlists/library.h>
#include <gui/sidebar.h>
#include <gui/window.h>
#include <glib/gi18n.h>
void __gui_pl_library_choose(GtkButton *button, gpointer data)
{
GtkFileFilter *filter;
const gchar *music;
GtkWidget *dialog;
gchar *path;
gint res;
filter = gtk_file_filter_new();
gtk_file_filter_add_mime_type(filter, "inode/directory");
dialog = gtk_file_chooser_dialog_new("Add Music", gui_window(),
GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_Open"), GTK_RESPONSE_ACCEPT,
NULL);
gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter);
music = g_get_user_special_dir(G_USER_DIRECTORY_MUSIC);
if (music)
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),
music);
res = gtk_dialog_run(GTK_DIALOG(dialog));
if (res == GTK_RESPONSE_ACCEPT) {
path = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
gui_pl_library_add(path);
g_free(path);
}
gtk_widget_destroy(dialog);
}
static bool __gui_pl_library_header(GtkTreeIter *iter)
{
if (gui_sidebar_iter_first(iter))
return gui_sidebar_iter_find(iter, "Library", PL_MAX_TYPE);
return false;
}
static bool __gui_pl_library_init_idle()
{
struct db_entry *library, *next;
struct playlist *playlist;
GtkTreeIter iter;
if (!__gui_pl_library_header(&iter))
return false;
db_for_each(library, next, library_db_get()) {
playlist = LIBRARY(library)->li_playlist;
gui_sidebar_iter_sort_child(&iter, playlist, "folder");
}
#ifndef CONFIG_TESTING
if (library_db_get()->db_size == 0)
__gui_pl_library_choose(NULL, NULL);
#endif /* CONFIG_TESTING */
return true;
}
void gui_pl_library_init()
{
idle_schedule(IDLE_SYNC, __gui_pl_library_init_idle, NULL);
}
struct playlist *gui_pl_library_add(const gchar *filename)
{
struct playlist *playlist;
GtkTreeIter iter;
if (!__gui_pl_library_header(&iter))
return false;
playlist = playlist_new(PL_LIBRARY, filename);
if (playlist) {
gui_sidebar_iter_sort_child(&iter, playlist, "folder");
gui_idle_enable();
}
return playlist;
}
void gui_pl_library_update(struct playlist *playlist)
{
GtkTreeIter iter, child;
if (!__gui_pl_library_header(&iter))
return;
if (!gui_sidebar_iter_down(&iter, &child))
return;
if (gui_sidebar_iter_find(&child, playlist->pl_name, playlist->pl_type))
gui_sidebar_iter_update(&child);
}
void gui_pl_library_select(struct playlist *playlist)
{
GtkTreeIter iter, child;
if (!__gui_pl_library_header(&iter))
return;
if (!gui_sidebar_iter_down(&iter, &child))
return;
if (gui_sidebar_iter_find(&child, playlist->pl_name, playlist->pl_type))
gui_sidebar_iter_select(&child);
}

139
gui/playlists/system.c Normal file
View File

@ -0,0 +1,139 @@
/*
* Copyright 2016 (c) Anna Schumaker.
*/
#include <core/audio.h>
#include <core/idle.h>
#include <core/playlist.h>
#include <core/string.h>
#include <gui/playlists/system.h>
#include <gui/sidebar.h>
static struct playlist *favorites;
static struct playlist *hidden;
static bool __gui_pl_system_is_playlist(struct playlist *playlist)
{
return string_match(playlist->pl_name, "Favorites") ||
string_match(playlist->pl_name, "Hidden");
}
static bool __gui_pl_system_is_dynamic(struct playlist *playlist)
{
return string_match(playlist->pl_name, "Most Played") ||
string_match(playlist->pl_name, "Least Played") ||
string_match(playlist->pl_name, "Unplayed");
}
static bool __gui_pl_system_find_descend_header(GtkTreeIter *iter,
const gchar *name)
{
GtkTreeIter header;
if (!gui_sidebar_iter_first(&header))
return false;
if (!gui_sidebar_iter_find(&header, name, PL_MAX_TYPE))
return false;
return gui_sidebar_iter_down(&header, iter);
}
void __gui_pl_system_favorite_toggled(GtkToggleButton *toggle, gpointer data)
{
if (gtk_toggle_button_get_active(toggle))
playlist_add(favorites, audio_cur_track());
else
playlist_remove(favorites, audio_cur_track());
}
void __gui_pl_system_hide_toggled(GtkToggleButton *toggle, gpointer data)
{
if (gtk_toggle_button_get_active(toggle)) {
if (playlist_add(hidden, audio_cur_track()))
audio_next();
} else
playlist_remove(hidden, audio_cur_track());
}
static bool __gui_pl_system_init_idle()
{
GtkTreeIter iter;
/* Add toplevel playlists. */
gui_sidebar_iter_first(&iter);
gui_sidebar_iter_add(&iter, playlist_lookup(PL_SYSTEM, "Queued Tracks"),
"audio-x-generic");
gui_sidebar_iter_add(&iter, playlist_lookup(PL_SYSTEM, "Collection"),
"media-optical");
gui_sidebar_iter_add(&iter, playlist_lookup(PL_SYSTEM, "History"),
"document-open-recent");
/* Add user-modifiable playlists. */
gui_sidebar_iter_find(&iter, "Playlists", PL_MAX_TYPE);
gui_sidebar_iter_append_child(&iter, playlist_lookup(PL_SYSTEM, "Favorites"),
"emblem-favorite");
gui_sidebar_iter_append_child(&iter, playlist_lookup(PL_SYSTEM, "Hidden"),
"window-close");
/* Add dynamic playlists. */
gui_sidebar_iter_find(&iter, "Dynamic", PL_MAX_TYPE);
gui_sidebar_iter_append_child(&iter, playlist_lookup(PL_SYSTEM, "Most Played"),
"go-up");
gui_sidebar_iter_append_child(&iter, playlist_lookup(PL_SYSTEM, "Least Played"),
"go-down");
gui_sidebar_iter_append_child(&iter, playlist_lookup(PL_SYSTEM, "Unplayed"),
"audio-x-generic");
return true;
}
void gui_pl_system_init()
{
favorites = playlist_lookup(PL_SYSTEM, "Favorites");
hidden = playlist_lookup(PL_SYSTEM, "Hidden");
idle_schedule(IDLE_SYNC, __gui_pl_system_init_idle, NULL);
}
void gui_pl_system_update(struct playlist *playlist)
{
GtkTreeIter iter;
if (__gui_pl_system_is_playlist(playlist)) {
if (!__gui_pl_system_find_descend_header(&iter, "Playlists"))
return;
} else if (__gui_pl_system_is_dynamic(playlist)) {
if (!__gui_pl_system_find_descend_header(&iter, "Dynamic"))
return;
} else {
if (!gui_sidebar_iter_first(&iter))
return;
}
if (gui_sidebar_iter_find(&iter, playlist->pl_name, playlist->pl_type))
gui_sidebar_iter_update(&iter);
}
void gui_pl_system_select(struct playlist *playlist)
{
GtkTreeIter iter;
if (__gui_pl_system_is_playlist(playlist)) {
if (!__gui_pl_system_find_descend_header(&iter, "Playlists"))
return;
} else if (__gui_pl_system_is_dynamic(playlist)) {
if (!__gui_pl_system_find_descend_header(&iter, "Dynamic"))
return;
} else {
if (!gui_sidebar_iter_first(&iter))
return;
}
if (gui_sidebar_iter_find(&iter, playlist->pl_name, playlist->pl_type))
gui_sidebar_iter_select(&iter);
}
void gui_pl_system_track_loaded(struct track *track)
{
gtk_toggle_button_set_active(gui_favorite_button(),
playlist_has(favorites, track));
gtk_toggle_button_set_active(gui_hide_button(),
playlist_has(hidden, track));
}

153
gui/playlists/user.c Normal file
View File

@ -0,0 +1,153 @@
/*
* Copyright 2016 (c) Anna Schumaker.
*/
#include <core/idle.h>
#include <core/playlist.h>
#include <gui/sidebar.h>
#include <gui/window.h>
#include <glib/gi18n.h>
static bool __gui_pl_user_header(GtkTreeIter *iter)
{
if (gui_sidebar_iter_first(iter))
return gui_sidebar_iter_find(iter, "Playlists", PL_MAX_TYPE);
return false;
}
static gint __gui_pl_user_compare(gconstpointer a, gconstpointer b)
{
struct playlist *pl_a = (struct playlist *)a;
struct playlist *pl_b = (struct playlist *)b;
return g_utf8_collate(pl_a->pl_name, pl_b->pl_name);
}
static bool __gui_pl_user_init_idle()
{
struct db_entry *user, *next;
struct playlist *playlist;
GtkTreeIter iter;
if (!__gui_pl_user_header(&iter))
return false;
db_for_each(user, next, pl_user_db_get()) {
playlist = &USER_PLAYLIST(user)->pl_playlist;
gui_sidebar_iter_sort_child(&iter, playlist, "text-x-generic");
}
return true;
}
void __gui_pl_user_editing_started(GtkCellRenderer *renderer,
GtkCellEditable *editable,
gchar *path, gpointer data)
{
struct playlist *playlist;
GtkTreeIter iter;
if (!gui_sidebar_iter_from_string(path, &iter))
return;
playlist = gui_sidebar_iter_playlist(&iter);
if (GTK_IS_ENTRY(editable))
gtk_entry_set_text(GTK_ENTRY(editable), playlist->pl_name);
}
void __gui_pl_user_edited(GtkCellRendererText *renderer, gchar *path,
gchar *new_name, gpointer data)
{
struct playlist *playlist;
GtkTreeIter iter;
if (!gui_sidebar_iter_from_string(path, &iter))
return;
playlist = gui_sidebar_iter_playlist(&iter);
pl_user_rename(playlist, new_name);
gui_sidebar_iter_update_playlist(&iter, playlist);
gui_sidebar_iter_set_editable(&iter, false);
}
void gui_pl_user_init()
{
idle_schedule(IDLE_SYNC, __gui_pl_user_init_idle, NULL);
}
struct playlist *gui_pl_user_add(const gchar *name)
{
struct playlist *playlist;
GtkTreeIter iter;
if (!__gui_pl_user_header(&iter))
return NULL;
playlist = playlist_new(PL_USER, name);
if (playlist)
gui_sidebar_iter_sort_child(&iter, playlist, "text-x-generic");
return playlist;
}
struct playlist *gui_pl_user_add_dialog(void)
{
unsigned int flags = GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL;
GtkWidget *entry, *dialog, *content;
struct playlist *playlist = NULL;
entry = gtk_entry_new();
dialog = gtk_dialog_new_with_buttons("New Playlist Name?",
gui_window(), flags,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_OK"), GTK_RESPONSE_ACCEPT,
NULL);
content = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
gtk_entry_set_activates_default(GTK_ENTRY(entry), true);
gtk_container_add(GTK_CONTAINER(content), entry);
gtk_widget_show_all(dialog);
if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
playlist = gui_pl_user_add(gtk_entry_get_text(GTK_ENTRY(entry)));
gtk_widget_destroy(dialog);
return playlist;
}
void gui_pl_user_update(struct playlist *playlist)
{
GtkTreeIter iter, child;
if (!__gui_pl_user_header(&iter))
return;
if (!gui_sidebar_iter_down(&iter, &child))
return;
if (gui_sidebar_iter_find(&child, playlist->pl_name, playlist->pl_type))
gui_sidebar_iter_update(&child);
}
void gui_pl_user_select(struct playlist *playlist)
{
GtkTreeIter iter, child;
if (!__gui_pl_user_header(&iter))
return;
if (!gui_sidebar_iter_down(&iter, &child))
return;
if (gui_sidebar_iter_find(&child, playlist->pl_name, playlist->pl_type))
gui_sidebar_iter_select(&child);
}
GList *gui_pl_user_list(void)
{
struct db_entry *user, *next;
struct playlist *playlist;
GList *list = NULL;
db_for_each(user, next, pl_user_db_get()) {
playlist = &USER_PLAYLIST(user)->pl_playlist;
list = g_list_insert_sorted(list, playlist,
__gui_pl_user_compare);
}
return list;
}

508
gui/sidebar.c Normal file
View File

@ -0,0 +1,508 @@
/*
* Copyright 2015 (c) Anna Schumaker.
*/
#include <core/settings.h>
#include <core/string.h>
#include <gui/model.h>
#include <gui/sidebar.h>
#include <gui/treeview.h>
enum sidebar_columns {
SB_IMAGE,
SB_NAME,
SB_TYPE,
SB_EDITABLE,
};
const gchar *SIDEBAR_SETTING = "gui.sidebar.pos";
static gchar *__gui_sidebar_size_str(struct playlist *playlist)
{
const gchar *fmt = "%s\n%d track%s";
unsigned int size;
if (!playlist)
return NULL;
size = playlist_size(playlist);
if (playlist_current() == playlist)
fmt = "<b>%s\n%d track%s</b>";
return g_markup_printf_escaped(fmt, playlist->pl_name, size,
(size != 1) ? "s" : "");
}
static void __gui_sidebar_set(GtkTreeIter *iter, const gchar *name,
const gchar *image, enum playlist_type_t type)
{
gtk_tree_store_set(gui_sidebar_store(), iter, SB_NAME, name,
SB_IMAGE, image,
SB_TYPE, type,
SB_EDITABLE, false, -1);
}
static void __gui_sidebar_set_playlist(GtkTreeIter *iter,
struct playlist *playlist,
const gchar *image)
{
gchar *text = __gui_sidebar_size_str(playlist);
__gui_sidebar_set(iter, text, image, playlist->pl_type);
g_free(text);
}
static void __gui_sidebar_add_header(GtkTreeIter *iter, const gchar *name,
const gchar *image)
{
gchar *formatted = g_strdup_printf("<big>%s</big>", name);
gtk_tree_store_insert(gui_sidebar_store(), iter, NULL, -1);
__gui_sidebar_set(iter, NULL, NULL, PL_MAX_TYPE);
gtk_tree_store_insert(gui_sidebar_store(), iter, NULL, -1);
__gui_sidebar_set(iter, formatted, image, PL_MAX_TYPE);
g_free(formatted);
}
static int __gui_sidebar_compare(GtkTreeIter *iter, const gchar *name,
enum playlist_type_t type)
{
gchar *cur;
int ret;
if (gui_sidebar_iter_type(iter) != type)
return gui_sidebar_iter_type(iter) - type;
cur = gui_sidebar_iter_name(iter);
ret = g_utf8_collate(cur, name);
g_free(cur);
return ret;
}
static inline void __gui_sidebar_filter_iter_convert(GtkTreeIter *iter,
GtkTreeIter *child)
{
gtk_tree_model_filter_convert_iter_to_child_iter(gui_sidebar_filter(),
child, iter);
}
static gchar *__gui_sidebar_filter_iter_name(GtkTreeIter *iter)
{
GtkTreeIter child;
__gui_sidebar_filter_iter_convert(iter, &child);
return gui_sidebar_iter_name(&child);
}
static gboolean __gui_sidebar_visible_func(GtkTreeModel *model,
GtkTreeIter *iter,
gpointer data)
{
enum playlist_type_t type = gui_sidebar_iter_type(iter);
if (type == PL_SYSTEM || type == PL_ARTIST)
return playlist_size(gui_sidebar_iter_playlist(iter)) > 0;
return TRUE;
}
static gboolean __gui_sidebar_can_select(GtkTreeSelection *selection,
GtkTreeModel *model, GtkTreePath *path,
gboolean selected, gpointer data)
{
GtkTreeIter iter, child;
gtk_tree_model_get_iter(model, &iter, path);
__gui_sidebar_filter_iter_convert(&iter, &child);
return gui_sidebar_iter_type(&child) != PL_MAX_TYPE;
}
void __gui_sidebar_selection_changed(GtkTreeSelection *selection, gpointer data)
{
bool active = false, sensitive = false;
struct playlist *playlist = NULL;
GtkTreeIter iter;
if (gui_sidebar_iter_current(&iter)) {
playlist = gui_sidebar_iter_playlist(&iter);
active = playlist->pl_random;
sensitive = (playlist->pl_ops->pl_set_random != NULL);
}
gui_treeview_set_playlist(playlist);
gtk_toggle_button_set_active(gui_random_button(), active);
gtk_widget_set_sensitive(GTK_WIDGET(gui_random_button()), sensitive);
}
static void __gui_sidebar_do_rename(GtkTreePath *path)
{
GtkTreeView *treeview = gui_sidebar_treeview();
GtkTreeModel *model = gtk_tree_view_get_model(treeview);
GtkTreeViewColumn *column = gtk_tree_view_get_column(treeview, SB_NAME);
GtkTreeIter iter, child;
if (!gtk_tree_model_get_iter(model, &iter, path))
return;
__gui_sidebar_filter_iter_convert(&iter, &child);
gui_sidebar_iter_set_editable(&child, true);
gtk_tree_view_set_cursor(treeview, path, column, true);
}
static GtkTreePath *__gui_sidebar_current_path(void)
{
GtkTreeView *treeview = gui_sidebar_treeview();
GtkTreeSelection *selection = gtk_tree_view_get_selection(treeview);
GtkTreeModel *model = gtk_tree_view_get_model(treeview);
GtkTreeIter iter;
if (!gtk_tree_selection_get_selected(selection, &model, &iter))
return NULL;
return gtk_tree_model_get_path(model, &iter);
}
bool __gui_sidebar_rename(GtkMenuItem *item, gpointer data)
{
GtkTreePath *path = __gui_sidebar_current_path();
if (path) {
__gui_sidebar_do_rename(path);
gtk_tree_path_free(path);
}
return path != NULL;
}
bool __gui_sidebar_select(GtkMenuItem *item, gpointer data)
{
GtkTreeView *treeview = gui_sidebar_treeview();
GtkTreePath *path = __gui_sidebar_current_path();
if (path) {
gtk_tree_view_row_activated(treeview, path, NULL);
gtk_tree_path_free(path);
}
return path != NULL;
}
bool __gui_sidebar_delete(GtkMenuItem *item, gpointer data)
{
GtkTreeIter iter;
if (!gui_sidebar_iter_current(&iter))
return false;
if (playlist_delete(gui_model_get_playlist()))
gtk_tree_store_remove(gui_sidebar_store(), &iter);
return true;
}
bool __gui_sidebar_keypress(GtkTreeView *treeview, GdkEventKey *event,
gpointer data)
{
switch (event->keyval) {
case GDK_KEY_BackSpace:
return __gui_sidebar_rename(NULL, NULL);
case GDK_KEY_Return:
return __gui_sidebar_select(NULL, NULL);
case GDK_KEY_Delete:
return __gui_sidebar_delete(NULL, NULL);
default:
return false;
}
}
bool __gui_sidebar_button_press(GtkTreeView *treeview, GdkEventButton *event,
gpointer data)
{
enum playlist_type_t type = PL_MAX_TYPE;
GtkTreePath *path;
GtkTreeIter iter;
bool ret = true;
if (!gtk_tree_view_get_path_at_pos(treeview, event->x, event->y,
&path, NULL, NULL, NULL))
return false;
if (event->button == GDK_BUTTON_SECONDARY) {
gtk_tree_view_set_cursor(treeview, path, NULL, false);
if (gui_sidebar_iter_current(&iter))
type = gui_sidebar_iter_type(&iter);
gtk_widget_set_visible(gui_builder_widget("rc_sidebar_rename"),
type == PL_USER);
gtk_menu_popup_at_pointer(gui_sidebar_menu(), (GdkEvent *)event);
} else if (event->type == GDK_2BUTTON_PRESS &&
event->button == GDK_BUTTON_MIDDLE) {
__gui_sidebar_do_rename(path);
} else
ret = false;
gtk_tree_path_free(path);
return ret;
}
void __gui_sidebar_resized(GtkPaned *pane, GParamSpec *pspec, gpointer data)
{
settings_set(SIDEBAR_SETTING, gtk_paned_get_position(pane));
}
void __gui_sidebar_random_toggled(GtkToggleButton *button, gpointer data)
{
struct playlist *playlist = gui_model_get_playlist();
bool active = gtk_toggle_button_get_active(button);
if (playlist)
playlist_set_random(playlist, active);
}
void gui_sidebar_init()
{
int pos = settings_get(SIDEBAR_SETTING);
GtkTreeSelection *selection;
GtkTreeIter iter;
gtk_tree_view_enable_model_drag_dest(gui_sidebar_treeview(),
gui_model_drag_targets, gui_model_n_targets,
GDK_ACTION_MOVE);
if (!gui_sidebar_iter_first(&iter)) {
__gui_sidebar_add_header(&iter, "Playlists", "emblem-documents");
__gui_sidebar_add_header(&iter, "Dynamic", "emblem-generic");
__gui_sidebar_add_header(&iter, "Library", "emblem-system");
selection = gtk_tree_view_get_selection(gui_sidebar_treeview());
gtk_tree_selection_set_select_function(selection,
__gui_sidebar_can_select,
NULL, NULL);
gtk_tree_model_filter_set_visible_func(gui_sidebar_filter(),
__gui_sidebar_visible_func,
NULL, NULL);
}
if (pos > 0)
gtk_paned_set_position(gui_sidebar(), pos);
}
gboolean gui_sidebar_iter_current(GtkTreeIter *iter)
{
GtkTreeView *treeview = gui_sidebar_treeview();
GtkTreeSelection *selection = gtk_tree_view_get_selection(treeview);
GtkTreeModel *model = GTK_TREE_MODEL(gui_sidebar_filter());
GtkTreeIter it;
if (!gtk_tree_selection_get_selected(selection, &model, &it))
return false;
__gui_sidebar_filter_iter_convert(&it, iter);
return true;
}
gboolean gui_sidebar_iter_first(GtkTreeIter *iter)
{
return gtk_tree_model_get_iter_first(gui_sidebar_model(), iter);
}
gboolean gui_sidebar_iter_next(GtkTreeIter *iter)
{
return gtk_tree_model_iter_next(gui_sidebar_model(), iter);
}
gboolean gui_sidebar_iter_down(GtkTreeIter *iter, GtkTreeIter *child)
{
return gtk_tree_model_iter_children(gui_sidebar_model(), child, iter);
}
gchar *gui_sidebar_iter_name(GtkTreeIter *iter)
{
gchar *text = NULL, *parsed = NULL, *name, **split;
gtk_tree_model_get(gui_sidebar_model(), iter, SB_NAME, &text, -1);
if (!text)
return g_strdup("");
pango_parse_markup(text, -1, 0, NULL, &parsed, NULL, NULL);
if (!parsed)
return g_strdup("");
split = g_strsplit(parsed, "\n", 2);
name = g_strdup(split[0]);
g_strfreev(split);
g_free(parsed);
g_free(text);
return name;
}
enum playlist_type_t gui_sidebar_iter_type(GtkTreeIter *iter)
{
enum playlist_type_t type;
gtk_tree_model_get(gui_sidebar_model(), iter, SB_TYPE, &type, -1);
return type;
}
bool gui_sidebar_iter_editable(GtkTreeIter *iter)
{
gboolean editable;
gtk_tree_model_get(gui_sidebar_model(), iter, SB_EDITABLE, &editable, -1);
return editable == TRUE;
}
struct playlist *gui_sidebar_iter_playlist(GtkTreeIter *iter)
{
enum playlist_type_t type = gui_sidebar_iter_type(iter);
gchar *name = gui_sidebar_iter_name(iter);
struct playlist *playlist = playlist_lookup(type, name);
g_free(name);
return playlist;
}
void gui_sidebar_iter_add(GtkTreeIter *iter, struct playlist *playlist,
const gchar *image)
{
GtkTreeIter new;
gtk_tree_store_insert_before(gui_sidebar_store(), &new, NULL, iter);
__gui_sidebar_set_playlist(&new, playlist, image);
}
void gui_sidebar_iter_sort_child(GtkTreeIter *iter, struct playlist *playlist,
const gchar *image)
{
GtkTreeIter child, new;
if (!gui_sidebar_iter_down(iter, &child))
goto out_append;
do {
if (__gui_sidebar_compare(&child, playlist->pl_name,
playlist->pl_type) >= 0) {
gtk_tree_store_insert_before(gui_sidebar_store(),
&new, iter, &child);
__gui_sidebar_set_playlist(&new, playlist, image);
return;
}
} while (gui_sidebar_iter_next(&child));
out_append:
gui_sidebar_iter_append_child(iter, playlist, image);
}
void gui_sidebar_iter_append_child(GtkTreeIter *iter, struct playlist *playlist,
const gchar *image)
{
GtkTreeIter new;
gtk_tree_store_insert_before(gui_sidebar_store(), &new, iter, NULL);
__gui_sidebar_set_playlist(&new, playlist, image);
}
void gui_sidebar_iter_update_playlist(GtkTreeIter *iter,
struct playlist *playlist)
{
gchar *text;
if (!playlist)
return;
text = __gui_sidebar_size_str(playlist);
gtk_tree_store_set(gui_sidebar_store(), iter, SB_NAME, text, -1);
g_free(text);
}
void gui_sidebar_iter_update(GtkTreeIter *iter)
{
gui_sidebar_iter_update_playlist(iter, gui_sidebar_iter_playlist(iter));
}
void gui_sidebar_iter_select(GtkTreeIter *iter)
{
GtkTreeSelection *selection;
GtkTreeIter filter;
gtk_tree_model_filter_convert_child_iter_to_iter(gui_sidebar_filter(),
&filter, iter);
selection = gtk_tree_view_get_selection(gui_sidebar_treeview());
gtk_tree_selection_select_iter(selection, &filter);
}
bool gui_sidebar_iter_set_editable(GtkTreeIter *iter, bool editable)
{
enum playlist_type_t type = gui_sidebar_iter_type(iter);
if (type != PL_USER)
return false;
gtk_tree_store_set(gui_sidebar_store(), iter, SB_EDITABLE, editable, -1);
return true;
}
void gui_sidebar_filter_path_select(GtkTreePath *path)
{
GtkTreeModel *model = GTK_TREE_MODEL(gui_sidebar_filter());
GtkTreeIter iter, child;
gtk_tree_model_get_iter(model, &iter, path);
__gui_sidebar_filter_iter_convert(&iter, &child);
if (playlist_select(gui_sidebar_iter_playlist(&child)))
gui_sidebar_iter_update(&child);
}
void gui_sidebar_filter_set_expand(GtkTreeIter *iter)
{
gchar *name = __gui_sidebar_filter_iter_name(iter);
gchar *setting = g_strdup_printf("gui.sidebar.expand.%s", name);
GtkTreePath *path;
if (settings_get(setting) == true) {
path = gtk_tree_model_get_path(
GTK_TREE_MODEL(gui_sidebar_filter()), iter);
gtk_tree_view_expand_row(gui_sidebar_treeview(), path, false);
gtk_tree_path_free(path);
}
g_free(setting);
g_free(name);
}
void gui_sidebar_filter_row_expanded(GtkTreeIter *iter, bool expanded)
{
gchar *name = __gui_sidebar_filter_iter_name(iter);
gchar *setting = g_strdup_printf("gui.sidebar.expand.%s", name);
settings_set(setting, expanded);
g_free(setting);
g_free(name);
}
gboolean gui_sidebar_iter_find(GtkTreeIter *iter, const gchar *name,
enum playlist_type_t type)
{
do {
if (__gui_sidebar_compare(iter, name, type) == 0)
return TRUE;
} while (gui_sidebar_iter_next(iter));
return FALSE;
}
gboolean gui_sidebar_iter_from_string(const gchar *path, GtkTreeIter *child)
{
GtkTreeModel *model = GTK_TREE_MODEL(gui_sidebar_filter());
GtkTreeIter iter;
if (!gtk_tree_model_get_iter_from_string(model, &iter, path))
return FALSE;
__gui_sidebar_filter_iter_convert(&iter, child);
return TRUE;
}
gboolean gui_sidebar_iter_from_xy(gint x, gint y, GtkTreeIter *child)
{
GtkTreeModel *model = GTK_TREE_MODEL(gui_sidebar_filter());
GtkTreePath *path;
GtkTreeIter iter;
if (!gtk_tree_view_get_path_at_pos(gui_sidebar_treeview(), x, y,
&path, NULL, NULL, NULL))
return false;
gtk_tree_model_get_iter(model, &iter, path);
__gui_sidebar_filter_iter_convert(&iter, child);
gtk_tree_path_free(path);
return true;
}

289
gui/treeview.c Normal file
View File

@ -0,0 +1,289 @@
/*
* Copyright 2016 (c) Anna Schumaker.
*/
#include <core/settings.h>
#include <gui/filter.h>
#include <gui/model.h>
#include <gui/treeview.h>
#include <stdlib.h>
struct col_map_entry {
enum compare_t compare;
const gchar *setting;
};
static const struct col_map_entry GUI_COL_MAP[GUI_MODEL_N_COLUMNS] = {
[GUI_MODEL_TRACK_NR] = { COMPARE_TRACK, "gui.queue.track" },
[GUI_MODEL_TITLE] = { COMPARE_TITLE, "gui.queue.title" },
[GUI_MODEL_LENGTH] = { COMPARE_LENGTH, "gui.queue.length" },
[GUI_MODEL_ARTIST] = { COMPARE_ARTIST, "gui.queue.artist" },
[GUI_MODEL_ALBUM] = { COMPARE_ALBUM, "gui.queue.album" },
[GUI_MODEL_YEAR] = { COMPARE_YEAR, "gui.queue.year" },
[GUI_MODEL_GENRE] = { COMPARE_GENRE, "gui.queue.genre" },
[GUI_MODEL_COUNT] = { COMPARE_COUNT, "gui.queue.count" },
[GUI_MODEL_LAST_PLAY] = { COMPARE_PLAYED, NULL },
};
static unsigned int sort_count = 0;
static gchar *sort_text = NULL;
static bool can_scroll = true;
static int __gui_treeview_colum_match_sort(enum compare_t compare)
{
struct playlist *playlist = gui_model_get_playlist();
GSList *cur = playlist ? playlist->pl_sort : NULL;
while (cur) {
int field = GPOINTER_TO_INT(cur->data);
if (abs(field) == compare)
return field;
cur = g_slist_next(cur);
}
return 0;
}
static void __gui_treeview_set_sort_indicators()
{
GtkTreeViewColumn *col;
unsigned int i, order;
int field;
for (i = 0; i < GUI_MODEL_N_COLUMNS; i++) {
col = gtk_tree_view_get_column(gui_treeview(), i);
if (!col)
continue;
field = __gui_treeview_colum_match_sort(GUI_COL_MAP[i].compare);
order = (field > 0) ? GTK_SORT_ASCENDING : GTK_SORT_DESCENDING;
gtk_tree_view_column_set_sort_indicator(col, field != 0);
gtk_tree_view_column_set_sort_order(col, order);
}
}
static void __gui_treeview_clear_sorting()
{
sort_count = 0;
if (sort_text) {
g_free(sort_text);
sort_text = NULL;
gtk_label_set_text(gui_sorting(), "");
}
}
static void __gui_treeview_set_sorting(gchar *text)
{
gchar *formatted;
__gui_treeview_clear_sorting();
if (!text)
return;
sort_text = g_strdup(text);
formatted = g_strdup_printf("Sorting: {%s}", text);
gtk_label_set_text(gui_sorting(), formatted);
g_free(formatted);
}
static int __gui_treeview_dec_sort(gpointer data)
{
if (sort_count > 0)
sort_count--;
if (sort_count == 0)
__gui_treeview_clear_sorting();
return FALSE;
}
static gchar *__gui_treeview_sort_text_append(GtkTreeViewColumn *col)
{
const gchar *title = gtk_tree_view_column_get_title(col);
gchar *text, **split;
unsigned int i;
if (!sort_text)
return g_strdup(title);
if (gtk_tree_view_column_get_sort_order(col) == GTK_SORT_ASCENDING)
return g_strdup_printf("%s, %s", sort_text, title);
/* Find the column and prefix it with a minus sign */
split = g_strsplit(sort_text, ", ", 0);
for (i = 0; split[i] != NULL; i++) {
if (g_strcmp0(split[i], title) == 0)
break;
}
g_free(split[i]);
split[i] = g_strdup_printf("-%s", title);
text = g_strjoinv(", ", split);
g_strfreev(split);
return text;
}
static void __gui_treeview_column_clicked(GtkTreeViewColumn *col,
gpointer data)
{
struct playlist *playlist = gui_model_get_playlist();
enum compare_t compare = GPOINTER_TO_UINT(data);
gchar *text;
if (!playlist)
return;
if (sort_count == 0)
playlist_clear_sort(playlist);
if (!playlist_sort(playlist, compare))
return;
__gui_treeview_set_sort_indicators();
text = __gui_treeview_sort_text_append(col);
__gui_treeview_set_sorting(text);
g_free(text);
sort_count++;
g_timeout_add_seconds(3, __gui_treeview_dec_sort, NULL);
}
void __gui_treeview_column_resized(GtkTreeViewColumn *col, GParamSpec *pspec,
gpointer data)
{
settings_set(GUI_COL_MAP[GPOINTER_TO_UINT(data)].setting,
gtk_tree_view_column_get_width(col));
}
void __gui_treeview_row_activated(GtkTreeView *treeview, GtkTreePath *path,
GtkTreeViewColumn *col, gpointer data)
{
can_scroll = false;
gui_filter_path_load_track(path);
can_scroll = true;
}
void __gui_treeview_drag_data_received(GtkTreeView *treeview, GdkDragContext *context,
gint x, gint y, GtkSelectionData *data,
guint info, guint time, gpointer user_data)
{
struct gui_model_drag_data *drag_data;
unsigned int to, from;
GtkTreePath *path;
drag_data = (void *)gtk_selection_data_get_data(data);
if (gtk_tree_view_get_path_at_pos(gui_treeview(), x, y,
&path, NULL, NULL, NULL))
gtk_tree_path_prev(path);
else if (!gtk_tree_view_get_visible_range(gui_treeview(), NULL, &path))
return;
from = drag_data->drag_row;
to = gui_filter_path_get_index(path);
if (playlist_rearrange(gui_model_get_playlist(), from, to)) {
gtk_tree_selection_unselect_all(gui_treeview_selection());
gtk_tree_selection_select_path(gui_treeview_selection(), path);
__gui_treeview_set_sort_indicators();
}
g_signal_stop_emission_by_name(treeview, "drag_data_received");
gtk_drag_finish(context, true, true, time);
gtk_tree_path_free(path);
}
bool __gui_treeview_drag_drop(GtkTreeView *treeview, GdkDragContext *context,
gint x, gint y, guint time, gpointer user_data)
{
gtk_drag_get_data(GTK_WIDGET(treeview), context,
gdk_atom_intern(GUI_DRAG_DATA, false), time);
return true;
}
void gui_treeview_init()
{
GtkTreeViewColumn *col;
int i, pos;
gtk_tree_view_set_model(gui_treeview(),
GTK_TREE_MODEL(gui_filter_get()));
gtk_tree_view_enable_model_drag_source(gui_treeview(), GDK_BUTTON1_MASK,
gui_model_drag_targets, gui_model_n_targets,
GDK_ACTION_MOVE);
gtk_tree_view_enable_model_drag_dest(gui_treeview(),
gui_model_drag_targets, gui_model_n_targets,
GDK_ACTION_MOVE);
for (i = 0; i < GUI_MODEL_N_COLUMNS; i++) {
col = gtk_tree_view_get_column(gui_treeview(), i);
if (col) {
g_signal_connect(col, "clicked",
G_CALLBACK(__gui_treeview_column_clicked),
GUINT_TO_POINTER(GUI_COL_MAP[i].compare));
g_signal_connect(col, "notify::width",
G_CALLBACK(__gui_treeview_column_resized),
GUINT_TO_POINTER(i));
pos = settings_get(GUI_COL_MAP[i].setting);
if (pos > 0)
gtk_tree_view_column_set_fixed_width(col, pos);
}
}
}
void gui_treeview_deinit()
{
__gui_treeview_clear_sorting();
}
void gui_treeview_set_playlist(struct playlist *playlist)
{
gui_filter_set_playlist(playlist);
__gui_treeview_clear_sorting();
__gui_treeview_set_sort_indicators();
gui_treeview_scroll();
}
void gui_treeview_scroll()
{
int pos = playlist_current_index(gui_model_get_playlist());
GtkTreePath *path;
if (!can_scroll || pos < 0)
return;
path = gui_filter_path_from_index(pos);
if (!path)
return;
gtk_tree_view_set_cursor(gui_treeview(), path, NULL, false);
gtk_tree_view_scroll_to_cell(gui_treeview(), path, NULL, true, 0.5, 0.5);
gtk_tree_path_free(path);
}
void gui_treeview_select_path_at_pos(unsigned int x, unsigned int y)
{
GtkTreePath *path;
if (gtk_tree_view_get_path_at_pos(gui_treeview(), x, y,
&path, NULL, NULL, NULL))
{
gtk_tree_selection_select_path(gui_treeview_selection(), path);
gtk_tree_path_free(path);
}
}
GList *gui_treeview_list_selected_tracks(void)
{
GtkTreeSelection *selection = gui_treeview_selection();
GList *rows = gtk_tree_selection_get_selected_rows(selection, NULL);
GList *cur = g_list_first(rows);
GList *list = NULL;
while (cur) {
list = g_list_append(list, gui_filter_path_get_track(cur->data));
cur = g_list_next(cur);
}
g_list_free_full(rows, (GDestroyNotify) gtk_tree_path_free);
gtk_tree_selection_unselect_all(selection);
return list;
}

88
gui/window.c Normal file
View File

@ -0,0 +1,88 @@
/*
* Copyright 2014 (c) Anna Schumaker.
*/
#include <core/settings.h>
#include <core/version.h>
#include <gui/window.h>
static const gchar *SETTINGS_WIDTH = "gui.window.width";
static const gchar *SETTINGS_HEIGHT = "gui.window.height";
static const gchar *SETTINGS_X = "gui.window.x";
static const gchar *SETTINGS_Y = "gui.window.y";
static int saved_width = 0;
static int saved_height = 0;
static int saved_x = 0;
static int saved_y = 0;
gboolean __window_configure(GtkWindow *window, GdkEventConfigure *event,
gpointer data)
{
int width = settings_get(SETTINGS_WIDTH);
int height = settings_get(SETTINGS_HEIGHT);
int x = settings_get(SETTINGS_X);
int y = settings_get(SETTINGS_Y);
if (event->width != width) {
saved_width = width;
settings_set(SETTINGS_WIDTH, event->width);
}
if (event->height != height) {
saved_height = height;
settings_set(SETTINGS_HEIGHT, event->height);
}
if (event->x != x) {
saved_x = x;
settings_set(SETTINGS_X, event->x);
}
if (event->y != y) {
saved_y = y;
settings_set(SETTINGS_Y, event->y);
}
return FALSE;
}
gboolean __window_state(GtkWindow *window, GdkEventWindowState *event,
gpointer data)
{
if (event->changed_mask & GDK_WINDOW_STATE_MAXIMIZED &&
event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) {
settings_set(SETTINGS_WIDTH, saved_width);
settings_set(SETTINGS_HEIGHT, saved_height);
settings_set(SETTINGS_X, saved_x);
settings_set(SETTINGS_Y, saved_y);
}
return FALSE;
}
void gui_window_init(const gchar *icon)
{
gchar *title = g_strdup_printf("Ocarina %s", get_version());
gtk_window_set_title(gui_window(), title);
gtk_window_set_icon_from_file(gui_window(), icon, NULL);
saved_width = settings_get(SETTINGS_WIDTH);
saved_height = settings_get(SETTINGS_HEIGHT);
saved_x = settings_get(SETTINGS_X);
saved_y = settings_get(SETTINGS_Y);
if (saved_width > 0 || saved_height > 0)
gtk_window_resize(gui_window(), saved_width, saved_height);
if (saved_x > 0 || saved_y > 0)
gtk_window_move(gui_window(), saved_x, saved_y);
g_free(title);
}
void gui_window_deinit()
{
gtk_widget_destroy(GTK_WIDGET(gui_window()));
}

View File

@ -1,61 +0,0 @@
# Bryan Schumaker (11/17/2010)
from libsaria.sources import library
from libsaria import path
splitext = path.splitext
def header(wfile):
wfile.write("<html><head>")
wfile.write("<script type=\"text/javascript\" src=\"controls.js\"></script>\n")
wfile.write("<script type=\"text/javascript\" src=\"utils.js\"></script>\n")
wfile.write("<script type=\"text/javascript\">")
wfile.write("function playSong(id){")
wfile.write("load_id(id);")
#wfile.write("var src=id+ext;")
#wfile.write("var audio = document.getElementById(\"audio\");")
#wfile.write("audio.innerHTML=\"<audio src=\\\"\" + src + \"\\\" controls autoplay></audio>\";")
#wfile.write("return false;")
wfile.write("}")
wfile.write("</script><body>")
def footer(wfile):
wfile.write("</body></html>")
def body(wfile, args):
artist = library.tag_tree[args["artist"]].value
album = library.tag_tree[args["artist"]][args["album"]].value
wfile.write("<table align=center width=75%>")
wfile.write("<tr><td><table align=center>")
wfile.write("<tr><td><font size=7>%s</font></td></tr>" % album)
wfile.write("<tr><td><font size=4>by %s</font></td></tr>" % artist)
wfile.write("</table></td></tr>")
img_ar = artist.replace("/", "%2F")
img_al = album.replace("/", "%2F")
wfile.write("<tr><td><table align=center width=100%><tr>")
wfile.write("<td align=center><table align=center width=100%>")
wfile.write("<tr><td align=center>")
wfile.write("<img src=\"artwork/%s/%s.jpg\" height=192/></td></tr>" % (img_ar, img_al))
wfile.write("<tr><td align=center id=\"audio\"></td></tr></table>")
wfile.write("<td align><table align=left>\n")
titles = []
for title, key in library.titles(args["artist"], args["album"]):
sid = library.song_id(args["artist"], args["album"], key)
track = library.get_attrs(sid, "track")
titles += [(track, sid, title)]
titles.sort()
tags = "<tr><td align=right>%s.</td><td><font onclick=\"playSong('%s');\">%s</font></td></tr>\n"
for id, sid, title in titles:
wfile.write(tags % (id, sid, title))
wfile.write("</table></td>")
wfile.write("</tr></table></td></tr>")
wfile.write("</table>")
def to_html(wfile, args):
header(wfile)
body(wfile, args)
footer(wfile)

View File

@ -1,92 +0,0 @@
<html>
<head>
<script type="text/javascript" src="utils.js"></script>
<script type="text/javascript" src="controls.js"></script>
<script type="text/javascript">
function set_playing()
{
var button = document.getElementById("button");
button.src = "images/pause.png";
button.onclick = pause2;
}
function set_paused()
{
var button = document.getElementById("button");
button.src = "images/play.png";
button.onclick = play2;
}
function set_play_button()
{
var req = new XMLHttpRequest();
req.onreadystatechange = function()
{
if (req.readyState == 4 && req.status == 200)
{
if (req.responseText == "True")
{
set_playing();
} else
{
set_paused();
}
}
}
req.open('GET', "controls.py?a=playing", true);
req.send();
}
function set_play_button_repeating()
{
set_play_button();
setTimeout("set_play_button_repeating()", 3000)
}
function play2()
{
play();
set_play_button();
}
function pause2()
{
pause();
set_play_button();
}
function stop2()
{
stop();
set_play_button();
}
</script>
</head>
<body>
<table>
<tr><td id="title"></td></tr>
<tr><td id="artist"></td></tr>
<tr><td id="album"></td></tr>
</table>
<table><tr>
<td><img id="button" src="images/play.png" onclick="play2();" /></td>
<td><img src="images/stop.png" onclick="stop2();" /></td>
<td><img src="images/next.png" onclick="next();" /></td>
</tr><tr>
<td><img src="images/rewind.png" onclick="rewind();" /></td>
<td><img src="images/forward.png" onclick="forward();" /></td>
</tr></table>
</body>
<script type="text/javascript">
set_attr("title", "title");
set_attr("artist", "artist");
set_attr("album", "album");
set_play_button_repeating();
</script>
</html>

46
html/controls.js vendored
View File

@ -1,46 +0,0 @@
// Bryan Schumaker (12 / 27 / 2010)
function control(action)
{
send_request("RPC/" + action);
}
function play()
{
control("play");
}
function load_id(id)
{
control("load&id="+id);
}
function pause()
{
control("pause");
}
function stop()
{
control("stop");
}
function next()
{
control("next");
}
function forward()
{
control("forward");
}
function rewind()
{
control("rewind");
}
function play_id(id)
{
control("play_id/" + id)
}

View File

@ -1,52 +0,0 @@
# Bryan Schumaker (11/18/2010)
import libsaria.audio
import libsaria.sources
import ocarina
controls = libsaria.controls
play = controls.play
pause = controls.pause
stop = controls.stop
next = controls.next
attrs = libsaria.sources.get_attrs
load_id = libsaria.sources.library.load_id
playing = controls.playing
forward = controls.seek_forward
rewind = controls.seek_backward
def to_html(wfile, args):
action = args["a"]
ret = False
if action == "play":
ret = play()
elif action == "pause":
ret = pause()
elif action == "stop":
ret = stop()
elif action == "next":
ret = next()
elif action == "forward":
ret = forward()
elif action == "rewind":
ret = rewind()
elif action == "version":
ret = ocarina.__vers__
elif action == "uptime":
ret = ocarina.now() - ocarina.__start__
elif action == "title":
ret = attrs("title")
elif action == "album":
ret = "from %s" % attrs("album")
elif action == "artist":
ret = "by %s" % attrs("artist")
elif action == "playing":
ret = playing()
elif action == "load":
load_id(int(args['id']))
play()
#else:
# print action, args
wfile.write(str(ret))

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 875 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 837 B

View File

@ -1,20 +0,0 @@
<html>
<!--<head>
<script type="text/javascript" src="utils.js"></script>-->
</head>
<body>
<table>
<tr><td><a href="library.html">Library Browser</a></td></tr>
<!--<tr><td><a href="library2.py">Library Browser 2</a></td></tr>
<tr><td><a href="controls.html">Remote Controls</a></td></tr>
<tr><td id="vers"></td><td id="up"></td></tr>-->
</table>
<!--<script type="text/javascript">
set_attr_once("version", "vers");
set_attr("uptime", "up");
</script>-->
</body>
</html>

View File

@ -1,24 +0,0 @@
# Bryan Schumaker
import libsaria
library = libsaria.sources.library
walk = library.walk
get_attrs = library.get_attrs
def header(wfile):
wfile.write("<html><body>")
def footer(wfile):
wfile.write("</body></html>")
def body(wfile):
link = "<a href=\"album.py?artist=%s&album=%s\">%s</a><br>"
for artist, ar_key in library.artists():
wfile.write("<h2>%s</h2>" % artist)
for album, al_key in library.albums(ar_key):
wfile.write(link % (ar_key, al_key, album))
#wfile.write("<a href=\"album.py?artist=\">%s</a><br>" % album)
def to_html(wfile, args):
header(wfile)
body(wfile)
footer(wfile)

View File

@ -1,45 +0,0 @@
# Bryan Schumaker (12 / 26 / 2010)
import libsaria
library = libsaria.sources.library
walk = library.walk
get_attrs = library.get_attrs
cols = [("Title", 400), ("Length", 60), ("Artist", 200), ("Album", 200), ("Year", 50)]
def header(wfile):
wfile.write("<html><body>")
def footer(wfile):
wfile.write("</body></html>")
def content_header(wfile):
wfile.write("<table><tr>")
for col, width in cols:
wfile.write("<td style=\"width:%spx;\">%s</td>" % (width, col))
wfile.write("</tr></table>")
wfile.write("<hr>")
def body(wfile):
wfile.write("header stuff goes here")
content_header(wfile)
wfile.write("<div style=\"height:80%;width:100%;overflow:auto;\">")
wfile.write("<table>")
colors = ["white", "aliceblue"]
i = 0
for id in walk():
wfile.write("<tr>")
for index, attr in enumerate(get_attrs(id, "title", "lenstr", "artist", "album", "year")):
wfile.write("<td style=\"width:%spx;background:%s;\">%s</td>" % (cols[index][1], colors[i], attr))
wfile.write("</tr>")
if i == 0:
i = 1
else:
i = 0
wfile.write("</table></div>")
wfile.write("footer stuff goes here")
def to_html(wfile, args):
header(wfile)
body(wfile)
footer(wfile)

View File

@ -1,5 +0,0 @@
function message()
{
document.getElementById("bryan").innerHTML = "Internal javascript test!";
}

View File

@ -1,25 +0,0 @@
# Bryan Schumaker
import libsaria
library = libsaria.sources.library
walk = library.walk
get_attrs = library.get_attrs
def header(wfile):
wfile.write("<html><body>")
def footer(wfile):
wfile.write("</body></html>")
def body(wfile):
wfile.write("<table border=1>")
for id in library.walk():
#attrs = get_attrs(id, "id", "title", "lenstr", "artist", "album", "year")
artist, album, title = library.get_attrs(id, "artist", "album", "title")
wfile.write("<tr><td>%s</td><td>%s</td><td>%s</td></tr>" % (artist, album, title))
wfile.write("</table>")
#wfile.write("Python!!!")
def to_html(wfile):
header(wfile)
body(wfile)
footer(wfile)

View File

@ -1,38 +0,0 @@
// Bryan Schumaker (12 / 27 / 2010)
function set_attr(attr, id)
{
var req = new XMLHttpRequest();
req.onreadystatechange = function()
{
if (req.readyState == 4 && req.status == 200)
{
document.getElementById(id).innerHTML = req.responseText;
}
}
req.open('GET', "controls.py?a=" + attr, true);
req.send();
setTimeout("set_attr(\"" + attr + "\", \"" + id + "\")", 3000)
}
function set_attr_once(attr, id)
{
var req = new XMLHttpRequest();
req.onreadystatechange = function()
{
if (req.readyState == 4 && req.status == 200)
{
document.getElementById(id).innerHTML = req.responseText;
}
}
req.open('GET', "controls.py?a=" + attr, true);
req.send();
}
function send_request(url)
{
var http = new XMLHttpRequest();
http.open('GET', url, true);
http.send();
}

View File

@ -1,22 +0,0 @@
<html>
<body>
<table width=100% height=100%><tr>
<td align="center" valign="middle">
<table>
<tr>
<td align="center"> <u>Select a radio station</u> </td>
</tr>
<tr>
<td align="center"> <a href="http://www.pandora.com">Pandora</a> </td>
</tr>
<tr>
<td align="center"> <a href="http://www.grooveshark.com">Grooveshark</a> </td>
</tr>
</table>
</body>
</html>

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 988 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

88
include/core/audio.h Normal file
View File

@ -0,0 +1,88 @@
/*
* Copyright 2013 (c) Anna Schumaker.
*
* The gst_init() function parses command line options passed to Ocarina
* through argv. Use the command `gst-inspect-1.0 --help-gst` to find
* what options are supported.
*/
#ifndef OCARINA_CORE_AUDIO_H
#define OCARINA_CORE_AUDIO_H
#include <core/tags/track.h>
#include <gst/gst.h>
struct audio_callbacks {
/* Called when a track is loaded. */
void (*audio_cb_load)(struct track *);
/* Called when playback state changes. */
void (*audio_cb_state_change)(GstState);
/* Called when the automatic pause state changes. */
void (*audio_cb_config_pause)(int);
};
/* Called to initialize the audio manager. */
void audio_init(int *, char ***, struct audio_callbacks *);
/* Called to deinitialize the audio manager. */
void audio_deinit();
/* Called to force-save the current track. */
void audio_save();
/* Called to load either a track or file for playback. */
bool audio_load(struct track *);
bool audio_load_filepath(const gchar *);
/* Called to get the current track. */
struct track *audio_cur_track();
/* Called to get the current playback state. */
GstState audio_cur_state();
/* Called to set the playback volume. */
void audio_set_volume(unsigned int);
/* Called to get the playback volume. */
unsigned int audio_get_volume();
/* Called to begin playback. */
bool audio_play();
/* Called to pause playback. */
bool audio_pause();
/* Called to seek playback to a specific offset, in nanoseconds. */
bool audio_seek(gint64);
/* Called to find the current playback position, in nanoseconds. */
gint64 audio_position();
/* Called to find the duration of the current track. */
gint64 audio_duration();
/* Called to load the next track. */
struct track *audio_next();
/* Called to load the previous track. */
struct track *audio_prev();
/*
* Called to configure automatic pausing.
* Returns true if the value has been changed.
*/
bool audio_pause_after(int);
int audio_get_pause_count(void);
#ifdef CONFIG_TESTING
void test_audio_eos();
void test_audio_error(GError *, gchar *);
GstElement *test_audio_pipeline();
#endif /* CONFIG_TESTING */
#endif /* OCARINA_CORE_AUDIO_H */

20
include/core/core.h Normal file
View File

@ -0,0 +1,20 @@
/*
* Copyright 2014 (c) Anna Schumaker.
*/
#ifndef OCARINA_CORE_CORE_H
#define OCARINA_CORE_CORE_H
#include <core/audio.h>
#include <core/idle.h>
#include <core/playlist.h>
#include <core/settings.h>
#include <core/tags/tags.h>
#include <stdbool.h>
/* Called to initialize all core Ocarina components. */
void core_init(int *, char ***, struct playlist_callbacks *,
struct audio_callbacks *, enum idle_sync_t);
/* Called to deinitialize all core Ocarina componentns. */
void core_deinit();
#endif /* OCARINA_CORE_CORE_H */

154
include/core/database.h Normal file
View File

@ -0,0 +1,154 @@
/*
* Copyright 2013 (c) Anna Schumaker.
*
* Databases are a generic store for information used by Ocarina. Users must
* provide a struct db_ops when initializing a database.
*
* When writing a database to disk, databases will store their size in additon
* to valid bits and values at each index. For example, let's say we have a
* database with the following values: { 1, 2, NULL, 4 }. The resulting file
* would look like:
*
* 4
* 1 1
* 1 2
* 0
* 1 4
* <valid> <data>
*
* The database class will add a newline after each struct db_entry.
*/
#ifndef OCARINA_CORE_CONTAINERS_DATABASE_H
#define OCARINA_CORE_CONTAINERS_DATABASE_H
#include <core/file.h>
struct db_entry {
unsigned int dbe_index; /* The db_entry's position in the database. */
gchar *dbe_key; /* The db_entry's hash key. */
void *dbe_data; /* The db_entry's private data. */
};
static inline void dbe_init(struct db_entry *dbe, void *data)
{
dbe->dbe_index = 0;
dbe->dbe_key = NULL;
dbe->dbe_data = data;
}
static inline void *DBE_DATA(struct db_entry *dbe)
{
if (dbe)
return dbe->dbe_data;
return NULL;
}
struct db_ops {
/* Allocate a new struct db_entry from a given key. */
struct db_entry *(*dbe_alloc)(const gchar *, unsigned int);
/* Free a struct db_entry. */
void (*dbe_free)(struct db_entry *);
/* Return a unique string representing a single struct db_entry. */
gchar *(*dbe_key)(struct db_entry *);
/* Read a single struct db_entry from disk. */
struct db_entry *(*dbe_read)(struct file *, unsigned int);
/* Write a single struct db_entry to disk. */
void (*dbe_write)(struct file *, struct db_entry *);
};
struct database {
unsigned int db_size; /* The database's count of valid entries. */
bool db_autosave; /* The database's automatic save setting. */
struct file db_file; /* The database's associated file object. */
GPtrArray *db_entries; /* The database's backing array. */
GHashTable *db_keys; /* The database's mapping of key -> value. */
const struct db_ops *db_ops; /* The database's operations vector. */
};
#define DB_INIT(fname, autosave, ops, fmin) \
{ \
.db_size = 0, \
.db_autosave = autosave, \
.db_file = FILE_INIT_DATA("", fname, fmin), \
.db_entries = g_ptr_array_new(), \
.db_keys = g_hash_table_new(g_str_hash, g_str_equal), \
.db_ops = ops, \
}
/*
* Initialize a database using filepath as a location on disk to store data
* and autosave as a hint for if this database should be automatically saved.
*/
void db_init(struct database *, const char *, bool, const struct db_ops *,
unsigned int);
/* Called to prevent memory leaks by freeing all remaining database entries. */
void db_deinit(struct database *);
/* Called to write the database to disk. */
void db_save(struct database *);
/* Save the database to disk iff database->db_autosave is set to True */
void db_autosave(struct database *);
/* Called to read the database from disk. */
void db_load(struct database *);
/* Returns the size of the backing std::vector. */
unsigned int db_actual_size(const struct database *);
/*
* Called to add a new item to the database. The caller MUST check if the
* database already contains a similar item before calling this function.
*/
struct db_entry *db_insert(struct database *, const gchar *);
/* Called to remove an item from the database. */
void db_remove(struct database *, struct db_entry *);
/*
* Called to shrink the database by removing any NULL pointers without
* changing the order of items in the database.
* Returns true if the database has been modified.
*/
bool db_defrag(struct database *);
/* Called to change the key of a database entry. */
void db_rekey(struct database *, struct db_entry *);
/* Returns the database item at the requested index. */
struct db_entry *db_at(const struct database *, unsigned int);
/* Returns the database item with the specified key. */
struct db_entry *db_get(struct database *, const gchar *);
/*
* Similar to db_get(), but allocate and return a new item if the
* database doesn't contain an item with the specified key.
*/
struct db_entry *db_find(struct database *, const gchar *);
/* Returns the first valid database item. */
struct db_entry *db_first(const struct database *);
/* Returns the next valid database item. */
struct db_entry *db_next(const struct database *, struct db_entry *);
#define db_for_each(ent, next, db) \
for (ent = db_first(db), next = db_next(db, ent); \
ent != NULL; \
ent = next, next = db_next(db, ent))
#endif /* OCARINA_CORE_CONTAINERS_DATABASE_H */

52
include/core/date.h Normal file
View File

@ -0,0 +1,52 @@
/*
* Copyright 2015 (c) Anna Schumaker.
*/
#ifndef OCARINA_CORE_DATE_H
#define OCARINA_CORE_DATE_H
#include <core/file.h>
#include <stdint.h>
struct date {
union {
struct {
uint16_t d_year;
uint8_t d_month;
uint8_t d_day;
};
uint32_t d_stamp;
};
};
/* Set the date structure. */
void date_set(struct date *, unsigned int, unsigned int, unsigned int);
/* Set the provided date structure to today's date. */
void date_today(struct date *);
/* Read the date from file. */
void date_read(struct file *, struct date *);
void date_read_stamp(struct file *, struct date *);
/* Write the date to file. */
void date_write(struct file *, struct date *);
void date_write_stamp(struct file *, struct date *);
/*
* Convert the date into a string.
* This function allocates a new string that MUST be freed with g_free().
*/
gchar *date_string(const struct date *);
/*
* Compare two dates.
*
* if ret < 0: lhs < rhs.
* if ret = 0: lhs == rhs.
* if ret > 0: lhs > rhs.
*/
int date_compare(const struct date *, const struct date *);
#endif /* OCARINA_CORE_DATE_H */

152
include/core/file.h Normal file
View File

@ -0,0 +1,152 @@
/*
* Copyright 2013 (c) Anna Schumaker.
*
* File data is store in the user's home directory according to the
* XDG / freedesktop.org specification, meaning all of our data will
* be stored in a subdirectory of $XDG_DATA_HOME. The actual subdirectory
* changes based on what configuration values the user has set when Ocarina
* is compiled.
*
* Config Value | Ocarina Directory
* ---------------|--------------------
* default | $XDG_DATA_HOME/ocarina/
* CONFIG_DEBUG | $XDG_DATA_HOME/ocarina-debug/
* CONFIG_TESTING | $XDG_DATA_HOME/ocarina-test/
*
* The beginning of every file is the current file version followed by a
* newline. For example:
*
* 42
* <data> <more data>
* <even more data>
*/
#ifndef OCARINA_CORE_FILE_H
#define OCARINA_CORE_FILE_H
#include <core/version.h>
#include <glib.h>
#include <glib/gstdio.h>
#include <stdbool.h>
enum open_mode {
CLOSED, /* File is not open. */
OPEN_READ, /* File is open for reading text. */
OPEN_READ_BINARY, /* File is open for reading binary data. */
OPEN_WRITE, /* File is open for writing text. */
OPEN_WRITE_BINARY, /* File is open for writing binary data. */
};
struct file {
FILE *f_file; /* The file's IO stream. */
const gchar *f_name; /* The file's basename. */
const gchar *f_subdir; /* The file's subdirectory. */
enum open_mode f_mode; /* The file's current open mode. */
unsigned int f_version; /* The file's current data version. */
unsigned int f_prev; /* The file's on-disk data version. */
unsigned int f_min; /* The file's minimum data version. */
const gchar *(*f_user_dir)(void); /* The file's user directory. */
};
#define FILE_INIT_DATA(fdir, fname, min) \
{ \
.f_file = NULL, \
.f_name = fname, \
.f_subdir = fdir, \
.f_mode = CLOSED, \
.f_version = OCARINA_MINOR_VERSION, \
.f_prev = 0, \
.f_min = min, \
.f_user_dir = g_get_user_data_dir, \
}
/* Initialize a file object. */
void file_init_data(struct file *, const gchar *, const gchar *, unsigned int);
void file_init_cache(struct file *, const gchar *, const gchar *);
/*
* Returns the full path of the file or an empty string if filename is not set.
* NOTE: This function allocates a new string that MUST be freed with g_free().
*/
gchar *file_path(struct file *);
/*
* Returns the path to the temporary file used for writes.
* NOTE: This function allocates a new string that MUST be freed with g_free().
*/
gchar *file_write_path(struct file *);
/* Returns the version number of the file. */
const unsigned int file_version(struct file *);
/* Returns true if the file exists on disk and false otherwise. */
bool file_exists(struct file *);
/*
* Call to open a file for either reading or writing. Callers
* are expected to call file_close() when IO is completed.
*
* When opening a file for reading (OPEN_READ / OPEN_READ_BINARY):
* - Check if the file exists
* - If open for reading text (OPEN_READ):
* - Read in file->_prev_version from the start of the file.
*
* When opening a file for writing (OPEN_WRITE / OPEN_WRITE_BINARY):
* - Create missing directories as needed.
* - Open a temporary file to protect data if Ocarina crashes.
* - If open for writing text (OPEN_WRITE):
* - Write file->_version to the start of the file (data files only).
*
* Returns true if the open was successful and false otherwise.
*/
bool file_open(struct file *, enum open_mode);
/*
* Closes an open file, setting file->f_file to NULL and file->f_mode
* to CLOSED. If the file was opened for writing, then rename the
* temporary file to file_path().
*/
void file_close(struct file *);
/*
* Called to read an unsigned int, signed int, single word, or entire
* line from the file.
* NOTE: file_readw() and file_readl() both return a new string that
* MUST be freed with g_free()
*/
gchar *file_readw(struct file *);
gchar *file_readl(struct file *);
unsigned int file_readu(struct file *);
static inline int file_readd(struct file *file)
{ return (int)file_readu(file); }
static inline unsigned short int file_readhu(struct file *file)
{ return (unsigned short int)file_readu(file); }
/*
* Write to a file with an fprintf(3) style format string.
* Returns the number of bytes successfully written.
*/
int file_writef(struct file *, const char *, ...);
/*
* Reads the contents of a file as binary data.
* NOTE: This function returns a new string which MUST be freed with g_free().
*/
gchar *file_read(struct file *);
/*
* Write binary data a cache file, similar to fwrite(3).
* Returns the number of bytes successfully written.
*/
int file_write(struct file *, const void *, size_t);
/* Import a file into the cache. */
bool file_import(struct file *, const gchar *);
/* Removes a closed file from disk. */
bool file_remove(struct file *);
#endif /* OCARINA_CORE_FILE_H */

44
include/core/idle.h Normal file
View File

@ -0,0 +1,44 @@
/*
* Copyright 2013 (c) Anna Schumaker.
*
* The idle queue is used to schedule function calls to run at a
* later time. It is expected that a higher layer can determine
* when the application is idle and call idle_run_task() accordingly.
*
* The idle layer keeps a count of the number of tasks added to the queue
* since the last time the queue was empty. Whenever a task is scheduled,
* the "queued" count is incremented by 1. When tasks are run, the "serviced"
* count is incremented by 1. These counters are reset to 0 once the queue
* is empty.
*/
#ifndef OCARINA_CORE_IDLE_H
#define OCARINA_CORE_IDLE_H
#include <stdbool.h>
enum idle_sync_t {
IDLE_SYNC, /* Run task in the main thread. */
IDLE_ASYNC, /* Run task in a separate thread. */
};
#define IDLE_FUNC(x) ((bool (*)(void *))x)
/* Called to initialize the idle queue. */
void idle_init(enum idle_sync_t);
/* Called to deinitialize the idle queue. */
void idle_deinit();
/* Called to schedule a function to run later. */
void idle_schedule(enum idle_sync_t, bool (*)(void *), void *);
/*
* Called to run the next task on the idle queue.
* Returns true if there are more tasks to run.
*/
bool idle_run_task();
/* Called to find the percentage of idle tasks that have been run. */
float idle_progress();
#endif /* OCARINA_CORE_IDLE_H */

81
include/core/playlist.h Normal file
View File

@ -0,0 +1,81 @@
/*
* Copyright 2013 (c) Anna Schumaker.
*
* The playlist manager is in charge of the various playlists Ocarina
* knows about. This code also manages a special queue used by the GUI
* to display the tracks in each playlist.
*/
#ifndef OCARINA_CORE_PLAYLIST_H
#define OCARINA_CORE_PLAYLIST_H
#include <core/playlists/artist.h>
#include <core/playlists/generic.h>
#include <core/playlists/library.h>
#include <core/playlists/system.h>
#include <core/playlists/user.h>
/* Called to initialize the playlist manager. */
void playlist_init(struct playlist_callbacks *);
/* Called to deinitialize the playlist manager. */
void playlist_deinit();
/* Called to force-save all playlists. */
void playlist_save();
/* Called to notify all playlists that a track has been played. */
void playlist_played(struct track *);
/* Called to notify all playlists that a track has been selected. */
void playlist_selected(struct track *);
/* Called to create a new playlist. */
struct playlist *playlist_new(enum playlist_type_t, const gchar *);
/* Called to delete a playlist. */
bool playlist_delete(struct playlist *);
/* Called to look up playlists either by name or id. */
struct playlist *playlist_lookup(enum playlist_type_t, const gchar *);
struct playlist *playlist_get(enum playlist_type_t, unsigned int);
/* Called to access the current playlist. */
struct playlist *playlist_current(void);
/* Called to select the current playlist. */
bool playlist_select(struct playlist *);
/* Called to get the next track from the default playlist. */
struct track *playlist_next(void);
/* Called to get a previously played track. */
struct track *playlist_prev(void);
/* Called to add a track to a playlist. */
bool playlist_add(struct playlist *, struct track *);
/* Called to remove a track from a playlist. */
bool playlist_remove(struct playlist *, struct track *);
/* Called to check if a specific track is in the playlist. */
bool playlist_has(struct playlist *, struct track *);
/* Called to set the playlist's random flag. */
void playlist_set_random(struct playlist *, bool);
/* Called to change the sort order of the playlist. */
bool playlist_sort(struct playlist *, enum compare_t);
/* Called to manually rearrange the order of the playlist. */
bool playlist_rearrange(struct playlist *, unsigned int, unsigned int);
/* Called to set the playlist's search text */
void playlist_set_search(struct playlist *, const gchar *);
#endif /* OCARINA_CORE_PLAYLIST_H */

View File

@ -0,0 +1,24 @@
/*
* Copyright 2016 (c) Anna Schumaker.
*/
#ifndef OCARINA_CORE_PLAYLISTS_ARTIST_H
#define OCARINA_CORE_PLAYLISTS_ARTIST_H
#include <core/playlists/generic.h>
/* Artist playlist type. */
extern struct playlist_type pl_artist;
/* Called to initialize artist playlists. */
void pl_artist_init(void);
/* Called to deinitialize library playlists. */
void pl_artist_deinit();
/* Called to tell system playlists about a new track. */
void pl_artist_new_track(struct track *);
/* Called to tell artist playlists that a track is getting deleted. */
void pl_artist_delete_track(struct track *);
#endif /* OCARINA_CORE_PLAYLISTS_ARTIST_H */

View File

@ -0,0 +1,91 @@
/*
* Copyright 2016 (c) Anna Schumaker.
*/
#ifndef OCARINA_CORE_PLAYLISTS_GENERIC_H
#define OCARINA_CORE_PLAYLISTS_GENERIC_H
#include <core/playlists/iterator.h>
#include <core/playlists/playlist.h>
enum playlist_save_flags {
PL_SAVE_FLAGS = (1 << 0), /* Save playlist random and sort data. */
PL_SAVE_ITER = (1 << 1), /* Save playlist iterator position. */
PL_SAVE_TRACKS = (1 << 2), /* Save playlist tracks. */
};
#define PL_SAVE_METADATA (PL_SAVE_FLAGS | PL_SAVE_ITER)
#define PL_SAVE_ALL (PL_SAVE_TRACKS | PL_SAVE_METADATA)
struct playlist_callbacks {
/* Called to notify that a new playlist has been allocated. */
void (*pl_cb_alloc)(struct playlist *);
/* Called to notify that a track has been added. */
void (*pl_cb_added)(struct playlist *, struct track *);
/*
* Called to notify that N instances of a track have been removed.
* Track may be NULL to indicate that several different tracks were
* removed at once.
*/
void (*pl_cb_removed)(struct playlist *, struct track *, unsigned int n);
/*
* Called to notify that a track has been updated.
* If the track is NULL, then the entire playlist should be updated.
*/
void (*pl_cb_updated)(struct playlist *, struct track *);
};
/* Called to set playlist callbacks. */
void playlist_generic_set_callbacks(struct playlist_callbacks *);
/* Generic playlist init functions. */
void playlist_generic_init(struct playlist *, unsigned int, ...);
/* Generic playlist deinit function. */
void playlist_generic_deinit(struct playlist *);
/* Generic playlist alloc function. */
struct playlist *playlist_generic_alloc(gchar *, enum playlist_type_t,
unsigned int, struct playlist_ops *,
unsigned int, ...);
/* Generic playlist free function. */
void playlist_generic_free(struct playlist *);
/* Generic playlist save function. */
void playlist_generic_save(struct playlist *, struct file *, unsigned int);
/* Generic playlist load function. */
void playlist_generic_load(struct playlist *, struct file *, unsigned int);
/* Generic playlist can-select function. */
bool playlist_generic_can_select(struct playlist *);
/* Generic playlist clear operation. */
void playlist_generic_clear(struct playlist *);
/* Generic playlist add track operations. */
bool playlist_generic_add(struct playlist *, struct track *);
bool playlist_generic_add_front(struct playlist *, struct track *);
/* Generic playlist remove track operation. */
bool playlist_generic_remove(struct playlist *, struct track *);
/* Generic playlist update track operation. */
void playlist_generic_update(struct playlist *, struct track *);
/* Generic playlist set_random operation. */
void playlist_generic_set_random(struct playlist *, bool);
/* Generic playlist sorting operations. */
void playlist_generic_sort(struct playlist *, enum compare_t);
void playlist_generic_resort(struct playlist *);
/* Generic playlist rearranging operation. */
bool playlist_generic_rearrange(struct playlist *, unsigned int, unsigned int);
/* Generic playlist next track operation. */
struct track *playlist_generic_next(struct playlist *);
#endif /* OCARINA_CORE_PLAYLISTS_GENERIC_H */

View File

@ -0,0 +1,83 @@
/*
* Copyright 2016 (c) Anna Schumaker.
*
* NOTE: The playlist_iter type is defined in include/core/playlists/playlist.h
*/
#ifndef OCARINA_CORE_PLAYLISTS_ITERATOR_H
#define OCARINA_CORE_PLAYLISTS_ITERATOR_H
#include <core/playlists/playlist.h>
/* Called to set the playlist iterator to a specific position. */
static inline playlist_iter playlist_iter_get(struct playlist *playlist,
unsigned int n)
{
return playlist ? g_queue_peek_nth_link(&playlist->pl_tracks, n) : NULL;
}
/* Called to advance the requested playlist iterator. */
static inline playlist_iter playlist_iter_next(playlist_iter iter)
{
return g_list_next(iter);
}
/* Called to get a pointer to the track at the requested iterator. */
static inline struct track *playlist_iter_track(playlist_iter iter)
{
return iter ? iter->data : NULL;
}
/* Called to find the playlist index of the requested iterator. */
static inline int playlist_iter_index(struct playlist *playlist,
playlist_iter iter)
{
return (playlist && iter) ? g_queue_link_index(&playlist->pl_tracks, iter) : -1;
}
/* Called to iterate over the entire playlist. */
#define playlist_for_each(playlist, it) \
for (it = playlist_iter_get(playlist, 0); it; it = playlist_iter_next(it))
/* Called to set the index of the current track. */
static inline bool playlist_current_set(struct playlist *playlist,
unsigned int n)
{
if (playlist)
playlist->pl_current = playlist_iter_get(playlist, n);
return playlist && playlist->pl_current;
}
/* Called to advance the current track. */
static inline bool playlist_current_next(struct playlist *playlist)
{
if (playlist)
playlist->pl_current = playlist_iter_next(playlist->pl_current);
return playlist && playlist->pl_current;
}
/* Called to rewind the current track. */
static inline bool playlist_current_previous(struct playlist *playlist)
{
if (playlist)
playlist->pl_current = g_list_previous(playlist->pl_current);
return playlist && playlist->pl_current;
}
/* Called to get a pointer to the current track. */
static inline struct track *playlist_current_track(struct playlist *playlist)
{
return playlist ? playlist_iter_track(playlist->pl_current) : NULL;
}
/* Called to get the playlist index of the current track. */
static inline int playlist_current_index(struct playlist *playlist)
{
return playlist ? playlist_iter_index(playlist, playlist->pl_current) : -1;
}
/* Called to find the nth track on a playlist. */
static inline struct track *playlist_at(struct playlist *playlist, unsigned int n)
{
return playlist_iter_track(playlist_iter_get(playlist, n));
}
#endif /* OCARINA_CORE_PLAYLISTS_ITERATOR_H */

View File

@ -0,0 +1,21 @@
/*
* Copyright 2016 (c) Anna Schumaker.
*/
#ifndef OCARINA_CORE_PLAYLISTS_LIBRARY_H
#define OCARINA_CORE_PLAYLISTS_LIBRARY_H
#include <core/playlists/generic.h>
/* Library playlist type. */
extern struct playlist_type pl_library;
/* Called to initialize library playlists. */
void pl_library_init(void);
/* Called to deinitialize system playlists. */
void pl_library_deinit();
/* Called to update a library path. */
void pl_library_update(struct playlist *);
#endif /* OCARINA_CORE_PLAYLISTS_LIBRARY_H */

View File

@ -0,0 +1,112 @@
/*
* Copyright 2016 (c) Anna Schumaker.
*/
#ifndef OCARINA_CORE_PLAYLISTS_PLAYLIST_H
#define OCARINA_CORE_PLAYLISTS_PLAYLIST_H
#include <core/tags/track.h>
#include <stdbool.h>
typedef GList * playlist_iter;
struct playlist;
enum playlist_type_t {
PL_SYSTEM,
PL_ARTIST,
PL_LIBRARY,
PL_USER,
PL_MAX_TYPE,
};
#define PL_RANDOM (1 << 1)
struct playlist_ops {
/* Called to add a track to a playlist. */
bool (*pl_add)(struct playlist *, struct track *);
/* Called to check if a playlist can be selected. */
bool (*pl_can_select)(struct playlist *);
/* Called to delete a playlist. */
bool (*pl_delete)(struct playlist *);
/* Called to remove a track from the playlist. */
bool (*pl_remove)(struct playlist *, struct track *);
/* Called to set a playlist flag. */
void (*pl_set_random)(struct playlist *, bool);
/* Called to sort the playlist. */
void (*pl_sort)(struct playlist *, enum compare_t);
/* Called to rearrange the playlist. */
bool (*pl_rearrange)(struct playlist *, unsigned int, unsigned int);
};
struct playlist {
enum playlist_type_t pl_type; /* This playlist's type. */
gchar *pl_name; /* This playlist's name. */
unsigned int pl_id; /* This playlist's identifier. */
GQueue pl_tracks; /* This playlist's queue of tracks. */
unsigned int pl_length; /* This playlist's length, in seconds. */
bool pl_random; /* This playlist's random setting. */
playlist_iter pl_current; /* This playlist's current track. */
GSList *pl_sort; /* This playlist's sort order. */
gchar **pl_search; /* This playlist's search text. */
const struct playlist_ops *pl_ops; /* This playlist's supported operations. */
};
#define DEFINE_PLAYLIST(type, name, id, ops) { \
.pl_type = type, \
.pl_name = name, \
.pl_id = id, \
.pl_ops = ops, \
}
struct playlist_type {
/* Called to save all playlists of the given type. */
void (*pl_save)(void);
/* Called to look up playlists. */
struct playlist *(*pl_lookup)(const gchar *);
struct playlist *(*pl_get)(unsigned int);
/* Called to create a new playlist. */
struct playlist *(*pl_new)(const gchar *);
/* Called to notify that a track has been played. */
void (*pl_played)(struct track *);
/* Called to notify that a track has been selected. */
void (*pl_selected)(struct track *);
};
/* Called to check if the playlist contains a specific track. */
static inline bool playlist_has(struct playlist *playlist, struct track *track)
{
return playlist ? g_queue_find(&playlist->pl_tracks, track) != NULL : false;
}
/* Called to find the size of a playlist. */
static inline unsigned int playlist_size(struct playlist *playlist)
{
return playlist ? g_queue_get_length(&playlist->pl_tracks) : 0;
}
/* Called to clear the sort order of the playlist. */
static inline void playlist_clear_sort(struct playlist *playlist)
{
if (playlist) {
g_slist_free(playlist->pl_sort);
playlist->pl_sort = NULL;
}
}
#endif /* OCARINA_CORE_PLAYLISTS_PLAYLIST_H */

View File

@ -0,0 +1,38 @@
/*
* Copyright 2016 (c) Anna Schumaker.
*/
#ifndef OCARINA_CORE_PLAYLISTS_SYSTEM_H
#define OCARINA_CORE_PLAYLISTS_SYSTEM_H
#include <core/playlists/generic.h>
enum sys_playlist_t {
SYS_PL_FAVORITES, /* Songs that the user likes. */
SYS_PL_HIDDEN, /* Songs that the user has hidden. */
SYS_PL_QUEUED, /* Songs that the user has queued up. */
SYS_PL_COLLECTION, /* Songs that have not been hidden. */
SYS_PL_HISTORY, /* Songs that have just been played. */
SYS_PL_UNPLAYED, /* Songs that have not been played yet. */
SYS_PL_MOST_PLAYED, /* Songs with an above average play count. */
SYS_PL_LEAST_PLAYED, /* Songs with a below average play count. */
SYS_PL_NUM_PLAYLISTS, /* Number of system playlists. */
};
/* System playlist type. */
extern struct playlist_type pl_system;
/* Called to initialize system playlists. */
void pl_system_init(void);
/* Called to deinitialize system playlists. */
void pl_system_deinit();
/* Called to tell system playlists about a new track. */
void pl_system_new_track(struct track *);
/* Called to tell system playlists that a track is getting deleted. */
void pl_system_delete_track(struct track *);
#endif /* OCARINA_CORE_PLAYLISTS_SYSTEM_H */

View File

@ -0,0 +1,33 @@
/*
* Copyright 2016 (c) Anna Schumaker.
*/
#ifndef OCARINA_CORE_PLAYLISTS_USER_H
#define OCARINA_CORE_PLAYLISTS_USER_H
#include <core/playlists/generic.h>
struct user_playlist {
struct playlist pl_playlist;
struct db_entry pl_dbe;
};
#define USER_PLAYLIST(dbe) ((struct user_playlist *)DBE_DATA(dbe))
/* User playlist type. */
extern struct playlist_type pl_user;
/* Called to initialize user playlists. */
void pl_user_init(void);
/* Called to deinitialize user playlists. */
void pl_user_deinit();
/* Called to tell user playlists that a track is getting deleted. */
void pl_user_delete_track(struct track *);
/* Called to rename a user playlist. */
bool pl_user_rename(struct playlist *, const gchar *);
struct database *pl_user_db_get();
#endif /* OCARINA_CORE_PLAYLISTS_USER_H */

25
include/core/print.h Normal file
View File

@ -0,0 +1,25 @@
/**
* Copyright (c) 2013 Anna Schumaker.
*/
#ifndef OCARINA_CORE_PRINT_H
#define OCARINA_CORE_PRINT_H
#include <cstdio>
#include <cstdarg>
/**
* Print a message to the console
*
* @param fmt Printf-style text format.
* @param ... Var-args matching the specified format.
*/
inline void print(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vprintf(fmt, ap);
va_end(ap);
}
#endif /* OCARINA_CORE_PRINT_H */

31
include/core/settings.h Normal file
View File

@ -0,0 +1,31 @@
/*
* Copyright 2015 (c) Anna Schumaker.
*
* The settings layer is used to store values configured by the user.
*/
#ifndef OCARINA_SETTINGS_H
#define OCARINA_SETTINGS_H
#include <glib.h>
#include <stdbool.h>
/* Called to initialize GUI settings. */
void settings_init();
/* Called to deinitialize GUI settings. */
void settings_deinit();
/* Called to configure a specific setting by key. */
void settings_set(const gchar *, unsigned int);
/* Called to access a specific setting by key. */
unsigned int settings_get(const gchar *);
/* Called to check if a specific settings exists. */
bool settings_has(const gchar *);
#ifdef CONFIG_TESTING
GHashTable *test_get_settings();
#endif /* CONFIG_TESTING */
#endif /* OCARINA_SETTINGS_H */

51
include/core/string.h Normal file
View File

@ -0,0 +1,51 @@
/*
* Copyright 2015 (c) Anna Schumaker.
*
* NOTE: All of these functions allocate and return a new string. It is the
* caller's responsibility to free these strings by calling g_free().
*/
#ifndef OCARINA_CORE_STRING_H
#define OCARINA_CORE_STRING_H
#include <glib.h>
#include <string.h>
#include <stdbool.h>
/* Convert number of seconds into a string with format mm:ss. */
gchar *string_sec2str(unsigned int);
/* Convert number of seconds into a long-form time string. */
gchar *string_sec2str_long(unsigned int);
/* Convert a struct tm to a locale-dependant date string. */
gchar *string_tm2str(struct tm *);
/*
* Compare two strings.
*
* if ret < 0: lhs < rhs, or rhs is empty.
* if ret = 0: lhs == rhs.
* if ret > 0: lhs > rhs, or lhs is empty.
*/
int string_compare_tokens(gchar **, gchar **);
/* Returns True if the two strings match. */
static inline bool string_match(const gchar *a, const gchar *b)
{
return (a && b) ? g_utf8_collate(a, b) == 0 : false;
}
/* Returns True if one of the tokens begins with the specified prefix. */
bool string_match_token(const gchar *, gchar **);
/* Returns True if string a is a subdirectory of string b. */
bool string_is_subdir(const gchar *, const gchar *);
/* Return the length of the string, with NULL checks */
static inline int string_length(const gchar *str)
{
return str ? strlen(str) : 0;
}
#endif /* OCARINA_CORE_STRING_H */

82
include/core/tags/album.h Normal file
View File

@ -0,0 +1,82 @@
/*
* Copyright 2014 (c) Anna Schumaker.
*
* The album tag is used to store the name and year of albums
* added to the tag database.
*
* When writing an album tag to disk, write out the album_artist, album_genre,
* and album_year fields followed by the album_name on the same line:
*
* ...0 0 1998 Hyrule Symphony
* ...0 0 2006 Twilight Princess
* ...0 0 2011 Skyward Sword
*/
#ifndef OCARINA_CORE_TAGS_ALBUM_H
#define OCARINA_CORE_TAGS_ALBUM_H
#include <core/database.h>
#include <core/tags/artist.h>
struct album {
unsigned int al_year; /* This album's year. */
gchar *al_name; /* This album's name. */
gchar **al_tokens; /* This album's tokenized strings. */
gchar **al_alts; /* This album's alternate ascii tokens. */
struct artist *al_artist;
struct genre *al_genre;
struct db_entry al_dbe;
};
#define ALBUM(dbe) ((struct album *)DBE_DATA(dbe))
/* Called to initialize the album database. */
void album_db_init();
/* Called to clean up the album database. */
void album_db_deinit();
/* Called to defragment the album database. */
bool album_db_defrag();
/* Called to clean up the album database after an upgrade. */
bool album_db_upgrade_done();
/* Called to find an album tag by artist, name and year. */
struct album *album_find(struct artist *, struct genre *,
const gchar *, unsigned int);
/* Called to get an album tag with a specific index. */
struct album *album_get(const unsigned int);
/* Called to compare two album tags by name. */
int album_compare(struct album *, struct album *);
/* Called to compare two album tags by year. */
int album_compare_year(struct album *, struct album *);
/* Called to check if an artist has a token that matches the given string. */
bool album_match_token(struct album *album, const gchar *);
/* Called to find the database index of the album tag. */
static inline unsigned int album_index(struct album *album)
{
return album->al_dbe.dbe_index;
}
/* Called to check if album artwork has been downloaded. */
bool album_artwork_exists(struct album *);
/*
* Called to find the path to an album's artwork.
* This function returns a new string that MUST be freed with g_free().
*/
gchar *album_artwork_path(struct album *);
/* Called to manually set artwork for a given album. */
bool album_artwork_import(struct album *, gchar *);
#ifdef CONFIG_TESTING
const struct db_ops *test_album_ops();
#endif /* CONFIG_TESTING */
#endif /* OCARINA_CORE_TAGS_ALBUM_H */

View File

@ -0,0 +1,64 @@
/*
* Copyright 2014 (c) Anna Schumaker.
*
* The Artist tag is used to store the name of artists
* added to the tag database.
*
* When writing an Artist tag to disk, only write out the
* artist_name field:
*
* ... Koji Kondo
* ... Hajime Wakai
*/
#ifndef OCARINA_CORE_TAGS_ARTIST_H
#define OCARINA_CORE_TAGS_ARTIST_H
#include <core/database.h>
struct artist {
gchar *ar_name; /* This artist's name. */
gchar **ar_tokens; /* This artist's tokenized strings. */
gchar **ar_alts; /* This artist's alternate ascii tokens. */
void *ar_playlist; /* This artist's associated playlist. */
struct db_entry ar_dbe;
};
#define ARTIST(dbe) ((struct artist *)DBE_DATA(dbe))
/* Called to initialize the artist database. */
void artist_db_init();
/* Called to clean up the artist database. */
void artist_db_deinit();
/* Called to access the artist database. */
const struct database *artist_db_get();
/*
* Called to find an artist tag by name. The difference is that artist_find()
* will allocate a new artiststruct if the requested one doesn't exist yet,
* but library_lookup() will return NULL in this situation.
*/
struct artist *artist_find(const gchar *);
struct artist *artist_lookup(const gchar *);
/* Called to get an artist tag with a specific index. */
struct artist *artist_get(const unsigned int);
/* Called to compare two artist tags. */
int artist_compare(struct artist *, struct artist *);
/* Called to check if an artist has a token that matches the given string. */
bool artist_match_token(struct artist *artist, const gchar *);
/* Called to find the database index of the artist tag. */
static inline unsigned int artist_index(struct artist *artist)
{
return artist->ar_dbe.dbe_index;
}
#ifdef CONFIG_TESTING
const struct db_ops *test_artist_ops();
#endif /* CONFIG_TESTING */
#endif /* OCARINA_CORE_TAGS_ARTIST_H */

55
include/core/tags/genre.h Normal file
View File

@ -0,0 +1,55 @@
/*
* Copyright 2014 (c) Anna Schumaker.
*
* The Genre tag is used to store the name of genres
* added to the tag database.
*
* When writing a Genre tag to disk, nol ywrite out the
* genre_name field:
*
* ... Video Game Music
* ... Game Music
*/
#ifndef OCARINA_CORE_TAGS_GENRE_H
#define OCARINA_CORE_TAGS_GENRE_H
#include <core/database.h>
struct genre {
gchar *ge_name; /* This genre's name. */
gchar **ge_tokens; /* This genre's tokenized strings. */
gchar **ge_alts; /* This genre's alternate ascii tokens. */
struct db_entry ge_dbe;
};
#define GENRE(dbe) ((struct genre *)DBE_DATA(dbe))
/* Called to initialize the genre database. */
void genre_db_init();
/* Called to clean up the genre database. */
void genre_db_deinit();
/* Called to find a genre tag by name. */
struct genre *genre_find(const gchar *);
/* Called to get a genre tag with a specific index. */
struct genre *genre_get(const unsigned int);
/* Called to compare two genre tags. */
int genre_compare(struct genre *, struct genre *);
/* Called to check if a genre has a token that matches the given string. */
bool genre_match_token(struct genre *, const gchar *);
/* Called to find the database index of the genre tag. */
static inline unsigned int genre_index(struct genre *genre)
{
return genre->ge_dbe.dbe_index;
}
#ifdef CONFIG_TESTING
const struct db_ops *test_genre_ops();
#endif /* CONFIG_TESTING */
#endif /* OCARINA_CORE_TAGS_GENRE_H */

View File

@ -0,0 +1,70 @@
/*
* Copyright 2014 (c) Anna Schumaker.
*
* The Library tag is used to store a single directory added
* to Ocarina by the user.
*
* When writing a Library tag to disk, write out the library_enabled
* and library_path fields for each tag.
*
* ... true /home/Zelda/Music
* ... false /home/Link/Music
*/
#ifndef OCARINA_CORE_TAGS_LIBRARY_H
#define OCARINA_CORE_TAGS_LIBRARY_H
#include <core/database.h>
struct library {
gchar *li_path; /* This library's root path. */
void *li_playlist; /* This library's associated playlist. */
struct db_entry li_dbe;
};
#define LIBRARY(dbe) ((struct library *)DBE_DATA(dbe))
/* Called to initialize the library database. */
void library_db_init();
/* Called to clean up the library database. */
void library_db_deinit();
/* Called to defragment the library database. */
bool library_db_defrag();
/* Called to access the library database. */
const struct database *library_db_get();
/*
* Called to find a library tag by path. The difference is that
* library_find() will allocate a new library struct if the requested one
* doesn't exist yet, but library_lookup() will return NULL in this situation.
*
* Note that path may be a subdirectory of the returned library.
*/
struct library *library_find(const gchar *);
struct library *library_lookup(const gchar *);
/* Called to get a library tag with a specific index. */
struct library *library_get(const unsigned int);
/* Called to remove a specific library tag. */
void library_remove(struct library *);
/* Called to find the database index of the library tag. */
static inline unsigned int library_index(struct library *library)
{
return library->li_dbe.dbe_index;
}
/*
* Called to find the full path of files under the library directory.
* This function allocates a new string that MUST be freed with g_free().
*/
gchar *library_file(struct library *, const gchar *);
#ifdef CONFIG_TESTING
const struct db_ops *test_library_ops();
#endif /* CONFIG_TESTING */
#endif /* OCARINA_CORE_TAGS_LIBRARY_H */

17
include/core/tags/tags.h Normal file
View File

@ -0,0 +1,17 @@
/**
* Copyright 2014 (c) Anna Schumaker.
*/
#ifndef OCARINA_CORE_TAGS_TAGS_H
#define OCARINA_CORE_TAGS_TAGS_H
/* Called to initialize and read all databases from disk. */
void tags_init();
/* Called to clean up all databases. */
void tags_deinit();
/* Called to defragment all databases. */
bool tags_defragment();
#endif /* OCARINA_CORE_TAGS_TAGS_H */

142
include/core/tags/track.h Normal file
View File

@ -0,0 +1,142 @@
/*
* Copyright 2014 (c) Anna Schumaker.
*
* The Track tag is used to store information about tracks
* that have been added to the tag database.
*
* When writing a Track tag to disk, write as many fields as
* possible on one line before spilling over to a second:
*
* library datestamp
* | album | count title
* | | number | | length | path
* | | | | | | | |
* ... 0 2 12 3741780495 13 232 Ocarina Medley |
* Hyrule Symphony/12 - Ocarina Medley.mp3 <---
* ... 0 2 13 3741780495 10 288 Legend of Zelda Medley
* Hyrule Symphony/13 - Legend of Zelda Medly.mp3
*/
#ifndef OCARINA_CORE_TAGS_TRACK_H
#define OCARINA_CORE_TAGS_TRACK_H
#include <core/database.h>
#include <core/date.h>
#include <core/tags/album.h>
#include <core/tags/artist.h>
#include <core/tags/genre.h>
#include <core/tags/library.h>
enum compare_t {
COMPARE_ARTIST = 1, /* Compare tracks by artist name. */
COMPARE_ALBUM = 2, /* Compare tracks by album name. */
COMPARE_COUNT = 3, /* Compare tracks by play count. */
COMPARE_GENRE = 4, /* Compare tracks by genre. */
COMPARE_LENGTH = 5, /* Compare tracks by length. */
COMPARE_PLAYED = 6, /* Compare tracks by last played date. */
COMPARE_TITLE = 7, /* Compare tracks by title. */
COMPARE_TRACK = 8, /* Compare tracks by track number. */
COMPARE_YEAR = 9, /* Compare tracks by year. */
};
struct track {
struct album *tr_album; /* This track's associated album. */
struct library *tr_library; /* This track's associated library. */
unsigned short int tr_count; /* This track's play count. */
unsigned short int tr_length; /* This track's length, in seconds. */
unsigned short int tr_track; /* This track's track number. */
struct date tr_date; /* This track's last-played date. */
gchar *tr_path; /* This track's path, relative to the library. */
gchar *tr_title; /* This track's title. */
gchar **tr_tokens; /* This track's tokenized strings. */
gchar **tr_alts; /* This track's alternate ascii tokens. */
struct db_entry tr_dbe;
};
#define TRACK(dbe) ((struct track *)DBE_DATA(dbe))
#define TRACK_IS_EXTERNAL(track) (track->tr_library == NULL)
/* Called to initialize the track database. */
void track_db_init();
/* Called to clean up the track database. */
void track_db_deinit();
/* Called to commit the track database. */
void track_db_commit();
/* Called to defragment the track database. */
bool track_db_defrag();
/* Called to update track database keys. */
void track_db_rekey();
/* Called to access the track database. */
const struct database *track_db_get();
/* Called to find the number of unplayed tracks in the database. */
unsigned int track_db_count_unplayed();
/* Called to find the total play count of all tracks in the database. */
unsigned int track_db_count_plays();
/* Called to find the average play count of tracks in the database. */
unsigned int track_db_average_plays();
/* Called to allocate a track without adding it to the database. */
struct track *track_alloc_external(const gchar *);
/* Called to free an external track. */
void track_free_external(struct track *);
/* Called to add a track tag to the database. */
struct track *track_add(struct library *, const gchar *);
/* Called to remove a specific track tag. */
void track_remove(struct track *);
/* Called to remove all tracks associated with a specific library. */
void track_remove_all(struct library *);
/* Called to get a track tag with a specific index. */
struct track *track_get(const unsigned int);
/* Called to look up a track tag using only a filepath. */
struct track *track_lookup(const gchar *);
/* Called to compare two track tags */
int track_compare(struct track *, struct track *, enum compare_t);
/* Called to check if a track has a token that matches the given string */
bool track_match_token(struct track *, const gchar *);
/* Called to find the database index of the track tag. */
static inline unsigned int track_index(struct track *track)
{
return track->tr_dbe.dbe_index;
}
/*
* Called to find the full path of the track tag.
* This function returns a new string that MUST be freed with g_free().
*/
gchar *track_path(struct track *);
/* Called to mark a track tag as played. */
void track_played(struct track *);
/*
* Called to find the date that this track was last played.
* This function returns a new string that MUST be freed with g_free().
*/
gchar *track_last_play(struct track *);
#ifdef CONFIG_TESTING
const struct db_ops *test_track_ops();
#endif /* CONFIG_TESTING */
#endif /* OCARINA_CORE_TAGS_TRACK_H */

27
include/core/version.h Normal file
View File

@ -0,0 +1,27 @@
/*
* Copyright 2013 (c) Anna Schumaker.
*/
#ifndef OCARINA_CORE_VERSION_H
#define OCARINA_CORE_VERSION_H
#ifdef CONFIG_TESTING
#define OCARINA_NAME "ocarina-test/"CONFIG_TESTING_DIR
#elif CONFIG_DEBUG
#define OCARINA_NAME "ocarina-debug"
#else
#define OCARINA_NAME "ocarina"
#endif
#define OCARINA_MAJOR_VERSION CONFIG_MAJOR
#define OCARINA_MINOR_VERSION CONFIG_MINOR
/*
* Scons sets the current version by passing the
* -DCONFIG_VERSION macro when Ocarina is compiled.
*/
static inline const char *get_version()
{
return CONFIG_VERSION;
}
#endif /* OCARINA_CORE_VERSION_H */

21
include/gui/artwork.h Normal file
View File

@ -0,0 +1,21 @@
/*
* Copyright 2016 (c) Anna Schumaker.
*/
#ifndef OCARINA_GUI_ARTWORK_H
#define OCARINA_GUI_ARTWORK_H
#include <core/tags/track.h>
#include <gui/builder.h>
/* Called to set artwork for a track. */
void gui_artwork_set_cover(void);
/* Called to import artwork for a track. */
void gui_artwork_import(struct track *, gchar *);
/* Called to get the cover image. */
static inline GtkImage *gui_artwork(void)
{
return GTK_IMAGE(gui_builder_widget("artwork"));
}
#endif /* OCARINA_GUI_ARTWORK_H */

109
include/gui/audio.h Normal file
View File

@ -0,0 +1,109 @@
/*
* Copyright 2016 (c) Anna Schumaker.
*/
#ifndef OCARINA_GUI_AUDIO_H
#define OCARINA_GUI_AUDIO_H
#include <core/audio.h>
#include <gui/builder.h>
/* Audio callback functions. */
extern struct audio_callbacks audio_cb;
/* Called to initialize the GUI audio controls. */
void gui_audio_init();
/* Called to stop the GUI audio timeout function. */
void gui_audio_deinit();
/* Called to update the current track position. */
int gui_audio_timeout();
int gui_audio_popover_timeout();
/* Called to get the label displaying the album tag. */
static inline GtkLabel *gui_album_tag(void)
{
return GTK_LABEL(gui_builder_widget("album_tag"));
}
/* Called to get the label displaying the artist tag. */
static inline GtkLabel *gui_artist_tag(void)
{
return GTK_LABEL(gui_builder_widget("artist_tag"));
}
/* Called to get the label displaying the title tag. */
static inline GtkLabel *gui_title_tag(void)
{
return GTK_LABEL(gui_builder_widget("title_tag"));
}
/* Called to get the label displaying the track's position. */
static inline GtkLabel *gui_position(void)
{
return GTK_LABEL(gui_builder_widget("position"));
}
/* Called to get the label displaying the track's duration. */
static inline GtkLabel *gui_duration(void)
{
return GTK_LABEL(gui_builder_widget("duration"));
}
/* Called to get the play button. */
static inline GtkButton *gui_play_button(void)
{
return GTK_BUTTON(gui_builder_widget("play_button"));
}
/* Called to get the pause button. */
static inline GtkButton *gui_pause_button(void)
{
return GTK_BUTTON(gui_builder_widget("pause_button"));
}
/* Called to get the previous button. */
static inline GtkButton *gui_prev_button(void)
{
return GTK_BUTTON(gui_builder_widget("prev_button"));
}
/* Called to get the next button. */
static inline GtkButton *gui_next_button(void)
{
return GTK_BUTTON(gui_builder_widget("next_button"));
}
/* Called to get the pause-after widgets. */
static inline GtkEntry *gui_pause_entry(void)
{
return GTK_ENTRY(gui_builder_widget("pause_entry"));
}
static inline GtkButton *gui_pause_down(void)
{
return GTK_BUTTON(gui_builder_widget("pause_down"));
}
static inline GtkButton *gui_pause_up(void)
{
return GTK_BUTTON(gui_builder_widget("pause_up"));
}
static inline GtkPopover *gui_pause_popover(void)
{
return GTK_POPOVER(gui_builder_widget("pause_popover"));
}
/* Called to get the seeking GtkAdjustment. */
static inline GtkAdjustment *gui_seek(void)
{
return GTK_ADJUSTMENT(gui_builder_object("seek"));
}
/* Called to get the volume button. */
static inline GtkScaleButton *gui_volume_button(void)
{
return GTK_SCALE_BUTTON(gui_builder_widget("volume_button"));
}
#endif /* OCARINA_GUI_AUDIO_H */

26
include/gui/builder.h Normal file
View File

@ -0,0 +1,26 @@
/*
* Copyright 2016 (c) Anna Schumaker.
*/
#ifndef OCARINA_GUI_BUILDER_H
#define OCARINA_GUI_BUILDER_H
#include <gtk/gtk.h>
/* Called to initialize the GTK builder. */
void gui_builder_init(const char *);
/* Called to deinitialize the GTK builder. */
void gui_builder_deinit();
/* Called to get an object from the GTK builder. */
GObject *gui_builder_object(const char *);
/* Called to get a widget from the GTK builder. */
GtkWidget *gui_builder_widget(const char *);
/* Called to find the height of a GTK builder widget. */
int gui_builder_widget_height(const char *);
#ifdef CONFIG_TESTING
GtkBuilder *test_get_gui_builder();
#endif /* CONFIG_TESTING */
#endif /* OCARINA_GUI_BUILDER_H */

56
include/gui/filter.h Normal file
View File

@ -0,0 +1,56 @@
/*
* Copyright 2016 (c) Anna Schumaker.
*/
#ifndef OCARINA_GUI_FILTER_H
#define OCARINA_GUI_FILTER_H
#include <core/playlist.h>
#include <gui/builder.h>
enum gui_filter_how {
GUI_FILTER_DEFAULT,
GUI_FILTER_ALBUM,
GUI_FILTER_ARTIST,
GUI_FILTER_GENRE,
GUI_FILTER_TITLE,
};
/* Called to initialize the filter model. */
void gui_filter_init();
/* Called to deinitialize the filter model. */
void gui_filter_deinit();
/* Called to set the current playlist. */
void gui_filter_set_playlist(struct playlist *);
/* Called to get the filter model. */
GtkTreeModelFilter *gui_filter_get();
/* Called to convert a filter model path into a track. */
struct track *gui_filter_path_get_track(GtkTreePath *);
/* Called to load the track at path. */
void gui_filter_path_load_track(GtkTreePath *);
/* Called to convert a filter model path into a queue index. */
unsigned int gui_filter_path_get_index(GtkTreePath *);
/* Called to convert a playlist iterator index into a path. */
GtkTreePath *gui_filter_path_from_index(unsigned int);
/* Called to refilter a playlist. Pass NULL to refilter the current playlist */
void gui_filter_refilter(struct playlist *);
/* Called to access the filter search-entry. */
static inline GtkSearchEntry *gui_filter_search(void)
{
return GTK_SEARCH_ENTRY(gui_builder_widget("filter_search"));
}
/* Called to access the filter-how chooser. */
static inline GtkComboBox *gui_filter_how(void)
{
return GTK_COMBO_BOX(gui_builder_widget("filter_how"));
}
#endif /* OCARINA_GUI_FILTER_H */

21
include/gui/idle.h Normal file
View File

@ -0,0 +1,21 @@
/*
* Copyright 2016 (c) Anna Schumaker.
*/
#ifndef OCARINA_GUI_IDLE_H
#define OCARINA_GUI_IDLE_H
#include <core/idle.h>
#include <gui/builder.h>
/* Called to enable processing idle queue tasks. */
void gui_idle_enable();
/* Called to disable processing idle queue tasks. */
void gui_idle_disable();
/* Called to get a pointer to the idle progress bar. */
static inline GtkProgressBar *gui_progress_bar()
{
return GTK_PROGRESS_BAR(gui_builder_widget("progress_bar"));
}
#endif /* OCARINA_GUI_IDLE_H */

Some files were not shown because too many files have changed in this diff Show More