git repos / blockattack-game

blame: source/code/sago/SagoTextBox.cpp

normal view · raw

55ea55dd sago007 2018-03-24 16:07 1
/*
55ea55dd sago007 2018-03-24 16:07 2
Copyright (c) 2018 Poul Sander
55ea55dd sago007 2018-03-24 16:07 3
55ea55dd sago007 2018-03-24 16:07 4
Permission is hereby granted, free of charge, to any person
55ea55dd sago007 2018-03-24 16:07 5
obtaining a copy of this software and associated documentation files
55ea55dd sago007 2018-03-24 16:07 6
(the "Software"), to deal in the Software without restriction,
55ea55dd sago007 2018-03-24 16:07 7
including without limitation the rights to use, copy, modify, merge,
55ea55dd sago007 2018-03-24 16:07 8
publish, distribute, sublicense, and/or sell copies of the Software,
55ea55dd sago007 2018-03-24 16:07 9
and to permit persons to whom the Software is furnished to do so,
55ea55dd sago007 2018-03-24 16:07 10
subject to the following conditions:
55ea55dd sago007 2018-03-24 16:07 11
55ea55dd sago007 2018-03-24 16:07 12
The above copyright notice and this permission notice shall be
55ea55dd sago007 2018-03-24 16:07 13
included in all copies or substantial portions of the Software.
55ea55dd sago007 2018-03-24 16:07 14
55ea55dd sago007 2018-03-24 16:07 15
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
55ea55dd sago007 2018-03-24 16:07 16
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
55ea55dd sago007 2018-03-24 16:07 17
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
55ea55dd sago007 2018-03-24 16:07 18
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
55ea55dd sago007 2018-03-24 16:07 19
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
55ea55dd sago007 2018-03-24 16:07 20
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
55ea55dd sago007 2018-03-24 16:07 21
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
55ea55dd sago007 2018-03-24 16:07 22
SOFTWARE.
55ea55dd sago007 2018-03-24 16:07 23
*/
55ea55dd sago007 2018-03-24 16:07 24
55ea55dd sago007 2018-03-24 16:07 25
#include "SagoTextBox.hpp"
55ea55dd sago007 2018-03-24 16:07 26
#include "SagoTextField.hpp"
55ea55dd sago007 2018-03-24 16:07 27
#include <vector>
55ea55dd sago007 2018-03-24 16:07 28
#include <iostream>
55ea55dd sago007 2018-03-24 16:07 29
#include "utf8.h"
55ea55dd sago007 2018-03-24 16:07 30
#include <algorithm>
55ea55dd sago007 2018-03-24 16:07 31
55ea55dd sago007 2018-03-24 16:07 32
namespace sago {
55ea55dd sago007 2018-03-24 16:07 33
55ea55dd sago007 2018-03-24 16:07 34
struct SagoTextBox::SagoTextBoxData {
1a09fcd5 sago007 2018-03-25 13:32 35
	const sago::SagoDataHolder* tex = nullptr;
55ea55dd sago007 2018-03-24 16:07 36
	std::string fontName = "freeserif";
55ea55dd sago007 2018-03-24 16:07 37
	SDL_Color color = { 255, 255, 255, 0 };
55ea55dd sago007 2018-03-24 16:07 38
	SDL_Color outlineColor = { 255, 255, 0, 0 };
55ea55dd sago007 2018-03-24 16:07 39
	int fontSize = 16;
55ea55dd sago007 2018-03-24 16:07 40
	int outline = 0;
55ea55dd sago007 2018-03-24 16:07 41
	std::string text = "";
55ea55dd sago007 2018-03-24 16:07 42
	std::string renderedText = "";
55ea55dd sago007 2018-03-24 16:07 43
	std::vector<SagoTextField> lines;
55ea55dd sago007 2018-03-24 16:07 44
	int maxWidth = 0;
55ea55dd sago007 2018-03-24 16:07 45
};
55ea55dd sago007 2018-03-24 16:07 46
55ea55dd sago007 2018-03-24 16:07 47
SagoTextBox::SagoTextBox() {
55ea55dd sago007 2018-03-24 16:07 48
	data = new SagoTextBoxData();
55ea55dd sago007 2018-03-24 16:07 49
}
55ea55dd sago007 2018-03-24 16:07 50
55ea55dd sago007 2018-03-24 16:07 51
SagoTextBox::~SagoTextBox() {
55ea55dd sago007 2018-03-24 16:07 52
	delete data;
55ea55dd sago007 2018-03-24 16:07 53
}
55ea55dd sago007 2018-03-24 16:07 54
1a09fcd5 sago007 2018-03-25 13:32 55
void SagoTextBox::SetHolder(const SagoDataHolder* holder) {
55ea55dd sago007 2018-03-24 16:07 56
	data->tex = holder;
55ea55dd sago007 2018-03-24 16:07 57
}
55ea55dd sago007 2018-03-24 16:07 58
55ea55dd sago007 2018-03-24 16:07 59
void SagoTextBox::SetText(const char* text) {
55ea55dd sago007 2018-03-24 16:07 60
	data->text = text;
55ea55dd sago007 2018-03-24 16:07 61
}
55ea55dd sago007 2018-03-24 16:07 62
0b8fb137 sago007 2018-03-31 19:53 63
void SagoTextBox::SetText(const std::string& text) {
0b8fb137 sago007 2018-03-31 19:53 64
	data->text = text;
0b8fb137 sago007 2018-03-31 19:53 65
}
0b8fb137 sago007 2018-03-31 19:53 66
55ea55dd sago007 2018-03-24 16:07 67
void SagoTextBox::SetColor(const SDL_Color& color) {
55ea55dd sago007 2018-03-24 16:07 68
	data->color = color;
55ea55dd sago007 2018-03-24 16:07 69
}
55ea55dd sago007 2018-03-24 16:07 70
55ea55dd sago007 2018-03-24 16:07 71
void SagoTextBox::SetFont(const char* fontName) {
55ea55dd sago007 2018-03-24 16:07 72
	data->fontName = fontName;
55ea55dd sago007 2018-03-24 16:07 73
}
55ea55dd sago007 2018-03-24 16:07 74
55ea55dd sago007 2018-03-24 16:07 75
void SagoTextBox::SetFontSize(int fontSize) {
55ea55dd sago007 2018-03-24 16:07 76
	data->fontSize = fontSize;
55ea55dd sago007 2018-03-24 16:07 77
}
55ea55dd sago007 2018-03-24 16:07 78
55ea55dd sago007 2018-03-24 16:07 79
void SagoTextBox::SetOutline(int outlineSize, const SDL_Color& color) {
55ea55dd sago007 2018-03-24 16:07 80
	data->outline = outlineSize;
55ea55dd sago007 2018-03-24 16:07 81
	data->outlineColor = color;
55ea55dd sago007 2018-03-24 16:07 82
}
55ea55dd sago007 2018-03-24 16:07 83
55ea55dd sago007 2018-03-24 16:07 84
void SagoTextBox::SetMaxWidth(int width) {
55ea55dd sago007 2018-03-24 16:07 85
	data->maxWidth = width;
55ea55dd sago007 2018-03-24 16:07 86
}
55ea55dd sago007 2018-03-24 16:07 87
55ea55dd sago007 2018-03-24 16:07 88
const std::string& SagoTextBox::GetText() const {
55ea55dd sago007 2018-03-24 16:07 89
	return data->text;
55ea55dd sago007 2018-03-24 16:07 90
}
55ea55dd sago007 2018-03-24 16:07 91
55ea55dd sago007 2018-03-24 16:07 92
void SagoTextBox::AppendLineToCache(const std::string& text) {
55ea55dd sago007 2018-03-24 16:07 93
	data->lines.resize(data->lines.size()+1);
55ea55dd sago007 2018-03-24 16:07 94
	SagoTextField& tf = data->lines.back();
55ea55dd sago007 2018-03-24 16:07 95
	tf.SetHolder(data->tex);
55ea55dd sago007 2018-03-24 16:07 96
	tf.SetFont(data->fontName.c_str());
55ea55dd sago007 2018-03-24 16:07 97
	tf.SetFontSize(data->fontSize);
55ea55dd sago007 2018-03-24 16:07 98
	tf.SetColor(data->color);
55ea55dd sago007 2018-03-24 16:07 99
	tf.SetOutline(data->outline, data->outlineColor);
0b8fb137 sago007 2018-03-31 19:53 100
	tf.SetText(text);
55ea55dd sago007 2018-03-24 16:07 101
}
55ea55dd sago007 2018-03-24 16:07 102
55ea55dd sago007 2018-03-24 16:07 103
55ea55dd sago007 2018-03-24 16:07 104
void SagoTextBox::SplitAndAppendLineToCache(TTF_Font* font, const std::string& text) {
55ea55dd sago007 2018-03-24 16:07 105
	int width = data->maxWidth;
55ea55dd sago007 2018-03-24 16:07 106
	TTF_SizeUTF8(font, text.c_str(),&width, nullptr);
55ea55dd sago007 2018-03-24 16:07 107
	if (data->maxWidth <= 0 || width <= data->maxWidth || text.length() == 1) {
55ea55dd sago007 2018-03-24 16:07 108
		AppendLineToCache(text);
55ea55dd sago007 2018-03-24 16:07 109
		return;
55ea55dd sago007 2018-03-24 16:07 110
	}
55ea55dd sago007 2018-03-24 16:07 111
	std::string::const_iterator splitLocation = text.begin()+1;
55ea55dd sago007 2018-03-24 16:07 112
	bool splitDone = false;
55ea55dd sago007 2018-03-24 16:07 113
	while (!splitDone) {
55ea55dd sago007 2018-03-24 16:07 114
		std::string::const_iterator nextSearchStart = splitLocation+1;
55ea55dd sago007 2018-03-24 16:07 115
		if (nextSearchStart == text.end()) {
55ea55dd sago007 2018-03-24 16:07 116
			splitDone = true;
55ea55dd sago007 2018-03-24 16:07 117
			continue;
55ea55dd sago007 2018-03-24 16:07 118
		}
55ea55dd sago007 2018-03-24 16:07 119
		std::string::const_iterator nextSpace = std::find(nextSearchStart, text.end(), ' ');
55ea55dd sago007 2018-03-24 16:07 120
		std::string attemptSubString(text.begin(), nextSpace);
55ea55dd sago007 2018-03-24 16:07 121
		TTF_SizeUTF8(font, attemptSubString.c_str(),&width, nullptr);
55ea55dd sago007 2018-03-24 16:07 122
		if (width <= data->maxWidth && nextSpace != text.end()) {
55ea55dd sago007 2018-03-24 16:07 123
			splitLocation = nextSpace;
55ea55dd sago007 2018-03-24 16:07 124
		}
55ea55dd sago007 2018-03-24 16:07 125
		else {
55ea55dd sago007 2018-03-24 16:07 126
			splitDone = true;
55ea55dd sago007 2018-03-24 16:07 127
		}
55ea55dd sago007 2018-03-24 16:07 128
	}
55ea55dd sago007 2018-03-24 16:07 129
	if (splitLocation == text.begin()+1) {
55ea55dd sago007 2018-03-24 16:07 130
		splitLocation = text.begin();
55ea55dd sago007 2018-03-24 16:07 131
		utf8::advance(splitLocation, 1, text.end());
55ea55dd sago007 2018-03-24 16:07 132
		splitDone = false;
55ea55dd sago007 2018-03-24 16:07 133
		while (!splitDone && splitLocation != text.end()) {
55ea55dd sago007 2018-03-24 16:07 134
			std::string::const_iterator nextSplit = splitLocation;
55ea55dd sago007 2018-03-24 16:07 135
			utf8::advance(nextSplit, 1, text.end());
55ea55dd sago007 2018-03-24 16:07 136
			std::string attemptSubString(text.begin(), nextSplit);
55ea55dd sago007 2018-03-24 16:07 137
			TTF_SizeUTF8(font, attemptSubString.c_str(), &width, nullptr);
55ea55dd sago007 2018-03-24 16:07 138
			if (width <= data->maxWidth) {
55ea55dd sago007 2018-03-24 16:07 139
				splitLocation = nextSplit;
55ea55dd sago007 2018-03-24 16:07 140
			}
55ea55dd sago007 2018-03-24 16:07 141
			else {
55ea55dd sago007 2018-03-24 16:07 142
				splitDone = true;
55ea55dd sago007 2018-03-24 16:07 143
			}
55ea55dd sago007 2018-03-24 16:07 144
		}
55ea55dd sago007 2018-03-24 16:07 145
	}
55ea55dd sago007 2018-03-24 16:07 146
	std::string firstPart(text.begin(), splitLocation);
55ea55dd sago007 2018-03-24 16:07 147
	AppendLineToCache(firstPart);
1a09fcd5 sago007 2018-03-25 13:32 148
	while (splitLocation != text.end() && *splitLocation == ' ') {
1a09fcd5 sago007 2018-03-25 13:32 149
		//Trim spaces after an automatic line break.
1a09fcd5 sago007 2018-03-25 13:32 150
		++splitLocation;
1a09fcd5 sago007 2018-03-25 13:32 151
	}
55ea55dd sago007 2018-03-24 16:07 152
	if (splitLocation == text.end()) {
55ea55dd sago007 2018-03-24 16:07 153
		return;
55ea55dd sago007 2018-03-24 16:07 154
	}
55ea55dd sago007 2018-03-24 16:07 155
	std::string secondPart(splitLocation, text.end());
55ea55dd sago007 2018-03-24 16:07 156
	SplitAndAppendLineToCache(font, secondPart);
55ea55dd sago007 2018-03-24 16:07 157
}
55ea55dd sago007 2018-03-24 16:07 158
55ea55dd sago007 2018-03-24 16:07 159
void SagoTextBox::UpdateCache() {
d8fe60bd sago007 2018-04-02 16:15 160
	if (!data->tex) {
d8fe60bd sago007 2018-04-02 16:15 161
		std::cerr << "FATAL: SagoTextBox::UpdateCache - DataHolder not set!\n";
d8fe60bd sago007 2018-04-02 16:15 162
		abort();
d8fe60bd sago007 2018-04-02 16:15 163
	}
e94af580 sago007 2020-12-30 17:45 164
	TTF_Font* font = data->tex->getFontPtr(data->fontName, data->fontSize);
55ea55dd sago007 2018-03-24 16:07 165
	const char delim = '\n';
55ea55dd sago007 2018-03-24 16:07 166
	const std::string& s = data->text;
55ea55dd sago007 2018-03-24 16:07 167
	auto start = 0U;
55ea55dd sago007 2018-03-24 16:07 168
	auto end = s.find(delim);
1a09fcd5 sago007 2018-03-25 13:32 169
	data->lines.clear();
e94af580 sago007 2020-12-30 17:45 170
	while (end != std::string::npos) {
55ea55dd sago007 2018-03-24 16:07 171
		const std::string& theSubString = s.substr(start, end - start);
55ea55dd sago007 2018-03-24 16:07 172
		SplitAndAppendLineToCache(font, theSubString);
55ea55dd sago007 2018-03-24 16:07 173
		start = end + 1;
55ea55dd sago007 2018-03-24 16:07 174
		end = s.find(delim, start);
55ea55dd sago007 2018-03-24 16:07 175
	}
55ea55dd sago007 2018-03-24 16:07 176
	SplitAndAppendLineToCache(font, s.substr(start, end));
55ea55dd sago007 2018-03-24 16:07 177
	data->renderedText = data->text;
55ea55dd sago007 2018-03-24 16:07 178
}
55ea55dd sago007 2018-03-24 16:07 179
4b21c89c Poul Sander 2025-03-04 20:33 180
void SagoTextBox::Draw(SDL_Renderer* target, int x, int y, SagoTextField::Alignment alignment, SagoLogicalResize* resize ) {
55ea55dd sago007 2018-03-24 16:07 181
	if (data->text != data->renderedText) {
55ea55dd sago007 2018-03-24 16:07 182
		UpdateCache();
55ea55dd sago007 2018-03-24 16:07 183
	}
e94af580 sago007 2020-12-30 17:45 184
	TTF_Font* font = data->tex->getFontPtr(data->fontName, data->fontSize);
55ea55dd sago007 2018-03-24 16:07 185
	int lineSkip = TTF_FontLineSkip(font);
55ea55dd sago007 2018-03-24 16:07 186
	for (size_t i = 0; i < data->lines.size(); ++i) {
4b21c89c Poul Sander 2025-03-04 20:33 187
		data->lines[i].Draw(target, x, y+i*lineSkip, alignment, sago::SagoTextField::VerticalAlignment::top, resize);
55ea55dd sago007 2018-03-24 16:07 188
	}
55ea55dd sago007 2018-03-24 16:07 189
}
55ea55dd sago007 2018-03-24 16:07 190
55ea55dd sago007 2018-03-24 16:07 191
}  //namespace sago