1
0
Fork 0
mirror of https://github.com/luanti-org/luanti.git synced 2025-07-27 17:28:41 +00:00

Formspec: add hypertext element

This commit is contained in:
Pierre-Yves Rollo 2019-09-10 15:11:26 +02:00 committed by SmallJoker
parent 8697090b35
commit 72416a6a1f
22 changed files with 1792 additions and 79 deletions

View file

@ -11,6 +11,7 @@ set(gui_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/guiScrollBar.cpp
${CMAKE_CURRENT_SOURCE_DIR}/guiSkin.cpp
${CMAKE_CURRENT_SOURCE_DIR}/guiTable.cpp
${CMAKE_CURRENT_SOURCE_DIR}/guiHyperText.cpp
${CMAKE_CURRENT_SOURCE_DIR}/guiVolumeChange.cpp
${CMAKE_CURRENT_SOURCE_DIR}/intlGUIEditBox.cpp
${CMAKE_CURRENT_SOURCE_DIR}/modalMenu.cpp

View file

@ -57,6 +57,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "client/guiscalingfilter.h"
#include "guiEditBoxWithScrollbar.h"
#include "intlGUIEditBox.h"
#include "guiHyperText.h"
#define MY_CHECKPOS(a,b) \
if (v_pos.size() != 2) { \
@ -155,16 +156,15 @@ void GUIFormSpecMenu::removeChildren()
{
const core::list<gui::IGUIElement*> &children = getChildren();
while(!children.empty()) {
while (!children.empty()) {
(*children.getLast())->remove();
}
if(m_tooltip_element) {
if (m_tooltip_element) {
m_tooltip_element->remove();
m_tooltip_element->drop();
m_tooltip_element = NULL;
m_tooltip_element = nullptr;
}
}
void GUIFormSpecMenu::setInitialFocus()
@ -1318,7 +1318,6 @@ void GUIFormSpecMenu::parseSimpleField(parserData* data,
void GUIFormSpecMenu::parseTextArea(parserData* data, std::vector<std::string>& parts,
const std::string &type)
{
std::vector<std::string> v_pos = split(parts[0],',');
std::vector<std::string> v_geom = split(parts[1],',');
std::string name = parts[2];
@ -1402,6 +1401,59 @@ void GUIFormSpecMenu::parseField(parserData* data, const std::string &element,
errorstream<< "Invalid field element(" << parts.size() << "): '" << element << "'" << std::endl;
}
void GUIFormSpecMenu::parseHyperText(parserData *data, const std::string &element)
{
std::vector<std::string> parts = split(element, ';');
if (parts.size() != 4 && m_formspec_version < FORMSPEC_API_VERSION) {
errorstream << "Invalid text element(" << parts.size() << "): '" << element << "'" << std::endl;
return;
}
std::vector<std::string> v_pos = split(parts[0], ',');
std::vector<std::string> v_geom = split(parts[1], ',');
std::string name = parts[2];
std::string text = parts[3];
MY_CHECKPOS("hypertext", 0);
MY_CHECKGEOM("hypertext", 1);
v2s32 pos;
v2s32 geom;
if (data->real_coordinates) {
pos = getRealCoordinateBasePos(false, v_pos);
geom = getRealCoordinateGeometry(v_geom);
} else {
pos = getElementBasePos(false, &v_pos);
pos -= padding;
pos.X += stof(v_pos[0]) * spacing.X;
pos.Y += stof(v_pos[1]) * spacing.Y + (m_btn_height * 2);
geom.X = (stof(v_geom[0]) * spacing.X) - (spacing.X - imgsize.X);
geom.Y = (stof(v_geom[1]) * imgsize.Y) - (spacing.Y - imgsize.Y);
}
core::rect<s32> rect = core::rect<s32>(pos.X, pos.Y, pos.X + geom.X, pos.Y + geom.Y);
if(m_form_src)
text = m_form_src->resolveText(text);
FieldSpec spec(
name,
utf8_to_wide(unescape_string(text)),
L"",
258 + m_fields.size()
);
spec.ftype = f_Unknown;
new GUIHyperText(
spec.flabel.c_str(), Environment, this, spec.fid, rect, m_client, m_tsrc);
m_fields.push_back(spec);
}
void GUIFormSpecMenu::parseLabel(parserData* data, const std::string &element)
{
std::vector<std::string> parts = split(element,';');
@ -2293,6 +2345,11 @@ void GUIFormSpecMenu::parseElement(parserData* data, const std::string &element)
return;
}
if (type == "hypertext") {
parseHyperText(data,description);
return;
}
if (type == "label") {
parseLabel(data,description);
return;
@ -2879,8 +2936,8 @@ void GUIFormSpecMenu::drawList(const ListDrawSpec &s, int layer,
if (!item.empty()) {
// Draw item stack
drawItemStack(driver, m_font, item,
rect, &AbsoluteClippingRect, m_client,
rotation_kind);
rect, &AbsoluteClippingRect, m_client, rotation_kind);
// Draw tooltip
if (hovering && !m_selected_item) {
std::string tooltip = item.getDescription(m_client->idef());
@ -2900,8 +2957,8 @@ void GUIFormSpecMenu::drawSelectedItem()
if (!m_selected_item) {
drawItemStack(driver, m_font, ItemStack(),
core::rect<s32>(v2s32(0, 0), v2s32(0, 0)),
NULL, m_client, IT_ROT_DRAGGED);
core::rect<s32>(v2s32(0, 0), v2s32(0, 0)), NULL,
m_client, IT_ROT_DRAGGED);
return;
}
@ -3482,9 +3539,10 @@ bool GUIFormSpecMenu::preprocessEvent(const SEvent& event)
}
}
}
// Mouse wheel events: send to hovered element instead of focused
if(event.EventType==EET_MOUSE_INPUT_EVENT
&& event.MouseInput.Event == EMIE_MOUSE_WHEEL) {
// Mouse wheel and move events: send to hovered element instead of focused
if (event.EventType == EET_MOUSE_INPUT_EVENT &&
(event.MouseInput.Event == EMIE_MOUSE_WHEEL ||
event.MouseInput.Event == EMIE_MOUSE_MOVED)) {
s32 x = event.MouseInput.X;
s32 y = event.MouseInput.Y;
gui::IGUIElement *hovered =
@ -3492,7 +3550,7 @@ bool GUIFormSpecMenu::preprocessEvent(const SEvent& event)
core::position2d<s32>(x, y));
if (hovered && isMyChild(hovered)) {
hovered->OnEvent(event);
return true;
return event.MouseInput.Event == EMIE_MOUSE_WHEEL;
}
}
@ -4041,8 +4099,8 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
}
m_old_pointer = m_pointer;
}
if (event.EventType == EET_GUI_EVENT) {
if (event.EventType == EET_GUI_EVENT) {
if (event.GUIEvent.EventType == gui::EGET_TAB_CHANGED
&& isVisible()) {
// find the element that was clicked
@ -4128,6 +4186,11 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
s.fdefault = L"Changed";
acceptInput(quit_mode_no);
s.fdefault = L"";
} else if ((s.ftype == f_Unknown) &&
(s.fid == event.GUIEvent.Caller->getID())) {
s.send = true;
acceptInput();
s.send = false;
}
}
}

View file

@ -469,6 +469,7 @@ protected:
video::SColor m_default_tooltip_bgcolor;
video::SColor m_default_tooltip_color;
private:
IFormSource *m_form_src;
TextDest *m_text_dst;
@ -529,6 +530,7 @@ private:
void parseSimpleField(parserData* data,std::vector<std::string> &parts);
void parseTextArea(parserData* data,std::vector<std::string>& parts,
const std::string &type);
void parseHyperText(parserData *data, const std::string &element);
void parseLabel(parserData* data, const std::string &element);
void parseVertLabel(parserData* data, const std::string &element);
void parseImageButton(parserData* data, const std::string &element,

1137
src/gui/guiHyperText.cpp Normal file

File diff suppressed because it is too large Load diff

229
src/gui/guiHyperText.h Normal file
View file

@ -0,0 +1,229 @@
/*
Minetest
Copyright (C) 2019 EvicenceBKidscode / Pierre-Yves Rollo <dev@pyrollo.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
#include "config.h" // for USE_FREETYPE
using namespace irr;
class ISimpleTextureSource;
class Client;
#if USE_FREETYPE
#include "irrlicht_changes/CGUITTFont.h"
#endif
class ParsedText
{
public:
ParsedText(const wchar_t *text);
~ParsedText();
enum ElementType
{
ELEMENT_TEXT,
ELEMENT_SEPARATOR,
ELEMENT_IMAGE,
ELEMENT_ITEM
};
enum BackgroundType
{
BACKGROUND_NONE,
BACKGROUND_COLOR
};
enum FloatType
{
FLOAT_NONE,
FLOAT_RIGHT,
FLOAT_LEFT
};
enum HalignType
{
HALIGN_CENTER,
HALIGN_LEFT,
HALIGN_RIGHT,
HALIGN_JUSTIFY
};
enum ValignType
{
VALIGN_MIDDLE,
VALIGN_TOP,
VALIGN_BOTTOM
};
typedef std::unordered_map<std::string, std::string> StyleList;
typedef std::unordered_map<std::string, std::string> AttrsList;
struct Tag
{
std::string name;
AttrsList attrs;
StyleList style;
};
struct Element
{
std::list<Tag *> tags;
ElementType type;
core::stringw text = "";
core::dimension2d<u32> dim;
core::position2d<s32> pos;
s32 drawwidth;
FloatType floating = FLOAT_NONE;
ValignType valign;
#if USE_FREETYPE
gui::CGUITTFont *font;
#else
gui::IGUIFont *font;
#endif
irr::video::SColor color;
irr::video::SColor hovercolor;
bool underline;
s32 baseline = 0;
// img & item specific attributes
std::string name;
v3s16 angle{0, 0, 0};
v3s16 rotation{0, 0, 0};
s32 margin = 10;
void setStyle(StyleList &style);
};
struct Paragraph
{
std::vector<Element> elements;
HalignType halign;
s32 margin = 10;
void setStyle(StyleList &style);
};
std::vector<Paragraph> m_paragraphs;
// Element style
s32 margin = 3;
ValignType valign = VALIGN_TOP;
BackgroundType background_type = BACKGROUND_NONE;
irr::video::SColor background_color;
Tag m_root_tag;
protected:
// Parser functions
void enterElement(ElementType type);
void endElement();
void enterParagraph();
void endParagraph();
void pushChar(wchar_t c);
ParsedText::Tag *newTag(const std::string &name, const AttrsList &attrs);
ParsedText::Tag *openTag(const std::string &name, const AttrsList &attrs);
bool closeTag(const std::string &name);
void parseGenericStyleAttr(const std::string &name, const std::string &value,
StyleList &style);
void parseStyles(const AttrsList &attrs, StyleList &style);
void globalTag(const ParsedText::AttrsList &attrs);
u32 parseTag(const wchar_t *text, u32 cursor);
void parse(const wchar_t *text);
std::unordered_map<std::string, StyleList> m_elementtags;
std::unordered_map<std::string, StyleList> m_paragraphtags;
std::vector<Tag *> m_tags;
std::list<Tag *> m_active_tags;
// Current values
StyleList m_style;
Element *m_element;
Paragraph *m_paragraph;
};
class TextDrawer
{
public:
TextDrawer(const wchar_t *text, Client *client, gui::IGUIEnvironment *environment,
ISimpleTextureSource *tsrc);
void place(const core::rect<s32> &dest_rect);
inline s32 getHeight() { return m_height; };
void draw(const core::rect<s32> &dest_rect,
const core::position2d<s32> &dest_offset);
ParsedText::Element *getElementAt(core::position2d<s32> pos);
ParsedText::Tag *m_hovertag;
protected:
struct RectWithMargin
{
core::rect<s32> rect;
s32 margin;
};
ParsedText m_text;
Client *m_client;
gui::IGUIEnvironment *m_environment;
s32 m_height;
s32 m_voffset;
std::vector<RectWithMargin> m_floating;
};
class GUIHyperText : public gui::IGUIElement
{
public:
//! constructor
GUIHyperText(const wchar_t *text, gui::IGUIEnvironment *environment,
gui::IGUIElement *parent, s32 id,
const core::rect<s32> &rectangle, Client *client,
ISimpleTextureSource *tsrc);
//! destructor
virtual ~GUIHyperText();
//! draws the element and its children
virtual void draw();
core::dimension2du getTextDimension();
bool OnEvent(const SEvent &event);
protected:
// GUI members
Client *m_client;
GUIScrollBar *m_vscrollbar;
TextDrawer m_drawer;
// Positioning
u32 m_scrollbar_width;
core::rect<s32> m_display_text_rect;
core::position2d<s32> m_text_scrollpos;
ParsedText::Element *getElementAt(s32 X, s32 Y);
void checkHover(s32 X, s32 Y);
};