mirror of
https://github.com/clangen/musikcube.git
synced 2025-02-06 03:39:50 +00:00
Moved line breaking logic into Text.h/cpp
This commit is contained in:
parent
650882ae01
commit
7c972bf011
@ -33,9 +33,7 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <stdafx.h>
|
||||
#include <math.h>
|
||||
#include <algorithm>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include "Text.h"
|
||||
#include "MultiLineEntry.h"
|
||||
|
||||
using namespace cursespp;
|
||||
@ -59,139 +57,9 @@ int64 MultiLineEntry::GetAttrs(size_t line) {
|
||||
return this->attrs;
|
||||
}
|
||||
|
||||
inline static void breakIntoSubLines(
|
||||
std::string& line,
|
||||
size_t width,
|
||||
std::vector<std::string>& output)
|
||||
{
|
||||
size_t len = u8cols(line);
|
||||
size_t count = (int)ceil((float)len / (float)width);
|
||||
|
||||
/* easy case: the line fits on a single line! */
|
||||
|
||||
if (count <= 1) {
|
||||
output.push_back(line);
|
||||
}
|
||||
|
||||
/* difficult case: the line needs to be split multiple sub-lines to fit
|
||||
the output display */
|
||||
|
||||
else {
|
||||
/* split by whitespace */
|
||||
|
||||
std::vector<std::string> words;
|
||||
boost::algorithm::split(words, line, boost::is_any_of(" \t\v\f\r"));
|
||||
|
||||
/* this isn't super efficient, but let's find all words that are greater
|
||||
than the width and break them into more sublines... it's possible to
|
||||
do this more efficiently in the loop below this with a bunch of additional
|
||||
logic, but let's keep things simple unless we run into performance
|
||||
problems! */
|
||||
|
||||
std::vector<std::string> sanitizedWords;
|
||||
for (size_t i = 0; i < words.size(); i++) {
|
||||
std::string word = words.at(i);
|
||||
size_t len = u8cols(word);
|
||||
|
||||
/* this word is fine, it'll easily fit on its own line of necessary */
|
||||
|
||||
if (width >= len) {
|
||||
sanitizedWords.push_back(word);
|
||||
}
|
||||
|
||||
/* otherwise, the word needs to be broken into multiple lines. */
|
||||
|
||||
else {
|
||||
std::string accum;
|
||||
|
||||
/* ugh, we gotta split on UTF8 characters, not actual characters.
|
||||
this makes things a bit more difficult... we iterate over the string
|
||||
one displayable character at a time, and break it apart into separate
|
||||
lines as necessary. */
|
||||
|
||||
std::string::iterator begin = word.begin();
|
||||
std::string::iterator end = word.begin();
|
||||
int count = 0;
|
||||
bool done = false;
|
||||
while (end != word.end()) {
|
||||
utf8::unchecked::next(end);
|
||||
++count;
|
||||
|
||||
if (count == width || end == word.end()) {
|
||||
sanitizedWords.push_back(std::string(begin, end));
|
||||
begin = end;
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
words.clear();
|
||||
|
||||
/* now we have a bunch of tokenized words. let's string them together
|
||||
into sequences that fit in the output window's width */
|
||||
|
||||
std::string accum;
|
||||
size_t accumLength = 0;
|
||||
|
||||
for (size_t i = 0; i < sanitizedWords.size(); i++) {
|
||||
std::string word = sanitizedWords.at(i);
|
||||
size_t wordLength = u8cols(word);
|
||||
size_t extra = (i != 0);
|
||||
|
||||
/* we have enough space for this new word. accumulate it. */
|
||||
|
||||
if (accumLength + extra + wordLength < width) {
|
||||
if (extra) {
|
||||
accum += " ";
|
||||
}
|
||||
|
||||
accum += word;
|
||||
accumLength += wordLength + extra;
|
||||
}
|
||||
|
||||
/* otherwise, flush the current line, and start a new one... */
|
||||
|
||||
else {
|
||||
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... */
|
||||
|
||||
if (wordLength == width) {
|
||||
output.push_back(word);
|
||||
accum = "";
|
||||
accumLength = 0;
|
||||
}
|
||||
|
||||
/* otherwise, let's start accumulating a new line! */
|
||||
|
||||
else {
|
||||
accum = word;
|
||||
accumLength = wordLength;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (accum.size()) {
|
||||
output.push_back(accum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MultiLineEntry::SetWidth(size_t width) {
|
||||
if (this->width != width) {
|
||||
this->width = width;
|
||||
|
||||
this->lines.clear();
|
||||
|
||||
std::vector<std::string> split;
|
||||
boost::algorithm::split(split, this->value, boost::is_any_of("\n"));
|
||||
|
||||
for (size_t i = 0; i < split.size(); i++) {
|
||||
breakIntoSubLines(split.at(i), this->width, this->lines);
|
||||
}
|
||||
this->lines = text::BreakLines(this->value, this->width);
|
||||
}
|
||||
}
|
||||
|
@ -41,6 +41,8 @@
|
||||
|
||||
using namespace cursespp;
|
||||
|
||||
static ILayoutPtr none;
|
||||
|
||||
class OverlayLayout :
|
||||
public LayoutBase,
|
||||
public std::enable_shared_from_this<OverlayLayout>
|
||||
@ -58,6 +60,6 @@ Overlays::Overlays() {
|
||||
}
|
||||
|
||||
ILayoutPtr Overlays::Top() {
|
||||
//return temp;
|
||||
return ILayoutPtr();
|
||||
// return temp;
|
||||
return none;
|
||||
}
|
@ -35,8 +35,13 @@
|
||||
#include "stdafx.h"
|
||||
#include "Text.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include <unordered_map>
|
||||
#include <algorithm>
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#define PAD(str, count) for (size_t i = 0; i < count; i++) { str += " "; }
|
||||
|
||||
@ -102,6 +107,140 @@ namespace cursespp {
|
||||
return padded;
|
||||
}
|
||||
}
|
||||
|
||||
inline void privateBreakLines(
|
||||
const std::string& line,
|
||||
size_t width,
|
||||
std::vector<std::string>& output)
|
||||
{
|
||||
size_t len = u8cols(line);
|
||||
size_t count = (int)ceil((float)len / (float)width);
|
||||
|
||||
/* easy case: the line fits on a single line! */
|
||||
|
||||
if (count <= 1) {
|
||||
output.push_back(line);
|
||||
}
|
||||
|
||||
/* difficult case: the line needs to be split multiple sub-lines to fit
|
||||
the output display */
|
||||
|
||||
else {
|
||||
/* split by whitespace */
|
||||
|
||||
std::vector<std::string> words;
|
||||
boost::algorithm::split(words, line, boost::is_any_of(" \t\v\f\r"));
|
||||
|
||||
/* this isn't super efficient, but let's find all words that are greater
|
||||
than the width and break them into more sublines... it's possible to
|
||||
do this more efficiently in the loop below this with a bunch of additional
|
||||
logic, but let's keep things simple unless we run into performance
|
||||
problems! */
|
||||
|
||||
std::vector<std::string> sanitizedWords;
|
||||
for (size_t i = 0; i < words.size(); i++) {
|
||||
std::string word = words.at(i);
|
||||
size_t len = u8cols(word);
|
||||
|
||||
/* this word is fine, it'll easily fit on its own line of necessary */
|
||||
|
||||
if (width >= len) {
|
||||
sanitizedWords.push_back(word);
|
||||
}
|
||||
|
||||
/* otherwise, the word needs to be broken into multiple lines. */
|
||||
|
||||
else {
|
||||
std::string accum;
|
||||
|
||||
/* ugh, we gotta split on UTF8 characters, not actual characters.
|
||||
this makes things a bit more difficult... we iterate over the string
|
||||
one displayable character at a time, and break it apart into separate
|
||||
lines as necessary. */
|
||||
|
||||
std::string::iterator begin = word.begin();
|
||||
std::string::iterator end = word.begin();
|
||||
int count = 0;
|
||||
bool done = false;
|
||||
while (end != word.end()) {
|
||||
utf8::unchecked::next(end);
|
||||
++count;
|
||||
|
||||
if (count == width || end == word.end()) {
|
||||
sanitizedWords.push_back(std::string(begin, end));
|
||||
begin = end;
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
words.clear();
|
||||
|
||||
/* now we have a bunch of tokenized words. let's string them together
|
||||
into sequences that fit in the output window's width */
|
||||
|
||||
std::string accum;
|
||||
size_t accumLength = 0;
|
||||
|
||||
for (size_t i = 0; i < sanitizedWords.size(); i++) {
|
||||
std::string word = sanitizedWords.at(i);
|
||||
size_t wordLength = u8cols(word);
|
||||
size_t extra = (i != 0);
|
||||
|
||||
/* we have enough space for this new word. accumulate it. */
|
||||
|
||||
if (accumLength + extra + wordLength < width) {
|
||||
if (extra) {
|
||||
accum += " ";
|
||||
}
|
||||
|
||||
accum += word;
|
||||
accumLength += wordLength + extra;
|
||||
}
|
||||
|
||||
/* otherwise, flush the current line, and start a new one... */
|
||||
|
||||
else {
|
||||
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... */
|
||||
|
||||
if (wordLength == width) {
|
||||
output.push_back(word);
|
||||
accum = "";
|
||||
accumLength = 0;
|
||||
}
|
||||
|
||||
/* otherwise, let's start accumulating a new line! */
|
||||
|
||||
else {
|
||||
accum = word;
|
||||
accumLength = wordLength;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (accum.size()) {
|
||||
output.push_back(accum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> BreakLines(const std::string& line, size_t width) {
|
||||
std::vector<std::string> result;
|
||||
std::vector<std::string> split;
|
||||
|
||||
boost::algorithm::split(split, line, boost::is_any_of("\n"));
|
||||
for (size_t i = 0; i < split.size(); i++) {
|
||||
privateBreakLines(split.at(i), width, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
namespace key {
|
||||
|
@ -46,6 +46,7 @@ namespace cursespp {
|
||||
|
||||
std::string Ellipsize(const std::string& str, size_t len);
|
||||
std::string Align(const std::string& str, TextAlign align, size_t len);
|
||||
std::vector<std::string> BreakLines(const std::string& line, size_t width);
|
||||
}
|
||||
|
||||
namespace key {
|
||||
|
Loading…
x
Reference in New Issue
Block a user