Add support for richText(richText not finished)
This commit is contained in:
parent
781e62f041
commit
073c6ab57a
|
@ -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
|
|
@ -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)
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -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);
|
||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
*
|
*
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,10 +11,6 @@
|
||||||
|
|
||||||
namespace sftk
|
namespace sftk
|
||||||
{
|
{
|
||||||
class Window;
|
|
||||||
|
|
||||||
typedef std::shared_ptr<Window> pWindow;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Window type
|
* @brief Window type
|
||||||
*
|
*
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
80
src/font.cpp
80
src/font.cpp
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue