Fixed many issues with text paragraphs in GUI
This commit is contained in:
parent
2d039dc47b
commit
eb490906a0
13 changed files with 132 additions and 37 deletions
|
|
@ -76,7 +76,7 @@ void TextBoxCanvasComponent::set_data_from(const CanvasComponent& other) {
|
|||
|
||||
void TextBoxCanvasComponent::init_text_box(DrawingProgram& drawP) {
|
||||
textBox->set_font_data(drawP.world.main.fonts); // Getting a segfault relating to the paragraph cache means that the font collection hasn't been set yet
|
||||
textBox->set_width(d.p2.x() - d.p1.x() - TEXTBOX_PADDING * 2.0f);
|
||||
textBox->set_max_width(d.p2.x() - d.p1.x() - TEXTBOX_PADDING * 2.0f);
|
||||
}
|
||||
|
||||
void TextBoxCanvasComponent::draw(SkCanvas* canvas, const DrawData& drawData, const std::shared_ptr<void>& predrawData) const {
|
||||
|
|
|
|||
|
|
@ -18,6 +18,10 @@ namespace GUIStuff {
|
|||
|
||||
void Element::clay_draw(SkCanvas* canvas, UpdateInputData& io, Clay_RenderCommand* command, bool skiaAA) {}
|
||||
|
||||
void Element::clear_bb() {
|
||||
boundingBox = std::nullopt;
|
||||
}
|
||||
|
||||
void Element::set_bounding_box_from_elem_data(const Clay_ElementData& elemData) {
|
||||
if(elemData.found)
|
||||
boundingBox = {{elemData.boundingBox.x, elemData.boundingBox.y}, {elemData.boundingBox.x + elemData.boundingBox.width, elemData.boundingBox.y + elemData.boundingBox.height}};
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ namespace GUIStuff {
|
|||
void set_bounding_box_from_elem_data(const Clay_ElementData& elemData);
|
||||
void set_parent_clipping_region(const std::optional<SCollision::AABB<float>>& bb);
|
||||
const std::optional<SCollision::AABB<float>>& get_bb() const;
|
||||
void clear_bb();
|
||||
virtual ~Element() = default;
|
||||
|
||||
int16_t zIndex;
|
||||
|
|
|
|||
|
|
@ -90,17 +90,23 @@ void FontPicker::layout(const Clay_ElementId& id, std::string* newFontName, cons
|
|||
|
||||
if(dropdownOpen) {
|
||||
gui.set_z_index(gui.get_z_index() + 1, [&] {
|
||||
gui.element<LayoutElement>("Font picker floating element", [&] (LayoutElement*, const Clay_ElementId& lId) {
|
||||
gui.element<LayoutElement>("DROPDOWN", [&](LayoutElement*, const Clay_ElementId& lId) {
|
||||
Clay_ElementData dropdownElemData = Clay_GetElementData(lId);
|
||||
float calculatedDropdownMaxHeight = 0.0f;
|
||||
if(dropdownElemData.found) {
|
||||
calculatedDropdownMaxHeight = std::max(gui.io.windowSize.y() - dropdownElemData.boundingBox.y - 2.0f, 0.0f);
|
||||
calculatedDropdownMaxHeight = std::min<float>(calculatedDropdownMaxHeight, 300);
|
||||
}
|
||||
CLAY(lId, {
|
||||
.layout = {
|
||||
.sizing = {.width = CLAY_SIZING_FIXED(250), .height = CLAY_SIZING_FIT(0, 300)},
|
||||
.layoutDirection = CLAY_TOP_TO_BOTTOM
|
||||
.sizing = {.width = CLAY_SIZING_FIXED(250), .height = CLAY_SIZING_FIT(0, calculatedDropdownMaxHeight)},
|
||||
.childGap = 0
|
||||
},
|
||||
.backgroundColor = convert_vec4<Clay_Color>(gui.io.theme->backColor1),
|
||||
.cornerRadius = CLAY_CORNER_RADIUS(4),
|
||||
.floating = {
|
||||
.offset = {
|
||||
.y = 2
|
||||
.y = 4
|
||||
},
|
||||
.zIndex = gui.get_z_index(),
|
||||
.attachPoints = {
|
||||
|
|
@ -114,16 +120,17 @@ void FontPicker::layout(const Clay_ElementId& id, std::string* newFontName, cons
|
|||
.width = CLAY_BORDER_OUTSIDE(1)
|
||||
}
|
||||
}) {
|
||||
scroll_area_many_entries(gui, "Font Selector", {
|
||||
ElementHelpers::scroll_area_many_entries(gui, "dropdown scroll area", {
|
||||
.entryHeight = ENTRY_HEIGHT,
|
||||
.entryCount = sortedFontList.size(),
|
||||
.clipHorizontal = true,
|
||||
.elementContent = [&] (size_t i) {
|
||||
.growing = true,
|
||||
.elementContent = [&](size_t i) {
|
||||
bool selectedEntry = val == i;
|
||||
gui.element<LayoutElement>("elem", [&](LayoutElement*, const Clay_ElementId& lId2) {
|
||||
CLAY(lId2, {
|
||||
gui.element<LayoutElement>("elem", [&] (LayoutElement*, const Clay_ElementId& lId) {
|
||||
CLAY(lId, {
|
||||
.layout = {
|
||||
.sizing = {.width = CLAY_SIZING_FIXED(250), .height = CLAY_SIZING_FIXED(25)},
|
||||
.sizing = {.width = CLAY_SIZING_FIXED(250), .height = CLAY_SIZING_GROW(0)},
|
||||
.childGap = 1,
|
||||
.childAlignment = {.x = CLAY_ALIGN_X_LEFT, .y = CLAY_ALIGN_Y_TOP},
|
||||
.layoutDirection = CLAY_TOP_TO_BOTTOM
|
||||
|
|
@ -138,7 +145,7 @@ void FontPicker::layout(const Clay_ElementId& id, std::string* newFontName, cons
|
|||
entryColor = gui.io.theme->backColor1;
|
||||
CLAY_AUTO_ID({
|
||||
.layout = {
|
||||
.sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIXED(25)},
|
||||
.sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0)},
|
||||
.padding = {.left = 2, .right = 2},
|
||||
.childAlignment = {.x = CLAY_ALIGN_X_LEFT, .y = CLAY_ALIGN_Y_CENTER}
|
||||
},
|
||||
|
|
@ -147,7 +154,9 @@ void FontPicker::layout(const Clay_ElementId& id, std::string* newFontName, cons
|
|||
TextParagraph::Data d;
|
||||
RichText::TextData::Paragraph& par = d.text.paragraphs.emplace_back();
|
||||
par.text = sortedFontList[i];
|
||||
d.width = 10000.0f; // Setting width to numeric_limits::max will lead to multiplying it by any number greater than 1 to = infinity, which will cause issues
|
||||
|
||||
d.allowNewlines = false;
|
||||
d.ellipsis = false;
|
||||
|
||||
RichText::PositionedTextStyleMod& positionedMod = d.text.tStyleMods.emplace_back();
|
||||
positionedMod.pos = {0, 0};
|
||||
|
|
@ -174,13 +183,6 @@ void FontPicker::layout(const Clay_ElementId& id, std::string* newFontName, cons
|
|||
gui.set_to_layout();
|
||||
}
|
||||
});
|
||||
},
|
||||
.innerContentExtraCallback = [&](const ScrollArea::InnerContentParameters& innerContentParams) {
|
||||
if(jumpToFontName) {
|
||||
if(val != std::numeric_limits<size_t>::max())
|
||||
innerContentParams.scrollOffset->y() = -static_cast<float>(val) * ENTRY_HEIGHT;
|
||||
jumpToFontName = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -159,7 +159,7 @@ template <typename T> void TextBox<T>::input_mouse_motion_callback(const InputMa
|
|||
template <typename T> void TextBox<T>::init_textbox(UpdateInputData& io) {
|
||||
if(!textbox) {
|
||||
textbox = std::make_shared<RichText::TextBox>();
|
||||
textbox->set_width(std::numeric_limits<float>::max());
|
||||
textbox->set_max_width(std::numeric_limits<float>::max());
|
||||
textbox->set_font_data(io.fonts);
|
||||
textbox->set_allow_newlines(false);
|
||||
cur = std::make_shared<RichText::TextBox::Cursor>();
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#include <include/core/SkPath.h>
|
||||
#include <iostream>
|
||||
#include "../GUIManager.hpp"
|
||||
#include "Helpers/ConvertVec.hpp"
|
||||
|
||||
namespace GUIStuff {
|
||||
|
||||
|
|
@ -14,20 +15,32 @@ void TextParagraph::layout(const Clay_ElementId& id, const Data& newData) {
|
|||
if(!textbox) {
|
||||
d = newData;
|
||||
textbox = std::make_unique<RichText::TextBox>();
|
||||
textbox->set_width(d.width);
|
||||
textbox->set_rich_text_data(d.text);
|
||||
textbox->set_ellipsis(newData.ellipsis);
|
||||
textbox->set_font_data(gui.io.fonts);
|
||||
textbox->set_allow_newlines(true);
|
||||
textbox->set_allow_newlines(newData.allowNewlines);
|
||||
textbox->set_max_width(newData.maxGrowX);
|
||||
textbox->set_max_height(newData.maxGrowY);
|
||||
skia::textlayout::TextStyle tStyle;
|
||||
tStyle.setFontFamilies(gui.io.fonts->get_default_font_families());
|
||||
tStyle.setFontSize(gui.io.fontSize);
|
||||
textbox->set_initial_text_style(tStyle);
|
||||
fontSize = gui.io.fontSize;
|
||||
redraw = true;
|
||||
}
|
||||
|
||||
if(d.width != newData.width) {
|
||||
d.width = newData.width;
|
||||
textbox->set_width(d.width);
|
||||
if(d.allowNewlines != newData.allowNewlines) {
|
||||
d.allowNewlines = newData.allowNewlines;
|
||||
textbox->set_allow_newlines(d.allowNewlines);
|
||||
redraw = true;
|
||||
}
|
||||
|
||||
if(gui.io.fontSize != fontSize) {
|
||||
fontSize = gui.io.fontSize;
|
||||
skia::textlayout::TextStyle tStyle;
|
||||
tStyle.setFontFamilies(gui.io.fonts->get_default_font_families());
|
||||
tStyle.setFontSize(gui.io.fontSize);
|
||||
textbox->set_initial_text_style(tStyle);
|
||||
redraw = true;
|
||||
}
|
||||
|
||||
|
|
@ -37,12 +50,29 @@ void TextParagraph::layout(const Clay_ElementId& id, const Data& newData) {
|
|||
redraw = true;
|
||||
}
|
||||
|
||||
if(d.maxGrowX != newData.maxGrowX) {
|
||||
d.maxGrowX = newData.maxGrowX;
|
||||
textbox->set_max_width(d.maxGrowX);
|
||||
redraw = true;
|
||||
}
|
||||
if(d.maxGrowY != newData.maxGrowY) {
|
||||
d.maxGrowY = newData.maxGrowY;
|
||||
textbox->set_max_height(d.maxGrowY);
|
||||
redraw = true;
|
||||
}
|
||||
|
||||
if(d.ellipsis != newData.ellipsis) {
|
||||
d.ellipsis = newData.ellipsis;
|
||||
textbox->set_ellipsis(d.ellipsis);
|
||||
redraw = true;
|
||||
}
|
||||
|
||||
if(redraw)
|
||||
gui.invalidate_draw_element(this);
|
||||
|
||||
CLAY(id, {
|
||||
.layout = {
|
||||
.sizing = {.width = CLAY_SIZING_FIXED(d.width), .height = CLAY_SIZING_FIXED(textbox->get_height())}
|
||||
.sizing = {.width = CLAY_SIZING_GROW(0, textbox->get_width()), .height = CLAY_SIZING_FIXED(textbox->get_height())}
|
||||
},
|
||||
.custom = { .customData = this }
|
||||
}) {}
|
||||
|
|
@ -54,7 +84,7 @@ void TextParagraph::clay_draw(SkCanvas* canvas, UpdateInputData& io, Clay_Render
|
|||
canvas->translate(bb.min.x(), bb.min.y());
|
||||
skia::textlayout::TextStyle tStyle;
|
||||
tStyle.setFontFamilies(gui.io.fonts->get_default_font_families());
|
||||
tStyle.setFontSize(gui.io.fontSize);
|
||||
tStyle.setFontSize(fontSize);
|
||||
tStyle.setForegroundPaint(SkPaint{io.theme->frontColor1});
|
||||
textbox->set_initial_text_style(tStyle);
|
||||
textbox->paint(canvas, { .skiaAA = skiaAA });
|
||||
|
|
|
|||
|
|
@ -8,7 +8,10 @@ class TextParagraph : public Element {
|
|||
public:
|
||||
struct Data {
|
||||
RichText::TextData text;
|
||||
float width;
|
||||
float maxGrowX = 10000.0f;
|
||||
float maxGrowY = 0.0f;
|
||||
bool ellipsis = true;
|
||||
bool allowNewlines = true;
|
||||
bool operator==(const Data& d) const = default;
|
||||
bool operator!=(const Data& d) const = default;
|
||||
};
|
||||
|
|
@ -18,6 +21,7 @@ class TextParagraph : public Element {
|
|||
virtual void clay_draw(SkCanvas* canvas, UpdateInputData& io, Clay_RenderCommand* command, bool skiaAA) override;
|
||||
private:
|
||||
Data d;
|
||||
float fontSize;
|
||||
std::unique_ptr<RichText::TextBox> textbox;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -544,7 +544,7 @@ void GUIManager::layout_if_necessary() {
|
|||
}
|
||||
|
||||
void GUIManager::layout() {
|
||||
constexpr int LAYOUT_RUN_COUNT = 4;
|
||||
constexpr int LAYOUT_RUN_COUNT = 6;
|
||||
for(int i = 0; i < LAYOUT_RUN_COUNT; i++)
|
||||
single_layout_run();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
#include "TextStyleModifier.hpp"
|
||||
#include "cereal/archives/portable_binary.hpp"
|
||||
#include <include/core/SkFontMetrics.h>
|
||||
#include <limits>
|
||||
#include <modules/skparagraph/include/DartTypes.h>
|
||||
#include <modules/skparagraph/include/Metrics.h>
|
||||
#include <modules/skparagraph/include/Paragraph.h>
|
||||
|
|
@ -838,13 +837,36 @@ int TextBox::get_line_number_at_from_byte_text_pos(TextPosition pos) {
|
|||
return paragraphs[pos.fParagraphIndex].p->getLineNumberAt(renderPos.fTextByteIndex);
|
||||
}
|
||||
|
||||
void TextBox::set_width(float newWidth) {
|
||||
void TextBox::set_max_width(float newWidth) {
|
||||
if(width != newWidth) {
|
||||
width = std::max(newWidth, 4.0f);
|
||||
needsRebuild = true;
|
||||
}
|
||||
}
|
||||
|
||||
void TextBox::set_max_height(float newMaxHeight) {
|
||||
if(maxHeight != newMaxHeight) {
|
||||
maxHeight = newMaxHeight;
|
||||
needsRebuild = true;
|
||||
}
|
||||
}
|
||||
|
||||
void TextBox::set_ellipsis(bool newEllipsis) {
|
||||
if(ellipsis != newEllipsis) {
|
||||
ellipsis = newEllipsis;
|
||||
needsRebuild = true;
|
||||
}
|
||||
}
|
||||
|
||||
float TextBox::get_width() {
|
||||
rebuild();
|
||||
float toRet = 0.0f;
|
||||
for(auto& p : paragraphs)
|
||||
toRet = std::max(toRet, p.p->getLongestLine());
|
||||
toRet += 1.0f;
|
||||
return toRet;
|
||||
}
|
||||
|
||||
float TextBox::get_height() {
|
||||
rebuild();
|
||||
return paragraphs.back().heightOffset + paragraphs.back().p->getHeight();
|
||||
|
|
@ -875,6 +897,10 @@ void TextBox::rebuild() {
|
|||
ParagraphData& pData = paragraphs[pIndex];
|
||||
skia::textlayout::ParagraphStyle pStyle = pData.pStyleData.get_paragraph_style();
|
||||
pStyle.setTextStyle(tStyle);
|
||||
if(ellipsis)
|
||||
pStyle.setEllipsis(SkString("..."));
|
||||
if(maxHeight != 0.0f)
|
||||
pStyle.setHeight(maxHeight);
|
||||
|
||||
if(!newlinesAllowed) {
|
||||
pStyle.setTextHeightBehavior(skia::textlayout::kDisableAll);
|
||||
|
|
|
|||
|
|
@ -107,7 +107,9 @@ class TextBox {
|
|||
};
|
||||
|
||||
TextPosition move(Movement movement, TextPosition pos, std::optional<float>* previousX = nullptr, bool flipDependingOnTextDirection = false);
|
||||
void set_width(float newWidth);
|
||||
void set_max_width(float newWidth);
|
||||
void set_max_height(float newMaxHeight);
|
||||
void set_ellipsis(bool newEllipsis);
|
||||
TextPosition insert(TextPosition pos, std::string_view textToInsert, const std::optional<TextStyleModifier::ModifierMap>& inputModMap = std::nullopt);
|
||||
TextPosition remove(TextPosition p1, TextPosition p2);
|
||||
void set_font_data(const std::shared_ptr<FontData>& fD);
|
||||
|
|
@ -129,6 +131,8 @@ class TextBox {
|
|||
SELECT_ALL
|
||||
};
|
||||
|
||||
float get_width();
|
||||
|
||||
void set_initial_text_style(const skia::textlayout::TextStyle& tStyle);
|
||||
void set_initial_text_style_modifier(const std::shared_ptr<TextStyleModifier>& modifier);
|
||||
void set_text_style_modifier_between(TextPosition p1, TextPosition p2, const std::shared_ptr<TextStyleModifier>& modifier);
|
||||
|
|
@ -193,7 +197,9 @@ class TextBox {
|
|||
int get_line_number_at_from_byte_text_pos(TextPosition pos);
|
||||
|
||||
bool newlinesAllowed = true;
|
||||
float width = 0.0f;
|
||||
bool ellipsis = false;
|
||||
float width = 4.0f;
|
||||
float maxHeight = 0.0f;
|
||||
bool needsRebuild = true;
|
||||
unsigned tabWidth = 4;
|
||||
std::shared_ptr<FontData> fontData;
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include "../GUIStuff/Elements/ImageDisplay.hpp"
|
||||
#include "../GUIStuff/Elements/LayoutElement.hpp"
|
||||
#include "../GUIStuff/Elements/SVGIcon.hpp"
|
||||
#include "../GUIStuff/Elements/TextParagraph.hpp"
|
||||
#include "../GUIStuff/Elements/PositionAdjustingPopupMenu.hpp"
|
||||
#include "../World.hpp"
|
||||
#include "Helpers/StringHelpers.hpp"
|
||||
|
|
@ -527,7 +528,7 @@ void FileSelectScreen::file_view() {
|
|||
}
|
||||
CLAY_AUTO_ID({
|
||||
.layout = {
|
||||
.sizing = { .width = CLAY_SIZING_FIT(0), .height = CLAY_SIZING_FIT(0)},
|
||||
.sizing = { .width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIT(0)},
|
||||
.childGap = 6,
|
||||
.childAlignment = { .x = CLAY_ALIGN_X_LEFT, .y = CLAY_ALIGN_Y_CENTER },
|
||||
.layoutDirection = CLAY_TOP_TO_BOTTOM
|
||||
|
|
@ -556,7 +557,24 @@ void FileSelectScreen::file_view() {
|
|||
.radius = 20
|
||||
});
|
||||
}
|
||||
text_label(gui, fileList[i].fileName);
|
||||
gui.element<LayoutElement>("file name layout elem", [&](LayoutElement* l, const Clay_ElementId& lId) {
|
||||
CLAY(lId, {
|
||||
.layout = {
|
||||
.sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIT(0)},
|
||||
.childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_TOP },
|
||||
},
|
||||
}) {
|
||||
if(l->get_bb()) {
|
||||
RichText::TextData fileNameText;
|
||||
fileNameText.paragraphs.emplace_back(fileList[i].fileName);
|
||||
gui.element<TextParagraph>("file name", TextParagraph::Data{
|
||||
.text = fileNameText,
|
||||
.maxGrowX = l->get_bb().value().width(),
|
||||
.maxGrowY = 0.0f
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
text_label_light(gui, fileList[i].lastModifyDate);
|
||||
}
|
||||
}
|
||||
|
|
@ -569,6 +587,7 @@ void FileSelectScreen::file_view() {
|
|||
.entryHeight = 150.0f,
|
||||
.entryCount = fileList.size(),
|
||||
.clipHorizontal = true,
|
||||
.xElementSize = CLAY_SIZING_FIT(0),
|
||||
.elementContent = [&](size_t i) {
|
||||
fileButton(i, true, Vector2f{100.0f, 100.0f});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1039,7 +1039,8 @@ void Toolbar::chat_box() {
|
|||
gui.new_id(id++, [&] {
|
||||
gui.element<TextParagraph>("text", TextParagraph::Data{
|
||||
.text = build_paragraph_from_chat_message(chatMessage, 1.0f),
|
||||
.width = CHATBOX_WIDTH
|
||||
.maxGrowX = CHATBOX_WIDTH,
|
||||
.ellipsis = false
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
@ -1088,7 +1089,8 @@ void Toolbar::chat_box() {
|
|||
}) {
|
||||
gui.element<TextParagraph>("message", TextParagraph::Data{
|
||||
.text = build_paragraph_from_chat_message(chatMessage, a),
|
||||
.width = CHATBOX_WIDTH
|
||||
.maxGrowX = CHATBOX_WIDTH,
|
||||
.ellipsis = false
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include "Helpers/StringHelpers.hpp"
|
||||
#include "Helpers/FileDownloader.hpp"
|
||||
#include "Screens/FileSelectScreen.hpp"
|
||||
#include "Screens/DrawingProgramScreen.hpp"
|
||||
#include "VersionConstants.hpp"
|
||||
#include "include/gpu/GpuTypes.h"
|
||||
#include <SDL3/SDL_filesystem.h>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue