Add support for richText(richText not finished)

This commit is contained in:
pointer-to-bios 2024-09-11 21:03:19 +08:00
parent 781e62f041
commit 073c6ab57a
16 changed files with 166 additions and 32 deletions

1
.gitmodules vendored
View File

@ -1,3 +1,4 @@
[submodule "deps/SFML"] [submodule "deps/SFML"]
path = deps/SFML path = deps/SFML
url = https://github.com/SFML/SFML.git url = https://github.com/SFML/SFML.git
branch = 2.6.1

View File

@ -10,8 +10,10 @@ set(CONTAINER src/containers)
set(SOURCES ${SOURCES} ${ROOT}/window.cpp) set(SOURCES ${SOURCES} ${ROOT}/window.cpp)
set(SOURCES ${SOURCES} ${ROOT}/font.cpp) set(SOURCES ${SOURCES} ${ROOT}/font.cpp)
set(SOURCES ${SOURCES} ${ROOT}/richText.cpp)
set(SOURCES ${SOURCES} ${CONTAINER}/container.cpp) set(SOURCES ${SOURCES} ${CONTAINER}/container.cpp)
set(SOURCES ${SOURCES} ${CONTAINER}/label.cpp) set(SOURCES ${SOURCES} ${CONTAINER}/label.cpp)
set(SOURCES ${SOURCES} ${CONTAINER}/rtlabel.cpp)
add_library(sftk SHARED ${SOURCES}) add_library(sftk SHARED ${SOURCES})
target_link_libraries(sftk PUBLIC sfml-graphics sfml-audio sfml-network) target_link_libraries(sftk PUBLIC sfml-graphics sfml-audio sfml-network)

BIN
demo/SarasaUiSC-Bold.ttf Normal file

Binary file not shown.

Binary file not shown.

BIN
demo/SarasaUiSC-Italic.ttf Normal file

Binary file not shown.

View File

@ -1,13 +1,17 @@
#include <iostream>
#include <sftk.hpp> #include <sftk.hpp>
int main() int main()
{ {
auto &window = sftk::Window::create(800, 600, L"demo1"); auto &window = sftk::Window::create(800, 600, L"demo1");
window.setBackgroudColor(sf::Color::White); window.setBackgroudColor(sf::Color::White);
auto &label = sftk::Label::create(L"hello SFTK.", sftk::Font("../demo/SarasaUiSC-Regular.ttf", "", 18)); auto &label = sftk::Label::create(
L"SFTK demo.\nBy Random World Studio.",
sftk::Font("../demo/SarasaUiSC-Regular.ttf", 18));
label.setColor(sf::Color::Black); label.setColor(sf::Color::Black);
label.setPosition(vec(100.f, 100.f)); window.registerEvent(
sftk::EventType::Resized,
std::function(
[&label](sf::Vector2f size)
{ label.setPosition(size - label.getSize()); }));
window.exec(); window.exec();
} }

View File

@ -38,7 +38,7 @@ namespace sftk
virtual bool isRoot() const; virtual bool isRoot() const;
virtual bool hasInternalChange() const; virtual bool hasInternalChange() const;
void update(sf::RenderWindow &window) const; void update(sf::RenderWindow &window, sf::View parentView) const;
template <class T> template <class T>
void registerEvent(EventType type, std::function<T> handler); void registerEvent(EventType type, std::function<T> handler);

View File

@ -1,5 +1,5 @@
#ifndef LABLE_HPP #ifndef LABEL_HPP
#define LABLE_HPP #define LABEL_HPP
#include <string> #include <string>
#include <vector> #include <vector>
@ -38,6 +38,10 @@ namespace sftk
Font font; Font font;
sf::Color color; sf::Color color;
// After setText() called, this vector will be filled.
std::vector<uint> wrongGlyphs;
// This vector records every characters' x offset.
std::vector<std::vector<float>> linesGlyphPrefixSum;
std::vector<float> linesWidths; std::vector<float> linesWidths;
}; };
}; };

View File

@ -33,7 +33,7 @@ namespace sftk
* { * {
* static char msg[] = "sftk::SomeClass 0x********_******** reported an exception."; * static char msg[] = "sftk::SomeClass 0x********_******** reported an exception.";
* SFTKException::formatAddress(msg, sizeof(msg)); * SFTKException::formatAddress(msg, sizeof(msg));
* return msg; * return const_cast<SomeClass *>(msg);
* } * }
* ``` * ```
* *

View File

@ -13,10 +13,9 @@ namespace sftk
{ {
public: public:
Font(); Font();
Font(std::string font, std::string fallback, int size); Font(std::string font, int size);
sf::Font font; sf::Font font;
sf::Font fallback;
int size; int size;
public: public:
@ -35,6 +34,42 @@ namespace sftk
}; };
}; };
class FontFamily
{
public:
enum FontType
{
Regular,
Bold,
Italic,
BoldItalic,
};
private:
static std::string genFontFileName(FontType ftype, std::string name);
public:
FontFamily();
FontFamily(std::string name, uint baseSize, std::string findPath = "");
sf::Font &operator[](FontType ftype);
std::string name;
uint baseSize;
sf::Font regular;
sf::Font bold;
sf::Font italic;
sf::Font boldItalic;
public:
class UnexceptedFontType : public SFTKException<FontFamily>
{
public:
UnexceptedFontType(FontFamily *fntfml);
const char *what() const noexcept override;
};
};
}; };
#endif #endif

View File

@ -16,7 +16,7 @@ constexpr sf::Vector3<T> vec(T x, T y, T z)
} }
template <class T> template <class T>
constexpr sf::Rect<T> vec(T x, T y, T width, T height) constexpr sf::Rect<T> rec(T x, T y, T width, T height)
{ {
return sf::Rect(x, y, width, height); return sf::Rect(x, y, width, height);
} }

View File

@ -11,10 +11,6 @@
namespace sftk namespace sftk
{ {
class Window;
typedef std::shared_ptr<Window> pWindow;
/** /**
* @brief Window type * @brief Window type
* *

View File

@ -5,6 +5,7 @@
#include <iostream> #include <iostream>
#include <chrono> #include <chrono>
#include <cmath>
using namespace sftk; using namespace sftk;
@ -29,7 +30,7 @@ Container::Container(pContainer parent)
: parent(nullptr), : parent(nullptr),
pos(vec(0.f, 0.f)), pos(vec(0.f, 0.f)),
size(vec(0.f, 0.f)), size(vec(0.f, 0.f)),
view(vec(0.f, 0.f, 0.f, 0.f)) view(rec(0.f, 0.f, 0.f, 0.f))
{ {
id = containerCounter++; id = containerCounter++;
if (!parent.get()) if (!parent.get())
@ -52,7 +53,7 @@ Container::Container(sf::Vector2f pos, sf::Vector2f size, pContainer parent)
: parent(nullptr), : parent(nullptr),
pos(pos), pos(pos),
size(size), size(size),
view(vec(0.f, 0.f, size.x, size.y)) view(rec(0.f, 0.f, size.x, size.y))
{ {
id = containerCounter++; id = containerCounter++;
if (!parent.get()) if (!parent.get())
@ -69,7 +70,7 @@ Container::Container(sf::Vector2f pos, sf::Vector2f size, pContainer parent)
globalContainers[id] = pthis; globalContainers[id] = pthis;
this->parent->children.push_back(pthis); this->parent->children.push_back(pthis);
auto rootsize = getRoot()->getSize(); auto rootsize = getRoot()->getSize();
view.setViewport(vec( view.setViewport(rec(
(parent->basepos.x + pos.x) / rootsize.x, (parent->basepos.y + pos.y) / rootsize.y, (parent->basepos.x + pos.x) / rootsize.x, (parent->basepos.y + pos.y) / rootsize.y,
size.x / rootsize.x, size.y / rootsize.y)); size.x / rootsize.x, size.y / rootsize.y));
for (auto &p : lastMousePressPos) for (auto &p : lastMousePressPos)
@ -80,7 +81,7 @@ Container::Container(sf::Vector2f pos, sf::Vector2f size, bool root)
: parent(nullptr), : parent(nullptr),
pos(pos), pos(pos),
size(size), size(size),
view(vec(0.f, 0.f, size.x, size.y)), view(rec(0.f, 0.f, size.x, size.y)),
basepos(vec(0.f, 0.f)) basepos(vec(0.f, 0.f))
{ {
if (!root) if (!root)
@ -89,7 +90,7 @@ Container::Container(sf::Vector2f pos, sf::Vector2f size, bool root)
} }
id = containerCounter++; id = containerCounter++;
globalContainers[id] = pContainer(this); globalContainers[id] = pContainer(this);
view.setViewport(vec(0.f, 0.f, 1.f, 1.f)); view.setViewport(rec(0.f, 0.f, 1.f, 1.f));
for (auto &p : lastMousePressPos) for (auto &p : lastMousePressPos)
p = vec(-1.f, -1.f); p = vec(-1.f, -1.f);
} }
@ -116,7 +117,7 @@ void Container::setPosition(sf::Vector2f pos)
{ {
this->pos = pos; this->pos = pos;
auto rootsize = getRoot()->getSize(); auto rootsize = getRoot()->getSize();
view.setViewport(vec( view.setViewport(rec(
(basepos.x + pos.x) / rootsize.x, (basepos.x + pos.y) / rootsize.y, (basepos.x + pos.x) / rootsize.x, (basepos.x + pos.y) / rootsize.y,
size.x / rootsize.x, size.y / rootsize.y)); size.x / rootsize.x, size.y / rootsize.y));
for (auto c : children) for (auto c : children)
@ -129,7 +130,7 @@ void Container::setSize(sf::Vector2f size)
{ {
this->size = size; this->size = size;
auto rootsize = getRoot()->getSize(); auto rootsize = getRoot()->getSize();
view.setViewport(vec( view.setViewport(rec(
(basepos.x + pos.x) / rootsize.x, (basepos.y + pos.y) / rootsize.y, (basepos.x + pos.x) / rootsize.x, (basepos.y + pos.y) / rootsize.y,
size.x / rootsize.x, size.y / rootsize.y)); size.x / rootsize.x, size.y / rootsize.y));
view.setSize(size); view.setSize(size);
@ -162,7 +163,7 @@ const sf::View &Container::getView() const
sf::FloatRect Container::getGlobalBouds() const sf::FloatRect Container::getGlobalBouds() const
{ {
return vec(basepos.x + pos.x, basepos.y + pos.y, size.x, size.y); return rec(basepos.x + pos.x, basepos.y + pos.y, size.x, size.y);
} }
bool Container::isRoot() const bool Container::isRoot() const
@ -175,13 +176,26 @@ bool Container::hasInternalChange() const
return false; return false;
} }
void Container::update(sf::RenderWindow &window) const static sf::FloatRect calViewportOverlap(sf::FloatRect vpa, sf::FloatRect vpb)
{ {
auto left = std::max(vpa.left, vpb.left);
auto right = std::min(vpa.left + vpa.width, vpb.left + vpb.width);
auto top = std::max(vpa.top, vpb.top);
auto bottom = std::min(vpa.top + vpa.height, vpb.top + vpb.height);
return sf::FloatRect(left, top, right - left, bottom - top);
}
void Container::update(sf::RenderWindow &window, sf::View parentView) const
{
auto view = this->view;
auto sz = getSize();
sf::View currView(rec(0.f, 0.f, sz.x, sz.y));
currView.setViewport(calViewportOverlap(view.getViewport(), parentView.getViewport()));
window.setView(view); window.setView(view);
draw(window); draw(window);
for (auto c : children) for (auto c : children)
{ {
c->update(window); c->update(window, currView);
} }
} }
@ -361,6 +375,7 @@ bool Container::dispatchEvent(Event &event)
} }
break; break;
case EventType::Resized: case EventType::Resized:
broadcast = true;
rsz = event.data.resized; rsz = event.data.resized;
if (resized) if (resized)
{ {

View File

@ -44,10 +44,13 @@ Label &Label::create(std::wstring text, Font font, pContainer parent)
void Label::setText(std::wstring text) void Label::setText(std::wstring text)
{ {
sf::Font font = this->font.font;
uint font_size = this->font.size;
this->text = text; this->text = text;
linesWidths.clear(); linesWidths.clear();
float currentLineWidth = 0; float currentLineWidth = 0;
float maxWidth = 0; float maxWidth = 0;
uint index = 0;
for (auto ch : text) for (auto ch : text)
{ {
if (ch == L'\n') if (ch == L'\n')
@ -57,7 +60,9 @@ void Label::setText(std::wstring text)
maxWidth = currentLineWidth; maxWidth = currentLineWidth;
currentLineWidth = 0; currentLineWidth = 0;
} }
auto glyph = font.font.getGlyph(ch, font.size, false); if (!font.hasGlyph(ch))
wrongGlyphs.push_back(index);
auto glyph = font.getGlyph(ch, font_size, false);
currentLineWidth += glyph.advance; currentLineWidth += glyph.advance;
} }
if (currentLineWidth != 0) if (currentLineWidth != 0)
@ -66,7 +71,7 @@ void Label::setText(std::wstring text)
if (currentLineWidth > maxWidth) if (currentLineWidth > maxWidth)
maxWidth = currentLineWidth; maxWidth = currentLineWidth;
} }
auto lineSpacing = font.font.getLineSpacing(font.size); auto lineSpacing = font.getLineSpacing(font_size);
Container::setSize(vec(maxWidth, linesWidths.size() * lineSpacing)); Container::setSize(vec(maxWidth, linesWidths.size() * lineSpacing));
} }

View File

@ -1,19 +1,19 @@
#include <font.hpp> #include <font.hpp>
#include <filesystem>
namespace fs = std::filesystem;
using namespace sftk; using namespace sftk;
Font::Font() {} Font::Font() {}
Font::Font(std::string font, std::string fallback, int size) Font::Font(std::string font, int size)
: size(size) : size(size)
{ {
if (font.empty()) if (font.empty())
throw new MainFontIsEmpty(this); throw new MainFontIsEmpty(this);
if (!this->font.loadFromFile(font)) if (!this->font.loadFromFile(font))
throw new FailedToLoadFont(this); throw new FailedToLoadFont(this);
if (!fallback.empty())
if (!this->fallback.loadFromFile(fallback))
throw new FailedToLoadFont(this);
} }
Font::MainFontIsEmpty::MainFontIsEmpty(Font *font) Font::MainFontIsEmpty::MainFontIsEmpty(Font *font)
@ -35,3 +35,75 @@ const char *Font::FailedToLoadFont::what() const noexcept
SFTKException::formatAddress(msg, sizeof(msg)); SFTKException::formatAddress(msg, sizeof(msg));
return const_cast<const char *>(msg); return const_cast<const char *>(msg);
} }
FontFamily::FontFamily() {}
FontFamily::FontFamily(std::string name, uint baseSize, std::string findPath)
: name(name), baseSize(baseSize)
{
fs::path path(findPath);
for (auto &entry : fs::recursive_directory_iterator(path))
{
if (fs::is_regular_file(entry))
{
auto fname = entry.path().filename().generic_string();
if (!fname.find(genFontFileName(FontType::Regular, name)))
regular.loadFromFile(entry.path());
else if (!fname.find(genFontFileName(FontType::Bold, name)))
bold.loadFromFile(entry.path());
else if (!fname.find(genFontFileName(FontType::Italic, name)))
italic.loadFromFile(entry.path());
else if (!fname.find(genFontFileName(FontType::BoldItalic, name)))
boldItalic.loadFromFile(entry.path());
}
}
}
sf::Font &FontFamily::operator[](FontType ftype)
{
switch (ftype)
{
case FontType::Regular:
return regular;
case FontType::Bold:
return bold;
case FontType::Italic:
return italic;
case FontType::BoldItalic:
return boldItalic;
default:
throw new UnexceptedFontType(this);
}
}
std::string FontFamily::genFontFileName(FontType ftype, std::string name)
{
name += '-';
switch (ftype)
{
case FontType::Regular:
name += "Regular";
break;
case FontType::Bold:
name += "Bold";
break;
case FontType::Italic:
name += "Italic";
break;
case FontType::BoldItalic:
name += "BoldItalic";
break;
}
return name;
}
FontFamily::UnexceptedFontType::UnexceptedFontType(FontFamily *fntfml)
: SFTKException(fntfml) {}
const char *FontFamily::UnexceptedFontType::what() const noexcept
{
static char msg[] = "sftk::FontFamily 0x********_********:"
" Using wrong index calling sftk::FontFamily::operator[](FontType).";
SFTKException::formatAddress(msg, sizeof(msg));
return const_cast<const char *>(msg);
}

View File

@ -48,7 +48,7 @@ void Window::exec()
if (event_occured || hasInternalChange()) if (event_occured || hasInternalChange())
{ {
sfwindow.clear(backgroud); sfwindow.clear(backgroud);
update(sfwindow); update(sfwindow, getView());
sfwindow.display(); sfwindow.display();
} }
} }