mirror of
https://github.com/clangen/musikcube.git
synced 2025-03-29 19:20:28 +00:00
Merge branch 'master' into clangen/upstream-pdcurses
This commit is contained in:
commit
edd0e2cb9b
@ -147,6 +147,7 @@ PlaybackService::PlaybackService(
|
||||
, unshuffled(library)
|
||||
, repeatMode(RepeatNone)
|
||||
, messageQueue(messageQueue)
|
||||
, timeChangeMode(TimeChangeSeek)
|
||||
, seekPosition(-1.0f)
|
||||
, index(NO_POSITION)
|
||||
, nextIndex(NO_POSITION)
|
||||
|
@ -30,6 +30,7 @@ set (CUBE_SRCS
|
||||
./app/util/ConsoleLogger.cpp
|
||||
./app/util/GlobalHotkeys.cpp
|
||||
./app/util/Hotkeys.cpp
|
||||
./app/util/MagicConstants.cpp
|
||||
./app/util/PreferenceKeys.cpp
|
||||
./app/util/Playback.cpp
|
||||
./app/util/Rating.cpp
|
||||
|
@ -43,7 +43,6 @@
|
||||
#include <app/util/Playback.h>
|
||||
#include <app/util/Messages.h>
|
||||
#include <app/overlay/PlayQueueOverlays.h>
|
||||
#include <app/overlay/BrowseOverlays.h>
|
||||
|
||||
#include "DirectoryLayout.h"
|
||||
|
||||
@ -178,7 +177,7 @@ void DirectoryLayout::OnDirectoryChanged(
|
||||
}
|
||||
|
||||
void DirectoryLayout::UpdateTitle() {
|
||||
std::string title = _TSTR("browse_title_tracks");
|
||||
std::string title = "";
|
||||
|
||||
size_t selected = this->directoryList->GetSelectedIndex();
|
||||
if (selected != ListWindow::NO_SELECTION) {
|
||||
@ -242,10 +241,22 @@ bool DirectoryLayout::KeyPress(const std::string& key) {
|
||||
}
|
||||
}
|
||||
else if (Hotkeys::Is(Hotkeys::ContextMenu, key)) {
|
||||
auto tracks = this->trackList->GetTrackList();
|
||||
auto index = this->trackList->GetSelectedTrackIndex();
|
||||
index = (index == ListWindow::NO_SELECTION) ? 0 : index;
|
||||
this->playback.Play(*tracks.get(), index);
|
||||
if (this->GetFocus() == this->directoryList) {
|
||||
size_t index = this->directoryList->GetSelectedIndex();
|
||||
if (index != DirectoryAdapter::NO_INDEX) {
|
||||
auto path = this->adapter->GetFullPathAt(index);
|
||||
if (path.size()) {
|
||||
PlayQueueOverlays::ShowAddDirectoryOverlay(
|
||||
Window::MessageQueue(), this->playback, this->library, path);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
auto tracks = this->trackList->GetTrackList();
|
||||
auto index = this->trackList->GetSelectedTrackIndex();
|
||||
index = (index == ListWindow::NO_SELECTION) ? 0 : index;
|
||||
this->playback.Play(*tracks.get(), index);
|
||||
}
|
||||
}
|
||||
else if (Hotkeys::Is(Hotkeys::ViewRefresh, key)) {
|
||||
this->queryHash = 0;
|
||||
|
@ -48,6 +48,7 @@
|
||||
#include <app/util/Hotkeys.h>
|
||||
#include <app/util/Messages.h>
|
||||
#include <app/util/PreferenceKeys.h>
|
||||
#include <app/util/MagicConstants.h>
|
||||
#include <core/support/Playback.h>
|
||||
|
||||
#include "LibraryLayout.h"
|
||||
@ -392,6 +393,14 @@ void LibraryLayout::ProcessMessage(musik::core::runtime::IMessage &message) {
|
||||
LayoutBase::ProcessMessage(message);
|
||||
}
|
||||
|
||||
void LibraryLayout::ShowDirectoryChooser() {
|
||||
BrowseOverlays::ShowDirectoryChooser(
|
||||
this->library,
|
||||
[this](std::string directory) {
|
||||
this->ShowDirectories(directory);
|
||||
});
|
||||
}
|
||||
|
||||
bool LibraryLayout::KeyPress(const std::string& key) {
|
||||
if (this->visibleLayout == this->browseLayout ||
|
||||
this->visibleLayout == this->directoryLayout)
|
||||
@ -419,8 +428,13 @@ bool LibraryLayout::KeyPress(const std::string& key) {
|
||||
else if (Hotkeys::Is(Hotkeys::NavigateLibraryBrowseChooseCategory, key)) {
|
||||
BrowseOverlays::ShowCategoryChooser(
|
||||
this->library,
|
||||
[this](std::string category) {
|
||||
this->ShowBrowse(category);
|
||||
[this](std::string category, std::string type) {
|
||||
if (type == MagicConstants::DirectoryCategoryType) {
|
||||
this->ShowDirectoryChooser();
|
||||
}
|
||||
else {
|
||||
this->ShowBrowse(category);
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
@ -443,11 +457,7 @@ bool LibraryLayout::KeyPress(const std::string& key) {
|
||||
return true;
|
||||
}
|
||||
else if (Hotkeys::Is(Hotkeys::NavigateLibraryBrowseDirectories, key)) {
|
||||
BrowseOverlays::ShowDirectoryChooser(
|
||||
this->library,
|
||||
[this](std::string directory) {
|
||||
this->ShowDirectories(directory);
|
||||
});
|
||||
this->ShowDirectoryChooser();
|
||||
return true;
|
||||
}
|
||||
else if (this->GetFocus() == this->transportView && Hotkeys::Is(Hotkeys::Up, key)) {
|
||||
|
@ -96,6 +96,7 @@ namespace musik {
|
||||
void ShowBrowse(const std::string& category = "");
|
||||
void ShowCategorySearch();
|
||||
void ShowTrackSearch();
|
||||
void ShowDirectoryChooser();
|
||||
void ShowDirectories(const std::string& directory);
|
||||
|
||||
void ChangeMainLayout(std::shared_ptr<cursespp::LayoutBase> newLayout);
|
||||
|
@ -35,7 +35,9 @@
|
||||
#include <stdafx.h>
|
||||
|
||||
#include "BrowseOverlays.h"
|
||||
#include <app/util/MagicConstants.h>
|
||||
#include <core/library/query/local/AllCategoriesQuery.h>
|
||||
#include <core/i18n/Locale.h>
|
||||
#include <cursespp/SimpleScrollAdapter.h>
|
||||
#include <cursespp/ListOverlay.h>
|
||||
#include <cursespp/DialogOverlay.h>
|
||||
@ -48,7 +50,7 @@ using namespace musik::core;
|
||||
using namespace musik::core::db;
|
||||
using namespace musik::core::db::local;
|
||||
|
||||
static const std::set<std::string> BLACKLIST = { "bitrate", "channels", "lyrics", "path_id" };
|
||||
static const std::set<std::string> BLACKLIST = { "bitrate", "channels", "lyrics", "path_id", "directory" };
|
||||
static std::string lastSelectedCategory, lastSelectedDirectory;
|
||||
|
||||
static void showNoPathsError() {
|
||||
@ -64,7 +66,7 @@ static void showNoPathsError() {
|
||||
|
||||
void BrowseOverlays::ShowCategoryChooser(
|
||||
musik::core::ILibraryPtr library,
|
||||
std::function<void(std::string)> callback)
|
||||
std::function<void(std::string, std::string)> callback)
|
||||
{
|
||||
using Adapter = cursespp::SimpleScrollAdapter;
|
||||
using ListOverlay = cursespp::ListOverlay;
|
||||
@ -77,16 +79,29 @@ void BrowseOverlays::ShowCategoryChooser(
|
||||
adapter->SetSelectable(true);
|
||||
|
||||
size_t index = 0;
|
||||
auto filtered = query->GetResult()->Filter([&index, adapter](const Value& value) -> bool {
|
||||
|
||||
auto result = query->GetResult();
|
||||
|
||||
auto filtered = result->Filter([&index, adapter](const Value& value) -> bool {
|
||||
auto str = value->ToString();
|
||||
if (BLACKLIST.find(str) == BLACKLIST.end()) {
|
||||
adapter->AddEntry(str);
|
||||
if (lastSelectedCategory == str) {
|
||||
index = adapter->GetEntryCount() - 1;
|
||||
}
|
||||
return true;
|
||||
return BLACKLIST.find(str) == BLACKLIST.end();
|
||||
});
|
||||
|
||||
filtered->Add(std::make_shared<SdkValue>(
|
||||
_TSTR("browse_title_directory"),
|
||||
-1LL,
|
||||
MagicConstants::DirectoryCategoryType));
|
||||
|
||||
filtered->Sort([](const auto a, const auto b) -> bool {
|
||||
return a->ToString() < b->ToString();
|
||||
});
|
||||
|
||||
filtered->Each([&index, adapter](const Value& value) {
|
||||
auto str = value->ToString();
|
||||
adapter->AddEntry(str);
|
||||
if (lastSelectedCategory == str) {
|
||||
index = adapter->GetEntryCount() - 1;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
std::shared_ptr<ListOverlay> dialog(new ListOverlay());
|
||||
@ -98,8 +113,9 @@ void BrowseOverlays::ShowCategoryChooser(
|
||||
.SetItemSelectedCallback(
|
||||
[callback, filtered]
|
||||
(ListOverlay* overlay, IScrollAdapterPtr adapter, size_t index) {
|
||||
lastSelectedCategory = filtered->At(index)->ToString();
|
||||
callback(lastSelectedCategory);
|
||||
auto selected = filtered->At(index);
|
||||
lastSelectedCategory = selected->ToString();
|
||||
callback(lastSelectedCategory, selected->GetType());
|
||||
});
|
||||
|
||||
cursespp::App::Overlays().Push(dialog);
|
||||
|
@ -43,7 +43,7 @@ namespace musik {
|
||||
public:
|
||||
static void ShowCategoryChooser(
|
||||
musik::core::ILibraryPtr library,
|
||||
std::function<void(std::string)> callback);
|
||||
std::function<void(std::string, std::string)> callback);
|
||||
|
||||
static void ShowDirectoryChooser(
|
||||
musik::core::ILibraryPtr library,
|
||||
|
@ -43,12 +43,14 @@
|
||||
|
||||
#include <core/library/query/local/CategoryTrackListQuery.h>
|
||||
#include <core/library/query/local/CategoryListQuery.h>
|
||||
#include <core/library/query/local/DirectoryTrackListQuery.h>
|
||||
#include <core/library/query/local/GetPlaylistQuery.h>
|
||||
#include <core/library/query/local/SavePlaylistQuery.h>
|
||||
#include <core/library/query/local/DeletePlaylistQuery.h>
|
||||
#include <core/runtime/Message.h>
|
||||
|
||||
#include <app/util/Messages.h>
|
||||
#include <app/util/MagicConstants.h>
|
||||
|
||||
#include <cursespp/App.h>
|
||||
#include <cursespp/SimpleScrollAdapter.h>
|
||||
@ -119,6 +121,31 @@ static std::string stringWithFormat(const std::string& key, const std::string& v
|
||||
return u8fmt(_TSTR(key), value.c_str());
|
||||
}
|
||||
|
||||
static std::shared_ptr<TrackList> queryTracksByCategory(
|
||||
ILibraryPtr library,
|
||||
const std::string& categoryType,
|
||||
const std::string& categoryValue,
|
||||
int64_t categoryId)
|
||||
{
|
||||
/* ShowAddDirectoryOverlay() calls through to ShowAddCategoryOverlay() with a
|
||||
special `fieldColumn` called `kDirectoryFieldColumn`. If we detect this case
|
||||
we'll run a special query for directory path matching */
|
||||
std::shared_ptr<TrackListQueryBase> query;
|
||||
if (categoryType == MagicConstants::DirectoryCategoryType) {
|
||||
query = std::make_shared<DirectoryTrackListQuery>(library, categoryValue);
|
||||
}
|
||||
else {
|
||||
query = std::make_shared<CategoryTrackListQuery>(library, categoryType, categoryId);
|
||||
}
|
||||
|
||||
library->Enqueue(query, ILibrary::QuerySynchronous);
|
||||
if (query->GetStatus() == IQuery::Finished) {
|
||||
return query->GetResult();
|
||||
}
|
||||
|
||||
return std::shared_ptr<TrackList>();
|
||||
}
|
||||
|
||||
static std::shared_ptr<CategoryListQuery> queryPlaylists(ILibraryPtr library) {
|
||||
std::shared_ptr<CategoryListQuery> query(
|
||||
new CategoryListQuery(Playlists::TABLE_NAME, ""));
|
||||
@ -209,30 +236,6 @@ static void createNewPlaylist(
|
||||
cursespp::App::Overlays().Push(dialog);
|
||||
}
|
||||
|
||||
static void createNewPlaylist(
|
||||
IMessageQueue& queue,
|
||||
ILibraryPtr library,
|
||||
const std::string& categoryType,
|
||||
int64_t categoryId)
|
||||
{
|
||||
std::shared_ptr<InputOverlay> dialog(new InputOverlay());
|
||||
|
||||
dialog->SetTitle(_TSTR("playqueue_overlay_playlist_name_title"))
|
||||
.SetWidth(_DIMEN("playqueue_playlist_name_overlay_width", DEFAULT_OVERLAY_WIDTH))
|
||||
.SetText("")
|
||||
.SetInputAcceptedCallback(
|
||||
[&queue, library, categoryType, categoryId](const std::string& name) {
|
||||
if (name.size()) {
|
||||
auto query = SavePlaylistQuery::Save(library, name, categoryType, categoryId);
|
||||
library->Enqueue(query, ILibrary::QuerySynchronous, [](auto query) {
|
||||
setLastPlaylistId(std::static_pointer_cast<SavePlaylistQuery>(query)->GetPlaylistId());
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
cursespp::App::Overlays().Push(dialog);
|
||||
}
|
||||
|
||||
void PlayQueueOverlays::ShowRenamePlaylistOverlay(
|
||||
ILibraryPtr library,
|
||||
const int64_t playlistId,
|
||||
@ -295,17 +298,14 @@ static void handleAddCategorySelectionToPlayQueue(
|
||||
PlaybackService& playback,
|
||||
ILibraryPtr library,
|
||||
const std::string& fieldColumn,
|
||||
const std::string& fieldValue,
|
||||
int64_t fieldId,
|
||||
size_t type)
|
||||
{
|
||||
std::shared_ptr<CategoryTrackListQuery> query(
|
||||
new CategoryTrackListQuery(library, fieldColumn, fieldId));
|
||||
auto tracks = queryTracksByCategory(library, fieldColumn, fieldValue, fieldId);
|
||||
|
||||
library->Enqueue(query, ILibrary::QuerySynchronous);
|
||||
|
||||
if (query->GetStatus() == IQuery::Finished) {
|
||||
if (tracks) {
|
||||
auto editor = playback.Edit();
|
||||
auto tracks = query->GetResult();
|
||||
size_t position = playback.GetIndex();
|
||||
|
||||
if (type == 0) { /* start */
|
||||
@ -355,6 +355,7 @@ static void showAddCategorySelectionToPlaylistOverlay(
|
||||
IMessageQueue& queue,
|
||||
ILibraryPtr library,
|
||||
const std::string& categoryType,
|
||||
const std::string& categoryValue,
|
||||
int64_t categoryId)
|
||||
{
|
||||
std::shared_ptr<CategoryListQuery> query = queryPlaylists(library);
|
||||
@ -376,20 +377,19 @@ static void showAddCategorySelectionToPlaylistOverlay(
|
||||
showPlaylistListOverlay(
|
||||
_TSTR("playqueue_overlay_select_playlist_title"),
|
||||
adapter,
|
||||
[&queue, library, categoryType, categoryId, result]
|
||||
[&queue, library, categoryType, categoryValue, categoryId, result]
|
||||
(ListOverlay* overlay, IScrollAdapterPtr adapter, size_t index) {
|
||||
if (index != ListWindow::NO_SELECTION) {
|
||||
if (index == 0) { /* new playlist */
|
||||
createNewPlaylist(queue, library, categoryType, categoryId);
|
||||
}
|
||||
else { /* add to existing */
|
||||
int64_t playlistId = (*result)[index - 1]->GetId();
|
||||
setLastPlaylistId(playlistId);
|
||||
|
||||
auto query = SavePlaylistQuery::Append(
|
||||
library, playlistId, categoryType, categoryId);
|
||||
|
||||
library->Enqueue(query, 0);
|
||||
auto tracks = queryTracksByCategory(library, categoryType, categoryValue, categoryId);
|
||||
if (tracks) {
|
||||
if (index == 0) { /* new playlist */
|
||||
createNewPlaylist(queue, tracks, library);
|
||||
}
|
||||
else { /* add to existing */
|
||||
int64_t playlistId = (*result)[index - 1]->GetId();
|
||||
setLastPlaylistId(playlistId);
|
||||
library->Enqueue(SavePlaylistQuery::Append(library, playlistId, tracks));
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -530,7 +530,7 @@ void PlayQueueOverlays::ShowAddCategoryOverlay(
|
||||
.SetWidth(_DIMEN("playqueue_playlist_add_to_queue_overlay_width", DEFAULT_OVERLAY_WIDTH))
|
||||
.SetSelectedIndex(selectedIndex)
|
||||
.SetItemSelectedCallback(
|
||||
[&playback, &messageQueue, library, fieldColumn, fieldId]
|
||||
[&playback, &messageQueue, library, fieldColumn, fieldValue, fieldId]
|
||||
(ListOverlay* overlay, IScrollAdapterPtr adapter, size_t index) {
|
||||
if (index == ListWindow::NO_SELECTION) {
|
||||
return;
|
||||
@ -540,17 +540,32 @@ void PlayQueueOverlays::ShowAddCategoryOverlay(
|
||||
|
||||
if (index == 0) {
|
||||
showAddCategorySelectionToPlaylistOverlay(
|
||||
messageQueue, library, fieldColumn, fieldId);
|
||||
messageQueue, library, fieldColumn, fieldValue, fieldId);
|
||||
}
|
||||
else {
|
||||
handleAddCategorySelectionToPlayQueue(
|
||||
playback, library, fieldColumn, fieldId, index - 1);
|
||||
playback, library, fieldColumn, fieldValue, fieldId, index - 1);
|
||||
}
|
||||
});
|
||||
|
||||
cursespp::App::Overlays().Push(dialog);
|
||||
}
|
||||
|
||||
void PlayQueueOverlays::ShowAddDirectoryOverlay(
|
||||
musik::core::runtime::IMessageQueue& messageQueue,
|
||||
musik::core::audio::PlaybackService& playback,
|
||||
musik::core::ILibraryPtr library,
|
||||
const std::string& directory)
|
||||
{
|
||||
ShowAddCategoryOverlay(
|
||||
messageQueue,
|
||||
playback,
|
||||
library,
|
||||
MagicConstants::DirectoryCategoryType,
|
||||
directory,
|
||||
-1LL);
|
||||
}
|
||||
|
||||
void PlayQueueOverlays::ShowAlbumDividerOverlay(
|
||||
IMessageQueue& messageQueue, PlaybackService& playback, ILibraryPtr library, TrackPtr firstTrack)
|
||||
{
|
||||
@ -598,12 +613,12 @@ void PlayQueueOverlays::ShowAlbumDividerOverlay(
|
||||
/* add to playlist */
|
||||
else if (index == 4) {
|
||||
showAddCategorySelectionToPlaylistOverlay(
|
||||
messageQueue, library, albumColumn, albumId);
|
||||
messageQueue, library, albumColumn, "", albumId);
|
||||
}
|
||||
/* the other are our standard play queue operations */
|
||||
else {
|
||||
handleAddCategorySelectionToPlayQueue(
|
||||
playback, library, albumColumn, albumId, index - 5);
|
||||
playback, library, albumColumn, "", albumId, index - 5);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -60,6 +60,12 @@ namespace musik {
|
||||
const std::string& fieldValue,
|
||||
int64_t fieldId);
|
||||
|
||||
static void ShowAddDirectoryOverlay(
|
||||
musik::core::runtime::IMessageQueue& messageQueue,
|
||||
musik::core::audio::PlaybackService& playback,
|
||||
musik::core::ILibraryPtr library,
|
||||
const std::string& directory);
|
||||
|
||||
static void ShowAlbumDividerOverlay(
|
||||
musik::core::runtime::IMessageQueue& messageQueue,
|
||||
musik::core::audio::PlaybackService& playback,
|
||||
|
44
src/musikcube/app/util/MagicConstants.cpp
Normal file
44
src/musikcube/app/util/MagicConstants.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2004-2019 musikcube team
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// * Neither the name of the author nor the names of other contributors may
|
||||
// be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <stdafx.h>
|
||||
#include "MagicConstants.h"
|
||||
|
||||
using namespace musik::cube;
|
||||
|
||||
namespace musik { namespace cube {
|
||||
|
||||
const std::string MagicConstants::DirectoryCategoryType = "__DirectoryCategoryType__";
|
||||
|
||||
} }
|
55
src/musikcube/app/util/MagicConstants.h
Normal file
55
src/musikcube/app/util/MagicConstants.h
Normal file
@ -0,0 +1,55 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2004-2019 musikcube team
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// * Neither the name of the author nor the names of other contributors may
|
||||
// be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace musik { namespace cube {
|
||||
|
||||
/**
|
||||
* MagicConstants is used to house shared constants that are typically used as markers
|
||||
* to glue together otherwise disjoint features that may make sense to interoperate in
|
||||
* and integrate in the UI layer. One example of this: present directory browsing as
|
||||
* a category type, even though it's a category in the database.
|
||||
*
|
||||
* We should strive for magic constants to be empty, but in some cases doing serious
|
||||
* refactors of subsystems is prohibitively expensive and would not gain much.
|
||||
*/
|
||||
struct MagicConstants {
|
||||
static const std::string DirectoryCategoryType;
|
||||
private: MagicConstants(){}
|
||||
};
|
||||
|
||||
} }
|
@ -304,6 +304,14 @@ static size_t writePlayingFormat(
|
||||
}
|
||||
}
|
||||
|
||||
/* any % in the value string might be parsed by wprintw, so replace it */
|
||||
std::size_t percentSignIndex = value.find("%");
|
||||
while (percentSignIndex != std::string::npos) {
|
||||
value.replace(percentSignIndex, 1, "%%");
|
||||
/* we replaced one % with 2 of them, so we need to skip ahead 2 chars */
|
||||
percentSignIndex = value.find("%", percentSignIndex + 2);
|
||||
}
|
||||
|
||||
ON(w, attr);
|
||||
checked_wprintw(w, value.c_str());
|
||||
OFF(w, attr);
|
||||
@ -737,4 +745,4 @@ void TransportWindow::Update(TimeMode timeMode) {
|
||||
OFF(c, repeatAttrs);
|
||||
|
||||
this->Invalidate();
|
||||
}
|
||||
}
|
||||
|
@ -77,19 +77,38 @@ static void resizedHandler(int signal) {
|
||||
resizeAt = App::Now() + REDRAW_DEBOUNCE_MS;
|
||||
}
|
||||
|
||||
static bool isLangUtf8() {
|
||||
const char* lang = std::getenv("LANG");
|
||||
static std::string getEnvironmentVariable(const std::string& name) {
|
||||
std::string result;
|
||||
const char* value = std::getenv(name.c_str());
|
||||
if (value) {
|
||||
result = value;
|
||||
}
|
||||
std::transform(result.begin(), result.end(), result.begin(), ::tolower);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!lang) {
|
||||
return false;
|
||||
static bool containsUtf8(const std::string& value) {
|
||||
return
|
||||
value.find("utf-8") != std::string::npos ||
|
||||
value.find("utf8") != std::string::npos;
|
||||
}
|
||||
|
||||
static bool isLangUtf8() {
|
||||
/* https://github.com/clangen/musikcube/issues/324 */
|
||||
|
||||
std::string lcAll = getEnvironmentVariable("LC_ALL");
|
||||
std::string lcCType = getEnvironmentVariable("LC_CTYPE");
|
||||
std::string lang = getEnvironmentVariable("LANG");
|
||||
|
||||
if (lcAll.size()) {
|
||||
return containsUtf8(lcAll);
|
||||
}
|
||||
|
||||
std::string str = std::string(lang);
|
||||
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
|
||||
if (lcCType.size()) {
|
||||
return containsUtf8(lcCType);
|
||||
}
|
||||
|
||||
return
|
||||
str.find("utf-8") != std::string::npos ||
|
||||
str.find("utf8") != std::string::npos;
|
||||
return containsUtf8(lang);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -67,6 +67,7 @@ bool sortByFocusOrder(IWindowPtr a, IWindowPtr b) {
|
||||
|
||||
LayoutBase::LayoutBase(IWindow* parent)
|
||||
: Window(parent)
|
||||
, focused(0)
|
||||
, focusMode(FocusModeCircular) {
|
||||
this->SetFrameVisible(false);
|
||||
}
|
||||
|
@ -298,7 +298,22 @@ namespace cursespp {
|
||||
{ "M-KEY_UP", "M-up" },
|
||||
{ "M-KEY_DOWN", "M-down" },
|
||||
{ "kUP5", "CTL_UP" },
|
||||
{ "kDN5", "CTL_DOWN" }
|
||||
{ "kDN5", "CTL_DOWN" },
|
||||
#ifdef PDCURSES_WINCON
|
||||
/* special bindings for the "Windows Terminal" app */
|
||||
{ "KEY_A2", "KEY_UP" },
|
||||
{ "KEY_C2", "KEY_DOWN" },
|
||||
{ "KEY_B3", "KEY_RIGHT" },
|
||||
{ "KEY_B1", "KEY_LEFT" },
|
||||
{ "KEY_A3", "KEY_PPAGE" },
|
||||
{ "KEY_C3", "KEY_NPAGE" },
|
||||
{ "KEY_A1", "KEY_HOME" },
|
||||
{ "KEY_C1", "KEY_END" },
|
||||
{ "CTL_PAD4", "CTL_LEFT" },
|
||||
{ "CTL_PAD6", "CTL_RIGHT" },
|
||||
{ "CTL_PAD8", "CTL_UP" },
|
||||
{ "CTL_PAD9", "CTL_DOWN" },
|
||||
#endif
|
||||
};
|
||||
|
||||
std::string Normalize(const std::string& kn) {
|
||||
|
@ -802,6 +802,7 @@ xcopy "$(SolutionDir)src\3rdparty\bin\win\font\*.ttf" "$(TargetDir)fonts\" /Y /e
|
||||
<ClCompile Include="app\util\ConsoleLogger.cpp" />
|
||||
<ClCompile Include="app\util\GlobalHotkeys.cpp" />
|
||||
<ClCompile Include="app\util\Hotkeys.cpp" />
|
||||
<ClCompile Include="app\util\MagicConstants.cpp" />
|
||||
<ClCompile Include="app\util\Playback.cpp" />
|
||||
<ClCompile Include="app\util\PreferenceKeys.cpp" />
|
||||
<ClCompile Include="app\util\Rating.cpp" />
|
||||
@ -883,6 +884,7 @@ xcopy "$(SolutionDir)src\3rdparty\bin\win\font\*.ttf" "$(TargetDir)fonts\" /Y /e
|
||||
<ClInclude Include="app\util\ConsoleLogger.h" />
|
||||
<ClInclude Include="app\util\GlobalHotkeys.h" />
|
||||
<ClInclude Include="app\util\Hotkeys.h" />
|
||||
<ClInclude Include="app\util\MagicConstants.h" />
|
||||
<ClInclude Include="app\util\Messages.h" />
|
||||
<ClInclude Include="app\util\Playback.h" />
|
||||
<ClInclude Include="app\util\PreferenceKeys.h" />
|
||||
|
@ -192,6 +192,9 @@
|
||||
<ClCompile Include="app\util\Rating.cpp">
|
||||
<Filter>app\util</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="app\util\MagicConstants.cpp">
|
||||
<Filter>app\util</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="stdafx.h" />
|
||||
@ -439,6 +442,9 @@
|
||||
<ClInclude Include="app\util\Rating.h">
|
||||
<Filter>app\util</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="app\util\MagicConstants.h">
|
||||
<Filter>app\util</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="cursespp">
|
||||
|
@ -27,7 +27,8 @@ using namespace musik::core;
|
||||
using namespace musik::core::audio;
|
||||
using namespace musik::core::runtime;
|
||||
|
||||
static const char* LOCKFILE = "/tmp/musikcubed.lock";
|
||||
static const char* DEFAULT_LOCKFILE = "/tmp/musikcubed.lock";
|
||||
static const char* LOCKFILE_OVERRIDE = "MUSIKCUBED_LOCKFILE_OVERRIDE";
|
||||
static const short EVENT_DISPATCH = 1;
|
||||
static const short EVENT_QUIT = 2;
|
||||
static const pid_t NOT_RUNNING = (pid_t) -1;
|
||||
@ -145,6 +146,15 @@ static void handleCommandLine(int argc, char** argv) {
|
||||
}
|
||||
}
|
||||
|
||||
static std::string getLockfileFn() {
|
||||
std::string result = DEFAULT_LOCKFILE;
|
||||
const char* userLock = std::getenv(LOCKFILE_OVERRIDE);
|
||||
if (userLock && strlen(userLock)) {
|
||||
result = userLock;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void stopDaemon() {
|
||||
pid_t pid = getDaemonPid();
|
||||
if (pid == NOT_RUNNING) {
|
||||
@ -173,7 +183,7 @@ static void stopDaemon() {
|
||||
}
|
||||
|
||||
static pid_t getDaemonPid() {
|
||||
std::ifstream lock(LOCKFILE);
|
||||
std::ifstream lock(getLockfileFn());
|
||||
if (lock.good()) {
|
||||
int pid;
|
||||
lock >> pid;
|
||||
@ -223,7 +233,7 @@ static void initDaemon() {
|
||||
close(STDOUT_FILENO);
|
||||
freopen("/tmp/musikcube.log", "w", stderr);
|
||||
|
||||
std::ofstream lock(LOCKFILE);
|
||||
std::ofstream lock(getLockfileFn());
|
||||
if (lock.good()) {
|
||||
lock << std::to_string((int) getpid());
|
||||
}
|
||||
@ -239,7 +249,7 @@ static void initForeground() {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
std::ofstream lock(LOCKFILE);
|
||||
std::ofstream lock(getLockfileFn());
|
||||
if (lock.good()) {
|
||||
lock << std::to_string((int) getpid());
|
||||
}
|
||||
@ -258,6 +268,7 @@ static void initUtf8() {
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
initUtf8();
|
||||
std::cout << "\n using lockfile at: " << getLockfileFn();
|
||||
handleCommandLine(argc, argv);
|
||||
exitIfRunning();
|
||||
|
||||
@ -286,5 +297,5 @@ int main(int argc, char** argv) {
|
||||
|
||||
plugin::Deinit();
|
||||
|
||||
remove(LOCKFILE);
|
||||
remove(getLockfileFn().c_str());
|
||||
}
|
||||
|
@ -134,6 +134,7 @@ FfmpegDecoder::FfmpegDecoder() {
|
||||
this->resampler = nullptr;
|
||||
this->bufferSize = AV_INPUT_BUFFER_PADDING_SIZE + BUFFER_SIZE;
|
||||
this->buffer = new unsigned char[this->bufferSize];
|
||||
this->outputFifo = nullptr;
|
||||
}
|
||||
|
||||
FfmpegDecoder::~FfmpegDecoder() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user