multiline labels
This commit is contained in:
@@ -20,7 +20,8 @@ namespace gui {
|
||||
using onnumberchange = std::function<void(GUI*, double)>;
|
||||
|
||||
enum class Align {
|
||||
left, center, right
|
||||
left, center, right,
|
||||
top=left, bottom=right,
|
||||
};
|
||||
|
||||
class UINode {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "controls.h"
|
||||
|
||||
#include <queue>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
#include "../../window/Events.h"
|
||||
@@ -30,9 +32,16 @@ Label::Label(std::wstring text, std::string fontName)
|
||||
|
||||
void Label::setText(std::wstring text) {
|
||||
this->text = text;
|
||||
lines = 1;
|
||||
for (size_t i = 0; i < text.length(); i++) {
|
||||
if (text[i] == L'\n') {
|
||||
lines++;
|
||||
}
|
||||
}
|
||||
lines = std::max(lines, 1U);
|
||||
}
|
||||
|
||||
std::wstring Label::getText() const {
|
||||
const std::wstring& Label::getText() const {
|
||||
return text;
|
||||
}
|
||||
|
||||
@@ -44,18 +53,45 @@ const std::string& Label::getFontName() const {
|
||||
return fontName;
|
||||
}
|
||||
|
||||
void Label::setVerticalAlign(Align align) {
|
||||
this->valign = align;
|
||||
}
|
||||
|
||||
Align Label::getVerticalAlign() const {
|
||||
return valign;
|
||||
}
|
||||
|
||||
float Label::getLineInterval() const {
|
||||
return lineInterval;
|
||||
}
|
||||
|
||||
void Label::setLineInterval(float interval) {
|
||||
lineInterval = interval;
|
||||
}
|
||||
|
||||
int Label::getTextYOffset() const {
|
||||
return textYOffset;
|
||||
}
|
||||
|
||||
int Label::getLineYOffset(uint line) const {
|
||||
return line * totalLineHeight + textYOffset;
|
||||
}
|
||||
|
||||
void Label::draw(const GfxContext* pctx, Assets* assets) {
|
||||
if (supplier) {
|
||||
setText(supplier());
|
||||
}
|
||||
|
||||
auto batch = pctx->getBatch2D();
|
||||
auto font = assets->getFont(fontName);
|
||||
|
||||
batch->color = getColor();
|
||||
Font* font = assets->getFont(fontName);
|
||||
|
||||
uint lineHeight = font->getLineHeight();
|
||||
glm::vec2 size = getSize();
|
||||
glm::vec2 newsize (
|
||||
font->calcWidth(text),
|
||||
font->getLineHeight()+font->getYOffset()
|
||||
(lines == 1 ? lineHeight : lineHeight*lineInterval)*lines + font->getYOffset()
|
||||
);
|
||||
|
||||
glm::vec2 coord = calcCoord();
|
||||
@@ -69,14 +105,48 @@ void Label::draw(const GfxContext* pctx, Assets* assets) {
|
||||
coord.x += size.x-newsize.x;
|
||||
break;
|
||||
}
|
||||
coord.y += (size.y-newsize.y)*0.5f;
|
||||
font->draw(batch, text, coord.x, coord.y);
|
||||
switch (valign) {
|
||||
case Align::top:
|
||||
break;
|
||||
case Align::center:
|
||||
coord.y += (size.y-newsize.y)*0.5f;
|
||||
break;
|
||||
case Align::bottom:
|
||||
coord.y += size.y-newsize.y;
|
||||
break;
|
||||
}
|
||||
textYOffset = coord.y;
|
||||
totalLineHeight = lineHeight * lineInterval;
|
||||
|
||||
if (multiline) {
|
||||
size_t offset = 0;
|
||||
for (uint i = 0; i < lines; i++) {
|
||||
std::wstring_view view(text.c_str()+offset, text.length()-offset);
|
||||
size_t end = view.find(L'\n');
|
||||
if (end != std::wstring::npos) {
|
||||
view = std::wstring_view(text.c_str()+offset, end);
|
||||
offset += end + 1;
|
||||
}
|
||||
font->draw(batch, view, coord.x, coord.y + i * totalLineHeight, FontStyle::none);
|
||||
}
|
||||
} else {
|
||||
font->draw(batch, text, coord.x, coord.y, FontStyle::none);
|
||||
}
|
||||
}
|
||||
|
||||
void Label::textSupplier(wstringsupplier supplier) {
|
||||
this->supplier = supplier;
|
||||
}
|
||||
|
||||
|
||||
void Label::setMultiline(bool multiline) {
|
||||
this->multiline = multiline;
|
||||
}
|
||||
|
||||
bool Label::isMultiline() const {
|
||||
return multiline;
|
||||
}
|
||||
|
||||
// ================================= Image ====================================
|
||||
Image::Image(std::string texture, glm::vec2 size) : UINode(glm::vec2(), size), texture(texture) {
|
||||
setInteractive(false);
|
||||
@@ -264,7 +334,7 @@ void TextBox::draw(const GfxContext* pctx, Assets* assets) {
|
||||
if (!isFocused())
|
||||
return;
|
||||
|
||||
const int yoffset = 2;
|
||||
const int yoffset = 0;
|
||||
const int lineHeight = font->getLineHeight();
|
||||
glm::vec2 lcoord = label->calcCoord();
|
||||
auto batch = pctx->getBatch2D();
|
||||
@@ -390,6 +460,16 @@ bool TextBox::isValid() const {
|
||||
return valid;
|
||||
}
|
||||
|
||||
void TextBox::setMultiline(bool multiline) {
|
||||
this->multiline = multiline;
|
||||
label->setMultiline(multiline);
|
||||
label->setVerticalAlign(multiline ? Align::top : Align::center);
|
||||
}
|
||||
|
||||
bool TextBox::isMultiline() const {
|
||||
return multiline;
|
||||
}
|
||||
|
||||
void TextBox::setOnEditStart(runnable oneditstart) {
|
||||
onEditStart = oneditstart;
|
||||
}
|
||||
|
||||
@@ -24,19 +24,40 @@ namespace gui {
|
||||
std::wstring text;
|
||||
std::string fontName;
|
||||
wstringsupplier supplier = nullptr;
|
||||
uint lines = 1;
|
||||
float lineInterval = 1.5f;
|
||||
Align valign = Align::center;
|
||||
|
||||
bool multiline = false;
|
||||
|
||||
// runtime values
|
||||
int textYOffset = 0;
|
||||
int totalLineHeight = 1;
|
||||
public:
|
||||
Label(std::string text, std::string fontName="normal");
|
||||
Label(std::wstring text, std::string fontName="normal");
|
||||
|
||||
virtual void setText(std::wstring text);
|
||||
std::wstring getText() const;
|
||||
const std::wstring& getText() const;
|
||||
|
||||
virtual void setFontName(std::string name);
|
||||
const std::string& getFontName() const;
|
||||
virtual const std::string& getFontName() const;
|
||||
|
||||
virtual void setVerticalAlign(Align align);
|
||||
virtual Align getVerticalAlign() const;
|
||||
|
||||
virtual float getLineInterval() const;
|
||||
virtual void setLineInterval(float interval);
|
||||
|
||||
virtual int getTextYOffset() const;
|
||||
virtual int getLineYOffset(uint line) const;
|
||||
|
||||
virtual void draw(const GfxContext* pctx, Assets* assets) override;
|
||||
|
||||
virtual void textSupplier(wstringsupplier supplier);
|
||||
|
||||
virtual void setMultiline(bool multiline);
|
||||
virtual bool isMultiline() const;
|
||||
};
|
||||
|
||||
class Image : public UINode {
|
||||
@@ -121,6 +142,8 @@ namespace gui {
|
||||
size_t selectionEnd = 0;
|
||||
size_t selectionOrigin = 0;
|
||||
|
||||
bool multiline = false;
|
||||
|
||||
size_t normalizeIndex(int index);
|
||||
|
||||
int calcIndexAt(int x) const;
|
||||
@@ -134,16 +157,9 @@ namespace gui {
|
||||
TextBox(std::wstring placeholder,
|
||||
glm::vec4 padding=glm::vec4(4.0f));
|
||||
|
||||
virtual std::shared_ptr<UINode> getAt(glm::vec2 pos, std::shared_ptr<UINode> self) override;
|
||||
|
||||
virtual void draw(const GfxContext* pctx, Assets* assets) override;
|
||||
virtual void drawBackground(const GfxContext* pctx, Assets* assets) override;
|
||||
virtual void typed(unsigned int codepoint) override;
|
||||
virtual void keyPressed(keycode key) override;
|
||||
virtual void setTextSupplier(wstringsupplier supplier);
|
||||
virtual void setTextConsumer(wstringconsumer consumer);
|
||||
virtual void setTextValidator(wstringchecker validator);
|
||||
virtual bool isFocuskeeper() const override {return true;}
|
||||
virtual void setFocusedColor(glm::vec4 color);
|
||||
virtual glm::vec4 getFocusedColor() const;
|
||||
virtual void setErrorColor(glm::vec4 color);
|
||||
@@ -161,11 +177,22 @@ namespace gui {
|
||||
virtual bool validate();
|
||||
virtual void setValid(bool valid);
|
||||
virtual bool isValid() const;
|
||||
|
||||
// multiline mode is in development
|
||||
virtual void setMultiline(bool multiline);
|
||||
virtual bool isMultiline() const;
|
||||
virtual void setOnEditStart(runnable oneditstart);
|
||||
|
||||
virtual void focus(GUI*) override;
|
||||
virtual void refresh() override;
|
||||
virtual void click(GUI*, int, int) override;
|
||||
virtual void mouseMove(GUI*, int x, int y) override;
|
||||
virtual bool isFocuskeeper() const override {return true;}
|
||||
virtual void draw(const GfxContext* pctx, Assets* assets) override;
|
||||
virtual void drawBackground(const GfxContext* pctx, Assets* assets) override;
|
||||
virtual void typed(unsigned int codepoint) override;
|
||||
virtual void keyPressed(keycode key) override;
|
||||
virtual std::shared_ptr<UINode> getAt(glm::vec2 pos, std::shared_ptr<UINode> self) override;
|
||||
};
|
||||
|
||||
class InputBindBox : public Panel {
|
||||
|
||||
@@ -17,6 +17,8 @@ static Align align_from_string(const std::string& str, Align def) {
|
||||
if (str == "left") return Align::left;
|
||||
if (str == "center") return Align::center;
|
||||
if (str == "right") return Align::right;
|
||||
if (str == "top") return Align::top;
|
||||
if (str == "bottom") return Align::bottom;
|
||||
return def;
|
||||
}
|
||||
|
||||
@@ -138,6 +140,11 @@ static std::shared_ptr<UINode> readLabel(UiXmlReader& reader, xml::xmlelement el
|
||||
std::wstring text = readAndProcessInnerText(element);
|
||||
auto label = std::make_shared<Label>(text);
|
||||
_readUINode(reader, element, *label);
|
||||
if (element->has("valign")) {
|
||||
label->setVerticalAlign(
|
||||
align_from_string(element->attr("valign").getText(), label->getVerticalAlign())
|
||||
);
|
||||
}
|
||||
return label;
|
||||
}
|
||||
|
||||
@@ -163,7 +170,7 @@ static std::shared_ptr<UINode> readButton(UiXmlReader& reader, xml::xmlelement e
|
||||
auto callback = scripting::create_runnable(
|
||||
reader.getEnvironment().getId(),
|
||||
element->attr("onclick").getText(),
|
||||
reader.getFilename()+".lua"
|
||||
reader.getFilename()
|
||||
);
|
||||
button->listenAction([callback](GUI*) {
|
||||
callback();
|
||||
@@ -188,7 +195,7 @@ static std::shared_ptr<UINode> readCheckBox(UiXmlReader& reader, xml::xmlelement
|
||||
auto consumer = scripting::create_bool_consumer(
|
||||
reader.getEnvironment().getId(),
|
||||
element->attr("consumer").getText(),
|
||||
reader.getFilename()+".lua"
|
||||
reader.getFilename()
|
||||
);
|
||||
checkbox->setConsumer(consumer);
|
||||
}
|
||||
@@ -197,7 +204,7 @@ static std::shared_ptr<UINode> readCheckBox(UiXmlReader& reader, xml::xmlelement
|
||||
auto supplier = scripting::create_bool_supplier(
|
||||
reader.getEnvironment().getId(),
|
||||
element->attr("supplier").getText(),
|
||||
reader.getFilename()+".lua"
|
||||
reader.getFilename()
|
||||
);
|
||||
checkbox->setSupplier(supplier);
|
||||
}
|
||||
@@ -210,12 +217,16 @@ static std::shared_ptr<UINode> readTextBox(UiXmlReader& reader, xml::xmlelement
|
||||
auto textbox = std::make_shared<TextBox>(placeholder, glm::vec4(0.0f));
|
||||
_readPanel(reader, element, *textbox);
|
||||
textbox->setText(text);
|
||||
|
||||
if (element->has("multiline")) {
|
||||
textbox->setMultiline(element->attr("multiline").asBool());
|
||||
}
|
||||
|
||||
if (element->has("consumer")) {
|
||||
auto consumer = scripting::create_wstring_consumer(
|
||||
reader.getEnvironment().getId(),
|
||||
element->attr("consumer").getText(),
|
||||
reader.getFilename()+".lua"
|
||||
reader.getFilename()
|
||||
);
|
||||
textbox->setTextConsumer(consumer);
|
||||
}
|
||||
@@ -224,7 +235,7 @@ static std::shared_ptr<UINode> readTextBox(UiXmlReader& reader, xml::xmlelement
|
||||
auto supplier = scripting::create_wstring_supplier(
|
||||
reader.getEnvironment().getId(),
|
||||
element->attr("consumer").getText(),
|
||||
reader.getFilename()+".lua"
|
||||
reader.getFilename()
|
||||
);
|
||||
textbox->setTextSupplier(supplier);
|
||||
}
|
||||
@@ -238,7 +249,7 @@ static std::shared_ptr<UINode> readTextBox(UiXmlReader& reader, xml::xmlelement
|
||||
auto validator = scripting::create_wstring_validator(
|
||||
reader.getEnvironment().getId(),
|
||||
element->attr("validator").getText(),
|
||||
reader.getFilename()+".lua"
|
||||
reader.getFilename()
|
||||
);
|
||||
textbox->setTextValidator(validator);
|
||||
}
|
||||
@@ -265,7 +276,7 @@ static std::shared_ptr<UINode> readTrackBar(UiXmlReader& reader, xml::xmlelement
|
||||
auto consumer = scripting::create_number_consumer(
|
||||
reader.getEnvironment().getId(),
|
||||
element->attr("consumer").getText(),
|
||||
reader.getFilename()+".lua"
|
||||
reader.getFilename()
|
||||
);
|
||||
bar->setConsumer(consumer);
|
||||
}
|
||||
@@ -273,7 +284,7 @@ static std::shared_ptr<UINode> readTrackBar(UiXmlReader& reader, xml::xmlelement
|
||||
auto supplier = scripting::create_number_supplier(
|
||||
reader.getEnvironment().getId(),
|
||||
element->attr("supplier").getText(),
|
||||
reader.getFilename()+".lua"
|
||||
reader.getFilename()
|
||||
);
|
||||
bar->setSupplier(supplier);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user