Some UI stuff
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
precision mediump float;
|
||||
|
||||
uniform vec4 text_color;
|
||||
uniform vec4 color;
|
||||
uniform sampler2D texture;
|
||||
|
||||
varying vec2 f_uv;
|
||||
@@ -10,5 +10,5 @@ varying vec2 f_uv;
|
||||
void main ()
|
||||
{
|
||||
|
||||
gl_FragColor = texture2D (texture, f_uv) * text_color;
|
||||
gl_FragColor = texture2D (texture, f_uv) * color;
|
||||
}
|
||||
|
||||
@@ -11,10 +11,10 @@ varying vec2 f_uv;
|
||||
|
||||
void main ()
|
||||
{
|
||||
float tex_w = 160.0;
|
||||
float tex_w = 144.0;
|
||||
float tex_h = 320.0;
|
||||
|
||||
float char_w = 10.0;
|
||||
float char_w = 9.0;
|
||||
float char_h = 20.0;
|
||||
|
||||
float chars_per_row = tex_w / char_w;
|
||||
|
||||
@@ -2,20 +2,22 @@
|
||||
|
||||
precision mediump float;
|
||||
|
||||
uniform sampler2D texture;
|
||||
uniform sampler2D background_image;
|
||||
uniform bool has_texture;
|
||||
uniform vec4 background_color;
|
||||
|
||||
varying vec2 f_uv;
|
||||
|
||||
void main ()
|
||||
{
|
||||
vec4 tex_color = texture2D (texture, f_uv);
|
||||
vec4 tex_color = texture2D (background_image, f_uv);
|
||||
|
||||
if (has_texture)
|
||||
{
|
||||
gl_FragColor = tex_color;
|
||||
gl_FragColor = vec4 (background_color.xyz, 1.0) * tex_color;
|
||||
}
|
||||
else
|
||||
{
|
||||
gl_FragColor = vec4 (0.0, 0.0, 0.0, 0.0);
|
||||
gl_FragColor = background_color;
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 2.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.1 KiB |
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 2.5 KiB |
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 380 B |
Binary file not shown.
@@ -86,11 +86,13 @@ graphics_render ()
|
||||
entman_render (view, planes);
|
||||
|
||||
/* We don't care about blending elsewhere for now. */
|
||||
glEnable (GL_SCISSOR_TEST);
|
||||
glEnable (GL_BLEND);
|
||||
glDisable (GL_DEPTH_TEST);
|
||||
uiman_render ();
|
||||
glEnable (GL_DEPTH_TEST);
|
||||
glDisable (GL_BLEND);
|
||||
glDisable (GL_SCISSOR_TEST);
|
||||
|
||||
SDL_GL_SwapWindow (sdl_window);
|
||||
|
||||
|
||||
@@ -161,8 +161,9 @@ resources_init ()
|
||||
RAT ("grass0", RLT ("res/textures/grass0.png"));
|
||||
RAT ("clouds", RLT ("res/textures/clouds.png"));
|
||||
|
||||
RAT ("font0", RLT ("res/textures/font.png"));
|
||||
|
||||
RAT ("font0", RLT ("res/textures/font_9x20.png"));
|
||||
RAT ("icons", RLT ("res/textures/icons.png"));
|
||||
|
||||
#undef RAP
|
||||
#undef RLP
|
||||
#undef RAT
|
||||
|
||||
+67
-25
@@ -14,6 +14,8 @@ extern vec3 camera_position;
|
||||
static Widget *ui_root;
|
||||
static mat4 projection;
|
||||
|
||||
static Widget *hovered_widget, *clicked_widget;
|
||||
|
||||
void
|
||||
uiman_init ()
|
||||
{
|
||||
@@ -22,24 +24,26 @@ uiman_init ()
|
||||
glm_ortho (0.0, (float) sdl_window_w, (float) sdl_window_h, 0.0, -1.0, 1.0, projection);
|
||||
|
||||
Widget *debug_menu = Widget_container_new (FALSE);
|
||||
Widget_set_texture (debug_menu, RESTEX ("terrain4"));
|
||||
Widget_set_background_color (debug_menu, 0, 0, 0, 0.7);
|
||||
Widget_set_position (debug_menu, 32, 32);
|
||||
Widget_set_size (debug_menu, 300, 150);
|
||||
Widget_set_size (debug_menu, 350, 150);
|
||||
Widget_add_child (ui_root, debug_menu);
|
||||
|
||||
Widget_add_child (debug_menu, Widget_label_make_float ("Frame time: %.3f", &delta_time, TEXT_ALIGN_LEFT));
|
||||
Widget_add_child (debug_menu, Widget_label_make_int ("Render distance: %d", &render_distance, TEXT_ALIGN_LEFT));
|
||||
Widget_add_child (debug_menu, Widget_label_make_int ("Chunks rendered: %d", &n_frame_chunks, TEXT_ALIGN_LEFT));
|
||||
Widget_add_child (debug_menu, Widget_label_make_int ("Entities rendered: %d", &n_frame_ents, TEXT_ALIGN_LEFT));
|
||||
Widget_add_child_weighed (debug_menu, Widget_label_make_float ("Frame time: %.3f", &delta_time, TEXT_ALIGN_LEFT), 1);
|
||||
Widget_add_child_weighed (debug_menu, Widget_label_make_int ("Render distance: %d", &render_distance, TEXT_ALIGN_LEFT), 1);
|
||||
Widget_add_child_weighed (debug_menu, Widget_label_make_int ("Chunks rendered: %d", &n_frame_chunks, TEXT_ALIGN_LEFT), 1);
|
||||
Widget_add_child_weighed (debug_menu, Widget_label_make_int ("Entities rendered: %d", &n_frame_ents, TEXT_ALIGN_LEFT), 1);
|
||||
|
||||
Widget *poscont = Widget_container_new (TRUE);
|
||||
Widget_add_child (poscont, Widget_label_make_float ("X: %.0f", &camera_position[0], TEXT_ALIGN_LEFT));
|
||||
Widget_add_child (poscont, Widget_label_make_float ("Y: %.0f", &camera_position[1], TEXT_ALIGN_CENTER));
|
||||
Widget_add_child (poscont, Widget_label_make_float ("Z: %.0f", &camera_position[2], TEXT_ALIGN_RIGHT));
|
||||
Widget_add_child (debug_menu, poscont);
|
||||
|
||||
Widget_add_child (debug_menu, Widget_label_make_flag_switch_button ("Toggle wireframe", "wireframe_enabled"));
|
||||
Widget_add_child (debug_menu, Widget_label_make_flag_switch_button ("Toggle flight", "flight_enabled"));
|
||||
Widget_add_child_weighed (poscont, Widget_label_make_float ("X: %.1f", &camera_position[0], TEXT_ALIGN_LEFT), 1);
|
||||
Widget_add_child_weighed (poscont, Widget_label_make_float ("Y: %.1f", &camera_position[1], TEXT_ALIGN_CENTER), 1);
|
||||
Widget_add_child_weighed (poscont, Widget_label_make_float ("Z: %.1f", &camera_position[2], TEXT_ALIGN_RIGHT), 1);
|
||||
Widget_add_child_weighed (debug_menu, poscont, 1);
|
||||
|
||||
Widget *butcont = Widget_container_new (TRUE);
|
||||
Widget_add_child_weighed (butcont, Widget_label_make_flag_switch_button ("Toggle wireframe", "wireframe_enabled"), 1);
|
||||
Widget_add_child_weighed (butcont, Widget_label_make_flag_switch_button ("Toggle flight", "flight_enabled"), 1);
|
||||
Widget_add_child_weighed (debug_menu, butcont, 1);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -51,7 +55,7 @@ uiman_tick ()
|
||||
void
|
||||
uiman_render ()
|
||||
{
|
||||
Widget_render (ui_root, projection);
|
||||
Widget_render (ui_root, projection, sdl_window_h);
|
||||
}
|
||||
|
||||
gboolean
|
||||
@@ -90,8 +94,22 @@ uiman_cb_mouse_motion (SDL_Event *event, void *data)
|
||||
{
|
||||
UNUSED (data);
|
||||
|
||||
Widget *widget = Widget_find_xy (ui_root, (vec2) { event->motion.x, event->motion.y });
|
||||
UNUSED (widget);
|
||||
Widget *new_hover = Widget_find_xy (ui_root, (vec2) { event->motion.x, event->motion.y });
|
||||
|
||||
if (new_hover != hovered_widget)
|
||||
{
|
||||
if (hovered_widget)
|
||||
{
|
||||
hovered_widget->hovered = FALSE;
|
||||
}
|
||||
|
||||
if (new_hover)
|
||||
{
|
||||
new_hover->hovered = TRUE;
|
||||
}
|
||||
|
||||
hovered_widget = new_hover;
|
||||
}
|
||||
|
||||
/* This callback always eats the event, because why would the game
|
||||
need mouse motion if the UI has stolen the focus? */
|
||||
@@ -101,9 +119,40 @@ uiman_cb_mouse_motion (SDL_Event *event, void *data)
|
||||
gboolean
|
||||
uiman_cb_button_down (SDL_Event *event, void *data)
|
||||
{
|
||||
UNUSED (event, data);
|
||||
UNUSED (data);
|
||||
|
||||
Widget *new_clicked = Widget_find_xy (ui_root, (vec2) { event->motion.x, event->motion.y });
|
||||
|
||||
if (new_clicked != clicked_widget)
|
||||
{
|
||||
if (clicked_widget && (clicked_widget->on_left_click || clicked_widget->on_right_click))
|
||||
{
|
||||
clicked_widget->clicked = FALSE;
|
||||
}
|
||||
|
||||
if (new_clicked && (new_clicked->on_left_click || new_clicked->on_right_click))
|
||||
{
|
||||
new_clicked->clicked = TRUE;
|
||||
}
|
||||
|
||||
clicked_widget = new_clicked;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
uiman_cb_button_up (SDL_Event *event, void *data)
|
||||
{
|
||||
UNUSED (data);
|
||||
|
||||
Widget *widget = Widget_find_xy (ui_root, (vec2) { event->motion.x, event->motion.y });
|
||||
|
||||
if (clicked_widget)
|
||||
{
|
||||
clicked_widget->clicked = FALSE;
|
||||
clicked_widget = NULL;
|
||||
}
|
||||
|
||||
if (widget)
|
||||
{
|
||||
@@ -119,14 +168,7 @@ uiman_cb_button_down (SDL_Event *event, void *data)
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
uiman_cb_button_up (SDL_Event *event, void *data)
|
||||
{
|
||||
UNUSED (event, data);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
+95
-38
@@ -1,10 +1,5 @@
|
||||
#include "widget.h"
|
||||
|
||||
/* TODO: padding */
|
||||
/* TODO: movable and resizable windows */
|
||||
/* TODO: "spinner" UI element */
|
||||
/* TODO: "checkbox" UI element */
|
||||
|
||||
static SimpleMesh quad;
|
||||
static unsigned int last_program;
|
||||
|
||||
@@ -17,7 +12,7 @@ ui_el_new_internal (WidgetKind kind)
|
||||
e->kind = kind;
|
||||
e->visible = true;
|
||||
e->children = g_array_new (false, false, sizeof (Widget *));
|
||||
e->layout_weight = 1;
|
||||
glm_vec4_zero (e->background_color);
|
||||
return e;
|
||||
}
|
||||
|
||||
@@ -42,7 +37,7 @@ Widget_label_new (const char *text, TextAlignment alignment)
|
||||
Widget *e = ui_el_new_internal (WIDGET_LABEL);
|
||||
e->label.text = g_string_new (text);
|
||||
e->label.text_alignment = alignment;
|
||||
glm_vec4_one (e->label.text_color);
|
||||
glm_vec4_one (e->label.color);
|
||||
return e;
|
||||
}
|
||||
|
||||
@@ -62,8 +57,8 @@ Widget_add_child_weighed (Widget *parent, Widget *child, float layout_weight)
|
||||
|
||||
void
|
||||
Widget_set_on_tick (Widget *widget,
|
||||
void (*on_tick) (Widget *, void *),
|
||||
void *userdata)
|
||||
void (*on_tick) (Widget *, void *),
|
||||
void *userdata)
|
||||
{
|
||||
widget->on_tick = on_tick;
|
||||
widget->tick_data = userdata;
|
||||
@@ -71,8 +66,8 @@ Widget_set_on_tick (Widget *widget,
|
||||
|
||||
void
|
||||
Widget_set_on_left_click (Widget *widget,
|
||||
void (*on_left_click) (Widget *, void *),
|
||||
void *userdata)
|
||||
void (*on_left_click) (Widget *, void *),
|
||||
void *userdata)
|
||||
{
|
||||
widget->on_left_click = on_left_click;
|
||||
widget->left_click_data = userdata;
|
||||
@@ -91,10 +86,28 @@ Widget_set_size (Widget *widget, float x, float y)
|
||||
}
|
||||
|
||||
void
|
||||
Widget_set_texture (Widget *widget, unsigned int texture)
|
||||
Widget_set_background_image (Widget *widget, unsigned int image)
|
||||
{
|
||||
widget->texture = texture;
|
||||
widget->has_texture = TRUE;
|
||||
widget->background_image = image;
|
||||
widget->has_background_image = TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
Widget_set_background_color (Widget *widget, float r, float g, float b, float a)
|
||||
{
|
||||
glm_vec4_copy ((vec4) { r, g, b, a }, widget->background_color);
|
||||
}
|
||||
|
||||
void
|
||||
Widget_set_hovered_bg_color (Widget *widget, float r, float g, float b, float a)
|
||||
{
|
||||
glm_vec4_copy ((vec4) { r, g, b, a }, widget->hovered_bg_color);
|
||||
}
|
||||
|
||||
void
|
||||
Widget_set_clicked_bg_color (Widget *widget, float r, float g, float b, float a)
|
||||
{
|
||||
glm_vec4_copy ((vec4) { r, g, b, a }, widget->clicked_bg_color);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -209,7 +222,7 @@ Widget_label_render_text (Widget *widget, mat4 projection)
|
||||
gunichar ch = g_utf8_get_char (p);
|
||||
|
||||
program_set_float (RESPRG ("uitext"), "character", ch);
|
||||
program_set_vec4 (RESPRG ("uitext"), "text_color", widget->label.text_color);
|
||||
program_set_vec4 (RESPRG ("uitext"), "color", widget->label.color);
|
||||
|
||||
mat3 model;
|
||||
glm_translate2d_make (model, (vec2) { widget->position[0] + offset + char_width, widget->position[1] });
|
||||
@@ -228,44 +241,69 @@ void
|
||||
Widget_container_layout (Widget *parent, gboolean horizontal)
|
||||
{
|
||||
float total_weights = 0.0;
|
||||
float total_fixed = 0.0;
|
||||
|
||||
for (unsigned int i = 0; i < parent->children->len; ++i)
|
||||
{
|
||||
Widget *child = g_array_index (parent->children, Widget *, i);
|
||||
total_weights += child->layout_weight;
|
||||
|
||||
if (child->layout_weight == 0.0)
|
||||
{
|
||||
total_fixed += horizontal ? child->size[0] : child->size[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
total_weights += child->layout_weight;
|
||||
}
|
||||
}
|
||||
|
||||
float weights_size = ((horizontal ? parent->size[0] : parent->size[1]) - total_fixed) / total_weights;
|
||||
|
||||
if (weights_size < 0)
|
||||
{
|
||||
g_warning ("Fixed size children exceed the size of the parent container.");
|
||||
}
|
||||
|
||||
float offset = 0.0;
|
||||
for (unsigned int i = 0; i < parent->children->len; ++i)
|
||||
{
|
||||
Widget *child = g_array_index (parent->children, Widget *, i);
|
||||
|
||||
if (horizontal)
|
||||
if (child->layout_weight == 0.0)
|
||||
{
|
||||
float weights_size = parent->size[0] / total_weights;
|
||||
child->size[0] = child->layout_weight * weights_size;
|
||||
child->size[1] = parent->size[1];
|
||||
|
||||
child->position[0] = parent->position[0] + offset;
|
||||
child->position[1] = parent->position[1];
|
||||
|
||||
offset += child->size[0];
|
||||
if (horizontal)
|
||||
{
|
||||
Widget_set_position (child, parent->position[0] + offset, parent->position[1]);
|
||||
child->size[1] = parent->size[1];
|
||||
offset += child->size[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
Widget_set_position (child, parent->position[0], parent->position[1] + offset);
|
||||
child->size[0] = parent->size[0];
|
||||
offset += child->size[1];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
float weights_size = parent->size[1] / total_weights;
|
||||
child->size[1] = child->layout_weight * weights_size;
|
||||
child->size[0] = parent->size[0];
|
||||
|
||||
child->position[1] = parent->position[1] + offset;
|
||||
child->position[0] = parent->position[0];
|
||||
|
||||
offset += child->size[1];
|
||||
if (horizontal)
|
||||
{
|
||||
Widget_set_position (child, parent->position[0] + offset, parent->position[1]);
|
||||
Widget_set_size (child, child->layout_weight * weights_size, parent->size[1]);
|
||||
offset += child->size[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
Widget_set_position (child, parent->position[0], parent->position[1] + offset);
|
||||
Widget_set_size (child, parent->size[0], child->layout_weight * weights_size);
|
||||
offset += child->size[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Widget_render (Widget *widget, mat4 projection)
|
||||
Widget_render (Widget *widget, mat4 projection, int window_height)
|
||||
{
|
||||
last_program = 0;
|
||||
|
||||
@@ -284,15 +322,31 @@ Widget_render (Widget *widget, mat4 projection)
|
||||
last_program = program_use (RESPRG ("uiwidget"));
|
||||
}
|
||||
|
||||
program_set_int (RESPRG ("uiwidget"), "has_texture", widget->has_texture);
|
||||
texture_use (widget->texture, 0); /* If it doesn't have a texture, it'll be 0 anyway. */
|
||||
|
||||
program_set_int (RESPRG ("uiwidget"), "has_background_image", widget->has_background_image);
|
||||
texture_use (widget->background_image, 0); /* If it doesn't have a texture, it'll be 0 anyway. */
|
||||
|
||||
program_set_vec4 (RESPRG ("uiwidget"), "background_color", widget->background_color);
|
||||
|
||||
if (widget->clicked)
|
||||
{
|
||||
program_set_vec4 (RESPRG ("uiwidget"), "background_color", widget->clicked_bg_color);
|
||||
}
|
||||
else if (widget->hovered)
|
||||
{
|
||||
program_set_vec4 (RESPRG ("uiwidget"), "background_color", widget->hovered_bg_color);
|
||||
}
|
||||
|
||||
mat3 model;
|
||||
glm_translate2d_make (model, widget->position);
|
||||
glm_scale2d (model, widget->size);
|
||||
|
||||
program_set_mat3 (RESPRG ("uiwidget"), "model", model);
|
||||
program_set_mat4 (RESPRG ("uiwidget"), "projection", projection);
|
||||
|
||||
/* X, Y is the lower left corner of the box. */
|
||||
glScissor (widget->position[0], window_height - widget->position[1]
|
||||
- widget->size[1], widget->size[0], widget->size[1]);
|
||||
|
||||
SimpleMesh_render (&quad, FALSE);
|
||||
|
||||
if (widget->kind == WIDGET_CONTAINER)
|
||||
@@ -308,7 +362,7 @@ Widget_render (Widget *widget, mat4 projection)
|
||||
for (unsigned int i = 0; i < widget->children->len; ++i)
|
||||
{
|
||||
Widget *child = g_array_index (widget->children, Widget *, i);
|
||||
Widget_render (child, projection);
|
||||
Widget_render (child, projection, window_height);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -373,6 +427,9 @@ Widget *
|
||||
Widget_label_make_flag_switch_button (const char *text, char *flag)
|
||||
{
|
||||
Widget *w = Widget_label_new (text, TEXT_ALIGN_CENTER);
|
||||
Widget_set_background_color (w, 1, 1, 1, 0.1);
|
||||
Widget_set_hovered_bg_color (w, 1, 1, 1, 0.2);
|
||||
Widget_set_clicked_bg_color (w, 1, 1, 1, 0.3);
|
||||
Widget_set_on_left_click (w, uicb_switch_flag, flag);
|
||||
return w;
|
||||
}
|
||||
|
||||
+18
-13
@@ -13,7 +13,8 @@ typedef enum WidgetKind
|
||||
{
|
||||
WIDGET_PLAIN,
|
||||
WIDGET_CONTAINER,
|
||||
WIDGET_LABEL
|
||||
WIDGET_LABEL,
|
||||
WIDGET_ICON
|
||||
} WidgetKind;
|
||||
|
||||
typedef struct ContainerWidget
|
||||
@@ -31,7 +32,7 @@ typedef enum TextAlignment
|
||||
typedef struct LabelWidget
|
||||
{
|
||||
GString *text;
|
||||
vec4 text_color;
|
||||
vec4 color;
|
||||
TextAlignment text_alignment;
|
||||
} LabelWidget;
|
||||
|
||||
@@ -47,13 +48,18 @@ typedef struct Widget
|
||||
};
|
||||
|
||||
gboolean visible;
|
||||
|
||||
gboolean hovered, clicked;
|
||||
|
||||
vec2 position;
|
||||
vec2 size;
|
||||
float layout_weight;
|
||||
|
||||
gboolean has_texture;
|
||||
unsigned int texture;
|
||||
vec4 background_color;
|
||||
vec4 hovered_bg_color;
|
||||
vec4 clicked_bg_color;
|
||||
|
||||
gboolean has_background_image;
|
||||
unsigned int background_image;
|
||||
|
||||
void (*on_left_click) (struct Widget *, void *);
|
||||
void *left_click_data;
|
||||
@@ -71,16 +77,15 @@ void Widget_add_child (Widget *parent, Widget *child);
|
||||
void Widget_add_child_weighed (Widget *parent, Widget *child,
|
||||
float layout_weight);
|
||||
|
||||
void Widget_set_on_tick (Widget *widget,
|
||||
void (*on_tick) (Widget *, void *),
|
||||
void *userdata);
|
||||
void Widget_set_on_left_click (Widget *widget,
|
||||
void (*on_left_click) (Widget *, void *),
|
||||
void *userdata);
|
||||
void Widget_set_on_tick (Widget *widget, void (*on_tick) (Widget *, void *), void *userdata);
|
||||
void Widget_set_on_left_click (Widget *widget, void (*on_left_click) (Widget *, void *), void *userdata);
|
||||
|
||||
void Widget_set_position (Widget *widget, float x, float y);
|
||||
void Widget_set_size (Widget *widget, float x, float y);
|
||||
void Widget_set_texture (Widget *widget, unsigned int texture);
|
||||
void Widget_set_background_image (Widget *widget, unsigned int image);
|
||||
void Widget_set_background_color (Widget *widget, float r, float g, float b, float a);
|
||||
void Widget_set_hovered_bg_color (Widget *widget, float r, float g, float b, float a);
|
||||
void Widget_set_clicked_bg_color (Widget *widget, float r, float g, float b, float a);
|
||||
|
||||
void Widget_label_set_text (Widget *widget, const char *text);
|
||||
void Widget_label_printf (Widget *widget, const char *format, ...);
|
||||
@@ -89,7 +94,7 @@ Widget *Widget_find_xy (Widget *widget, vec2 point);
|
||||
|
||||
void ui_widget_mesh_init ();
|
||||
void Widget_tick (Widget *widget);
|
||||
void Widget_render (Widget *widget, mat4 projection);
|
||||
void Widget_render (Widget *widget, mat4 projection, int window_height);
|
||||
|
||||
/* ---------------------------------------------- */
|
||||
typedef struct LabelFormatData
|
||||
|
||||
Reference in New Issue
Block a user