From b3a189b2408c0a9bfa4c6990ab122857f170b05a Mon Sep 17 00:00:00 2001 From: casey Date: Sat, 2 Jul 2016 20:57:08 -0700 Subject: [PATCH] Fixed column alignment in TrackListView with respect to multi-byte characters. --- src/musikbox/app/layout/IndexerLayout.cpp | 6 +- src/musikbox/app/layout/NowPlayingLayout.cpp | 59 ++++++++++---------- src/musikbox/app/layout/SearchLayout.cpp | 5 +- src/musikbox/app/util/GlobalHotkeys.cpp | 2 +- src/musikbox/app/window/TrackListView.cpp | 49 ++++++++-------- src/musikbox/cursespp/Text.cpp | 31 ++++++++++ src/musikbox/cursespp/Text.h | 7 +++ src/musikbox/cursespp/TextLabel.cpp | 36 +++--------- src/musikbox/cursespp/TextLabel.h | 11 +--- 9 files changed, 106 insertions(+), 100 deletions(-) diff --git a/src/musikbox/app/layout/IndexerLayout.cpp b/src/musikbox/app/layout/IndexerLayout.cpp index f8f79fc78..bbc0b46d7 100755 --- a/src/musikbox/app/layout/IndexerLayout.cpp +++ b/src/musikbox/app/layout/IndexerLayout.cpp @@ -144,13 +144,13 @@ int64 IndexerLayout::ListItemDecorator( void IndexerLayout::InitializeWindows() { this->title.reset(new TextLabel()); - this->title->SetText("settings", TextLabel::AlignCenter); + this->title->SetText("settings", text::AlignCenter); this->browseLabel.reset(new TextLabel()); - this->browseLabel->SetText("browse (SPACE to add)", TextLabel::AlignLeft); + this->browseLabel->SetText("browse (SPACE to add)", text::AlignLeft); this->addedPathsLabel.reset(new TextLabel()); - this->addedPathsLabel->SetText("indexed paths (BACKSPACE to remove)", TextLabel::AlignLeft); + this->addedPathsLabel->SetText("indexed paths (BACKSPACE to remove)", text::AlignLeft); this->addedPathsList.reset(new cursespp::ListWindow(&this->addedPathsAdapter)); this->browseList.reset(new cursespp::ListWindow(&this->browseAdapter)); diff --git a/src/musikbox/app/layout/NowPlayingLayout.cpp b/src/musikbox/app/layout/NowPlayingLayout.cpp index 788d51224..5f1fe6e05 100755 --- a/src/musikbox/app/layout/NowPlayingLayout.cpp +++ b/src/musikbox/app/layout/NowPlayingLayout.cpp @@ -148,42 +148,41 @@ bool NowPlayingLayout::KeyPress(const std::string& key) { #define ALBUM_COL_WIDTH 14 #define DURATION_COL_WIDTH 5 /* 00:00 */ -/* see TrackListView.cpp for more info */ -#define DISPLAY_WIDTH(chars, str) \ - chars + (str.size() - u8len(str)) - static std::string formatWithAlbum(TrackPtr track, size_t width) { - std::string trackNum = track->GetValue(constants::Track::TRACK_NUM); - std::string artist = track->GetValue(constants::Track::ARTIST); - std::string album = track->GetValue(constants::Track::ALBUM); - std::string title = track->GetValue(constants::Track::TITLE); - std::string duration = track->GetValue(constants::Track::DURATION); + std::string trackNum = text::Align( + track->GetValue(constants::Track::TRACK_NUM), + text::AlignLeft, + TRACK_COL_WIDTH); - int column0Width = DISPLAY_WIDTH(TRACK_COL_WIDTH, trackNum); - int column2Width = DISPLAY_WIDTH(DURATION_COL_WIDTH, duration); - int column3Width = DISPLAY_WIDTH(ARTIST_COL_WIDTH, artist); - int column4Width = DISPLAY_WIDTH(ALBUM_COL_WIDTH, album); + std::string duration = text::Align( + duration::Duration(track->GetValue(constants::Track::DURATION)), + text::AlignRight, + DURATION_COL_WIDTH); - size_t column1CharacterCount = + std::string album = text::Align( + track->GetValue(constants::Track::ALBUM), + text::AlignLeft, + ALBUM_COL_WIDTH); + + std::string artist = text::Align( + track->GetValue(constants::Track::ARTIST), + text::AlignLeft, + ARTIST_COL_WIDTH); + + size_t titleWidth = width - - column0Width - - column2Width - - column3Width - - column4Width - - (3 * 4); /* 3 = spacing */ + TRACK_COL_WIDTH - + DURATION_COL_WIDTH - + ALBUM_COL_WIDTH - + ARTIST_COL_WIDTH - + (4 * 3); /* 3 = spacing */ - int column1Width = DISPLAY_WIDTH(column1CharacterCount, title); - - text::Ellipsize(artist, ARTIST_COL_WIDTH); - text::Ellipsize(album, ALBUM_COL_WIDTH); - text::Ellipsize(title, column1CharacterCount); - duration = duration::Duration(duration); + std::string title = text::Align( + track->GetValue(constants::Track::TITLE), + text::AlignLeft, + titleWidth); return boost::str( boost::format("%s %s %s %s %s") - % group(setw(column0Width), setfill(' '), trackNum) - % group(setw(column1Width), setiosflags(std::ios::left), setfill(' '), title) - % group(setw(column2Width), setiosflags(std::ios::right), setfill(' '), duration) - % group(setw(column3Width), setiosflags(std::ios::left), setfill(' '), artist) - % group(setw(column4Width), setiosflags(std::ios::left), setfill(' '), album)); + % trackNum % title % duration % album % artist); } \ No newline at end of file diff --git a/src/musikbox/app/layout/SearchLayout.cpp b/src/musikbox/app/layout/SearchLayout.cpp index 1c58a6e35..523012642 100755 --- a/src/musikbox/app/layout/SearchLayout.cpp +++ b/src/musikbox/app/layout/SearchLayout.cpp @@ -36,6 +36,7 @@ #include #include +#include #include #include #include "SearchLayout.h" @@ -97,9 +98,9 @@ void SearchLayout::Layout() { this->AddWindow(view); \ view->SetFocusOrder(order); -#define CREATE_LABEL(view, text) \ +#define CREATE_LABEL(view, value) \ view.reset(new cursespp::TextLabel()); \ - view->SetText(text, cursespp::TextLabel::AlignCenter); \ + view->SetText(value, cursespp::text::AlignCenter); \ this->AddWindow(view); void SearchLayout::InitializeWindows(PlaybackService& playback) { diff --git a/src/musikbox/app/util/GlobalHotkeys.cpp b/src/musikbox/app/util/GlobalHotkeys.cpp index 882b05f34..28798649f 100755 --- a/src/musikbox/app/util/GlobalHotkeys.cpp +++ b/src/musikbox/app/util/GlobalHotkeys.cpp @@ -56,7 +56,7 @@ bool GlobalHotkeys::Handle(const std::string& kn) { playback::PauseOrResume(this->transport); return true; } - if (kn == "M-i") { + else if (kn == "M-i") { this->transport.SetVolume(this->transport.Volume() + 0.05); /* 5% */ return true; } diff --git a/src/musikbox/app/window/TrackListView.cpp b/src/musikbox/app/window/TrackListView.cpp index ca149ba7c..acbe88ba1 100755 --- a/src/musikbox/app/window/TrackListView.cpp +++ b/src/musikbox/app/window/TrackListView.cpp @@ -169,42 +169,37 @@ size_t TrackListView::Adapter::GetEntryCount() { #define ARTIST_COL_WIDTH 17 #define DURATION_COL_WIDTH 5 /* 00:00 */ -/* so this part is a bit tricky... we draw multiple columns, but we use -standard std::setw() stuff, which is not aware of multi-byte characters. -so we have to manually adjust the widths (i.e. we can't just use simple -constants) */ -#define DISPLAY_WIDTH(chars, str) \ - chars + (str.size() - u8len(str)) - static std::string formatWithoutAlbum(TrackPtr track, size_t width) { - std::string trackNum = track->GetValue(constants::Track::TRACK_NUM); - std::string artist = track->GetValue(constants::Track::ARTIST); - std::string title = track->GetValue(constants::Track::TITLE); - std::string duration = track->GetValue(constants::Track::DURATION); + std::string trackNum = text::Align( + track->GetValue(constants::Track::TRACK_NUM), + text::AlignLeft, + TRACK_COL_WIDTH); - int column0Width = DISPLAY_WIDTH(TRACK_COL_WIDTH, trackNum); - int column2Width = DISPLAY_WIDTH(DURATION_COL_WIDTH, duration); - int column3Width = DISPLAY_WIDTH(ARTIST_COL_WIDTH, artist); + std::string duration = text::Align( + duration::Duration(track->GetValue(constants::Track::DURATION)), + text::AlignRight, + DURATION_COL_WIDTH); - size_t column1CharacterCount = + std::string artist = text::Align( + track->GetValue(constants::Track::ARTIST), + text::AlignLeft, + ARTIST_COL_WIDTH); + + size_t titleWidth = width - - column0Width - - column2Width - - column3Width - + TRACK_COL_WIDTH - + DURATION_COL_WIDTH - + ARTIST_COL_WIDTH - (3 * 3); /* 3 = spacing */ - int column1Width = DISPLAY_WIDTH(column1CharacterCount, title); - - text::Ellipsize(artist, ARTIST_COL_WIDTH); - text::Ellipsize(title, column1CharacterCount); - duration = duration::Duration(duration); + std::string title = text::Align( + track->GetValue(constants::Track::TITLE), + text::AlignLeft, + titleWidth); return boost::str( boost::format("%s %s %s %s") - % group(setw(column0Width), setfill(' '), trackNum) - % group(setw(column1Width), setiosflags(std::ios::left), setfill(' '), title) - % group(setw(column2Width), setiosflags(std::ios::right), setfill(' '), duration) - % group(setw(column3Width), setiosflags(std::ios::left), setfill(' '), artist)); + % trackNum % title % duration % artist); } IScrollAdapter::EntryPtr TrackListView::Adapter::GetEntry(size_t index) { diff --git a/src/musikbox/cursespp/Text.cpp b/src/musikbox/cursespp/Text.cpp index 2ce45d05a..981fc71ab 100755 --- a/src/musikbox/cursespp/Text.cpp +++ b/src/musikbox/cursespp/Text.cpp @@ -37,6 +37,8 @@ #include +#define PAD(str, count) for (size_t i = 0; i < count; i++) { str += " "; } + namespace cursespp { namespace text { void Truncate(std::string& str, size_t len) { @@ -69,5 +71,34 @@ namespace cursespp { str += ".."; } } + + std::string Align(const std::string& str, TextAlign align, size_t cx) { + size_t len = u8len(str); + + if (len > cx) { + std::string ellipsized = str; + Ellipsize(ellipsized, cx); + return ellipsized; + } + else if (align == AlignLeft) { + size_t pad = cx - len; + std::string left = str; + PAD(left, pad); + return left; + } + else { + size_t leftPad = (align == AlignRight) + ? (cx - len) + : (cx - len) / 2; + + size_t rightPad = cx - (leftPad + len); + + std::string padded; + PAD(padded, leftPad); + padded += str; + PAD(padded, rightPad); + return padded; + } + } } } diff --git a/src/musikbox/cursespp/Text.h b/src/musikbox/cursespp/Text.h index 4fe7f4d36..ff1c6ff89 100755 --- a/src/musikbox/cursespp/Text.h +++ b/src/musikbox/cursespp/Text.h @@ -38,7 +38,14 @@ namespace cursespp { namespace text { + enum TextAlign { + AlignLeft, + AlignCenter, + AlignRight + }; + void Truncate(std::string& str, size_t len); void Ellipsize(std::string& str, size_t len); + std::string Align(const std::string& str, TextAlign align, size_t len); } } diff --git a/src/musikbox/cursespp/TextLabel.cpp b/src/musikbox/cursespp/TextLabel.cpp index ce537d90c..dce4b61e6 100755 --- a/src/musikbox/cursespp/TextLabel.cpp +++ b/src/musikbox/cursespp/TextLabel.cpp @@ -46,44 +46,22 @@ using namespace cursespp; inline static void redrawContents( IWindow &window, - const TextLabel::Alignment alignment, + const text::TextAlign alignment, const std::string& text) { + std::string aligned = text::Align( + text, alignment, window.GetContentWidth()); + WINDOW* c = window.GetContent(); werase(c); - - int len = (int) u8len(text); - int cx = window.GetContentWidth(); - - if (len > cx) { - std::string ellipsized = text; - text::Ellipsize(ellipsized, cx); - wprintw(c, ellipsized.c_str()); - } - else if (alignment == TextLabel::AlignLeft) { - wprintw(c, text.c_str()); - } - else { /* center */ - int leftPad = - (alignment == TextLabel::AlignRight) - ? (cx - len) - : (cx - len) / 2; - - std::string padded; - for (int i = 0; i < leftPad; i++) { - padded += " "; - } - - padded += text; - wprintw(c, padded.c_str()); - } + wprintw(c, aligned.c_str()); window.Repaint(); } TextLabel::TextLabel() : Window() -, alignment(AlignLeft) { +, alignment(text::AlignLeft) { this->SetFrameVisible(false); } @@ -95,7 +73,7 @@ void TextLabel::Show() { redrawContents(*this, this->alignment, this->buffer); } -void TextLabel::SetText(const std::string& value, const Alignment alignment) { +void TextLabel::SetText(const std::string& value, const text::TextAlign alignment) { if (value != this->buffer || alignment != this->alignment) { this->buffer = value; this->alignment = alignment; diff --git a/src/musikbox/cursespp/TextLabel.h b/src/musikbox/cursespp/TextLabel.h index 9e2b44478..83a1b1f7c 100755 --- a/src/musikbox/cursespp/TextLabel.h +++ b/src/musikbox/cursespp/TextLabel.h @@ -37,6 +37,7 @@ #include #include #include +#include #include namespace cursespp { @@ -48,18 +49,12 @@ namespace cursespp { public cursespp::Window { #endif public: - enum Alignment { - AlignLeft, - AlignCenter, - AlignRight - }; - TextLabel(); virtual ~TextLabel(); virtual void SetText( const std::string& value, - const Alignment alignment = AlignLeft); + const text::TextAlign alignment = text::AlignLeft); virtual std::string GetText() { return this->buffer; } @@ -67,6 +62,6 @@ namespace cursespp { private: std::string buffer; - Alignment alignment; + text::TextAlign alignment; }; }