mirror of
https://github.com/clangen/musikcube.git
synced 2024-10-02 04:52:32 +00:00
Merge branch 'master' of github.com:clangen/musikcube
This commit is contained in:
commit
7d6ac3d6b9
@ -63,6 +63,7 @@ set (musikcube_LINK_LIBS
|
||||
${BOOST_LINK_LIBS}
|
||||
dl
|
||||
curl
|
||||
pthread
|
||||
)
|
||||
|
||||
include_directories (
|
||||
@ -79,6 +80,10 @@ if (CMAKE_SYSTEM_NAME MATCHES "Darwin")
|
||||
include_directories("/usr/local/include")
|
||||
endif ()
|
||||
|
||||
if (EXISTS "/etc/arch-release")
|
||||
add_definitions (-DNO_NCURSESW)
|
||||
endif()
|
||||
|
||||
add_subdirectory(src/core)
|
||||
add_subdirectory(src/glue)
|
||||
add_subdirectory(src/musikcube)
|
||||
|
@ -4,8 +4,6 @@ a cross-platform, terminal-based audio engine, library, player and server writte
|
||||
|
||||
musikcube compiles and runs easily on windows, macos and linux. it also runs well on a raspberry pi with raspbian, and can be setup as a streaming audio server.
|
||||
|
||||
if you'd like to check out a quick demo, you can view an [asciinema cast here](https://asciinema.org/a/129748).
|
||||
|
||||
[keyboard shortcuts are described in the user guide.](https://github.com/clangen/musikcube/wiki/user-guide)
|
||||
|
||||
# screenshots
|
||||
@ -22,7 +20,7 @@ and on linux:
|
||||
|
||||
![linux screenshot](https://raw.githubusercontent.com/clangen/clangen-projects-static/master/musikcube/screenshots/linux.png)
|
||||
|
||||
here's a little demo:
|
||||
here's a demo (made with asciinema):
|
||||
|
||||
[![asciicast](https://asciinema.org/a/129748.png)](https://asciinema.org/a/129748)
|
||||
|
||||
|
@ -36,6 +36,7 @@
|
||||
|
||||
#include <core/debug.h>
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <queue>
|
||||
#include <thread>
|
||||
|
@ -76,7 +76,7 @@ std::string musik::core::GetApplicationDirectory() {
|
||||
result = result.substr(0, last); /* remove filename component */
|
||||
#else
|
||||
std::string pathToProc = boost::str(boost::format("/proc/%d/exe") % (int) getpid());
|
||||
char pathbuf[PATH_MAX + 1];
|
||||
char pathbuf[PATH_MAX + 1] = { 0 };
|
||||
readlink(pathToProc.c_str(), pathbuf, PATH_MAX);
|
||||
result.assign(pathbuf);
|
||||
size_t last = result.find_last_of("/");
|
||||
@ -266,4 +266,4 @@ close_and_return:
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
}
|
||||
|
@ -285,7 +285,7 @@ static size_t writePlayingFormat(
|
||||
}
|
||||
|
||||
ON(w, attr);
|
||||
wprintw(w, value.c_str());
|
||||
checked_wprintw(w, value.c_str());
|
||||
OFF(w, attr);
|
||||
|
||||
remaining -= cols;
|
||||
@ -477,7 +477,7 @@ void TransportWindow::Update(TimeMode timeMode) {
|
||||
|
||||
if (stopped) {
|
||||
ON(c, disabled);
|
||||
wprintw(c, Strings.STOPPED.c_str());
|
||||
checked_wprintw(c, Strings.STOPPED.c_str());
|
||||
displayCache->Reset();
|
||||
OFF(c, disabled);
|
||||
}
|
||||
@ -489,7 +489,7 @@ void TransportWindow::Update(TimeMode timeMode) {
|
||||
wmove(c, 0, cx - shuffleLabelLen);
|
||||
int64_t shuffleAttrs = this->playback.IsShuffled() ? gb : disabled;
|
||||
ON(c, shuffleAttrs);
|
||||
wprintw(c, shuffleLabel.c_str());
|
||||
checked_wprintw(c, shuffleLabel.c_str());
|
||||
OFF(c, shuffleAttrs);
|
||||
|
||||
/* volume slider */
|
||||
@ -604,20 +604,20 @@ void TransportWindow::Update(TimeMode timeMode) {
|
||||
wmove(c, 1, 0); /* move cursor to the second line */
|
||||
|
||||
ON(c, volumeAttrs);
|
||||
wprintw(c, volume.c_str());
|
||||
checked_wprintw(c, volume.c_str());
|
||||
OFF(c, volumeAttrs);
|
||||
|
||||
ON(c, currentTimeAttrs); /* blink if paused */
|
||||
wprintw(c, "%s ", currentTime.c_str());
|
||||
checked_wprintw(c, "%s ", currentTime.c_str());
|
||||
OFF(c, currentTimeAttrs);
|
||||
|
||||
ON(c, timerAttrs);
|
||||
waddstr(c, timerTrack.c_str()); /* may be a very long string */
|
||||
wprintw(c, " %s", displayCache->totalTime.c_str());
|
||||
checked_waddstr(c, timerTrack.c_str()); /* may be a very long string */
|
||||
checked_wprintw(c, " %s", displayCache->totalTime.c_str());
|
||||
OFF(c, timerAttrs);
|
||||
|
||||
ON(c, repeatAttrs);
|
||||
wprintw(c, repeatModeLabel.c_str());
|
||||
checked_wprintw(c, repeatModeLabel.c_str());
|
||||
OFF(c, repeatAttrs);
|
||||
|
||||
this->Invalidate();
|
||||
|
@ -90,7 +90,7 @@ void Checkbox::OnRedraw() {
|
||||
wattron(c, COLOR_PAIR(attrs));
|
||||
}
|
||||
|
||||
wprintw(c, ellipsized.c_str());
|
||||
checked_wprintw(c, ellipsized.c_str());
|
||||
|
||||
if (attrs != -1) {
|
||||
wattroff(c, COLOR_PAIR(attrs));
|
||||
|
@ -169,7 +169,7 @@ void DialogOverlay::RecalculateSize() {
|
||||
}
|
||||
|
||||
void DialogOverlay::Redraw() {
|
||||
if (this->width <= 0 || this->height <= 0) {
|
||||
if (!this->IsVisible() || this->width <= 0 || this->height <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -181,7 +181,7 @@ void DialogOverlay::Redraw() {
|
||||
if (this->title.size()) {
|
||||
wmove(c, currentY, currentX);
|
||||
wattron(c, A_BOLD);
|
||||
wprintw(c, text::Ellipsize(this->title, this->width - 4).c_str());
|
||||
checked_wprintw(c, text::Ellipsize(this->title, this->width - 4).c_str());
|
||||
wattroff(c, A_BOLD);
|
||||
currentY += 2;
|
||||
}
|
||||
@ -189,8 +189,8 @@ void DialogOverlay::Redraw() {
|
||||
if (this->message.size()) {
|
||||
for (size_t i = 0; i < messageLines.size(); i++) {
|
||||
wmove(c, currentY, currentX);
|
||||
wprintw(c, this->messageLines.at(i).c_str());
|
||||
checked_wprintw(c, this->messageLines.at(i).c_str());
|
||||
++currentY;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -172,7 +172,7 @@ void InputOverlay::RecalculateSize() {
|
||||
}
|
||||
|
||||
void InputOverlay::Redraw() {
|
||||
if (this->width <= 0 || this->height <= 0) {
|
||||
if (!this->IsVisible() || this->width <= 0 || this->height <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -181,7 +181,7 @@ void InputOverlay::Redraw() {
|
||||
if (this->title.size()) {
|
||||
wmove(c, 0, 1);
|
||||
wattron(c, A_BOLD);
|
||||
wprintw(c, text::Ellipsize(this->title, this->width - 4).c_str());
|
||||
checked_wprintw(c, text::Ellipsize(this->title, this->width - 4).c_str());
|
||||
wattroff(c, A_BOLD);
|
||||
}
|
||||
}
|
@ -213,7 +213,7 @@ void ListOverlay::RecalculateSize() {
|
||||
}
|
||||
|
||||
void ListOverlay::Redraw() {
|
||||
if (this->width <= 0 || this->height <= 0) {
|
||||
if (!this->IsVisible() || this->width <= 0 || this->height <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -225,7 +225,7 @@ void ListOverlay::Redraw() {
|
||||
if (this->title.size()) {
|
||||
wmove(c, currentY, currentX);
|
||||
wattron(c, A_BOLD);
|
||||
wprintw(c, text::Ellipsize(this->title, this->width - 4).c_str());
|
||||
checked_wprintw(c, text::Ellipsize(this->title, this->width - 4).c_str());
|
||||
wattroff(c, A_BOLD);
|
||||
currentY += 2;
|
||||
}
|
||||
@ -234,4 +234,4 @@ void ListOverlay::Redraw() {
|
||||
|
||||
void ListOverlay::RefreshAdapter() {
|
||||
this->listWindow->OnAdapterChanged();
|
||||
}
|
||||
}
|
||||
|
@ -113,7 +113,7 @@ void ScrollAdapterBase::DrawPage(ScrollableWindow* scrollable, size_t index, Scr
|
||||
WINDOW* window = scrollable->GetContent();
|
||||
werase(window);
|
||||
|
||||
if (this->height == 0 || this->width == 0 || this->GetEntryCount() == 0) {
|
||||
if (!scrollable->IsVisible() || !window || this->height == 0 || this->width == 0 || this->GetEntryCount() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -158,7 +158,7 @@ void ScrollAdapterBase::DrawPage(ScrollableWindow* scrollable, size_t index, Scr
|
||||
|
||||
/* string is padded above, we don't need a \n */
|
||||
|
||||
wprintw(window, "%s", line.c_str());
|
||||
checked_wprintw(window, "%s", line.c_str());
|
||||
|
||||
if (attrs != -1) {
|
||||
wattroff(window, attrs);
|
||||
|
@ -185,7 +185,7 @@ void ShortcutsWindow::OnRedraw() {
|
||||
int64_t keyAttrs = (e->attrs == -1) ? normalAttrs : COLOR_PAIR(e->attrs);
|
||||
keyAttrs = (e->key == this->activeKey) ? activeAttrs : keyAttrs;
|
||||
|
||||
wprintw(c, " ");
|
||||
checked_wprintw(c, " ");
|
||||
--remaining;
|
||||
|
||||
if (remaining == 0) {
|
||||
@ -202,7 +202,7 @@ void ShortcutsWindow::OnRedraw() {
|
||||
}
|
||||
|
||||
wattron(c, keyAttrs);
|
||||
wprintw(c, key.c_str());
|
||||
checked_wprintw(c, key.c_str());
|
||||
wattroff(c, keyAttrs);
|
||||
|
||||
remaining -= len;
|
||||
@ -217,7 +217,7 @@ void ShortcutsWindow::OnRedraw() {
|
||||
len = remaining;
|
||||
}
|
||||
|
||||
wprintw(c, value.c_str());
|
||||
checked_wprintw(c, value.c_str());
|
||||
|
||||
remaining -= len;
|
||||
}
|
||||
|
@ -102,7 +102,7 @@ void TextInput::OnRedraw() {
|
||||
|
||||
if (!this->IsFocused() && !columns && hintText.size()) {
|
||||
/* draw the hint if we have one and there's no string yet */
|
||||
waddstr(c, u8substr(hintText, 0, columns).c_str());
|
||||
checked_waddstr(c, u8substr(hintText, 0, columns).c_str());
|
||||
}
|
||||
else {
|
||||
/* mask the string if we're in password mode */
|
||||
@ -121,7 +121,7 @@ void TextInput::OnRedraw() {
|
||||
|
||||
/* finally, draw the offset/trimmed, potentially masked, padded
|
||||
string to the output */
|
||||
waddstr(c, trimmed.c_str());
|
||||
checked_waddstr(c, trimmed.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,7 +72,7 @@ void TextLabel::OnRedraw() {
|
||||
}
|
||||
|
||||
wmove(c, 0, 0);
|
||||
waddstr(c, aligned.c_str());
|
||||
checked_waddstr(c, aligned.c_str());
|
||||
|
||||
if (attrs != -1) {
|
||||
wattroff(c, COLOR_PAIR(attrs));
|
||||
|
@ -100,7 +100,7 @@ void ToastOverlay::RecalculateSize() {
|
||||
}
|
||||
|
||||
void ToastOverlay::OnRedraw() {
|
||||
if (this->width <= 0 || this->height <= 0) {
|
||||
if (!this->IsVisible() || this->width <= 0 || this->height <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -108,6 +108,6 @@ void ToastOverlay::OnRedraw() {
|
||||
|
||||
for (int i = 0; i < (int) this->titleLines.size(); i++) {
|
||||
wmove(c, i, 1);
|
||||
wprintw(c, text::Ellipsize(this->titleLines[i], this->width - 4).c_str());
|
||||
checked_wprintw(c, text::Ellipsize(this->titleLines[i], this->width - 4).c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -389,18 +389,37 @@ void Window::SetFocusedFrameColor(int64_t color) {
|
||||
this->RepaintBackground();
|
||||
}
|
||||
|
||||
void Window::DrawFrameAndTitle() {
|
||||
box(this->frame, 0, 0);
|
||||
|
||||
/* draw the title, if one is specified */
|
||||
size_t titleLen = u8len(this->title);
|
||||
if (titleLen > 0) {
|
||||
int max = this->width - 4; /* 4 = corner + space + space + corner */
|
||||
if (max > 3) { /* 3 = first character plus ellipse (e.g. 'F..')*/
|
||||
std::string adjusted = " " + text::Ellipsize(this->title, (size_t) max - 2) + " ";
|
||||
wmove(this->frame, 0, 2);
|
||||
checked_waddstr(this->frame, adjusted.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Window::RepaintBackground() {
|
||||
bool focused = IsFocused();
|
||||
|
||||
if (this->drawFrame &&
|
||||
this->frameColor != CURSESPP_DEFAULT_COLOR &&
|
||||
this->frame &&
|
||||
this->content != this->frame)
|
||||
{
|
||||
wbkgd(this->frame, COLOR_PAIR(IsFocused()
|
||||
wbkgd(this->frame, COLOR_PAIR(focused
|
||||
? this->focusedFrameColor : this->frameColor));
|
||||
|
||||
this->DrawFrameAndTitle();
|
||||
}
|
||||
|
||||
if (this->content) {
|
||||
wbkgd(this->content, COLOR_PAIR(IsFocused()
|
||||
wbkgd(this->content, COLOR_PAIR(focused
|
||||
? this->focusedContentColor : this->contentColor));
|
||||
}
|
||||
|
||||
@ -621,8 +640,6 @@ void Window::Create() {
|
||||
sub-window inside */
|
||||
|
||||
else {
|
||||
box(this->frame, 0, 0);
|
||||
|
||||
this->content = newwin(
|
||||
this->height - 2,
|
||||
this->width - 2,
|
||||
@ -646,16 +663,7 @@ void Window::Create() {
|
||||
wbkgd(this->content, COLOR_PAIR(currentContentColor));
|
||||
}
|
||||
|
||||
/* draw the title, if one is specified */
|
||||
size_t titleLen = u8len(this->title);
|
||||
if (titleLen > 0) {
|
||||
int max = this->width - 4; /* 4 = corner + space + space + corner */
|
||||
if (max > 3) { /* 3 = first character plus ellipse (e.g. 'F..')*/
|
||||
std::string adjusted = " " + text::Ellipsize(this->title, (size_t) max - 2) + " ";
|
||||
wmove(this->frame, 0, 2);
|
||||
waddstr(this->frame, adjusted.c_str());
|
||||
}
|
||||
}
|
||||
this->DrawFrameAndTitle();
|
||||
}
|
||||
|
||||
this->Show();
|
||||
|
@ -136,6 +136,7 @@ namespace cursespp {
|
||||
virtual void Destroy();
|
||||
void Recreate();
|
||||
void Clear();
|
||||
void DrawFrameAndTitle();
|
||||
void RepaintBackground();
|
||||
void RecreateForUpdatedDimensions();
|
||||
void DestroyIfBadBounds();
|
||||
|
@ -39,13 +39,18 @@
|
||||
#undef MOUSE_MOVED
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#include <curses.h>
|
||||
#include <panel.h>
|
||||
#elif defined __APPLE__
|
||||
#if defined(WIN32) || defined(__APPLE__) || defined(NO_NCURSESW)
|
||||
#include <curses.h>
|
||||
#include <panel.h>
|
||||
#else
|
||||
#include <ncursesw/curses.h>
|
||||
#include <ncursesw/panel.h>
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#define checked_wprintw(window, format, ...) \
|
||||
if (window && format) { wprintw(window, format, ##__VA_ARGS__); }
|
||||
|
||||
#define checked_waddstr(window, str) \
|
||||
if (window && str) { waddstr(window, str); }
|
||||
|
@ -226,7 +226,7 @@ bool TaglibMetadataReader::GetID3v2Tag(const char* uri, musik::core::sdk::ITrack
|
||||
}
|
||||
|
||||
if (!allTags["TCOP"].isEmpty()) { /* ID3v2.3*/
|
||||
this->SetTagValue("year", allTags["TDRC"].front()->toString().substr(0, 4), track);
|
||||
this->SetTagValue("year", allTags["TCOP"].front()->toString().substr(0, 4), track);
|
||||
}
|
||||
|
||||
/* TRCK is the track number (or "trackNum/totalTracks") */
|
||||
|
Loading…
Reference in New Issue
Block a user