mirror of
https://github.com/clangen/musikcube.git
synced 2025-02-11 18:40:28 +00:00
Updated debug
module (pulled from upstream f8n
) and simplified ConsoleLayout
. Also fixed up some more instances where we were using raw int64_t
attrs instead of Color in cursespp.
This commit is contained in:
parent
2ef57ec0ba
commit
20d0f02d2d
@ -123,7 +123,7 @@ bool Stream::OpenStream(std::string uri) {
|
||||
this->dataStream = DataStreamFactory::OpenSharedDataStream(uri.c_str());
|
||||
|
||||
if (!this->dataStream) {
|
||||
musik::debug::err(TAG, "failed to open " + uri);
|
||||
musik::debug::error(TAG, "failed to open " + uri);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -99,7 +99,7 @@ namespace musik { namespace core { namespace audio {
|
||||
|
||||
if (!factory) {
|
||||
/* nothing can decode this type of file */
|
||||
musik::debug::err(TAG, "nothing could open " + uri);
|
||||
musik::debug::error(TAG, "nothing could open " + uri);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -113,7 +113,7 @@ namespace musik { namespace core { namespace audio {
|
||||
/* ask the decoder to open the data stream. if it returns true we're
|
||||
good to start pulling data out of it! */
|
||||
if (!decoder->Open(dataStream)) {
|
||||
musik::debug::err(TAG, "open ok, but decode failed " + uri);
|
||||
musik::debug::error(TAG, "open ok, but decode failed " + uri);
|
||||
decoder->Release();
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -32,10 +32,8 @@
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "pch.hpp"
|
||||
|
||||
#include <core/debug.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include <core/support/Common.h>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <queue>
|
||||
@ -43,68 +41,71 @@
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
#include <time.h>
|
||||
|
||||
using namespace musik;
|
||||
using namespace musik::core;
|
||||
|
||||
sigslot::signal3<debug::log_level, std::string, std::string> debug::string_logged;
|
||||
class log_queue;
|
||||
|
||||
namespace musik {
|
||||
/*
|
||||
* Basically ripped and simplified from message_queue. Log statements get
|
||||
* enqueued and processed on a background thread.
|
||||
*/
|
||||
class log_queue {
|
||||
static std::vector<std::unique_ptr<musik::debug::IBackend>> backends;
|
||||
static std::thread* thread = nullptr;
|
||||
static log_queue* queue = nullptr;
|
||||
static std::recursive_mutex mutex;
|
||||
static volatile bool cancel = true;
|
||||
|
||||
enum class debug_level {
|
||||
verbose = 0,
|
||||
info = 1,
|
||||
warning = 2,
|
||||
error = 3
|
||||
};
|
||||
|
||||
class log_queue {
|
||||
public:
|
||||
struct log_entry {
|
||||
log_entry(debug::log_level l, const std::string& t, const std::string& m) {
|
||||
level_ = l;
|
||||
tag_ = t;
|
||||
message_ = m;
|
||||
log_entry(debug_level l, const std::string& t, const std::string& m) {
|
||||
level = l;
|
||||
tag = t;
|
||||
message = m;
|
||||
}
|
||||
|
||||
debug::log_level level_;
|
||||
std::string tag_;
|
||||
std::string message_;
|
||||
debug_level level;
|
||||
std::string tag;
|
||||
std::string message;
|
||||
};
|
||||
|
||||
class stopped_exception {
|
||||
};
|
||||
|
||||
private:
|
||||
std::queue<log_entry*> queue_;
|
||||
std::condition_variable wait_for_next_item_condition_;
|
||||
std::mutex queue_mutex_;
|
||||
volatile bool active_;
|
||||
|
||||
public:
|
||||
log_queue() {
|
||||
active_ = true;
|
||||
active = true;
|
||||
}
|
||||
|
||||
log_entry* pop_top() {
|
||||
std::unique_lock<std::mutex> lock(queue_mutex_);
|
||||
while ((queue_.size() == 0) && (active_ == true)) {
|
||||
wait_for_next_item_condition_.wait(lock);
|
||||
std::unique_lock<std::mutex> lock(queue_mutex);
|
||||
while ((queue.size() == 0) && (active == true)) {
|
||||
wait_for_next_item_condition.wait(lock);
|
||||
}
|
||||
|
||||
if (!active_) {
|
||||
return NULL;
|
||||
if (!active) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
log_entry* top = queue_.front();
|
||||
queue_.pop();
|
||||
log_entry* top = queue.front();
|
||||
queue.pop();
|
||||
return top;
|
||||
}
|
||||
|
||||
bool push(log_entry* f) {
|
||||
std::unique_lock<std::mutex> lock(queue_mutex_);
|
||||
std::unique_lock<std::mutex> lock(queue_mutex);
|
||||
|
||||
if (active_) {
|
||||
bool was_empty = (queue_.size() == 0);
|
||||
queue_.push(f);
|
||||
if (active) {
|
||||
bool was_empty = (queue.size() == 0);
|
||||
queue.push(f);
|
||||
|
||||
if (was_empty) {
|
||||
wait_for_next_item_condition_.notify_one();
|
||||
wait_for_next_item_condition.notify_one();
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -114,32 +115,46 @@ namespace musik {
|
||||
}
|
||||
|
||||
void stop() {
|
||||
std::unique_lock<std::mutex> lock(queue_mutex_);
|
||||
active_ = false;
|
||||
std::unique_lock<std::mutex> lock(queue_mutex);
|
||||
active = false;
|
||||
|
||||
while (queue_.size() > 0) {
|
||||
log_entry* top = queue_.front();
|
||||
queue_.pop();
|
||||
while (queue.size() > 0) {
|
||||
log_entry* top = queue.front();
|
||||
queue.pop();
|
||||
delete top;
|
||||
}
|
||||
|
||||
wait_for_next_item_condition_.notify_all();
|
||||
wait_for_next_item_condition.notify_all();
|
||||
}
|
||||
};
|
||||
} // namespace autom8
|
||||
|
||||
static std::thread* thread_ = NULL;
|
||||
static log_queue* queue_ = NULL;
|
||||
static std::recursive_mutex system_mutex_;
|
||||
static volatile bool cancel_ = true;
|
||||
private:
|
||||
std::queue<log_entry*> queue;
|
||||
std::condition_variable wait_for_next_item_condition;
|
||||
std::mutex queue_mutex;
|
||||
volatile bool active;
|
||||
};
|
||||
|
||||
static void thread_proc() {
|
||||
std::string s;
|
||||
try {
|
||||
while (!cancel_) {
|
||||
log_queue::log_entry* entry = queue_->pop_top();
|
||||
while (!cancel) {
|
||||
log_queue::log_entry* entry = queue->pop_top();
|
||||
if (entry) {
|
||||
debug::string_logged(entry->level_, entry->tag_, entry->message_);
|
||||
for (auto& backend : backends) {
|
||||
switch (entry->level) {
|
||||
case debug_level::verbose:
|
||||
backend->verbose(entry->tag, entry->message);
|
||||
break;
|
||||
case debug_level::info:
|
||||
backend->info(entry->tag, entry->message);
|
||||
break;
|
||||
case debug_level::warning:
|
||||
backend->warning(entry->tag, entry->message);
|
||||
break;
|
||||
case debug_level::error:
|
||||
backend->verbose(entry->tag, entry->message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
delete entry;
|
||||
}
|
||||
}
|
||||
@ -148,57 +163,174 @@ static void thread_proc() {
|
||||
}
|
||||
}
|
||||
|
||||
void debug::init() {
|
||||
std::unique_lock<std::recursive_mutex> lock(system_mutex_);
|
||||
void musik::debug::Start(std::vector<musik::debug::IBackend*> backends) {
|
||||
std::unique_lock<std::recursive_mutex> lock(mutex);
|
||||
|
||||
if (queue_ || thread_) {
|
||||
if (queue || thread) {
|
||||
return;
|
||||
}
|
||||
|
||||
deinit();
|
||||
for (auto backend : backends) {
|
||||
::backends.push_back(std::unique_ptr<musik::debug::IBackend>(backend));
|
||||
}
|
||||
|
||||
cancel_ = false;
|
||||
queue_ = new log_queue();
|
||||
thread_ = new std::thread(std::bind(&thread_proc));
|
||||
cancel = false;
|
||||
queue = new log_queue();
|
||||
thread = new std::thread(std::bind(&thread_proc));
|
||||
|
||||
info("LOG SESSION", "---------- START ----------");
|
||||
}
|
||||
|
||||
void debug::deinit() {
|
||||
std::unique_lock<std::recursive_mutex> lock(system_mutex_);
|
||||
void musik::debug::Stop() {
|
||||
std::unique_lock<std::recursive_mutex> lock(mutex);
|
||||
|
||||
cancel_ = true;
|
||||
cancel = true;
|
||||
|
||||
if (thread_ && queue_) {
|
||||
/* ordering is important here... stop the queue, then
|
||||
join the thread. stop will trigger a stopped_exception the
|
||||
thread may be blocking on, waiting for the next message */
|
||||
queue_->stop();
|
||||
thread_->join();
|
||||
if (thread && queue) {
|
||||
queue->stop();
|
||||
thread->join();
|
||||
|
||||
/* don't delete anything until the join has completed */
|
||||
delete thread_;
|
||||
thread_ = NULL;
|
||||
delete queue_;
|
||||
queue_ = NULL;
|
||||
delete thread;
|
||||
thread = nullptr;
|
||||
delete queue;
|
||||
queue = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void debug::info(const std::string& tag, const std::string& string) {
|
||||
log(debug::level_info, tag, string);
|
||||
}
|
||||
static void enqueue(debug_level level, const std::string& tag, const std::string& string) {
|
||||
std::unique_lock<std::recursive_mutex> lock(mutex);
|
||||
|
||||
void debug::warn(const std::string& tag, const std::string& string) {
|
||||
log(debug::level_warning, tag, string);
|
||||
}
|
||||
|
||||
void debug::err(const std::string& tag, const std::string& string) {
|
||||
log(debug::level_error, tag, string);
|
||||
}
|
||||
|
||||
void debug::log(log_level level, const std::string& tag, const std::string& string) {
|
||||
std::unique_lock<std::recursive_mutex> lock(system_mutex_);
|
||||
|
||||
if (queue_) {
|
||||
queue_->push(new log_queue::log_entry(level, tag, string));
|
||||
if (queue) {
|
||||
queue->push(new log_queue::log_entry(level, tag, string));
|
||||
}
|
||||
}
|
||||
|
||||
void musik::debug::verbose(const std::string& tag, const std::string& string) {
|
||||
enqueue(debug_level::verbose, tag, string);
|
||||
}
|
||||
|
||||
void musik::debug::v(const std::string& tag, const std::string& string) {
|
||||
enqueue(debug_level::verbose, tag, string);
|
||||
}
|
||||
|
||||
void musik::debug::info(const std::string& tag, const std::string& string) {
|
||||
enqueue(debug_level::info, tag, string);
|
||||
}
|
||||
|
||||
void musik::debug::i(const std::string& tag, const std::string& string) {
|
||||
enqueue(debug_level::info, tag, string);
|
||||
}
|
||||
|
||||
void musik::debug::warning(const std::string& tag, const std::string& string) {
|
||||
enqueue(debug_level::warning, tag, string);
|
||||
}
|
||||
|
||||
void musik::debug::w(const std::string& tag, const std::string& string) {
|
||||
enqueue(debug_level::warning, tag, string);
|
||||
}
|
||||
|
||||
void musik::debug::error(const std::string& tag, const std::string& string) {
|
||||
enqueue(debug_level::error, tag, string);
|
||||
}
|
||||
|
||||
void musik::debug::e(const std::string& tag, const std::string& string) {
|
||||
enqueue(debug_level::error, tag, string);
|
||||
}
|
||||
|
||||
////////// backend utils //////////
|
||||
|
||||
namespace musik {
|
||||
|
||||
static std::string timestamp() {
|
||||
time_t rawtime = { 0 };
|
||||
struct tm * timeinfo;
|
||||
char buffer [64];
|
||||
time(&rawtime);
|
||||
timeinfo = localtime (&rawtime);
|
||||
strftime (buffer, sizeof(buffer), "%T", timeinfo);
|
||||
return std::string(buffer);
|
||||
}
|
||||
|
||||
static void writeTo(
|
||||
std::ostream& out,
|
||||
const std::string& level,
|
||||
const std::string& tag,
|
||||
const std::string& message)
|
||||
{
|
||||
out << timestamp() << " [" << level << "] [" << tag << "] " << message << "\n";
|
||||
out.flush();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
////////// FileBackend //////////
|
||||
|
||||
namespace musik {
|
||||
|
||||
debug::FileBackend::FileBackend(const std::string& fn)
|
||||
: out(fn.c_str()) {
|
||||
|
||||
}
|
||||
|
||||
debug::FileBackend::FileBackend(FileBackend&& fn) {
|
||||
this->out.swap(fn.out);
|
||||
}
|
||||
|
||||
debug::FileBackend::~FileBackend() {
|
||||
}
|
||||
|
||||
void debug::FileBackend::verbose(const std::string& tag, const std::string& string) {
|
||||
writeTo(this->out, "verbose", tag, string);
|
||||
}
|
||||
|
||||
void debug::FileBackend::info(const std::string& tag, const std::string& string) {
|
||||
writeTo(this->out, "info", tag, string);
|
||||
}
|
||||
|
||||
void debug::FileBackend::warning(const std::string& tag, const std::string& string) {
|
||||
writeTo(this->out, "warning", tag, string);
|
||||
}
|
||||
|
||||
void debug::FileBackend::error(const std::string& tag, const std::string& string) {
|
||||
writeTo(this->out, "error", tag, string);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
////////// SimpleFileBackend //////////
|
||||
|
||||
namespace musik {
|
||||
|
||||
debug::SimpleFileBackend::SimpleFileBackend()
|
||||
: FileBackend(GetDataDirectory() + "log.txt") {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
////////// ConsoleBackend //////////
|
||||
|
||||
namespace musik {
|
||||
|
||||
debug::ConsoleBackend::ConsoleBackend() {
|
||||
}
|
||||
|
||||
debug::ConsoleBackend::~ConsoleBackend() {
|
||||
}
|
||||
|
||||
void debug::ConsoleBackend::verbose(const std::string& tag, const std::string& string) {
|
||||
writeTo(std::cout, "verbose", tag, string);
|
||||
}
|
||||
|
||||
void debug::ConsoleBackend::info(const std::string& tag, const std::string& string) {
|
||||
writeTo(std::cout, "info", tag, string);
|
||||
}
|
||||
|
||||
void debug::ConsoleBackend::warning(const std::string& tag, const std::string& string) {
|
||||
writeTo(std::cout, "warning", tag, string);
|
||||
}
|
||||
|
||||
void debug::ConsoleBackend::error(const std::string& tag, const std::string& string) {
|
||||
writeTo(std::cerr, "error", tag, string);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -32,29 +32,65 @@
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef __C_AUTOM8_DEBUG_HPP__
|
||||
#define __C_AUTOM8_DEBUG_HPP__
|
||||
#pragma once
|
||||
|
||||
#include <sigslot/sigslot.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
|
||||
namespace musik {
|
||||
class debug {
|
||||
public:
|
||||
enum log_level {
|
||||
level_info = 0,
|
||||
level_warning,
|
||||
level_error
|
||||
};
|
||||
public:
|
||||
class IBackend {
|
||||
public:
|
||||
virtual ~IBackend() { }
|
||||
virtual void verbose(const std::string& tag, const std::string& string) = 0;
|
||||
virtual void info(const std::string& tag, const std::string& string) = 0;
|
||||
virtual void warning(const std::string& tag, const std::string& string) = 0;
|
||||
virtual void error(const std::string& tag, const std::string& string) = 0;
|
||||
};
|
||||
|
||||
static void init();
|
||||
static void deinit();
|
||||
static sigslot::signal3<log_level, std::string, std::string> string_logged;
|
||||
static void log(log_level level, const std::string& tag, const std::string& string);
|
||||
static void info(const std::string& tag, const std::string& string);
|
||||
static void warn(const std::string& tag, const std::string& string);
|
||||
static void err(const std::string& tag, const std::string& string);
|
||||
class FileBackend : public IBackend {
|
||||
public:
|
||||
FileBackend(const std::string& fn);
|
||||
FileBackend(FileBackend&& fn);
|
||||
virtual ~FileBackend() override;
|
||||
virtual void verbose(const std::string& tag, const std::string& string) override;
|
||||
virtual void info(const std::string& tag, const std::string& string) override;
|
||||
virtual void warning(const std::string& tag, const std::string& string) override;
|
||||
virtual void error(const std::string& tag, const std::string& string) override;
|
||||
private:
|
||||
std::ofstream out;
|
||||
};
|
||||
|
||||
class SimpleFileBackend: public FileBackend {
|
||||
public:
|
||||
SimpleFileBackend();
|
||||
SimpleFileBackend(const std::string& fn) = delete;
|
||||
SimpleFileBackend(FileBackend&& fn) = delete;
|
||||
};
|
||||
|
||||
class ConsoleBackend : public IBackend {
|
||||
public:
|
||||
ConsoleBackend();
|
||||
virtual ~ConsoleBackend() override;
|
||||
virtual void verbose(const std::string& tag, const std::string& string) override;
|
||||
virtual void info(const std::string& tag, const std::string& string) override;
|
||||
virtual void warning(const std::string& tag, const std::string& string) override;
|
||||
virtual void error(const std::string& tag, const std::string& string) override;
|
||||
};
|
||||
|
||||
static void Start(std::vector<IBackend*> backends = { new SimpleFileBackend() });
|
||||
static void Stop();
|
||||
|
||||
static void verbose(const std::string& tag, const std::string& string);
|
||||
static void v(const std::string& tag, const std::string& string);
|
||||
static void info(const std::string& tag, const std::string& string);
|
||||
static void i(const std::string& tag, const std::string& string);
|
||||
static void warning(const std::string& tag, const std::string& string);
|
||||
static void w(const std::string& tag, const std::string& string);
|
||||
static void error(const std::string& tag, const std::string& string);
|
||||
static void e(const std::string& tag, const std::string& string);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -57,7 +57,7 @@ LocalFileStream::~LocalFileStream() {
|
||||
this->Close();
|
||||
}
|
||||
catch (...) {
|
||||
musik::debug::err(TAG, "error closing file");
|
||||
musik::debug::error(TAG, "error closing file");
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,12 +73,12 @@ bool LocalFileStream::Open(const char *filename, unsigned int options) {
|
||||
boost::filesystem::path file(filename);
|
||||
|
||||
if (!boost::filesystem::exists(file)) {
|
||||
debug::err(TAG, "open failed " + this->uri);
|
||||
debug::error(TAG, "open failed " + this->uri);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!boost::filesystem::is_regular(file)) {
|
||||
debug::err(TAG, "not a regular file" + this->uri);
|
||||
debug::error(TAG, "not a regular file" + this->uri);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -99,7 +99,7 @@ bool LocalFileStream::Open(const char *filename, unsigned int options) {
|
||||
catch(...) {
|
||||
}
|
||||
|
||||
debug::err(TAG, "open failed " + std::string(filename));
|
||||
debug::error(TAG, "open failed " + std::string(filename));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -309,7 +309,7 @@ ITrackList* LocalSimpleDataProvider::QueryTracks(const char* query, int limit, i
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
musik::debug::err(TAG, "QueryTracks failed");
|
||||
musik::debug::error(TAG, "QueryTracks failed");
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
@ -329,7 +329,7 @@ ITrack* LocalSimpleDataProvider::QueryTrackById(int64_t trackId) {
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
musik::debug::err(TAG, "QueryTrackById failed");
|
||||
musik::debug::error(TAG, "QueryTrackById failed");
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
@ -351,7 +351,7 @@ ITrack* LocalSimpleDataProvider::QueryTrackByExternalId(const char* externalId)
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
musik::debug::err(TAG, "QueryTrackByExternalId failed");
|
||||
musik::debug::error(TAG, "QueryTrackByExternalId failed");
|
||||
}
|
||||
}
|
||||
|
||||
@ -388,7 +388,7 @@ ITrackList* LocalSimpleDataProvider::QueryTracksByCategory(
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
musik::debug::err(TAG, "QueryTracksByCategory failed");
|
||||
musik::debug::error(TAG, "QueryTracksByCategory failed");
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
@ -413,7 +413,7 @@ ITrackList* LocalSimpleDataProvider::QueryTracksByCategories(
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
musik::debug::err(TAG, "QueryTracksByCategory failed");
|
||||
musik::debug::error(TAG, "QueryTracksByCategory failed");
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
@ -433,7 +433,7 @@ IValueList* LocalSimpleDataProvider::ListCategories() {
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
musik::debug::err(TAG, "ListCategories failed");
|
||||
musik::debug::error(TAG, "ListCategories failed");
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
@ -459,7 +459,7 @@ IValueList* LocalSimpleDataProvider::QueryCategoryWithPredicate(
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
musik::debug::err(TAG, "QueryCategory failed");
|
||||
musik::debug::error(TAG, "QueryCategory failed");
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
@ -481,7 +481,7 @@ IValueList* LocalSimpleDataProvider::QueryCategoryWithPredicates(
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
musik::debug::err(TAG, "QueryCategory failed");
|
||||
musik::debug::error(TAG, "QueryCategory failed");
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
@ -503,7 +503,7 @@ IMapList* LocalSimpleDataProvider::QueryAlbums(
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
musik::debug::err(TAG, "QueryAlbums failed");
|
||||
musik::debug::error(TAG, "QueryAlbums failed");
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
@ -555,7 +555,7 @@ static uint64_t savePlaylist(
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
musik::debug::err(TAG, "SavePlaylist failed");
|
||||
musik::debug::error(TAG, "SavePlaylist failed");
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -600,7 +600,7 @@ int64_t LocalSimpleDataProvider::SavePlaylistWithExternalIds(
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
musik::debug::err(TAG, "SavePlaylistWithExternalIds failed");
|
||||
musik::debug::error(TAG, "SavePlaylistWithExternalIds failed");
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -632,7 +632,7 @@ bool LocalSimpleDataProvider::RenamePlaylist(const int64_t playlistId, const cha
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
musik::debug::err(TAG, "RenamePlaylist failed");
|
||||
musik::debug::error(TAG, "RenamePlaylist failed");
|
||||
}
|
||||
}
|
||||
|
||||
@ -651,7 +651,7 @@ bool LocalSimpleDataProvider::DeletePlaylist(const int64_t playlistId) {
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
musik::debug::err(TAG, "DeletePlaylist failed");
|
||||
musik::debug::error(TAG, "DeletePlaylist failed");
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -676,7 +676,7 @@ static bool appendToPlaylist(
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
musik::debug::err(TAG, "AppendToPlaylist failed");
|
||||
musik::debug::error(TAG, "AppendToPlaylist failed");
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -713,7 +713,7 @@ bool LocalSimpleDataProvider::AppendToPlaylistWithExternalIds(
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
musik::debug::err(TAG, "AppendToPlaylistWithExternalIds failed");
|
||||
musik::debug::error(TAG, "AppendToPlaylistWithExternalIds failed");
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -748,7 +748,7 @@ size_t LocalSimpleDataProvider::RemoveTracksFromPlaylist(
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
musik::debug::err(TAG, "RemoveTracksFromPlaylist failed");
|
||||
musik::debug::error(TAG, "RemoveTracksFromPlaylist failed");
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -768,7 +768,7 @@ ITrackList* LocalSimpleDataProvider::QueryTracksByExternalId(
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
musik::debug::err(TAG, "QueryTracksByExternalId failed");
|
||||
musik::debug::error(TAG, "QueryTracksByExternalId failed");
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
@ -145,7 +145,7 @@ void PluginFactory::LoadPlugins() {
|
||||
catch (...) {
|
||||
std::cerr << "exception while loading plugin " << filename << std::endl;
|
||||
|
||||
musik::debug::err(TAG, "exception while loading plugin " + filename);
|
||||
musik::debug::error(TAG, "exception while loading plugin " + filename);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -154,7 +154,7 @@ void PluginFactory::LoadPlugins() {
|
||||
|
||||
std::cerr << "exception while loading plugin " << filename << " " << err << std::endl;
|
||||
|
||||
musik::debug::err(
|
||||
musik::debug::error(
|
||||
TAG,
|
||||
"could not load shared library " + filename +
|
||||
" error: " + std::string(err));
|
||||
|
@ -25,13 +25,13 @@ set (CUBE_SRCS
|
||||
./app/overlay/ReassignHotkeyOverlay.cpp
|
||||
./app/overlay/ServerOverlay.cpp
|
||||
./app/overlay/VisualizerOverlay.cpp
|
||||
./app/util/ConsoleLogger.cpp
|
||||
./app/util/GlobalHotkeys.cpp
|
||||
./app/util/Hotkeys.cpp
|
||||
./app/util/PreferenceKeys.cpp
|
||||
./app/util/Playback.cpp
|
||||
./app/util/UpdateCheck.cpp
|
||||
./app/window/CategoryListView.cpp
|
||||
./app/window/LogWindow.cpp
|
||||
./app/window/TrackListView.cpp
|
||||
./app/window/TransportWindow.cpp
|
||||
./cursespp/App.cpp
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include <cursespp/Screen.h>
|
||||
|
||||
#include <app/layout/MainLayout.h>
|
||||
#include <app/util/ConsoleLogger.h>
|
||||
#include <app/util/GlobalHotkeys.h>
|
||||
#include <app/util/Hotkeys.h>
|
||||
#include <app/util/PreferenceKeys.h>
|
||||
@ -107,7 +108,7 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
#ifndef WIN32
|
||||
#if 1 /*DEBUG*/
|
||||
freopen("/tmp/musikcube.log", "w", stderr);
|
||||
freopen("/tmp/musikcube_error.log", "w", stderr);
|
||||
#else
|
||||
freopen("/dev/null", "w", stderr);
|
||||
#endif
|
||||
@ -120,7 +121,9 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
musik::core::MigrateOldDataDirectory();
|
||||
|
||||
musik::debug::init();
|
||||
auto fileLogger = new musik::debug::SimpleFileBackend();
|
||||
auto consoleLogger = new ConsoleLogger(Window::MessageQueue());
|
||||
musik::debug::Start({ fileLogger, consoleLogger });
|
||||
|
||||
ILibraryPtr library = LibraryFactory::Default();
|
||||
library->SetMessageQueue(Window::MessageQueue());
|
||||
@ -194,8 +197,7 @@ int main(int argc, char* argv[]) {
|
||||
app.SetMinimumSize(MIN_WIDTH, MIN_HEIGHT);
|
||||
|
||||
/* main layout */
|
||||
using Main = std::shared_ptr<MainLayout>;
|
||||
Main mainLayout(new MainLayout(app, playback, library));
|
||||
auto mainLayout = std::make_shared<MainLayout>(app, consoleLogger, playback, library);
|
||||
|
||||
mainLayout->Start();
|
||||
|
||||
@ -209,8 +211,8 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
/* blocking event loop */
|
||||
app.Run(mainLayout);
|
||||
/* done with the app */
|
||||
|
||||
/* done with the app */
|
||||
mainLayout->Stop();
|
||||
|
||||
#ifdef WIN32
|
||||
@ -225,7 +227,7 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
LibraryFactory::Instance().Shutdown();
|
||||
|
||||
musik::debug::deinit();
|
||||
musik::debug::Stop();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,118 +1,57 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2007-2017 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 "ConsoleLayout.h"
|
||||
|
||||
#include <core/i18n/Locale.h>
|
||||
#include <cursespp/App.h>
|
||||
#include <cursespp/Screen.h>
|
||||
#include <cursespp/MultiLineEntry.h>
|
||||
#include <cursespp/Colors.h>
|
||||
|
||||
#include <core/sdk/IPlugin.h>
|
||||
#include <core/plugin/PluginFactory.h>
|
||||
|
||||
#include <cursespp/ToastOverlay.h>
|
||||
#include <app/util/Hotkeys.h>
|
||||
#include <app/util/Messages.h>
|
||||
#include <app/version.h>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/format.hpp>
|
||||
|
||||
template <class T>
|
||||
bool tostr(T& t, const std::string& s) {
|
||||
std::istringstream iss(s);
|
||||
return !(iss >> t).fail();
|
||||
}
|
||||
|
||||
using namespace musik::core;
|
||||
using namespace musik::core::audio;
|
||||
using namespace musik::core::sdk;
|
||||
using namespace musik::cube;
|
||||
using namespace musik::core;
|
||||
using namespace musik::core::runtime;
|
||||
using namespace cursespp;
|
||||
|
||||
typedef IScrollAdapter::EntryPtr EntryPtr;
|
||||
|
||||
ConsoleLayout::ConsoleLayout(ITransport& transport, ILibraryPtr library)
|
||||
ConsoleLayout::ConsoleLayout(ConsoleLogger* logger)
|
||||
: LayoutBase()
|
||||
, transport(transport)
|
||||
, library(library) {
|
||||
this->SetFrameVisible(false);
|
||||
|
||||
this->outputAdapter.reset(new SimpleScrollAdapter());
|
||||
this->outputAdapter->SetMaxEntries(500);
|
||||
|
||||
this->logs.reset(new LogWindow(this));
|
||||
this->logs->SetFrameTitle(_TSTR("console_debug_logs_title"));
|
||||
this->output.reset(new ScrollableWindow(this->outputAdapter, this));
|
||||
this->output->SetFrameTitle(_TSTR("console_command_output_title"));
|
||||
this->commands.reset(new cursespp::TextInput());
|
||||
this->commands->SetFrameTitle(_TSTR("console_command_title"));
|
||||
|
||||
this->commands->SetFocusOrder(0);
|
||||
this->output->SetFocusOrder(1);
|
||||
this->logs->SetFocusOrder(2);
|
||||
|
||||
this->AddWindow(this->commands);
|
||||
this->AddWindow(this->logs);
|
||||
this->AddWindow(this->output);
|
||||
|
||||
this->commands->EnterPressed.connect(this, &ConsoleLayout::OnEnterPressed);
|
||||
|
||||
this->Help();
|
||||
}
|
||||
|
||||
ConsoleLayout::~ConsoleLayout() {
|
||||
|
||||
, logger(logger) {
|
||||
this->adapter = logger->Adapter();
|
||||
this->adapter->Changed.connect(this, &ConsoleLayout::OnAdapterChanged);
|
||||
this->listView = std::make_shared<ListWindow>(this->adapter);
|
||||
this->listView->SelectionChanged.connect(this, &ConsoleLayout::OnSelectionChanged);
|
||||
this->listView->EntryActivated.connect(this, &ConsoleLayout::OnItemActivated);
|
||||
this->listView->SetFrameTitle(_TSTR("console_list_title"));
|
||||
this->AddWindow(this->listView);
|
||||
this->listView->SetFocusOrder(0);
|
||||
this->listView->ScrollToBottom();
|
||||
}
|
||||
|
||||
void ConsoleLayout::OnLayout() {
|
||||
const int cx = this->GetWidth();
|
||||
const int cy = this->GetHeight();
|
||||
LayoutBase::OnLayout();
|
||||
int cx = this->GetContentWidth();
|
||||
int cy = this->GetContentHeight();
|
||||
this->listView->MoveAndResize(0, 0, cx, cy);
|
||||
}
|
||||
|
||||
const int leftCx = cx / 2;
|
||||
const int rightCx = cx - leftCx;
|
||||
void ConsoleLayout::OnAdapterChanged(SimpleScrollAdapter* adapter) {
|
||||
if (this->scrolledToBottom) {
|
||||
this->listView->ScrollToBottom();
|
||||
}
|
||||
}
|
||||
|
||||
/* top left */
|
||||
this->output->MoveAndResize(0, 0, leftCx, cy - 3);
|
||||
void ConsoleLayout::OnSelectionChanged(cursespp::ListWindow* window, size_t index, size_t prev) {
|
||||
auto count = this->logger->Adapter()->GetEntryCount();
|
||||
this->scrolledToBottom = index == (count - 1);
|
||||
}
|
||||
|
||||
/* bottom left */
|
||||
this->commands->MoveAndResize(0, cy - 3, leftCx, 3);
|
||||
void ConsoleLayout::OnVisibilityChanged(bool visible) {
|
||||
LayoutBase::OnVisibilityChanged(visible);
|
||||
if (visible && this->scrolledToBottom) {
|
||||
this->listView->ScrollToBottom();
|
||||
}
|
||||
}
|
||||
|
||||
/* right */
|
||||
this->logs->MoveAndResize(cx / 2, 0, rightCx, cy);
|
||||
void ConsoleLayout::OnItemActivated(cursespp::ListWindow* window, size_t index) {
|
||||
ToastOverlay::Show(this->logger->Adapter()->StringAt(index), -1);
|
||||
}
|
||||
|
||||
void ConsoleLayout::SetShortcutsWindow(ShortcutsWindow* shortcuts) {
|
||||
@ -140,202 +79,3 @@ void ConsoleLayout::SetShortcutsWindow(ShortcutsWindow* shortcuts) {
|
||||
shortcuts->SetActive(Hotkeys::Get(Hotkeys::NavigateConsole));
|
||||
}
|
||||
}
|
||||
|
||||
void ConsoleLayout::WriteOutput(const std::string& str, Color attrs) {
|
||||
this->outputAdapter->AddEntry(EntryPtr(new MultiLineEntry(str, attrs)));
|
||||
this->output->OnAdapterChanged();
|
||||
}
|
||||
|
||||
void ConsoleLayout::OnEnterPressed(TextInput *input) {
|
||||
std::string command = this->commands->GetText();
|
||||
this->commands->SetText("");
|
||||
|
||||
this->WriteOutput("> " + command + "\n", Color::TextDefault);
|
||||
|
||||
if (!this->ProcessCommand(command)) {
|
||||
if (command.size()) {
|
||||
this->WriteOutput(
|
||||
"illegal command: '" +
|
||||
command +
|
||||
"'\n", Color::TextError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ConsoleLayout::Seek(const std::vector<std::string>& args) {
|
||||
if (args.size() > 0) {
|
||||
double newPosition = 0;
|
||||
if (tostr<double>(newPosition, args[0])) {
|
||||
transport.SetPosition(newPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ConsoleLayout::SetVolume(const std::vector<std::string>& args) {
|
||||
if (args.size() > 0) {
|
||||
float newVolume = 0;
|
||||
if (tostr<float>(newVolume, args[0])) {
|
||||
this->SetVolume(newVolume / 100.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ConsoleLayout::SetVolume(float volume) {
|
||||
transport.SetVolume(volume);
|
||||
}
|
||||
|
||||
void ConsoleLayout::Help() {
|
||||
Color s = Color::Default;
|
||||
|
||||
this->WriteOutput("help:\n", s);
|
||||
this->WriteOutput(" <tab> to switch between windows", s);
|
||||
this->WriteOutput("", s);
|
||||
this->WriteOutput(" addir <dir>: add a music directory", s);
|
||||
this->WriteOutput(" rmdir <dir>: remove a music directory", s);
|
||||
this->WriteOutput(" lsdirs: list scanned directories", s);
|
||||
this->WriteOutput(" rescan: rescan paths for new metadata", s);
|
||||
this->WriteOutput("", s);
|
||||
this->WriteOutput(" play <uri>: play audio at <uri>", s);
|
||||
this->WriteOutput(" pause: pause/resume", s);
|
||||
this->WriteOutput(" stop: stop and clean up everything", s);
|
||||
this->WriteOutput(" volume: <0 - 100>: set % volume", s);
|
||||
this->WriteOutput(" clear: clear the log window", s);
|
||||
this->WriteOutput(" seek <seconds>: seek to <seconds> into track", s);
|
||||
this->WriteOutput("", s);
|
||||
this->WriteOutput(" plugins: list loaded plugins", s);
|
||||
this->WriteOutput("", s);
|
||||
this->WriteOutput(" version: show musikcube app version", s);
|
||||
this->WriteOutput("", s);
|
||||
this->WriteOutput(" <ctrl+d>: quit\n", s);
|
||||
}
|
||||
|
||||
bool ConsoleLayout::ProcessCommand(const std::string& cmd) {
|
||||
std::vector<std::string> args;
|
||||
boost::algorithm::split(args, cmd, boost::is_any_of(" "));
|
||||
|
||||
auto it = args.begin();
|
||||
while (it != args.end()) {
|
||||
std::string trimmed = boost::algorithm::trim_copy(*it);
|
||||
if (trimmed.size()) {
|
||||
*it = trimmed;
|
||||
++it;
|
||||
}
|
||||
else {
|
||||
it = args.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
if (args.size() == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string name = args.size() > 0 ? args[0] : "";
|
||||
args.erase(args.begin());
|
||||
|
||||
if (name == "plugins") {
|
||||
this->ListPlugins();
|
||||
}
|
||||
else if (name == "clear") {
|
||||
this->logs->ClearContents();
|
||||
}
|
||||
else if (name == "version") {
|
||||
const std::string v = boost::str(boost::format("v%s") % VERSION);
|
||||
this->WriteOutput(v, Color::Default);
|
||||
}
|
||||
else if (name == "play" || name == "pl" || name == "p") {
|
||||
return this->PlayFile(args);
|
||||
}
|
||||
else if (name == "addir") {
|
||||
std::string path = boost::algorithm::join(args, " ");
|
||||
library->Indexer()->AddPath(path);
|
||||
}
|
||||
else if (name == "rmdir") {
|
||||
std::string path = boost::algorithm::join(args, " ");
|
||||
library->Indexer()->RemovePath(path);
|
||||
}
|
||||
else if (name == "lsdirs") {
|
||||
std::vector<std::string> paths;
|
||||
library->Indexer()->GetPaths(paths);
|
||||
this->WriteOutput("paths:");
|
||||
for (size_t i = 0; i < paths.size(); i++) {
|
||||
this->WriteOutput(" " + paths.at(i));
|
||||
}
|
||||
this->WriteOutput("");
|
||||
}
|
||||
else if (name == "rescan" || name == "scan" || name == "index") {
|
||||
library->Indexer()->Schedule(IIndexer::SyncType::All);
|
||||
}
|
||||
else if (name == "h" || name == "help") {
|
||||
this->Help();
|
||||
}
|
||||
else if (name == "pa" || name == "pause") {
|
||||
this->Pause();
|
||||
}
|
||||
else if (name == "s" || name =="stop") {
|
||||
this->Stop();
|
||||
}
|
||||
else if (name == "sk" || name == "seek") {
|
||||
this->Seek(args);
|
||||
}
|
||||
else if (name == "plugins") {
|
||||
this->ListPlugins();
|
||||
}
|
||||
else if (name == "sdk") {
|
||||
this->WriteOutput(" sdk/api revision: " +
|
||||
std::to_string(musik::core::sdk::SdkVersion));
|
||||
}
|
||||
else if (name == "v" || name == "volume") {
|
||||
this->SetVolume(args);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ConsoleLayout::PlayFile(const std::vector<std::string>& args) {
|
||||
if (args.size() > 0) {
|
||||
std::string filename = boost::algorithm::join(args, " ");
|
||||
transport.Start(filename, ITransport::Gain(), ITransport::StartMode::Immediate);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ConsoleLayout::Pause() {
|
||||
int state = this->transport.GetPlaybackState();
|
||||
if (state == PlaybackPaused) {
|
||||
this->transport.Resume();
|
||||
}
|
||||
else if (state == PlaybackPlaying) {
|
||||
this->transport.Pause();
|
||||
}
|
||||
}
|
||||
|
||||
void ConsoleLayout::Stop() {
|
||||
this->transport.Stop();
|
||||
}
|
||||
|
||||
void ConsoleLayout::ListPlugins() {
|
||||
using musik::core::sdk::IPlugin;
|
||||
using musik::core::PluginFactory;
|
||||
|
||||
typedef std::vector<std::shared_ptr<IPlugin> > PluginList;
|
||||
typedef PluginFactory::NullDeleter<IPlugin> Deleter;
|
||||
|
||||
PluginList plugins = PluginFactory::Instance()
|
||||
.QueryInterface<IPlugin, Deleter>("GetPlugin");
|
||||
|
||||
PluginList::iterator it = plugins.begin();
|
||||
for (; it != plugins.end(); it++) {
|
||||
std::string format =
|
||||
" " + std::string((*it)->Name()) + "\n"
|
||||
" version: " + std::string((*it)->Version()) + "\n"
|
||||
" by " + std::string((*it)->Author()) + "\n";
|
||||
|
||||
this->WriteOutput(format, Color::TextDefault);
|
||||
}
|
||||
}
|
||||
|
@ -1,96 +1,36 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2007-2017 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 <cursespp/Colors.h>
|
||||
#include <cursespp/LayoutBase.h>
|
||||
#include <cursespp/TextInput.h>
|
||||
#include <cursespp/ShortcutsWindow.h>
|
||||
#include <cursespp/ScrollableWindow.h>
|
||||
#include <cursespp/ListWindow.h>
|
||||
#include <cursespp/ITopLevelLayout.h>
|
||||
#include <app/util/ConsoleLogger.h>
|
||||
|
||||
#include <app/window/LogWindow.h>
|
||||
#include <app/window/TransportWindow.h>
|
||||
namespace musik { namespace cube {
|
||||
|
||||
#include <vector>
|
||||
class ConsoleLayout:
|
||||
public cursespp::LayoutBase,
|
||||
public cursespp::ITopLevelLayout,
|
||||
public sigslot::has_slots<>
|
||||
{
|
||||
public:
|
||||
ConsoleLayout(ConsoleLogger* logger);
|
||||
|
||||
#include <core/audio/ITransport.h>
|
||||
virtual void OnLayout() override;
|
||||
virtual void SetShortcutsWindow(cursespp::ShortcutsWindow* w) override;
|
||||
|
||||
namespace musik {
|
||||
namespace cube {
|
||||
class ConsoleLayout :
|
||||
public cursespp::LayoutBase,
|
||||
public cursespp::ITopLevelLayout,
|
||||
public sigslot::has_slots<>
|
||||
{
|
||||
public:
|
||||
ConsoleLayout(
|
||||
musik::core::audio::ITransport& transport,
|
||||
musik::core::ILibraryPtr library);
|
||||
protected:
|
||||
void OnVisibilityChanged(bool visible) override;
|
||||
|
||||
~ConsoleLayout();
|
||||
private:
|
||||
void OnAdapterChanged(cursespp::SimpleScrollAdapter* adapter);
|
||||
void OnSelectionChanged(cursespp::ListWindow* window, size_t index, size_t prev);
|
||||
void OnItemActivated(cursespp::ListWindow* window, size_t index);
|
||||
|
||||
virtual void SetShortcutsWindow(
|
||||
cursespp::ShortcutsWindow* shortcuts);
|
||||
ConsoleLogger* logger;
|
||||
ConsoleLogger::AdapterPtr adapter;
|
||||
std::shared_ptr<cursespp::ListWindow> listView;
|
||||
cursespp::ShortcutsWindow* shortcuts;
|
||||
bool scrolledToBottom { true };
|
||||
};
|
||||
|
||||
protected:
|
||||
virtual void OnLayout();
|
||||
|
||||
private:
|
||||
void OnEnterPressed(cursespp::TextInput* input);
|
||||
|
||||
void ListPlugins();
|
||||
bool ProcessCommand(const std::string& cmd);
|
||||
bool PlayFile(const std::vector<std::string>& args);
|
||||
void Pause();
|
||||
void Stop();
|
||||
void Seek(const std::vector<std::string>& args);
|
||||
void SetVolume(const std::vector<std::string>& args);
|
||||
void SetVolume(float volume);
|
||||
void Help();
|
||||
|
||||
void WriteOutput(
|
||||
const std::string& str,
|
||||
cursespp::Color attrs = cursespp::Color::Default);
|
||||
|
||||
std::shared_ptr<LogWindow> logs;
|
||||
std::shared_ptr<cursespp::TextInput> commands;
|
||||
std::shared_ptr<cursespp::ScrollableWindow> output;
|
||||
std::shared_ptr<cursespp::SimpleScrollAdapter> outputAdapter;
|
||||
musik::core::audio::ITransport& transport;
|
||||
musik::core::ILibraryPtr library;
|
||||
};
|
||||
}
|
||||
}
|
||||
} }
|
@ -80,6 +80,7 @@ static void updateSyncingText(TextLabel* label, int updates) {
|
||||
|
||||
MainLayout::MainLayout(
|
||||
cursespp::App& app,
|
||||
musik::cube::ConsoleLogger* logger,
|
||||
musik::core::audio::PlaybackService& playback,
|
||||
ILibraryPtr library)
|
||||
: shortcutsFocused(false)
|
||||
@ -93,7 +94,7 @@ MainLayout::MainLayout(
|
||||
library->Indexer()->Progress.connect(this, &MainLayout::OnIndexerProgress);
|
||||
|
||||
this->libraryLayout = std::make_shared<LibraryLayout>(playback, library);
|
||||
this->consoleLayout = std::make_shared<ConsoleLayout>(playback.GetTransport(), library);
|
||||
this->consoleLayout = std::make_shared<ConsoleLayout>(logger);
|
||||
this->settingsLayout = std::make_shared<SettingsLayout>(app, library, playback);
|
||||
this->hotkeysLayout = std::make_shared<HotkeysLayout>();
|
||||
|
||||
|
@ -46,6 +46,8 @@
|
||||
|
||||
#include <core/audio/MasterTransport.h>
|
||||
|
||||
#include <app/util/ConsoleLogger.h>
|
||||
|
||||
#include <sigslot/sigslot.h>
|
||||
|
||||
namespace musik {
|
||||
@ -54,6 +56,7 @@ namespace musik {
|
||||
public:
|
||||
MainLayout(
|
||||
cursespp::App& app,
|
||||
ConsoleLogger* logger,
|
||||
musik::core::audio::PlaybackService& playback,
|
||||
musik::core::ILibraryPtr library);
|
||||
|
||||
|
82
src/musikcube/app/util/ConsoleLogger.cpp
Normal file
82
src/musikcube/app/util/ConsoleLogger.cpp
Normal file
@ -0,0 +1,82 @@
|
||||
#include "ConsoleLogger.h"
|
||||
#include <cursespp/SimpleScrollAdapter.h>
|
||||
#include <cursespp/SingleLineEntry.h>
|
||||
#include <core/runtime/Message.h>
|
||||
#include <app/util/Messages.h>
|
||||
|
||||
#include <time.h>
|
||||
|
||||
using namespace musik;
|
||||
using namespace musik::core::runtime;
|
||||
using namespace musik::cube;
|
||||
using namespace cursespp;
|
||||
|
||||
static std::string timestamp() {
|
||||
time_t rawtime = { 0 };
|
||||
char buffer[64] = { 0 };
|
||||
time(&rawtime);
|
||||
#ifdef WIN32
|
||||
struct tm timeinfo = { 0 };
|
||||
localtime_s(&timeinfo, &rawtime);
|
||||
strftime(buffer, sizeof(buffer), "%T", &timeinfo);
|
||||
#else
|
||||
struct tm* timeinfo = localtime(&rawtime);
|
||||
strftime(buffer, sizeof(buffer), "%T", timeinfo);
|
||||
#endif
|
||||
return std::string(buffer);
|
||||
}
|
||||
|
||||
struct LogMessage: public Message {
|
||||
std::string logValue;
|
||||
Color color;
|
||||
|
||||
LogMessage(IMessageTarget* target, const std::string& value, const Color color)
|
||||
: Message(target, message::DebugLog, 0, 0) {
|
||||
this->logValue = value;
|
||||
this->color = color;
|
||||
}
|
||||
};
|
||||
|
||||
ConsoleLogger::ConsoleLogger(IMessageQueue& messageQueue)
|
||||
: messageQueue(messageQueue) {
|
||||
this->adapter = std::make_shared<SimpleScrollAdapter>();
|
||||
this->adapter->SetSelectable(true);
|
||||
}
|
||||
|
||||
void ConsoleLogger::verbose(const std::string& tag, const std::string& string) {
|
||||
this->FormatAndDispatch(tag, "v", string, Color::Default);
|
||||
}
|
||||
|
||||
void ConsoleLogger::info(const std::string& tag, const std::string& string) {
|
||||
this->FormatAndDispatch(tag, "i", string, Color::Default);
|
||||
}
|
||||
|
||||
void ConsoleLogger::warning(const std::string& tag, const std::string& string) {
|
||||
this->FormatAndDispatch(tag, "w", string, Color::TextWarning);
|
||||
}
|
||||
|
||||
void ConsoleLogger::error(const std::string& tag, const std::string& string) {
|
||||
this->FormatAndDispatch(tag, "e", string, Color::TextError);
|
||||
}
|
||||
|
||||
void ConsoleLogger::FormatAndDispatch(
|
||||
const std::string& tag, const std::string& level, const std::string& str, Color color)
|
||||
{
|
||||
const std::string formatted = u8fmt(
|
||||
"%s [%s] [%s] %s", timestamp().c_str(), level.c_str(), tag.c_str(), str.c_str());
|
||||
|
||||
this->messageQueue.Post(std::make_shared<LogMessage>(this, formatted, color));
|
||||
}
|
||||
|
||||
void ConsoleLogger::ProcessMessage(IMessage& message) {
|
||||
if (message.Type() == message::DebugLog) {
|
||||
auto log = static_cast<LogMessage*>(&message);
|
||||
auto entry = std::make_shared<SingleLineEntry>(log->logValue);
|
||||
entry->SetAttrs(log->color);
|
||||
this->adapter->AddEntry(entry);
|
||||
}
|
||||
}
|
||||
|
||||
ConsoleLogger::AdapterPtr ConsoleLogger::Adapter() {
|
||||
return this->adapter;
|
||||
}
|
43
src/musikcube/app/util/ConsoleLogger.h
Normal file
43
src/musikcube/app/util/ConsoleLogger.h
Normal file
@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include <core/debug.h>
|
||||
#include <core/runtime/IMessageQueue.h>
|
||||
#include <cursespp/Colors.h>
|
||||
#include <cursespp/SimpleScrollAdapter.h>
|
||||
#include <sigslot/sigslot.h>
|
||||
|
||||
namespace musik { namespace cube {
|
||||
|
||||
class ConsoleLogger:
|
||||
public musik::debug::IBackend,
|
||||
public musik::core::runtime::IMessageTarget,
|
||||
public sigslot::has_slots<>
|
||||
{
|
||||
public:
|
||||
using AdapterPtr = std::shared_ptr<cursespp::SimpleScrollAdapter>;
|
||||
|
||||
ConsoleLogger(musik::core::runtime::IMessageQueue& messageQueue);
|
||||
ConsoleLogger(const ConsoleLogger& other) = delete;
|
||||
ConsoleLogger& operator=(const ConsoleLogger& other) = delete;
|
||||
|
||||
virtual void verbose(const std::string& tag, const std::string& string) override;
|
||||
virtual void info(const std::string& tag, const std::string& string) override;
|
||||
virtual void warning(const std::string& tag, const std::string& string) override;
|
||||
virtual void error(const std::string& tag, const std::string& string) override;
|
||||
|
||||
virtual void ProcessMessage(musik::core::runtime::IMessage &message) override;
|
||||
|
||||
AdapterPtr Adapter();
|
||||
|
||||
private:
|
||||
void FormatAndDispatch(
|
||||
const std::string& tag,
|
||||
const std::string& level,
|
||||
const std::string& str,
|
||||
cursespp::Color color);
|
||||
|
||||
AdapterPtr adapter;
|
||||
musik::core::runtime::IMessageQueue& messageQueue;
|
||||
};
|
||||
|
||||
} }
|
@ -63,6 +63,7 @@ namespace musik {
|
||||
static const int JumpToHotkeys = First + 12;
|
||||
static const int SetLastFmState = First + 13;
|
||||
static const int UpdateEqualizer = First + 14;
|
||||
static const int DebugLog = First + 15;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,141 +0,0 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2007-2017 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 "LogWindow.h"
|
||||
|
||||
#include <app/util/Messages.h>
|
||||
|
||||
#include <cursespp/MultiLineEntry.h>
|
||||
#include <cursespp/Colors.h>
|
||||
#include <cursespp/Screen.h>
|
||||
|
||||
using namespace musik::cube;
|
||||
using namespace cursespp;
|
||||
|
||||
typedef IScrollAdapter::IEntry IEntry;
|
||||
|
||||
#define DEBOUNCE_REFRESH() this->Debounce(message::RefreshLogs, 0, 0, 250)
|
||||
|
||||
LogWindow::LogWindow(IWindow *parent)
|
||||
: ScrollableWindow(nullptr, parent) {
|
||||
this->adapter = new SimpleScrollAdapter();
|
||||
this->adapter->SetMaxEntries(500);
|
||||
|
||||
musik::debug::string_logged.connect(this, &LogWindow::OnLogged);
|
||||
musik::debug::warn("LogWindow", "initialized");
|
||||
}
|
||||
|
||||
LogWindow::~LogWindow() {
|
||||
delete this->adapter;
|
||||
}
|
||||
|
||||
IScrollAdapter& LogWindow::GetScrollAdapter() {
|
||||
return (IScrollAdapter&) *this->adapter;
|
||||
}
|
||||
|
||||
void LogWindow::ClearContents() {
|
||||
this->adapter->Clear();
|
||||
this->OnAdapterChanged();
|
||||
}
|
||||
|
||||
void LogWindow::ProcessMessage(musik::core::runtime::IMessage &message) {
|
||||
if (message.Type() == message::RefreshLogs) {
|
||||
this->Update();
|
||||
}
|
||||
else {
|
||||
ScrollableWindow::ProcessMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
void LogWindow::OnVisibilityChanged(bool visible) {
|
||||
ScrollableWindow::OnVisibilityChanged(visible);
|
||||
|
||||
if (visible) {
|
||||
DEBOUNCE_REFRESH();
|
||||
}
|
||||
}
|
||||
|
||||
void LogWindow::Update() {
|
||||
std::unique_lock<std::mutex> lock(pendingMutex);
|
||||
|
||||
if (!pending.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < pending.size(); i++) {
|
||||
Color attrs = Color::TextDefault;
|
||||
|
||||
LogEntry* entry = pending[i];
|
||||
|
||||
switch (entry->level) {
|
||||
case musik::debug::level_error: {
|
||||
attrs = Color::TextError;
|
||||
break;
|
||||
}
|
||||
|
||||
case musik::debug::level_warning: {
|
||||
attrs = Color::TextWarning;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::string s = boost::str(boost::format(
|
||||
"[%1%] %2%") % entry->tag % entry->message);
|
||||
|
||||
this->adapter->AddEntry(std::shared_ptr<IEntry>(new MultiLineEntry(s, attrs)));
|
||||
|
||||
delete entry;
|
||||
}
|
||||
|
||||
this->OnAdapterChanged();
|
||||
pending.clear();
|
||||
}
|
||||
|
||||
void LogWindow::OnLogged( /* from a background thread */
|
||||
musik::debug::log_level level,
|
||||
std::string tag,
|
||||
std::string message)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(pendingMutex);
|
||||
|
||||
LogEntry *entry = new LogEntry();
|
||||
entry->level = level;
|
||||
entry->tag = tag;
|
||||
entry->message = message;
|
||||
pending.push_back(entry);
|
||||
|
||||
DEBOUNCE_REFRESH();
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2007-2017 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 <mutex>
|
||||
|
||||
#include <sigslot/sigslot.h>
|
||||
|
||||
#include <core/debug.h>
|
||||
#include <core/runtime/IMessage.h>
|
||||
|
||||
#include <cursespp/ScrollableWindow.h>
|
||||
#include <cursespp/SimpleScrollAdapter.h>
|
||||
|
||||
namespace musik {
|
||||
namespace cube {
|
||||
class LogWindow:
|
||||
public cursespp::ScrollableWindow,
|
||||
public sigslot::has_slots<>
|
||||
{
|
||||
public:
|
||||
LogWindow(cursespp::IWindow *parent = NULL);
|
||||
virtual ~LogWindow();
|
||||
|
||||
void ClearContents();
|
||||
|
||||
virtual void ProcessMessage(musik::core::runtime::IMessage &message);
|
||||
virtual void OnVisibilityChanged(bool visible);
|
||||
|
||||
protected:
|
||||
virtual cursespp::IScrollAdapter& GetScrollAdapter();
|
||||
|
||||
private:
|
||||
void Update();
|
||||
|
||||
void OnLogged(
|
||||
musik::debug::log_level level,
|
||||
std::string tag,
|
||||
std::string message);
|
||||
|
||||
struct LogEntry {
|
||||
int level;
|
||||
std::string tag;
|
||||
std::string message;
|
||||
};
|
||||
|
||||
std::mutex pendingMutex;
|
||||
std::vector<LogEntry*> pending;
|
||||
cursespp::SimpleScrollAdapter* adapter;
|
||||
};
|
||||
}
|
||||
}
|
@ -39,7 +39,7 @@
|
||||
|
||||
using namespace cursespp;
|
||||
|
||||
MultiLineEntry::MultiLineEntry(const std::string& value, int64_t attrs) {
|
||||
MultiLineEntry::MultiLineEntry(const std::string& value, Color attrs) {
|
||||
this->value = value;
|
||||
this->charCount = value.size();
|
||||
this->width = -1;
|
||||
@ -54,7 +54,7 @@ std::string MultiLineEntry::GetLine(size_t n) {
|
||||
return this->lines.at(n);
|
||||
}
|
||||
|
||||
int64_t MultiLineEntry::GetAttrs(size_t line) {
|
||||
Color MultiLineEntry::GetAttrs(size_t line) {
|
||||
return this->attrs;
|
||||
}
|
||||
|
||||
|
@ -131,7 +131,7 @@ void ScrollAdapterBase::DrawPage(ScrollableWindow* scrollable, size_t index, Scr
|
||||
size_t count = entry->GetLineCount();
|
||||
|
||||
for (size_t i = 0; i < count && drawnLines < this->height; i++) {
|
||||
int64_t attrs = -1;
|
||||
Color attrs = Color::Default;
|
||||
|
||||
if (this->decorator) {
|
||||
attrs = this->decorator(scrollable, topIndex + e, i, entry);
|
||||
|
@ -38,7 +38,6 @@
|
||||
#include <cursespp/SingleLineEntry.h>
|
||||
#include <cursespp/MultiLineEntry.h>
|
||||
#include <cursespp/ScrollableWindow.h>
|
||||
#include <cursespp/Colors.h>
|
||||
#include <utf8/utf8/unchecked.h>
|
||||
|
||||
using namespace cursespp;
|
||||
@ -76,13 +75,25 @@ void SimpleScrollAdapter::SetMaxEntries(size_t maxEntries) {
|
||||
EntryPtr SimpleScrollAdapter::GetEntry(cursespp::ScrollableWindow* window, size_t index) {
|
||||
auto entry = this->entries.at(index);
|
||||
|
||||
/* this is pretty damned gross, but super convenient. */
|
||||
/* this is pretty damned gross, but super convenient; we always use SingleLineEntry
|
||||
internally, so we can do a static_cast<>. we allow the user to customize the
|
||||
color of the line when it's de-selected, so when it becomes selected we remember
|
||||
the original color. upon de-select, the color is restored (see indexToColor) */
|
||||
if (window && selectable) {
|
||||
SingleLineEntry* single = static_cast<SingleLineEntry*>(entry.get());
|
||||
single->SetAttrs(Color(Color::Default));
|
||||
auto it = indexToColor.find(index);
|
||||
if (index == window->GetScrollPosition().logicalIndex) {
|
||||
if (it == indexToColor.end()) {
|
||||
indexToColor[index] = single->GetAttrs(0);
|
||||
}
|
||||
single->SetAttrs(Color(Color::ListItemHighlighted));
|
||||
}
|
||||
else {
|
||||
if (it != indexToColor.end()) {
|
||||
single->SetAttrs(it->second);
|
||||
indexToColor.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return entry;
|
||||
|
@ -40,14 +40,14 @@ using namespace cursespp;
|
||||
|
||||
SingleLineEntry::SingleLineEntry(const std::string& value) {
|
||||
this->value = value;
|
||||
this->attrs = -1;
|
||||
this->attrs = Color::Default;
|
||||
}
|
||||
|
||||
void SingleLineEntry::SetWidth(size_t width) {
|
||||
this->width = width;
|
||||
}
|
||||
|
||||
int64_t SingleLineEntry::GetAttrs(size_t line) {
|
||||
Color SingleLineEntry::GetAttrs(size_t line) {
|
||||
return this->attrs;
|
||||
}
|
||||
|
||||
|
@ -34,6 +34,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cursespp/Colors.h>
|
||||
|
||||
namespace cursespp {
|
||||
class ScrollableWindow;
|
||||
|
||||
@ -63,7 +65,7 @@ namespace cursespp {
|
||||
virtual size_t GetLineCount() = 0;
|
||||
virtual std::string GetLine(size_t line) = 0;
|
||||
virtual void SetWidth(size_t width) = 0;
|
||||
virtual int64_t GetAttrs(size_t line) = 0;
|
||||
virtual Color GetAttrs(size_t line) = 0;
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<IEntry> EntryPtr;
|
||||
|
@ -39,19 +39,19 @@
|
||||
namespace cursespp {
|
||||
class MultiLineEntry : public IScrollAdapter::IEntry {
|
||||
public:
|
||||
MultiLineEntry(const std::string& value, int64_t attrs = -1);
|
||||
MultiLineEntry(const std::string& value, Color attrs = Color::Default);
|
||||
virtual ~MultiLineEntry() { }
|
||||
|
||||
virtual size_t GetLineCount();
|
||||
virtual std::string GetLine(size_t line);
|
||||
virtual void SetWidth(size_t width);
|
||||
virtual int64_t GetAttrs(size_t line);
|
||||
virtual Color GetAttrs(size_t line);
|
||||
|
||||
private:
|
||||
std::string value;
|
||||
std::vector<std::string> lines;
|
||||
size_t charCount;
|
||||
int64_t attrs;
|
||||
Color attrs;
|
||||
size_t width;
|
||||
};
|
||||
}
|
@ -35,6 +35,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <cursespp/curses_config.h>
|
||||
#include <cursespp/Colors.h>
|
||||
#include <cursespp/IScrollAdapter.h>
|
||||
#include <functional>
|
||||
#include <deque>
|
||||
@ -42,7 +43,7 @@
|
||||
namespace cursespp {
|
||||
class ScrollAdapterBase : public IScrollAdapter {
|
||||
public:
|
||||
typedef std::function<int64_t(
|
||||
typedef std::function<Color(
|
||||
ScrollableWindow*,
|
||||
size_t,
|
||||
size_t,
|
||||
|
@ -35,9 +35,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <cursespp/curses_config.h>
|
||||
#include <cursespp/Colors.h>
|
||||
#include <cursespp/ScrollAdapterBase.h>
|
||||
#include <sigslot/sigslot.h>
|
||||
#include <deque>
|
||||
#include <map>
|
||||
|
||||
namespace cursespp {
|
||||
class SimpleScrollAdapter : public ScrollAdapterBase {
|
||||
@ -61,7 +63,7 @@ namespace cursespp {
|
||||
private:
|
||||
typedef std::deque<EntryPtr> EntryList; /* TODO: this is O(n) lookup */
|
||||
typedef EntryList::iterator Iterator;
|
||||
|
||||
std::map<size_t, Color> indexToColor;
|
||||
EntryList entries;
|
||||
size_t maxEntries;
|
||||
bool selectable;
|
||||
|
@ -44,7 +44,7 @@ namespace cursespp {
|
||||
virtual ~SingleLineEntry() { }
|
||||
|
||||
virtual void SetWidth(size_t width);
|
||||
virtual int64_t GetAttrs(size_t line);
|
||||
virtual Color GetAttrs(size_t line);
|
||||
virtual size_t GetLineCount();
|
||||
virtual std::string GetLine(size_t line);
|
||||
|
||||
@ -55,6 +55,6 @@ namespace cursespp {
|
||||
private:
|
||||
size_t width;
|
||||
std::string value;
|
||||
int64_t attrs;
|
||||
Color attrs;
|
||||
};
|
||||
}
|
@ -35,9 +35,7 @@
|
||||
"browse_no_paths_overlay_error_message": "you have not configured any metadata paths.\n\nyou must add at least one path in the settings screen before you can browse by directory.",
|
||||
"browse_no_subdirectories_toast": "there are no more sub-directories.\n\npress '%s' to play the selection.",
|
||||
|
||||
"console_command_output_title": "command output",
|
||||
"console_debug_logs_title": "debug logs",
|
||||
"console_command_title": "command",
|
||||
"console_list_title": "debug logs",
|
||||
|
||||
"hotkeys_title": "key bindings",
|
||||
"hotkeys_reset_defaults": "reset all",
|
||||
@ -172,7 +170,7 @@
|
||||
|
||||
"shortcuts_settings": "settings",
|
||||
"shortcuts_library": "library",
|
||||
"shortcuts_console": "console",
|
||||
"shortcuts_console": "logs",
|
||||
"shortcuts_quit": "quit",
|
||||
"shortcuts_browse": "browse",
|
||||
"shortcuts_filter": "filter",
|
||||
|
@ -212,7 +212,7 @@ static void startDaemon() {
|
||||
std::cerr << "\n ERROR! couldn't create pipe\n\n";
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
close(STDIN_FILENO);
|
||||
close(STDOUT_FILENO);
|
||||
freopen("/tmp/musikcube.log", "w", stderr);
|
||||
@ -237,7 +237,7 @@ int main(int argc, char** argv) {
|
||||
|
||||
srand((unsigned int) time(0));
|
||||
|
||||
debug::init();
|
||||
debug::Start();
|
||||
|
||||
EvMessageQueue messageQueue;
|
||||
auto library = LibraryFactory::Default();
|
||||
|
Loading…
x
Reference in New Issue
Block a user