Skip to content

Commit

Permalink
improved handling for double-width characters in track name
Browse files Browse the repository at this point in the history
  • Loading branch information
d99kris committed May 3, 2022
1 parent 65a1bda commit a542e2d
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 24 deletions.
8 changes: 5 additions & 3 deletions namp.pro
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,23 @@ TEMPLATE = app
CONFIG += c++11 debug
QT += core multimedia

DEFINES += VERSION="\\\"2.19\\\""
DEFINES += VERSION="\\\"2.20\\\""

HEADERS = src/audioplayer.h \
src/common.h \
src/log.h \
src/scrobbler.h \
src/uikeyhandler.h \
src/uiview.h
src/uiview.h \
src/util.h

SOURCES = src/audioplayer.cpp \
src/main.cpp \
src/log.cpp \
src/scrobbler.cpp \
src/uikeyhandler.cpp \
src/uiview.cpp
src/uiview.cpp \
src/util.cpp

LIBS += -lncursesw \
-ltag
Expand Down
4 changes: 2 additions & 2 deletions res/namp.1
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man.
.TH NAMP "1" "April 2022" "namp v2.19" "User Commands"
.TH NAMP "1" "May 2022" "namp v2.20" "User Commands"
.SH NAME
namp \- ncurses audio media player
.SH SYNOPSIS
Expand Down Expand Up @@ -84,7 +84,7 @@ Written by Kristofer Berggren.
.SH "REPORTING BUGS"
Report bugs at https://github.com/d99kris/namp/
.SH COPYRIGHT
Copyright \(co 2015\-2021 Kristofer Berggren
Copyright \(co 2015\-2022 Kristofer Berggren
.br
This is free software; see the source for copying
conditions. There is NO warranty; not even for
Expand Down
2 changes: 1 addition & 1 deletion src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ static void ShowVersion()
std::cout <<
"namp v" VERSION "\n"
"\n"
"Copyright (C) 2015-2021 Kristofer Berggren\n"
"Copyright (C) 2015-2022 Kristofer Berggren\n"
"This is free software; see the source for copying\n"
"conditions. There is NO warranty; not even for\n"
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
Expand Down
39 changes: 21 additions & 18 deletions src/uiview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "scrobbler.h"
#include "log.h"
#include "uiview.h"
#include "util.h"

UIView::UIView(QObject *p_Parent, Scrobbler* p_Scrobbler)
: QObject(p_Parent)
Expand Down Expand Up @@ -324,10 +325,11 @@ void UIView::DrawPlayer()
}

// Track title
wchar_t trackName[28] = { 0 };
mvwprintw(m_PlayerWindow, 1, 11, "%-27s", "");
swprintf(trackName, 28, L"%s", GetPlayerTrackName(27).toUtf8().constData());
mvwaddnwstr(m_PlayerWindow, 1, 11, trackName, 27);
const int viewLength = 27;
std::string fullName = GetPlayerTrackName(viewLength).toStdString();
std::wstring trackName = Util::TrimPadWString(Util::ToWString(fullName), viewLength);
mvwaddnwstr(m_PlayerWindow, 1, 11, trackName.c_str(), trackName.size());

// Volume
mvwprintw(m_PlayerWindow, 2, 11, "- + PL");
Expand Down Expand Up @@ -357,8 +359,9 @@ QString UIView::GetPlayerTrackName(int p_MaxLength)
snprintf(position, sizeof(position), "(%d:%02d)", (m_TrackDurationSec / 60), (m_TrackDurationSec % 60));
trackName = m_Playlist.at(m_PlaylistPosition).name + " " + position;
}

if (trackName.size() > p_MaxLength)

const int trackNameLen = Util::WStringWidth(Util::ToWString(trackName.toStdString()));
if (trackNameLen > p_MaxLength)
{
if (m_ScrollTitle)
{
Expand All @@ -380,7 +383,7 @@ QString UIView::GetPlayerTrackName(int p_MaxLength)
{
// When timer elapsed, increment scroll position
lastUpdateTime.start();
const int maxScrollOffset = trackName.size() - p_MaxLength - 1;
const int maxScrollOffset = trackNameLen - p_MaxLength - 1;
if (trackScrollOffset < maxScrollOffset)
{
// During scroll, view each offset for 1 sec
Expand Down Expand Up @@ -492,13 +495,13 @@ void UIView::DrawPlaylist()
for (int i = 0; i < viewCount; ++i)
{
const int playlistIndex = i + m_PlaylistOffset;
const int viewLength = m_PlaylistWindowWidth - 3;
wchar_t trackName[viewLength];
swprintf(trackName, viewLength, L"%s", m_Playlist.at(playlistIndex).name.toStdString().c_str());
const int viewLength = m_PlaylistWindowWidth - 4;
std::string fullName = m_Playlist.at(playlistIndex).name.toStdString();
std::wstring trackName = Util::TrimPadWString(Util::ToWString(fullName), viewLength);
wattron(m_PlaylistWindow, (playlistIndex == m_PlaylistSelected) ? A_REVERSE : A_NORMAL);
std::wstring spaces(viewLength - 1, L' ');
mvwaddnwstr(m_PlaylistWindow, i + 1, 2, spaces.c_str(), viewLength - 1);
mvwaddnwstr(m_PlaylistWindow, i + 1, 2, trackName, viewLength - 1);
std::wstring spaces(viewLength, L' ');
mvwaddnwstr(m_PlaylistWindow, i + 1, 2, spaces.c_str(), spaces.size());
mvwaddnwstr(m_PlaylistWindow, i + 1, 2, trackName.c_str(), trackName.size());
wattroff(m_PlaylistWindow, (playlistIndex == m_PlaylistSelected) ? A_REVERSE : A_NORMAL);
}
}
Expand All @@ -521,13 +524,13 @@ void UIView::DrawPlaylist()
for (int i = 0; i < viewCount; ++i)
{
const int playlistIndex = i + m_PlaylistOffset;
const int viewLength = m_PlaylistWindowWidth - 3;
wchar_t trackName[viewLength];
swprintf(trackName, viewLength, L"%s", m_Resultlist.at(playlistIndex).name.toStdString().c_str());
const int viewLength = m_PlaylistWindowWidth - 4;
std::string fullName = m_Resultlist.at(playlistIndex).name.toStdString();
std::wstring trackName = Util::TrimPadWString(Util::ToWString(fullName), viewLength);
wattron(m_PlaylistWindow, (playlistIndex == m_PlaylistSelected) ? A_REVERSE : A_NORMAL);
std::wstring spaces(viewLength - 1, L' ');
mvwaddnwstr(m_PlaylistWindow, i + 1, 2, spaces.c_str(), viewLength - 1);
mvwaddnwstr(m_PlaylistWindow, i + 1, 2, trackName, viewLength - 1);
std::wstring spaces(viewLength, L' ');
mvwaddnwstr(m_PlaylistWindow, i + 1, 2, spaces.c_str(), spaces.size());
mvwaddnwstr(m_PlaylistWindow, i + 1, 2, trackName.c_str(), trackName.size());
wattroff(m_PlaylistWindow, (playlistIndex == m_PlaylistSelected) ? A_REVERSE : A_NORMAL);
}

Expand Down
69 changes: 69 additions & 0 deletions src/util.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// util.cpp
//
// Copyright (c) 2022 Kristofer Berggren
// All rights reserved.
//
// namp is distributed under the GPLv2 license, see LICENSE for details.
//

#include "util.h"

#include <algorithm>
#include <codecvt>
#include <locale>

std::string Util::ToString(const std::wstring& p_WStr)
{
try
{
return std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t>{ }.to_bytes(p_WStr);
}
catch (...)
{
std::wstring wstr = p_WStr;
wstr.erase(std::remove_if(wstr.begin(), wstr.end(), [](wchar_t wch) { return !isascii(wch); }), wstr.end());
std::string str = std::string(wstr.begin(), wstr.end());
return str;
}
}

std::wstring Util::ToWString(const std::string& p_Str)
{
try
{
return std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t>{ }.from_bytes(p_Str);
}
catch (...)
{
std::string str = p_Str;
str.erase(std::remove_if(str.begin(), str.end(), [](unsigned char ch) { return !isascii(ch); }), str.end());
std::wstring wstr = std::wstring(str.begin(), str.end());
return wstr;
}
}

std::wstring Util::TrimPadWString(const std::wstring& p_Str, int p_Len)
{
p_Len = std::max(p_Len, 0);
std::wstring str = p_Str;
if (WStringWidth(str) > p_Len)
{
str = str.substr(0, p_Len);
int subLen = p_Len;
while (WStringWidth(str) > p_Len)
{
str = str.substr(0, --subLen);
}
}
else if (WStringWidth(str) < p_Len)
{
str = str + std::wstring(p_Len - WStringWidth(str), ' ');
}
return str;
}

int Util::WStringWidth(const std::wstring& p_WStr)
{
int width = wcswidth(p_WStr.c_str(), p_WStr.size());
return (width != -1) ? width : p_WStr.size();
}
20 changes: 20 additions & 0 deletions src/util.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// util.h
//
// Copyright (c) 2022 Kristofer Berggren
// All rights reserved.
//
// namp is distributed under the GPLv2 license, see LICENSE for details.
//

#pragma once

#include <string>

class Util
{
public:
static std::string ToString(const std::wstring& p_WStr);
static std::wstring ToWString(const std::string& p_Str);
static std::wstring TrimPadWString(const std::wstring& p_Str, int p_Len);
static int WStringWidth(const std::wstring& p_WStr);
};

0 comments on commit a542e2d

Please sign in to comment.