- Created IWindow interface

- Renamed BorderedWindow -> Window
- Fixed more layout bugs in SimpleScrollAdapter -- I think it's stable
  now for reals.
This commit is contained in:
casey 2016-05-09 18:51:36 -07:00
parent b5a9a22020
commit d96b44f236
22 changed files with 359 additions and 389 deletions

View File

@ -56,13 +56,25 @@ static const std::string TAG = "Indexer";
using namespace musik::core;
static std::string normalizeDir(std::string path) {
path = boost::filesystem::path(path).make_preferred().string();
std::string sep(1, boost::filesystem::path::preferred_separator);
if (path.substr(path.size() - 1, 1) != sep) {
path += sep;
}
return path;
}
static std::string normalizePath(const std::string& path) {
return boost::filesystem::path(path).make_preferred().string();
}
Indexer::Indexer()
: thread(NULL)
, overallProgress(0)
, currentProgress(0)
, status(0)
, restart(false)
, nofFiles(0)
, filesIndexed(0)
, filesSaved(0) {
}
@ -82,27 +94,6 @@ Indexer::~Indexer(){
}
}
//////////////////////////////////////////
///\brief
///Get the current status (text)
//////////////////////////////////////////
std::string Indexer::GetStatus() {
boost::mutex::scoped_lock lock(this->progressMutex);
switch (status) {
case 1: return boost::str(boost::format("counting... %1%") % this->nofFiles);
case 2: return boost::str(boost::format("indexing... %.2f") % (this->overallProgress * 100)) + "%";
case 3: return boost::str(boost::format("removing... %.2f") % (this->overallProgress * 100)) + "%";
case 4: return "cleaning...";
case 5: return "optimizing...";
case 6: return boost::str(boost::format("running analyzers...: %.2f%% (current %.1f%%)")
% (100.0 * this->overallProgress / (double) this->nofFiles)
% (this->currentProgress * 100.0));
}
return "doing something... (unknown)";
}
//////////////////////////////////////////
///\brief
///Restart the sync
@ -140,17 +131,10 @@ bool Indexer::Restarted() {
///\remarks
///If the path already exists it will not be added.
//////////////////////////////////////////
void Indexer::AddPath(std::string path) {
boost::filesystem::path fsPath(path);
path = fsPath.string(); /* canonicalize */
if (path.substr(path.size() -1, 1) != "/") {
path += "/";
}
void Indexer::AddPath(const std::string& path) {
Indexer::AddRemoveContext context;
context.add = true;
context.path = path;
context.path = normalizeDir(path);
{
boost::mutex::scoped_lock lock(this->exitMutex);
@ -167,11 +151,10 @@ void Indexer::AddPath(std::string path) {
///\param sPath
///Path to remove
//////////////////////////////////////////
void Indexer::RemovePath(std::string path) {
void Indexer::RemovePath(const std::string& path) {
Indexer::AddRemoveContext context;
context.add = false;
context.path = path;
context.path = normalizeDir(path);
{
boost::mutex::scoped_lock lock(this->exitMutex);
@ -195,7 +178,6 @@ void Indexer::Synchronize() {
{
boost::mutex::scoped_lock lock(this->progressMutex);
this->nofFiles = 0;
this->filesIndexed = 0;
}
@ -209,7 +191,7 @@ void Indexer::Synchronize() {
{
db::Statement stmt("SELECT id, path FROM paths", this->dbConnection);
while (stmt.Step()==db::Row) {
while (stmt.Step() == db::Row) {
try {
DBID id = stmt.ColumnInt(0);
std::string path = stmt.ColumnText(1);
@ -225,31 +207,17 @@ void Indexer::Synchronize() {
}
}
/* count the files that need to be processed */
// {
// boost::mutex::scoped_lock lock(this->progressMutex);
// this->status = 1;
// this->overallProgress = 0.0;
// }
//for(std::size_t i = 0; i < paths.size(); ++i){
// std::string path = paths[i];
// this->CountFiles(path);
// }
/* add new files */
{
boost::mutex::scoped_lock lock(this->progressMutex);
this->status = 2;
this->overallProgress = 0.0;
this->filesSaved = 0;
}
for(std::size_t i = 0; i < paths.size(); ++i) {
std::string path = paths[i];
this->SyncDirectory(path ,0, pathIds[i], path);
this->SyncDirectory(path, path ,0, pathIds[i]);
}
/* remove undesired entries from db (files themselves will remain) */
@ -259,7 +227,6 @@ void Indexer::Synchronize() {
{
boost::mutex::scoped_lock lock(this->progressMutex);
this->status = 3;
this->overallProgress = 0.0;
}
if (!this->Restarted() && !this->Exited()) {
@ -272,7 +239,6 @@ void Indexer::Synchronize() {
{
boost::mutex::scoped_lock lock(this->progressMutex);
this->overallProgress = 0.0;
this->status = 4;
}
@ -287,8 +253,7 @@ void Indexer::Synchronize() {
{
boost::mutex::scoped_lock lock(this->progressMutex);
this->overallProgress = 0.0;
this->status = 5;
this->status = 5;
}
if(!this->Restarted() && !this->Exited()){
@ -307,37 +272,6 @@ void Indexer::Synchronize() {
musik::debug::info(TAG, "done!");
}
//////////////////////////////////////////
///\brief
///Counts the number of files to synchronize
///
///\param dir
///Folder to count files in.
//////////////////////////////////////////
void Indexer::CountFiles(const std::string &dir) {
if (!this->Exited() && !this->Restarted()) {
boost::filesystem::path path(dir);
try{
boost::filesystem::directory_iterator invalidFile;
boost::filesystem::directory_iterator file(path);
for ( ; file != invalidFile; ++file) {
if (is_directory(file->status())) {
this->CountFiles(file->path().string());
}
else {
boost::mutex::scoped_lock lock(this->progressMutex);
this->nofFiles++;
}
}
}
catch(...) {
}
}
}
//////////////////////////////////////////
///\brief
///Reads all tracks in a folder
@ -355,19 +289,19 @@ void Indexer::CountFiles(const std::string &dir) {
//////////////////////////////////////////
void Indexer::SyncDirectory(
const std::string &inDir,
const std::string &syncRoot,
const std::string &currentPath,
DBID parentDirId,
DBID pathId,
std::string &syncPath)
DBID pathId)
{
if(this->Exited() || this->Restarted()) {
if (this->Exited() || this->Restarted()) {
return;
}
boost::filesystem::path path(inDir);
std::string dir = path.string(); /* canonicalize slash*/
std::string normalizedSyncRoot = normalizeDir(syncRoot);
std::string normalizedCurrentPath = normalizeDir(currentPath);
std::string leaf = boost::filesystem::path(currentPath).leaf().string(); /* trailing subdir in currentPath */
std::string leaf(path.leaf().string());
DBID dirId = 0;
/* get relative folder id */
@ -378,17 +312,15 @@ void Indexer::SyncDirectory(
stmt.BindInt(1, pathId);
stmt.BindInt(2, parentDirId);
if(stmt.Step() == db::Row) {
if (stmt.Step() == db::Row) {
dirId = stmt.ColumnInt(0);
}
}
boost::thread::yield();
/* no ID yet? needs to be inserted... */
if (dirId == 0) {
std::string relativePath(dir.substr(syncPath.size()));
std::string relativePath(normalizedCurrentPath.substr(normalizedSyncRoot.size()));
db::CachedStatement stmt("INSERT INTO folders (name, path_id, parent_id, relative_path) VALUES(?,?,?,?)", this->dbConnection);
stmt.BindText(0, leaf);
@ -403,29 +335,25 @@ void Indexer::SyncDirectory(
dirId = this->dbConnection.LastInsertedId();
}
boost::thread::yield(); /* whistle... */
/* start recursive filesystem scan */
try { /* boost::filesystem may throw */
/* for each file in the current path... */
boost::filesystem::path path(currentPath);
boost::filesystem::directory_iterator end;
boost::filesystem::directory_iterator file(path);
for( ; file != end && !this->Exited() && !this->Restarted();++file) {
for( ; file != end && !this->Exited() && !this->Restarted(); file++) {
if (is_directory(file->status())) {
/* recursion here */
musik::debug::info(TAG, "scanning " + file->path().string());
this->SyncDirectory(file->path().string(), dirId, pathId, syncPath);
this->SyncDirectory(syncRoot, file->path().string(), dirId, pathId);
}
else {
++this->filesIndexed;
/* update overallProgress every so often... */
if (this->filesIndexed % 25 == 0) {
boost::mutex::scoped_lock lock(this->progressMutex);
this->overallProgress = (double) this->filesIndexed / (double)this->nofFiles;
}
musik::core::IndexerTrack track(0);
/* get cached filesize, parts, size, etc */
@ -456,8 +384,6 @@ void Indexer::SyncDirectory(
}
}
}
boost::thread::yield();
}
}
catch(...) {
@ -646,13 +572,6 @@ void Indexer::SyncDelete(const std::vector<DBID>& paths) {
stmtSyncPath.Reset();
while(stmt.Step() == db::Row && !this->Exited() && !this->Restarted()) {
{
boost::mutex::scoped_lock lock(this->progressMutex);
if (songs > 0) {
this->overallProgress = 0.2+0.8*(double)count/(double)(songs);
}
}
bool remove = true;
std::string file = stmt.ColumnText(1);
@ -732,20 +651,14 @@ void Indexer::SyncCleanup() {
///\brief
///Get a vector with all sync paths
//////////////////////////////////////////
std::vector<std::string> Indexer::GetPaths() {
std::vector<std::string> paths;
db::Connection tempDB;
tempDB.Open(this->database.c_str());
db::Statement stmt("SELECT path FROM paths ORDER BY id", tempDB);
void Indexer::GetPaths(std::vector<std::string>& paths) {
db::Connection connection;
connection.Open(this->database.c_str());
db::Statement stmt("SELECT path FROM paths ORDER BY id", connection);
while (stmt.Step() == db::Row) {
paths.push_back(stmt.ColumnText(0));
}
return paths;
}
static int optimize(
@ -888,19 +801,9 @@ void Indexer::RunAnalyzers() {
{
boost::mutex::scoped_lock lock(this->progressMutex);
this->overallProgress = 0;
this->currentProgress = 0;
this->nofFiles = 0;
this->status = 6;
}
/* figure out how many files we need to process */
db::Statement totalTracks("SELECT count(*) FROM tracks", this->dbConnection);
if (totalTracks.Step() == db::Row){
this->nofFiles = totalTracks.ColumnInt(0);
}
/* for each track... */
DBID trackId = 0;
@ -942,11 +845,6 @@ void Indexer::RunAnalyzers() {
audio::BufferPtr buffer;
while ((buffer = stream->GetNextProcessedOutputBuffer()) && !runningAnalyzers.empty()) {
{
boost::mutex::scoped_lock lock(this->progressMutex);
this->currentProgress = stream->DecoderProgress();
}
PluginVector::iterator plugin = runningAnalyzers.begin();
while(plugin != runningAnalyzers.end()) {
if ((*plugin)->Analyze(&track, buffer.get())) {
@ -976,11 +874,6 @@ void Indexer::RunAnalyzers() {
if(successPlugins>0) {
track.Save(this->dbConnection, this->libraryPath,folderId);
}
{
boost::mutex::scoped_lock lock(this->progressMutex);
this->currentProgress = 0;
}
}
}
}
@ -990,11 +883,6 @@ void Indexer::RunAnalyzers() {
return;
}
{
boost::mutex::scoped_lock lock(this->progressMutex);
this->overallProgress++;
}
getNextTrack.BindInt(0, trackId);
}

View File

@ -62,14 +62,13 @@ namespace musik { namespace core {
Indexer();
~Indexer();
void AddPath(std::string sPath);
void RemovePath(std::string sPath);
std::vector<std::string> GetPaths();
void AddPath(const std::string& paths);
void RemovePath(const std::string& paths);
void GetPaths(std::vector<std::string>& paths);
bool Startup(std::string setLibraryPath);
void ThreadLoop();
std::string GetStatus();
void RestartSync(bool bNewRestart=true);
bool Restarted();
@ -91,16 +90,17 @@ namespace musik { namespace core {
boost::thread *thread;
boost::mutex progressMutex;
double overallProgress;
double currentProgress;
int nofFiles;
int filesIndexed;
int filesSaved;
void CountFiles(const std::string &dir);
void Synchronize();
void SyncDirectory(const std::string& dir, DBID parentDirId, DBID pathId, std::string &syncPath);
void SyncDirectory(
const std::string& syncRoot,
const std::string& currentPath,
DBID parentDirId,
DBID pathId);
void SyncDelete(const std::vector<DBID>& paths);
void SyncCleanup();
void ProcessAddRemoveQueue();

View File

@ -1,130 +0,0 @@
#pragma once
#include "stdafx.h"
#include "BorderedWindow.h"
BorderedWindow::BorderedWindow() {
this->border = this->contents = 0;
this->height = 0;
this->width = 0;
this->x = 0;
this->y = 0;
this->contentColor = -1;
this->borderColor = -1;
this->scrollable = false;
}
BorderedWindow::~BorderedWindow() {
this->Destroy();
}
void BorderedWindow::SetSize(int width, int height) {
this->width = width;
this->height = height;
}
void BorderedWindow::SetPosition(int x, int y) {
this->x = x;
this->y = y;
}
int BorderedWindow::GetWidth() const {
return this->width;
}
int BorderedWindow::GetHeight() const {
return this->height;
}
int BorderedWindow::GetContentHeight() const {
return this->height - 2;
}
int BorderedWindow::GetContentWidth() const {
return this->width - 2;
}
int BorderedWindow::GetX() const {
return this->x;
}
int BorderedWindow::GetY() const {
return this->y;
}
void BorderedWindow::SetContentColor(int color) {
this->contentColor = color;
if (this->contentColor != -1 && this->contents) {
wbkgd(this->contents, COLOR_PAIR(this->contentColor));
this->Repaint();
}
}
void BorderedWindow::SetBorderColor(int color) {
this->borderColor = color;
if (this->borderColor != -1 && this->border) {
wbkgd(this->border, COLOR_PAIR(this->borderColor));
this->Repaint();
}
}
void BorderedWindow::SetScrollable(bool scrollable) {
this->scrollable = scrollable;
}
bool BorderedWindow::GetScrollable() const {
return this->scrollable;
}
WINDOW* BorderedWindow::GetContents() const {
return this->contents;
}
void BorderedWindow::Create() {
this->Destroy();
this->border = newwin(this->height, this->width, this->y, this->x);
box(this->border, 0, 0);
wrefresh(this->border);
this->contents = derwin(
this->border,
this->height - 2,
this->width - 2,
1,
1);
scrollok(this->contents, this->scrollable);
if (this->contentColor != -1) {
wbkgd(this->contents, COLOR_PAIR(this->contentColor));
}
if (this->borderColor != -1) {
wbkgd(this->border, COLOR_PAIR(this->borderColor));
}
touchwin(this->contents);
wrefresh(this->contents);
}
void BorderedWindow::Clear() {
wclear(this->contents);
}
void BorderedWindow::Repaint() {
if (this->border && this->contents) {
wrefresh(this->border);
wrefresh(this->contents);
}
}
void BorderedWindow::Destroy() {
if (this->border) {
delwin(this->contents);
delwin(this->border);
this->border = this->contents = NULL;
}
}

View File

@ -1,37 +0,0 @@
#pragma once
#include "curses_config.h"
class BorderedWindow {
public:
BorderedWindow();
virtual ~BorderedWindow();
void Create();
void Destroy();
virtual void Repaint();
virtual void SetContentColor(int color);
virtual void SetBorderColor(int color);
protected:
WINDOW* GetContents() const;
void SetSize(int width, int height);
void SetPosition(int x, int y);
void SetScrollable(bool scrollable);
void Clear();
int GetWidth() const;
int GetHeight() const;
int GetContentHeight() const;
int GetContentWidth() const;
int GetX() const;
int GetY() const;
bool GetScrollable() const;
private:
WINDOW* border;
WINDOW* contents;
int width, height, x, y, contentColor, borderColor;
bool scrollable;
};

View File

@ -46,15 +46,19 @@ CommandWindow::~CommandWindow() {
delete[] buffer;
}
void CommandWindow::Focus() {
wmove(this->GetContent(), 0, bufferPosition);
}
void CommandWindow::WriteChar(int ch) {
if (bufferPosition >= MAX_SIZE) {
return;
}
waddch(this->GetContents(), ch);
waddch(this->GetContent(), ch);
if (ch == 8) { /* backspace */
wdelch(this->GetContents());
wdelch(this->GetContent());
if (bufferPosition > 0) {
--bufferPosition;
@ -72,7 +76,7 @@ void CommandWindow::WriteChar(int ch) {
}
}
wclear(this->GetContents());
wclear(this->GetContent());
this->bufferPosition = 0;
}
else {
@ -144,8 +148,8 @@ bool CommandWindow::ProcessCommand(const std::string& cmd) {
library->Indexer()->RemovePath(path);
}
else if (name == "lsdirs") {
/* should not be returning a vector, should be pass by ref */
std::vector<std::string> paths = library->Indexer()->GetPaths();
std::vector<std::string> paths;
library->Indexer()->GetPaths(paths);
this->output->WriteLine("paths:");
for (size_t i = 0; i < paths.size(); i++) {
this->output->WriteLine(" " + paths.at(i));

View File

@ -1,7 +1,7 @@
#pragma once
#include "curses_config.h"
#include "BorderedWindow.h"
#include "Window.h"
#include "OutputWindow.h"
#include "IInput.h"
#include <core/playback/Transport.h>
@ -10,12 +10,13 @@
using musik::core::LibraryPtr;
using namespace musik::core::audio;
class CommandWindow : public BorderedWindow, public IInput {
class CommandWindow : public Window, public IInput {
public:
CommandWindow(Transport& transport, OutputWindow& output);
~CommandWindow();
virtual void WriteChar(int ch);
virtual void Focus();
private:
void ListPlugins() const;

View File

@ -5,4 +5,5 @@
class IInput {
public:
virtual void WriteChar(int ch) = 0;
virtual void Focus() = 0;
};

8
src/musikbox/ILayout.h Executable file
View File

@ -0,0 +1,8 @@
#pragma once
#include "IWindow.h"
class ILayout {
virtual IWindow* focusNext() = 0;
virtual IWindow* focusPrev() = 0;
};

26
src/musikbox/IWindow.h Executable file
View File

@ -0,0 +1,26 @@
#pragma once
#include "curses_config.h"
class IWindow {
public:
virtual void Repaint() = 0;
virtual void SetContentColor(int color) = 0;
virtual void SetFrameColor(int color) = 0;
virtual void SetSize(int width, int height) = 0;
virtual void SetPosition(int x, int y) = 0;
virtual int GetWidth() const = 0;
virtual int GetHeight() const = 0;
virtual int GetContentHeight() const = 0;
virtual int GetContentWidth() const = 0;
virtual int GetX() const = 0;
virtual int GetY() const = 0;
virtual WINDOW* GetFrame() const = 0;
virtual WINDOW* GetContent() const = 0;
};

View File

@ -35,7 +35,7 @@ void LogWindow::Update() {
return;
}
WINDOW* contents = this->GetContents();
WINDOW* contents = this->GetContent();
for (size_t i = 0; i < pending.size(); i++) {
int64 attrs = COLOR_PAIR(BOX_COLOR_WHITE_ON_BLUE);

View File

@ -79,7 +79,6 @@ int main(int argc, char* argv[])
start_color();
use_default_colors();
refresh();
curs_set(0);
#ifdef __PDCURSES__
PDC_set_title("musikbox ♫");
@ -96,28 +95,51 @@ int main(int argc, char* argv[])
CommandWindow command(tp, output);
TransportWindow transport(tp);
std::vector<BorderedWindow*> order;
std::vector<IWindow*> order;
order.push_back(&command);
order.push_back(&logs);
order.push_back(&output);
/* set the initial state: select the command window and get
the focused state painting properly. it will be done automatically
every time after this */
size_t index = 0;
BorderedWindow *focused = order.at(index);
focused->SetBorderColor(BOX_COLOR_RED_ON_BLACK);
IWindow *focused = order.at(index);
ScrollableWindow *scrollable = NULL;
IInput *input = &command;
focused->SetFrameColor(BOX_COLOR_RED_ON_BLACK);
curs_set(1);
input->Focus();
wtimeout(focused->GetContent(), 500);
bool disable = false;
int ch;
timeout(500);
while (ch = getch()) {
ScrollableWindow *scrollable = dynamic_cast<ScrollableWindow*>(focused);
IInput *input = dynamic_cast<IInput*>(focused);
bool quit = false;
while (!quit) {
/* if the focused item is an IInput, then get characters from it,
so it can draw a pretty cursor if it wants */
ch = (input != NULL) ? wgetch(focused->GetContent()) : getch();
if (ch == -1) { /* timeout */
logs.Update();
if (!disable) {
logs.Update();
}
transport.Repaint();
resources.Repaint();
}
else if (ch == 'f') {
disable = true;
}
else if (ch == 9) { /* tab */
focused->SetBorderColor(BOX_COLOR_WHITE_ON_BLACK);
if (input != NULL) {
wtimeout(focused->GetContent(), 0);
}
focused->SetFrameColor(BOX_COLOR_WHITE_ON_BLACK);
index++;
if (index >= order.size()) {
@ -125,7 +147,19 @@ int main(int argc, char* argv[])
}
focused = order.at(index);
focused->SetBorderColor(BOX_COLOR_RED_ON_BLACK);
focused->SetFrameColor(BOX_COLOR_RED_ON_BLACK);
scrollable = dynamic_cast<ScrollableWindow*>(focused);
input = dynamic_cast<IInput*>(focused);
if (input != NULL) {
curs_set(1);
input->Focus();
wtimeout(focused->GetContent(), 500);
}
else {
curs_set(0);
}
}
else if (ch >= KEY_F(0) && ch <= KEY_F(12)) {
}

View File

@ -34,11 +34,11 @@ void ResourcesWindow::Repaint() {
float physicalMemoryUsed = (float) systemInfo->GetUsedPhysicalMemory() / BYTES_PER_MEGABYTE;
wprintw(
this->GetContents(),
this->GetContent(),
"cpu %.2f%% - virt %.2f (mb) - phys %.2f (mb)",
systemInfo->GetCpuUsage(),
virtualMemoryUsed,
physicalMemoryUsed);
BorderedWindow::Repaint();
Window::Repaint();
}

View File

@ -1,10 +1,10 @@
#pragma once
#include "curses_config.h"
#include "BorderedWindow.h"
#include "Window.h"
#include "SystemInfo.h"
class ResourcesWindow : public BorderedWindow {
class ResourcesWindow : public Window {
public:
ResourcesWindow();
virtual ~ResourcesWindow();

View File

@ -8,7 +8,7 @@
#include <core/debug.h>
ScrollableWindow::ScrollableWindow()
: BorderedWindow() {
: Window() {
scrollPosition = 0;
scrolledToBottom = true;
}
@ -22,7 +22,7 @@ void ScrollableWindow::OnAdapterChanged() {
this->ScrollToBottom();
}
else {
GetScrollAdapter().DrawPage(this->GetContents(), this->scrollPosition);
GetScrollAdapter().DrawPage(this->GetContent(), this->scrollPosition);
this->Repaint();
}
}
@ -37,7 +37,7 @@ size_t ScrollableWindow::GetLastVisible() {
}
void ScrollableWindow::ScrollToTop() {
GetScrollAdapter().DrawPage(this->GetContents(), 0);
GetScrollAdapter().DrawPage(this->GetContent(), 0);
this->scrollPosition = 0;
this->Repaint();
this->CheckScrolledToBottom();
@ -52,7 +52,7 @@ void ScrollableWindow::ScrollToBottom() {
int actual = total - height;
actual = (actual < 0) ? 0 : actual;
adapter->DrawPage(this->GetContents(), actual);
adapter->DrawPage(this->GetContent(), actual);
this->scrollPosition = actual;
this->Repaint();
@ -63,7 +63,7 @@ void ScrollableWindow::ScrollUp(int delta) {
int actual = (int) this->scrollPosition - delta;
actual = (actual < 0) ? 0 : actual;
GetScrollAdapter().DrawPage(this->GetContents(), actual);
GetScrollAdapter().DrawPage(this->GetContent(), actual);
this->scrollPosition = (size_t) actual;
this->Repaint();
@ -81,7 +81,7 @@ void ScrollableWindow::ScrollDown(int delta) {
int actual = (int) this->scrollPosition + delta;
actual = (actual > max) ? max : actual;
adapter->DrawPage(this->GetContents(), actual);
adapter->DrawPage(this->GetContent(), actual);
this->scrollPosition = (size_t) actual;
this->Repaint();

View File

@ -1,10 +1,10 @@
#pragma once
#include "curses_config.h"
#include "BorderedWindow.h"
#include "Window.h"
#include "IScrollAdapter.h"
class ScrollableWindow : public BorderedWindow {
class ScrollableWindow : public Window {
public:
ScrollableWindow();
~ScrollableWindow();

View File

@ -6,6 +6,15 @@
#define MAX_ENTRY_COUNT 0xffffffff
inline static int utf8Length(const std::string& str) {
try {
return utf8::distance(str.begin(), str.end());
}
catch (...) {
return str.length();
}
}
SimpleScrollAdapter::SimpleScrollAdapter() {
this->lineCount = 0;
@ -66,7 +75,7 @@ void SimpleScrollAdapter::DrawPage(WINDOW* window, size_t lineNumber) {
Iterator end = this->entries.end();
size_t remaining = this->height;
size_t w = this->width;
size_t c = lineNumber - (*it)->GetIndex();
size_t c = lineNumber - ((*it)->GetIndex() - removedOffset);
do {
size_t count = (*it)->GetLineCount();
@ -78,7 +87,12 @@ void SimpleScrollAdapter::DrawPage(WINDOW* window, size_t lineNumber) {
for (size_t i = c; i < count && remaining != 0; i++) {
std::string line = (*it)->GetLine(i).c_str();
wprintw(window, "%s\n", line.c_str());
size_t len = utf8Length(line);
/* don't add a newline if we're going to hit the end of the line, the
newline will be added automatically. */
wprintw(window, "%s%s", line.c_str(), len >= this->width ? "" : "\n");
--remaining;
}
@ -181,15 +195,6 @@ void SimpleScrollAdapter::Entry::SetAttrs(int64 attrs) {
this->attrs = attrs;
}
inline static int utf8Length(const std::string& str) {
try {
return utf8::distance(str.begin(), str.end());
}
catch (...) {
return str.length();
}
}
inline static void breakIntoSubLines(
std::string& line,
size_t width,
@ -222,7 +227,7 @@ inline static void breakIntoSubLines(
std::vector<std::string> sanitizedWords;
for (size_t i = 0; i < words.size(); i++) {
std::string word = words.at(i);
size_t len = std::distance(word.begin(), word.end());
size_t len = utf8Length(word);
/* this word is fine, it'll easily fit on its own line of necessary */
@ -248,7 +253,7 @@ inline static void breakIntoSubLines(
utf8::unchecked::next(end);
++count;
if (count == width - 1 || end == word.end()) {
if (count == width || end == word.end()) {
sanitizedWords.push_back(std::string(begin, end));
begin = end;
count = 0;
@ -268,7 +273,7 @@ inline static void breakIntoSubLines(
for (size_t i = 0; i < sanitizedWords.size(); i++) {
std::string word = sanitizedWords.at(i);
size_t wordLength = utf8Length(word);
size_t extra = (i != 0) && (sanitizedWords.size() - 1);
size_t extra = (i != 0) && (i != sanitizedWords.size() - 1);
/* we have enough space for this new word. accumulate it. the
+1 here is to take the space into account */
@ -285,7 +290,9 @@ inline static void breakIntoSubLines(
/* otherwise, flush the current line, and start a new one... */
else {
output.push_back(accum);
if (accum.size()) {
output.push_back(accum);
}
/* special case -- if the word is the exactly length of the
width, just add it as a new line and reset... */
@ -312,7 +319,6 @@ inline static void breakIntoSubLines(
}
void SimpleScrollAdapter::Entry::SetWidth(size_t width) {
width--;
if (this->width != width) {
this->width = width;

View File

@ -35,12 +35,12 @@ TransportWindow::~TransportWindow() {
void TransportWindow::Repaint() {
this->Clear();
WINDOW *c = this->GetContents();
WINDOW *c = this->GetContent();
float volume = (this->transport->Volume() * 100.0);
wprintw(c, "volume %.1f%%\n", volume);
wprintw(c, "filename: ");
BorderedWindow::Repaint();
Window::Repaint();
}

View File

@ -1,13 +1,13 @@
#pragma once
#include "curses_config.h"
#include "BorderedWindow.h"
#include "Window.h"
#include "OutputWindow.h"
#include <core/playback/Transport.h>
using namespace musik::core::audio;
class TransportWindow : public BorderedWindow {
class TransportWindow : public Window {
public:
TransportWindow(Transport& transport);
~TransportWindow();

123
src/musikbox/Window.cpp Executable file
View File

@ -0,0 +1,123 @@
#pragma once
#include "stdafx.h"
#include "Window.h"
Window::Window() {
this->frame = this->content = 0;
this->height = 0;
this->width = 0;
this->x = 0;
this->y = 0;
this->contentColor = -1;
this->frameColor = -1;
}
Window::~Window() {
this->Destroy();
}
void Window::SetSize(int width, int height) {
this->width = width;
this->height = height;
}
void Window::SetPosition(int x, int y) {
this->x = x;
this->y = y;
}
int Window::GetWidth() const {
return this->width;
}
int Window::GetHeight() const {
return this->height;
}
int Window::GetContentHeight() const {
return this->height - 2;
}
int Window::GetContentWidth() const {
return this->width - 2;
}
int Window::GetX() const {
return this->x;
}
int Window::GetY() const {
return this->y;
}
void Window::SetContentColor(int color) {
this->contentColor = color;
if (this->contentColor != -1 && this->content) {
wbkgd(this->content, COLOR_PAIR(this->contentColor));
this->Repaint();
}
}
void Window::SetFrameColor(int color) {
this->frameColor = color;
if (this->frameColor != -1 && this->frame) {
wbkgd(this->frame, COLOR_PAIR(this->frameColor));
this->Repaint();
}
}
WINDOW* Window::GetContent() const {
return this->content;
}
WINDOW* Window::GetFrame() const {
return this->frame;
}
void Window::Create() {
this->Destroy();
this->frame = newwin(this->height, this->width, this->y, this->x);
box(this->frame, 0, 0);
wrefresh(this->frame);
this->content = derwin(
this->frame,
this->height - 2,
this->width - 2,
1,
1);
if (this->contentColor != -1) {
wbkgd(this->content, COLOR_PAIR(this->contentColor));
}
if (this->frameColor != -1) {
wbkgd(this->frame, COLOR_PAIR(this->frameColor));
}
touchwin(this->content);
wrefresh(this->content);
}
void Window::Clear() {
wclear(this->content);
}
void Window::Repaint() {
if (this->frame && this->content) {
wrefresh(this->frame);
wrefresh(this->content);
}
}
void Window::Destroy() {
if (this->frame) {
delwin(this->content);
delwin(this->frame);
this->frame = this->content = NULL;
}
}

38
src/musikbox/Window.h Executable file
View File

@ -0,0 +1,38 @@
#pragma once
#include "curses_config.h"
#include "IWindow.h"
class Window : public IWindow {
public:
Window();
virtual ~Window();
void Create();
void Destroy();
virtual void Repaint();
virtual void SetContentColor(int color);
virtual void SetFrameColor(int color);
virtual void SetSize(int width, int height);
virtual void SetPosition(int x, int y);
virtual int GetWidth() const;
virtual int GetHeight() const;
virtual int GetContentHeight() const;
virtual int GetContentWidth() const;
virtual int GetX() const;
virtual int GetY() const;
virtual WINDOW* GetFrame() const;
virtual WINDOW* GetContent() const;
protected:
void Clear();
private:
WINDOW* frame;
WINDOW* content;
int width, height, x, y, contentColor, frameColor;
};

View File

@ -115,7 +115,7 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="BorderedWindow.cpp" />
<ClCompile Include="Window.cpp" />
<ClCompile Include="Colors.cpp" />
<ClCompile Include="CommandWindow.cpp" />
<ClCompile Include="IInput.h" />
@ -136,10 +136,12 @@
<ClCompile Include="TransportWindow.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="BorderedWindow.h" />
<ClInclude Include="Window.h" />
<ClInclude Include="Colors.h" />
<ClInclude Include="CommandWindow.h" />
<ClInclude Include="curses_config.h" />
<ClInclude Include="ILayout.h" />
<ClInclude Include="IWindow.h" />
<ClInclude Include="LogWindow.h" />
<ClInclude Include="OutputWindow.h" />
<ClInclude Include="ResourcesWindow.h" />

View File

@ -4,9 +4,6 @@
<ClCompile Include="TransportEvents.cpp" />
<ClCompile Include="Main.cpp" />
<ClCompile Include="stdafx.cpp" />
<ClCompile Include="BorderedWindow.cpp">
<Filter>curses</Filter>
</ClCompile>
<ClCompile Include="Colors.cpp">
<Filter>curses</Filter>
</ClCompile>
@ -43,13 +40,13 @@
<ClCompile Include="IInput.h">
<Filter>curses</Filter>
</ClCompile>
<ClCompile Include="Window.cpp">
<Filter>curses</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="TransportEvents.h" />
<ClInclude Include="stdafx.h" />
<ClInclude Include="BorderedWindow.h">
<Filter>curses</Filter>
</ClInclude>
<ClInclude Include="Colors.h">
<Filter>curses</Filter>
</ClInclude>
@ -83,6 +80,15 @@
<ClInclude Include="TransportWindow.h">
<Filter>windows</Filter>
</ClInclude>
<ClInclude Include="ILayout.h">
<Filter>curses</Filter>
</ClInclude>
<ClInclude Include="IWindow.h">
<Filter>curses</Filter>
</ClInclude>
<ClInclude Include="Window.h">
<Filter>curses</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="curses">