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() {
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));

View File

@ -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);
}

View File

@ -36,6 +36,7 @@
#include <cursespp/Colors.h>
#include <cursespp/Screen.h>
#include <cursespp/Text.h>
#include <core/library/LocalLibraryConstants.h>
#include <app/query/CategoryTrackListQuery.h>
#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) {

View File

@ -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;
}

View File

@ -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) {

View File

@ -37,6 +37,8 @@
#include <boost/lexical_cast.hpp>
#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;
}
}
}
}

View File

@ -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);
}
}

View File

@ -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;

View File

@ -37,6 +37,7 @@
#include <cursespp/curses_config.h>
#include <cursespp/Window.h>
#include <cursespp/IInput.h>
#include <cursespp/Text.h>
#include <sigslot/sigslot.h>
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;
};
}