add 'cursor' ui property
This commit is contained in:
parent
10f0bd0290
commit
cb9690ebc7
@ -48,6 +48,7 @@ Properties that apply to all elements:
|
||||
| tooltip | string | yes | yes | tooltip text |
|
||||
| tooltipDelay | float | yes | yes | tooltip delay |
|
||||
| contentOffset | vec2 | yes | *no* | element content offset |
|
||||
| cursor | string | yes | yes | cursor displayed on hover |
|
||||
|
||||
Common element methods:
|
||||
|
||||
|
||||
@ -44,6 +44,7 @@ Examples:
|
||||
- `gravity` - automatic positioning of the element in the container. (Does not work in automatic containers like panel). Values: *top-left, top-center, top-right, center-left, center-center, center-right, bottom-left, bottom-center, bottom-right*.
|
||||
- `z-index` - determines the order of elements, with a larger value it will overlap elements with a smaller one.
|
||||
- `interactive` - if false, hovering over the element and all sub-elements will be ignored.
|
||||
- `cursor` - the cursor displayed when hovering over the element (arrow/text/pointer/crosshair/ew-resize/ns-resize/...).
|
||||
|
||||
# Template attributes
|
||||
|
||||
|
||||
@ -48,6 +48,7 @@ document["worlds-panel"]:clear()
|
||||
| tooltip | string | да | да | текст всплывающей подсказки |
|
||||
| tooltipDelay | float | да | да | задержка всплывающей подсказки |
|
||||
| contentOffset | vec2 | да | *нет* | смещение содержимого |
|
||||
| cursor | string | да | да | курсор, отображаемый при наведении |
|
||||
|
||||
Общие методы элементов:
|
||||
|
||||
|
||||
@ -48,6 +48,7 @@
|
||||
- `gravity` - автоматическое позиционирование элемента в контейнере. (Не работает в автоматических контейнерах, как panel). Значения: *top-left, top-center, top-right, center-left, center-center, center-right, bottom-left, bottom-center, bottom-right*.
|
||||
- `z-index` - определяет порядок элементов, при большем значении будет перекрывать элементы с меньшим.
|
||||
- `interactive` - при значении false наведение на элемент и все под-элементы будет игнорироваться.
|
||||
- `cursor` - курсор, отображаемый при наведении на элемент (arrow/text/pointer/crosshair/ew-resize/ns-resize/...).
|
||||
|
||||
# Атрибуты шаблонов
|
||||
|
||||
|
||||
39
src/graphics/core/commons.cpp
Normal file
39
src/graphics/core/commons.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
#include "commons.hpp"
|
||||
|
||||
#include <map>
|
||||
|
||||
std::optional<CursorShape> CursorShape_from(std::string_view name) {
|
||||
static std::map<std::string_view, CursorShape> shapes = {
|
||||
{"arrow", CursorShape::ARROW},
|
||||
{"text", CursorShape::TEXT},
|
||||
{"crosshair", CursorShape::CROSSHAIR},
|
||||
{"pointer", CursorShape::POINTER},
|
||||
{"ew-resize", CursorShape::EW_RESIZE},
|
||||
{"ns-resize", CursorShape::NS_RESIZE},
|
||||
{"nwse-resize", CursorShape::NWSE_RESIZE},
|
||||
{"nesw-resize", CursorShape::NESW_RESIZE},
|
||||
{"all-resize", CursorShape::ALL_RESIZE},
|
||||
{"not-allowed", CursorShape::NOT_ALLOWED}
|
||||
};
|
||||
const auto& found = shapes.find(name);
|
||||
if (found == shapes.end()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return found->second;
|
||||
}
|
||||
|
||||
std::string to_string(CursorShape shape) {
|
||||
static std::string names[] = {
|
||||
"arrow",
|
||||
"text",
|
||||
"crosshair",
|
||||
"pointer",
|
||||
"ew-resize",
|
||||
"ns-resize",
|
||||
"nwse-resize",
|
||||
"nesw-resize",
|
||||
"all-resize",
|
||||
"not-allowed"
|
||||
};
|
||||
return names[static_cast<int>(shape)];
|
||||
}
|
||||
@ -1,5 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <optional>
|
||||
|
||||
enum class DrawPrimitive {
|
||||
point = 0,
|
||||
line,
|
||||
@ -7,9 +10,47 @@ enum class DrawPrimitive {
|
||||
};
|
||||
|
||||
enum class BlendMode {
|
||||
normal, addition, inversion
|
||||
/// @brief Normal blending mode.
|
||||
normal,
|
||||
/// @brief Additive blending mode.
|
||||
addition,
|
||||
/// @brief Subtractive blending mode.
|
||||
inversion
|
||||
};
|
||||
|
||||
/// @brief Standard GLFW 3.4 cursor shapes (same order and count as in GLFW).
|
||||
/// It also works in GLFW 3.3 (unsupported shapes will be replaced with the arrow).
|
||||
enum class CursorShape {
|
||||
/// @brief Regular arrow
|
||||
ARROW,
|
||||
/// @brief Text input I-beam
|
||||
TEXT,
|
||||
/// @brief Crosshair
|
||||
CROSSHAIR,
|
||||
/// @brief Pointing hand
|
||||
POINTER,
|
||||
/// @brief Horizontal resize arrow
|
||||
EW_RESIZE,
|
||||
/// @brief Vertical resize arrow
|
||||
NS_RESIZE,
|
||||
|
||||
// GLFW 3.4+ cursor shapes
|
||||
|
||||
/// @brief Diagonal resize arrow (top-left to bottom-right)
|
||||
NWSE_RESIZE,
|
||||
/// @brief Diagonal resize arrow (top-right to bottom-left)
|
||||
NESW_RESIZE,
|
||||
/// @brief All-direction resize arrow
|
||||
ALL_RESIZE,
|
||||
/// @brief Operation not allowed
|
||||
NOT_ALLOWED,
|
||||
|
||||
LAST=NOT_ALLOWED
|
||||
};
|
||||
|
||||
std::optional<CursorShape> CursorShape_from(std::string_view name);
|
||||
std::string to_string(CursorShape shape);
|
||||
|
||||
class Flushable {
|
||||
public:
|
||||
virtual ~Flushable() = default;
|
||||
|
||||
@ -212,6 +212,10 @@ void GUI::draw(const DrawContext& pctx, const Assets& assets) {
|
||||
|
||||
batch2D->begin();
|
||||
container->draw(ctx, assets);
|
||||
|
||||
if (hover) {
|
||||
Window::setCursor(hover->getCursor());
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<UINode> GUI::getFocused() const {
|
||||
|
||||
@ -25,6 +25,7 @@ TextBox::TextBox(std::wstring placeholder, glm::vec4 padding)
|
||||
input(L""),
|
||||
placeholder(std::move(placeholder))
|
||||
{
|
||||
setCursor(CursorShape::TEXT);
|
||||
setOnUpPressed(nullptr);
|
||||
setOnDownPressed(nullptr);
|
||||
setColor(glm::vec4(0.0f, 0.0f, 0.0f, 0.75f));
|
||||
|
||||
@ -150,6 +150,14 @@ float UINode::getTooltipDelay() const {
|
||||
return tooltipDelay;
|
||||
}
|
||||
|
||||
void UINode::setCursor(CursorShape shape) {
|
||||
cursor = shape;
|
||||
}
|
||||
|
||||
CursorShape UINode::getCursor() const {
|
||||
return cursor;
|
||||
}
|
||||
|
||||
glm::vec2 UINode::calcPos() const {
|
||||
if (parent) {
|
||||
return pos + parent->calcPos() + parent->getContentOffset();
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "delegates.hpp"
|
||||
#include "graphics/core/commons.hpp"
|
||||
#include "window/input.hpp"
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
@ -112,6 +113,8 @@ namespace gui {
|
||||
std::wstring tooltip;
|
||||
/// @brief element tooltip delay
|
||||
float tooltipDelay = 0.5f;
|
||||
/// @brief cursor shape when mouse is over the element
|
||||
CursorShape cursor = CursorShape::ARROW;
|
||||
|
||||
UINode(glm::vec2 size);
|
||||
public:
|
||||
@ -206,6 +209,9 @@ namespace gui {
|
||||
virtual void setTooltipDelay(float delay);
|
||||
virtual float getTooltipDelay() const;
|
||||
|
||||
virtual void setCursor(CursorShape shape);
|
||||
virtual CursorShape getCursor() const;
|
||||
|
||||
virtual glm::vec4 calcColor() const;
|
||||
|
||||
/// @brief Get inner content offset. Used for scroll
|
||||
|
||||
@ -156,6 +156,11 @@ static void _readUINode(
|
||||
if (element.has("tooltip-delay")) {
|
||||
node.setTooltipDelay(element.attr("tooltip-delay").asFloat());
|
||||
}
|
||||
if (element.has("cursor")) {
|
||||
if (auto cursor = CursorShape_from(element.attr("cursor").getText())) {
|
||||
node.setCursor(*cursor);
|
||||
}
|
||||
}
|
||||
|
||||
if (auto onclick = create_action(reader, element, "onclick")) {
|
||||
node.listenAction(onclick);
|
||||
|
||||
@ -401,6 +401,10 @@ static int p_get_line_pos(UINode*, lua::State* L) {
|
||||
return lua::pushcfunction(L, l_get_line_pos);
|
||||
}
|
||||
|
||||
static int p_get_cursor(UINode* node, lua::State* L) {
|
||||
return lua::pushstring(L, to_string(node->getCursor()));
|
||||
}
|
||||
|
||||
static int l_gui_getattr(lua::State* L) {
|
||||
auto docname = lua::require_string(L, 1);
|
||||
auto element = lua::require_string(L, 2);
|
||||
@ -455,6 +459,7 @@ static int l_gui_getattr(lua::State* L) {
|
||||
{"paste", p_get_paste},
|
||||
{"inventory", p_get_inventory},
|
||||
{"focused", p_get_focused},
|
||||
{"cursor", p_get_cursor},
|
||||
};
|
||||
auto func = getters.find(attr);
|
||||
if (func != getters.end()) {
|
||||
@ -616,6 +621,12 @@ static void p_set_focused(
|
||||
}
|
||||
}
|
||||
|
||||
static void p_set_cursor(UINode* node, lua::State* L, int idx) {
|
||||
if (auto cursor = CursorShape_from(lua::require_string(L, idx))) {
|
||||
node->setCursor(*cursor);
|
||||
}
|
||||
}
|
||||
|
||||
static int l_gui_setattr(lua::State* L) {
|
||||
auto docname = lua::require_string(L, 1);
|
||||
auto element = lua::require_string(L, 2);
|
||||
@ -658,6 +669,7 @@ static int l_gui_setattr(lua::State* L) {
|
||||
{"checked", p_set_checked},
|
||||
{"page", p_set_page},
|
||||
{"inventory", p_set_inventory},
|
||||
{"cursor", p_set_cursor},
|
||||
};
|
||||
auto func = setters.find(attr);
|
||||
if (func != setters.end()) {
|
||||
|
||||
@ -29,6 +29,7 @@ int Window::posY = 0;
|
||||
int Window::framerate = -1;
|
||||
double Window::prevSwap = 0.0;
|
||||
bool Window::fullscreen = false;
|
||||
CursorShape Window::cursor = CursorShape::ARROW;
|
||||
|
||||
static util::ObjectsKeeper observers_keeper;
|
||||
|
||||
@ -125,6 +126,8 @@ void error_callback(int error, const char* description) {
|
||||
}
|
||||
}
|
||||
|
||||
static GLFWcursor* standard_cursors[static_cast<int>(CursorShape::LAST) + 1] = {};
|
||||
|
||||
int Window::initialize(DisplaySettings* settings) {
|
||||
Window::settings = settings;
|
||||
Window::width = settings->width.get();
|
||||
@ -219,6 +222,10 @@ int Window::initialize(DisplaySettings* settings) {
|
||||
logger.info() << "monitor content scale: " << scale.x << "x" << scale.y;
|
||||
|
||||
input_util::initialize();
|
||||
|
||||
for (int i = 0; i <= static_cast<int>(CursorShape::LAST); i++) {
|
||||
standard_cursors[i] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR + i);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -305,6 +312,9 @@ void Window::popScissor() {
|
||||
|
||||
void Window::terminate() {
|
||||
observers_keeper = util::ObjectsKeeper();
|
||||
for (int i = 0; i <= static_cast<int>(CursorShape::LAST); i++) {
|
||||
glfwDestroyCursor(standard_cursors[i]);
|
||||
}
|
||||
glfwTerminate();
|
||||
}
|
||||
|
||||
@ -380,6 +390,15 @@ DisplaySettings* Window::getSettings() {
|
||||
return settings;
|
||||
}
|
||||
|
||||
void Window::setCursor(CursorShape shape) {
|
||||
if (cursor == shape) {
|
||||
return;
|
||||
}
|
||||
cursor = shape;
|
||||
// NULL cursor is valid for GLFW
|
||||
glfwSetCursor(window, standard_cursors[static_cast<int>(shape)]);
|
||||
}
|
||||
|
||||
std::unique_ptr<ImageData> Window::takeScreenshot() {
|
||||
auto data = std::make_unique<ubyte[]>(width * height * 3);
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#include <stack>
|
||||
#include <vector>
|
||||
|
||||
#include "graphics/core/commons.hpp"
|
||||
#include "typedefs.hpp"
|
||||
|
||||
class ImageData;
|
||||
@ -20,6 +21,7 @@ class Window {
|
||||
static bool fullscreen;
|
||||
static int framerate;
|
||||
static double prevSwap;
|
||||
static CursorShape cursor;
|
||||
|
||||
static bool tryToMaximize(GLFWwindow* window, GLFWmonitor* monitor);
|
||||
public:
|
||||
@ -46,6 +48,8 @@ public:
|
||||
static void popScissor();
|
||||
static void resetScissor();
|
||||
|
||||
static void setCursor(CursorShape shape);
|
||||
|
||||
static void clear();
|
||||
static void clearDepth();
|
||||
static void setBgColor(glm::vec3 color);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user