Fixed column alignment in TrackListView with respect to multi-byte

characters.
This commit is contained in:
casey 2016-07-02 20:57:08 -07:00
parent 2b1a924165
commit b3a189b240
9 changed files with 106 additions and 100 deletions

View File

@ -144,13 +144,13 @@ int64 IndexerLayout::ListItemDecorator(
void IndexerLayout::InitializeWindows() { void IndexerLayout::InitializeWindows() {
this->title.reset(new TextLabel()); this->title.reset(new TextLabel());
this->title->SetText("settings", TextLabel::AlignCenter); this->title->SetText("settings", text::AlignCenter);
this->browseLabel.reset(new TextLabel()); 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.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->addedPathsList.reset(new cursespp::ListWindow(&this->addedPathsAdapter));
this->browseList.reset(new cursespp::ListWindow(&this->browseAdapter)); this->browseList.reset(new cursespp::ListWindow(&this->browseAdapter));

View File

@ -148,42 +148,41 @@ bool NowPlayingLayout::KeyPress(const std::string& key) {
#define ALBUM_COL_WIDTH 14 #define ALBUM_COL_WIDTH 14
#define DURATION_COL_WIDTH 5 /* 00:00 */ #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) { static std::string formatWithAlbum(TrackPtr track, size_t width) {
std::string trackNum = track->GetValue(constants::Track::TRACK_NUM); std::string trackNum = text::Align(
std::string artist = track->GetValue(constants::Track::ARTIST); track->GetValue(constants::Track::TRACK_NUM),
std::string album = track->GetValue(constants::Track::ALBUM); text::AlignLeft,
std::string title = track->GetValue(constants::Track::TITLE); TRACK_COL_WIDTH);
std::string duration = track->GetValue(constants::Track::DURATION);
int column0Width = DISPLAY_WIDTH(TRACK_COL_WIDTH, trackNum); std::string duration = text::Align(
int column2Width = DISPLAY_WIDTH(DURATION_COL_WIDTH, duration); duration::Duration(track->GetValue(constants::Track::DURATION)),
int column3Width = DISPLAY_WIDTH(ARTIST_COL_WIDTH, artist); text::AlignRight,
int column4Width = DISPLAY_WIDTH(ALBUM_COL_WIDTH, album); 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 - width -
column0Width - TRACK_COL_WIDTH -
column2Width - DURATION_COL_WIDTH -
column3Width - ALBUM_COL_WIDTH -
column4Width - ARTIST_COL_WIDTH -
(3 * 4); /* 3 = spacing */ (4 * 3); /* 3 = spacing */
int column1Width = DISPLAY_WIDTH(column1CharacterCount, title); std::string title = text::Align(
track->GetValue(constants::Track::TITLE),
text::Ellipsize(artist, ARTIST_COL_WIDTH); text::AlignLeft,
text::Ellipsize(album, ALBUM_COL_WIDTH); titleWidth);
text::Ellipsize(title, column1CharacterCount);
duration = duration::Duration(duration);
return boost::str( return boost::str(
boost::format("%s %s %s %s %s") boost::format("%s %s %s %s %s")
% group(setw(column0Width), setfill(' '), trackNum) % trackNum % title % duration % album % artist);
% 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));
} }

View File

@ -36,6 +36,7 @@
#include <cursespp/Colors.h> #include <cursespp/Colors.h>
#include <cursespp/Screen.h> #include <cursespp/Screen.h>
#include <cursespp/Text.h>
#include <core/library/LocalLibraryConstants.h> #include <core/library/LocalLibraryConstants.h>
#include <app/query/CategoryTrackListQuery.h> #include <app/query/CategoryTrackListQuery.h>
#include "SearchLayout.h" #include "SearchLayout.h"
@ -97,9 +98,9 @@ void SearchLayout::Layout() {
this->AddWindow(view); \ this->AddWindow(view); \
view->SetFocusOrder(order); view->SetFocusOrder(order);
#define CREATE_LABEL(view, text) \ #define CREATE_LABEL(view, value) \
view.reset(new cursespp::TextLabel()); \ view.reset(new cursespp::TextLabel()); \
view->SetText(text, cursespp::TextLabel::AlignCenter); \ view->SetText(value, cursespp::text::AlignCenter); \
this->AddWindow(view); this->AddWindow(view);
void SearchLayout::InitializeWindows(PlaybackService& playback) { void SearchLayout::InitializeWindows(PlaybackService& playback) {

View File

@ -56,7 +56,7 @@ bool GlobalHotkeys::Handle(const std::string& kn) {
playback::PauseOrResume(this->transport); playback::PauseOrResume(this->transport);
return true; return true;
} }
if (kn == "M-i") { else if (kn == "M-i") {
this->transport.SetVolume(this->transport.Volume() + 0.05); /* 5% */ this->transport.SetVolume(this->transport.Volume() + 0.05); /* 5% */
return true; return true;
} }

View File

@ -169,42 +169,37 @@ size_t TrackListView::Adapter::GetEntryCount() {
#define ARTIST_COL_WIDTH 17 #define ARTIST_COL_WIDTH 17
#define DURATION_COL_WIDTH 5 /* 00:00 */ #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) { static std::string formatWithoutAlbum(TrackPtr track, size_t width) {
std::string trackNum = track->GetValue(constants::Track::TRACK_NUM); std::string trackNum = text::Align(
std::string artist = track->GetValue(constants::Track::ARTIST); track->GetValue(constants::Track::TRACK_NUM),
std::string title = track->GetValue(constants::Track::TITLE); text::AlignLeft,
std::string duration = track->GetValue(constants::Track::DURATION); TRACK_COL_WIDTH);
int column0Width = DISPLAY_WIDTH(TRACK_COL_WIDTH, trackNum); std::string duration = text::Align(
int column2Width = DISPLAY_WIDTH(DURATION_COL_WIDTH, duration); duration::Duration(track->GetValue(constants::Track::DURATION)),
int column3Width = DISPLAY_WIDTH(ARTIST_COL_WIDTH, artist); 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 - width -
column0Width - TRACK_COL_WIDTH -
column2Width - DURATION_COL_WIDTH -
column3Width - ARTIST_COL_WIDTH -
(3 * 3); /* 3 = spacing */ (3 * 3); /* 3 = spacing */
int column1Width = DISPLAY_WIDTH(column1CharacterCount, title); std::string title = text::Align(
track->GetValue(constants::Track::TITLE),
text::Ellipsize(artist, ARTIST_COL_WIDTH); text::AlignLeft,
text::Ellipsize(title, column1CharacterCount); titleWidth);
duration = duration::Duration(duration);
return boost::str( return boost::str(
boost::format("%s %s %s %s") boost::format("%s %s %s %s")
% group(setw(column0Width), setfill(' '), trackNum) % trackNum % title % duration % artist);
% 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));
} }
IScrollAdapter::EntryPtr TrackListView::Adapter::GetEntry(size_t index) { IScrollAdapter::EntryPtr TrackListView::Adapter::GetEntry(size_t index) {

View File

@ -37,6 +37,8 @@
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#define PAD(str, count) for (size_t i = 0; i < count; i++) { str += " "; }
namespace cursespp { namespace cursespp {
namespace text { namespace text {
void Truncate(std::string& str, size_t len) { void Truncate(std::string& str, size_t len) {
@ -69,5 +71,34 @@ namespace cursespp {
str += ".."; 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;
}
}
} }
} }

View File

@ -38,7 +38,14 @@
namespace cursespp { namespace cursespp {
namespace text { namespace text {
enum TextAlign {
AlignLeft,
AlignCenter,
AlignRight
};
void Truncate(std::string& str, size_t len); void Truncate(std::string& str, size_t len);
void Ellipsize(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);
} }
} }

View File

@ -46,44 +46,22 @@ using namespace cursespp;
inline static void redrawContents( inline static void redrawContents(
IWindow &window, IWindow &window,
const TextLabel::Alignment alignment, const text::TextAlign alignment,
const std::string& text) const std::string& text)
{ {
std::string aligned = text::Align(
text, alignment, window.GetContentWidth());
WINDOW* c = window.GetContent(); WINDOW* c = window.GetContent();
werase(c); werase(c);
wprintw(c, aligned.c_str());
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());
}
window.Repaint(); window.Repaint();
} }
TextLabel::TextLabel() TextLabel::TextLabel()
: Window() : Window()
, alignment(AlignLeft) { , alignment(text::AlignLeft) {
this->SetFrameVisible(false); this->SetFrameVisible(false);
} }
@ -95,7 +73,7 @@ void TextLabel::Show() {
redrawContents(*this, this->alignment, this->buffer); 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) { if (value != this->buffer || alignment != this->alignment) {
this->buffer = value; this->buffer = value;
this->alignment = alignment; this->alignment = alignment;

View File

@ -37,6 +37,7 @@
#include <cursespp/curses_config.h> #include <cursespp/curses_config.h>
#include <cursespp/Window.h> #include <cursespp/Window.h>
#include <cursespp/IInput.h> #include <cursespp/IInput.h>
#include <cursespp/Text.h>
#include <sigslot/sigslot.h> #include <sigslot/sigslot.h>
namespace cursespp { namespace cursespp {
@ -48,18 +49,12 @@ namespace cursespp {
public cursespp::Window { public cursespp::Window {
#endif #endif
public: public:
enum Alignment {
AlignLeft,
AlignCenter,
AlignRight
};
TextLabel(); TextLabel();
virtual ~TextLabel(); virtual ~TextLabel();
virtual void SetText( virtual void SetText(
const std::string& value, const std::string& value,
const Alignment alignment = AlignLeft); const text::TextAlign alignment = text::AlignLeft);
virtual std::string GetText() { return this->buffer; } virtual std::string GetText() { return this->buffer; }
@ -67,6 +62,6 @@ namespace cursespp {
private: private:
std::string buffer; std::string buffer;
Alignment alignment; text::TextAlign alignment;
}; };
} }