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"]
path = deps/SFML
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}/font.cpp)
set(SOURCES ${SOURCES} ${ROOT}/richText.cpp)
set(SOURCES ${SOURCES} ${CONTAINER}/container.cpp)
set(SOURCES ${SOURCES} ${CONTAINER}/label.cpp)
set(SOURCES ${SOURCES} ${CONTAINER}/rtlabel.cpp)
add_library(sftk SHARED ${SOURCES})
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>
int main()
{
auto &window = sftk::Window::create(800, 600, L"demo1");
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.setPosition(vec(100.f, 100.f));
window.registerEvent(
sftk::EventType::Resized,
std::function(
[&label](sf::Vector2f size)
{ label.setPosition(size - label.getSize()); }));
window.exec();
}

View File

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

View File

@ -1,5 +1,5 @@
#ifndef LABLE_HPP
#define LABLE_HPP
#ifndef LABEL_HPP
#define LABEL_HPP
#include <string>
#include <vector>
@ -38,6 +38,10 @@ namespace sftk
Font font;
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;
};
};

View File

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

View File

@ -13,10 +13,9 @@ namespace sftk
{
public:
Font();
Font(std::string font, std::string fallback, int size);
Font(std::string font, int size);
sf::Font font;
sf::Font fallback;
int size;
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

View File

@ -16,7 +16,7 @@ constexpr sf::Vector3<T> vec(T x, T y, T z)
}
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);
}

View File

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

View File

@ -5,6 +5,7 @@
#include <iostream>
#include <chrono>
#include <cmath>
using namespace sftk;
@ -29,7 +30,7 @@ Container::Container(pContainer parent)
: parent(nullptr),
pos(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++;
if (!parent.get())
@ -52,7 +53,7 @@ Container::Container(sf::Vector2f pos, sf::Vector2f size, pContainer parent)
: parent(nullptr),
pos(pos),
size(size),
view(vec(0.f, 0.f, size.x, size.y))
view(rec(0.f, 0.f, size.x, size.y))
{
id = containerCounter++;
if (!parent.get())
@ -69,7 +70,7 @@ Container::Container(sf::Vector2f pos, sf::Vector2f size, pContainer parent)
globalContainers[id] = pthis;
this->parent->children.push_back(pthis);
auto rootsize = getRoot()->getSize();
view.setViewport(vec(
view.setViewport(rec(
(parent->basepos.x + pos.x) / rootsize.x, (parent->basepos.y + pos.y) / rootsize.y,
size.x / rootsize.x, size.y / rootsize.y));
for (auto &p : lastMousePressPos)
@ -80,7 +81,7 @@ Container::Container(sf::Vector2f pos, sf::Vector2f size, bool root)
: parent(nullptr),
pos(pos),
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))
{
if (!root)
@ -89,7 +90,7 @@ Container::Container(sf::Vector2f pos, sf::Vector2f size, bool root)
}
id = containerCounter++;
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)
p = vec(-1.f, -1.f);
}
@ -116,7 +117,7 @@ void Container::setPosition(sf::Vector2f pos)
{
this->pos = pos;
auto rootsize = getRoot()->getSize();
view.setViewport(vec(
view.setViewport(rec(
(basepos.x + pos.x) / rootsize.x, (basepos.x + pos.y) / rootsize.y,
size.x / rootsize.x, size.y / rootsize.y));
for (auto c : children)
@ -129,7 +130,7 @@ void Container::setSize(sf::Vector2f size)
{
this->size = size;
auto rootsize = getRoot()->getSize();
view.setViewport(vec(
view.setViewport(rec(
(basepos.x + pos.x) / rootsize.x, (basepos.y + pos.y) / rootsize.y,
size.x / rootsize.x, size.y / rootsize.y));
view.setSize(size);
@ -162,7 +163,7 @@ const sf::View &Container::getView() 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
@ -175,13 +176,26 @@ bool Container::hasInternalChange() const
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);
draw(window);
for (auto c : children)
{
c->update(window);
c->update(window, currView);
}
}
@ -361,6 +375,7 @@ bool Container::dispatchEvent(Event &event)
}
break;
case EventType::Resized:
broadcast = true;
rsz = event.data.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)
{
sf::Font font = this->font.font;
uint font_size = this->font.size;
this->text = text;
linesWidths.clear();
float currentLineWidth = 0;
float maxWidth = 0;
uint index = 0;
for (auto ch : text)
{
if (ch == L'\n')
@ -57,7 +60,9 @@ void Label::setText(std::wstring text)
maxWidth = currentLineWidth;
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;
}
if (currentLineWidth != 0)
@ -66,7 +71,7 @@ void Label::setText(std::wstring text)
if (currentLineWidth > maxWidth)
maxWidth = currentLineWidth;
}
auto lineSpacing = font.font.getLineSpacing(font.size);
auto lineSpacing = font.getLineSpacing(font_size);
Container::setSize(vec(maxWidth, linesWidths.size() * lineSpacing));
}

View File

@ -1,19 +1,19 @@
#include <font.hpp>
#include <filesystem>
namespace fs = std::filesystem;
using namespace sftk;
Font::Font() {}
Font::Font(std::string font, std::string fallback, int size)
Font::Font(std::string font, int size)
: size(size)
{
if (font.empty())
throw new MainFontIsEmpty(this);
if (!this->font.loadFromFile(font))
throw new FailedToLoadFont(this);
if (!fallback.empty())
if (!this->fallback.loadFromFile(fallback))
throw new FailedToLoadFont(this);
}
Font::MainFontIsEmpty::MainFontIsEmpty(Font *font)
@ -35,3 +35,75 @@ const char *Font::FailedToLoadFont::what() const noexcept
SFTKException::formatAddress(msg, sizeof(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())
{
sfwindow.clear(backgroud);
update(sfwindow);
update(sfwindow, getView());
sfwindow.display();
}
}