Files
Mike Nelson 7f48375a6d Add underlining as a custom decorator (#6399)
* add underlining and corner border custom decorators

* some cleanup

* CLANG
2024-12-18 17:33:39 +09:00

249 lines
8.8 KiB
C++

#include "RocketDecorators.h"
#include <Rocket/Core/RenderInterface.h>
#include <Rocket/Core/Vertex.h>
namespace scpui {
namespace decorators {
// ================================
// Element Underline Implementation
// ================================
DecoratorUnderline::DecoratorUnderline(float thickness, LineStyle style, float length, float space, Rocket::Core::Colourb color, bool element_color)
: line_thickness(thickness), line_style(style), line_length(length), line_space(space), line_color(color), use_element_color(element_color)
{
}
DecoratorUnderline::~DecoratorUnderline() = default;
// Generate per-element data, if needed (return NULL if not needed)
Rocket::Core::DecoratorDataHandle DecoratorUnderline::GenerateElementData(Rocket::Core::Element* /*element*/)
{
return 0; // No per-element data needed
}
// Release any element-specific data
void DecoratorUnderline::ReleaseElementData(Rocket::Core::DecoratorDataHandle /*element_data*/)
{
// No element-specific data to release in this case
}
void DecoratorUnderline::RenderElement(Rocket::Core::Element* element,
Rocket::Core::DecoratorDataHandle /*element_data*/)
{
// Get the size of the element's content area
Rocket::Core::Vector2f element_size = element->GetBox().GetSize(Rocket::Core::Box::CONTENT);
// Determine line rendering properties based on style
float dash_length = 5.0f;
float space_length = 3.0f;
switch (line_style) {
case LineStyle::Dotted:
dash_length = line_thickness; // Dotted lines are small circles
space_length = line_space;
break;
case LineStyle::Dashed:
space_length = line_space;
dash_length = line_length;
break;
case LineStyle::Solid:
default:
space_length = 0; // No space for solid lines
break;
}
// Calculate the starting position (bottom-left of the content area)
Rocket::Core::Vector2f start = element->GetAbsoluteOffset(Rocket::Core::Box::CONTENT);
float x_position = start.x;
float y_position = start.y + element_size.y - (line_thickness * 2); // Adjusted y-position using the thickness
Rocket::Core::RenderInterface* render_interface = element->GetRenderInterface();
// Create space for vertices and indices for all dashes
std::vector<Rocket::Core::Vertex> vertices;
std::vector<int> indices;
int vertex_count = 0;
Rocket::Core::Colourb render_color = line_color;
if (use_element_color) {
render_color = element->GetProperty<Rocket::Core::Colourb>("color");
}
// Loop through to create each dash as a rectangle (or dot)
while (x_position < start.x + element_size.x) {
float dash_end_x = std::min(x_position + dash_length, start.x + element_size.x);
// Create four vertices for the rectangle (two triangles)
Rocket::Core::Vertex top_left, top_right, bottom_left, bottom_right;
// Set vertex positions
top_left.position = Rocket::Core::Vector2f(x_position, y_position);
top_right.position = Rocket::Core::Vector2f(dash_end_x, y_position);
bottom_left.position = Rocket::Core::Vector2f(x_position, y_position + line_thickness);
bottom_right.position = Rocket::Core::Vector2f(dash_end_x, y_position + line_thickness);
// Set the color
top_left.colour = render_color;
top_right.colour = render_color;
bottom_left.colour = render_color;
bottom_right.colour = render_color;
// Set texture coordinates to 0 since we have no texture
top_left.tex_coord = Rocket::Core::Vector2f(0, 0);
top_right.tex_coord = Rocket::Core::Vector2f(0, 0);
bottom_left.tex_coord = Rocket::Core::Vector2f(0, 0);
bottom_right.tex_coord = Rocket::Core::Vector2f(0, 0);
// Add the vertices to the list
vertices.push_back(top_left);
vertices.push_back(top_right);
vertices.push_back(bottom_left);
vertices.push_back(bottom_right);
// Add indices for two triangles
indices.push_back(vertex_count); // First triangle
indices.push_back(vertex_count + 1);
indices.push_back(vertex_count + 2);
indices.push_back(vertex_count + 1); // Second triangle
indices.push_back(vertex_count + 3);
indices.push_back(vertex_count + 2);
// Move to the next dash position
x_position += dash_length + space_length;
// Increment vertex count for the next set of triangles
vertex_count += 4;
}
// Render the geometry
render_interface->RenderGeometry(vertices.data(),
(int)vertices.size(),
indices.data(),
(int)indices.size(),
0,
Rocket::Core::Vector2f(0, 0));
}
// =============================
// Corner Borders Implementation
// =============================
DecoratorCornerBorders::DecoratorCornerBorders(float thickness, float length_h, float length_v, Rocket::Core::Colourb color)
: border_thickness(thickness), border_length_h(length_h), border_length_v(length_v), border_color(color)
{
}
DecoratorCornerBorders::~DecoratorCornerBorders() = default;
// Generate per-element data, if needed (return NULL if not needed)
Rocket::Core::DecoratorDataHandle DecoratorCornerBorders::GenerateElementData(Rocket::Core::Element* /*element*/)
{
return 0; // No per-element data needed
}
// Release any element-specific data
void DecoratorCornerBorders::ReleaseElementData(Rocket::Core::DecoratorDataHandle /*element_data*/)
{
// No element-specific data to release in this case
}
void DecoratorCornerBorders::RenderElement(Rocket::Core::Element* element,
Rocket::Core::DecoratorDataHandle /*element_data*/)
{
// Get the size of the element's content area
Rocket::Core::Vector2f element_size = element->GetBox().GetSize(Rocket::Core::Box::CONTENT);
Rocket::Core::Vector2f start = element->GetAbsoluteOffset(Rocket::Core::Box::CONTENT);
Rocket::Core::RenderInterface* render_interface = element->GetRenderInterface();
// Create space for vertices and indices for the corner borders
std::vector<Rocket::Core::Vertex> vertices;
std::vector<int> indices;
int vertex_count = 0;
// Define the four corner positions, moved inward by thickness
Rocket::Core::Vector2f top_left = start + Rocket::Core::Vector2f(border_thickness, border_thickness);
Rocket::Core::Vector2f top_right =
start + Rocket::Core::Vector2f(element_size.x - border_thickness, border_thickness);
Rocket::Core::Vector2f bottom_left =
start + Rocket::Core::Vector2f(border_thickness, element_size.y - border_thickness);
Rocket::Core::Vector2f bottom_right =
start + Rocket::Core::Vector2f(element_size.x - border_thickness, element_size.y - border_thickness);
// Function to add a line segment as two triangles
auto add_line_segment = [&](const Rocket::Core::Vector2f& start_pos, const Rocket::Core::Vector2f& end_pos, float thickness) {
// Vector direction of the line
Rocket::Core::Vector2f direction = end_pos - start_pos;
// Normalize direction and calculate the perpendicular vector for thickness
Rocket::Core::Vector2f perpendicular =
Rocket::Core::Vector2f(-direction.y, direction.x).Normalise() * thickness;
// Define the four vertices of the line as a rectangle (two triangles)
Rocket::Core::Vertex v1, v2, v3, v4;
v1.position = start_pos - perpendicular;
v2.position = start_pos + perpendicular;
v3.position = end_pos - perpendicular;
v4.position = end_pos + perpendicular;
// Set color
v1.colour = border_color;
v2.colour = border_color;
v3.colour = border_color;
v4.colour = border_color;
// Add vertices
vertices.push_back(v1);
vertices.push_back(v2);
vertices.push_back(v3);
vertices.push_back(v4);
// Add indices for two triangles
indices.push_back(vertex_count);
indices.push_back(vertex_count + 1);
indices.push_back(vertex_count + 2);
indices.push_back(vertex_count + 1);
indices.push_back(vertex_count + 3);
indices.push_back(vertex_count + 2);
vertex_count += 4;
};
// Define the lengths for horizontal and vertical borders
Rocket::Core::Vector2f horizontal(border_length_h, 0);
Rocket::Core::Vector2f vertical(0, border_length_v);
// Add corner borders by adding two line segments for each corner, moved inward by thickness
// Top-left corner
add_line_segment(top_left, top_left + horizontal, border_thickness); // Horizontal line
add_line_segment(top_left, top_left + vertical, border_thickness); // Vertical line
// Top-right corner
add_line_segment(top_right, top_right - horizontal, border_thickness); // Horizontal line
add_line_segment(top_right, top_right + vertical, border_thickness); // Vertical line
// Bottom-left corner
add_line_segment(bottom_left, bottom_left + horizontal, border_thickness); // Horizontal line
add_line_segment(bottom_left, bottom_left - vertical, border_thickness); // Vertical line
// Bottom-right corner
add_line_segment(bottom_right, bottom_right - horizontal, border_thickness); // Horizontal line
add_line_segment(bottom_right, bottom_right - vertical, border_thickness); // Vertical line
// Render the geometry
render_interface->RenderGeometry(vertices.data(),
(int)vertices.size(),
indices.data(),
(int)indices.size(),
0,
Rocket::Core::Vector2f(0, 0));
}
} // namespace decorators
} // namespace scpui