Implemented the top layer
This commit is contained in:
1 parent
51174824b2
commit
4cdc17489e
1 file changed
+204
-57
@@ -96,6 +96,17 @@ static inline int point_in_rect(int x, int y, GUI_Rectangle rect)
|
|||||||
&& (x <= rect.x1)
|
&& (x <= rect.x1)
|
||||||
&& (y <= rect.y1);
|
&& (y <= rect.y1);
|
||||||
}
|
}
|
||||||
|
static inline int point_in_rect_with_offset(
|
||||||
|
int x, int y,
|
||||||
|
GUI_Rectangle rect,
|
||||||
|
int x_offset, int y_offset)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
(x >= (rect.x0+x_offset))
|
||||||
|
&& (y >= (rect.y0+y_offset))
|
||||||
|
&& (x <= (rect.x1+x_offset))
|
||||||
|
&& (y <= (rect.y1+y_offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -225,6 +236,10 @@ typedef struct {
|
|||||||
GUI_Draw_Command *first_draw_command;
|
GUI_Draw_Command *first_draw_command;
|
||||||
int num_draw_commands;
|
int num_draw_commands;
|
||||||
Pixel_Buffer *pixel_buffer;
|
Pixel_Buffer *pixel_buffer;
|
||||||
|
bool should_draw;
|
||||||
|
// TODO(Zelaven): Offsets like for the subtrees.
|
||||||
|
int offset_x;
|
||||||
|
int offset_y;
|
||||||
} GUI_Layer;
|
} GUI_Layer;
|
||||||
|
|
||||||
|
|
||||||
@@ -355,7 +370,14 @@ void fff(GUI_Context *context)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define GUIWITH_INNER2(token) defer ## token
|
||||||
|
#define GUIWITH_INNER(token) GUIWITH_INNER2(token)
|
||||||
|
#define GUIWITH(storage_variable, TYPE, value_to_use)\
|
||||||
|
for(struct {TYPE temp; int i;} GUIWITH_INNER(__LINE__) = {.temp=(storage_variable), .i = ((storage_variable) = (value_to_use), 0)}; !GUIWITH_INNER(__LINE__).i; GUIWITH_INNER(__LINE__).i += 1, ((storage_variable) = GUIWITH_INNER(__LINE__).temp))
|
||||||
|
|
||||||
|
#define GUI_ON_LAYER(context, layer) \
|
||||||
|
(layer)->should_draw = true;\
|
||||||
|
GUIWITH(context->current_layer, GUI_Layer*, layer)
|
||||||
|
|
||||||
|
|
||||||
// ---
|
// ---
|
||||||
@@ -364,7 +386,7 @@ void fff(GUI_Context *context)
|
|||||||
// TODO(Zelaven): The mouse coordinates are in the context, so no need to pass
|
// TODO(Zelaven): The mouse coordinates are in the context, so no need to pass
|
||||||
// them as parameters.
|
// them as parameters.
|
||||||
#undef ENABLE_DEBUG
|
#undef ENABLE_DEBUG
|
||||||
#define ENABLE_DEBUG 0
|
#define ENABLE_DEBUG 1
|
||||||
void gui_apply_input(
|
void gui_apply_input(
|
||||||
GUI_Context *context,
|
GUI_Context *context,
|
||||||
int mouse_x,
|
int mouse_x,
|
||||||
@@ -380,12 +402,15 @@ void gui_apply_input(
|
|||||||
{
|
{
|
||||||
GUI_Layer *top_layer = &context->top_layer;
|
GUI_Layer *top_layer = &context->top_layer;
|
||||||
GUI_Subtree *root_subtree = (GUI_Subtree*)top_layer->subtree_rdic.root;
|
GUI_Subtree *root_subtree = (GUI_Subtree*)top_layer->subtree_rdic.root;
|
||||||
if(root_subtree != NULL)
|
if(top_layer->should_draw && root_subtree != NULL)
|
||||||
{
|
{
|
||||||
GUI_Node *top_layer_root =
|
GUI_Node *top_layer_root =
|
||||||
(GUI_Node*)root_subtree->rdic.root;
|
(GUI_Node*)root_subtree->rdic.root;
|
||||||
if(top_layer_root != NULL)
|
if(top_layer_root != NULL)
|
||||||
if(point_in_rect(mouse_x, mouse_y, top_layer_root->rect))
|
if(point_in_rect_with_offset(
|
||||||
|
mouse_x, mouse_y,
|
||||||
|
top_layer_root->rect,
|
||||||
|
top_layer->offset_x, top_layer->offset_y))
|
||||||
{
|
{
|
||||||
hit_layer = &context->top_layer;
|
hit_layer = &context->top_layer;
|
||||||
hit_root_subtree = root_subtree;
|
hit_root_subtree = root_subtree;
|
||||||
@@ -579,6 +604,65 @@ GUI_Subtree_Reference gui_get_subtree(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GUI_Node_Reference gui_context_prepare_layer(
|
||||||
|
GUI_Context *context,
|
||||||
|
GUI_Layer *layer,
|
||||||
|
GUI_Node_Reference last_root_reference,
|
||||||
|
int width, int height,
|
||||||
|
GUI_Layout_Direction layout_direction,
|
||||||
|
GUI_Style *style)
|
||||||
|
{
|
||||||
|
layer->should_draw = false;
|
||||||
|
GUI_Subtree_Reference root_subtree = layer->root_subtree;
|
||||||
|
//root_subtree = gui_get_subtree(context, root_subtree);
|
||||||
|
root_subtree.rdic_ref = rdic_context_start_frame(
|
||||||
|
&layer->subtree_rdic, root_subtree.rdic_ref);
|
||||||
|
if(root_subtree.node == NULL)
|
||||||
|
{
|
||||||
|
return (GUI_Node_Reference){0};
|
||||||
|
}
|
||||||
|
layer->root_subtree = root_subtree;
|
||||||
|
root_subtree.node->rdic.freelist = context->node_freelist;
|
||||||
|
|
||||||
|
//static GUI_Subtree background_subtree = {0};
|
||||||
|
//background_subtree.rdic.freelist = context->node_freelist;
|
||||||
|
//context->background_layer.first_subtree = &background_subtree;
|
||||||
|
//context->background_layer.last_subtree = &background_subtree;
|
||||||
|
//context->current_subtree = &background_subtree;
|
||||||
|
|
||||||
|
GUI_Node_Reference new_root_reference = {
|
||||||
|
.rdic_ref = rdic_context_start_frame(
|
||||||
|
//&background_subtree.rdic, last_root_reference.rdic)
|
||||||
|
&root_subtree.node->rdic, last_root_reference.rdic_ref)
|
||||||
|
};
|
||||||
|
if(new_root_reference.node == NULL)
|
||||||
|
{
|
||||||
|
return (GUI_Node_Reference){0};
|
||||||
|
}
|
||||||
|
//RDIC_Node_Reference new_root_reference = rdic_context_start_frame(
|
||||||
|
// &background_subtree.rdic,
|
||||||
|
// last_root_reference);
|
||||||
|
|
||||||
|
GUI_Node *root = (GUI_Node*)new_root_reference.node;
|
||||||
|
root->dirty = false;
|
||||||
|
if(!gui_node_references_equal(last_root_reference, new_root_reference)) {
|
||||||
|
root->dirty = true;
|
||||||
|
}
|
||||||
|
if(layout_direction != root->layout_direction) {
|
||||||
|
root->dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
root->debug_string = GUI_STRING("root");
|
||||||
|
root->layout_direction = layout_direction;
|
||||||
|
root->semantic_size[GUI_AXIS2_X] = (GUI_Size)
|
||||||
|
{.size_rule = GUI_SIZERULE_PIXELS, .value = width, .strictness = 100,};
|
||||||
|
root->semantic_size[GUI_AXIS2_Y] = (GUI_Size)
|
||||||
|
{.size_rule = GUI_SIZERULE_PIXELS, .value = height, .strictness = 100,};
|
||||||
|
root->style = style;
|
||||||
|
|
||||||
|
return new_root_reference;
|
||||||
|
}
|
||||||
|
|
||||||
#undef ENABLE_DEBUG
|
#undef ENABLE_DEBUG
|
||||||
#define ENABLE_DEBUG 0
|
#define ENABLE_DEBUG 0
|
||||||
// TODO(Zelaven): Make this cause redrawing of root on parameter change.
|
// TODO(Zelaven): Make this cause redrawing of root on parameter change.
|
||||||
@@ -608,55 +692,14 @@ GUI_Node_Reference gui_context_start_frame(
|
|||||||
context->mouse_pressed, context->mouse_down);
|
context->mouse_pressed, context->mouse_down);
|
||||||
|
|
||||||
context->current_layer = &context->background_layer;
|
context->current_layer = &context->background_layer;
|
||||||
|
GUI_Node_Reference new_root_reference = gui_context_prepare_layer(
|
||||||
|
context, context->current_layer, last_root_reference,
|
||||||
|
width, height, layout_direction, style);
|
||||||
|
|
||||||
GUI_Subtree_Reference root_subtree = context->current_layer->root_subtree;
|
context->current_layer->should_draw = true;
|
||||||
//root_subtree = gui_get_subtree(context, root_subtree);
|
|
||||||
root_subtree.rdic_ref = rdic_context_start_frame(
|
|
||||||
&context->current_layer->subtree_rdic, root_subtree.rdic_ref);
|
|
||||||
if(root_subtree.node == NULL)
|
|
||||||
{
|
|
||||||
return (GUI_Node_Reference){0};
|
|
||||||
}
|
|
||||||
context->current_layer->root_subtree = root_subtree;
|
|
||||||
root_subtree.node->rdic.freelist = context->node_freelist;
|
|
||||||
|
|
||||||
//static GUI_Subtree background_subtree = {0};
|
|
||||||
//background_subtree.rdic.freelist = context->node_freelist;
|
|
||||||
//context->background_layer.first_subtree = &background_subtree;
|
|
||||||
//context->background_layer.last_subtree = &background_subtree;
|
|
||||||
//context->current_subtree = &background_subtree;
|
|
||||||
|
|
||||||
GUI_Node_Reference new_root_reference = {
|
|
||||||
.rdic_ref = rdic_context_start_frame(
|
|
||||||
//&background_subtree.rdic, last_root_reference.rdic)
|
|
||||||
&root_subtree.node->rdic, last_root_reference.rdic_ref)
|
|
||||||
};
|
|
||||||
if(new_root_reference.node == NULL)
|
|
||||||
{
|
|
||||||
return (GUI_Node_Reference){0};
|
|
||||||
}
|
|
||||||
//RDIC_Node_Reference new_root_reference = rdic_context_start_frame(
|
|
||||||
// &background_subtree.rdic,
|
|
||||||
// last_root_reference);
|
|
||||||
GUI_Node *root = (GUI_Node*)new_root_reference.node;
|
|
||||||
root->dirty = false;
|
|
||||||
if(!gui_node_references_equal(last_root_reference, new_root_reference)) {
|
|
||||||
root->dirty = true;
|
|
||||||
}
|
|
||||||
if(layout_direction != root->layout_direction) {
|
|
||||||
root->dirty = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
gui_apply_input(context, context->mouse_x, context->mouse_y);
|
gui_apply_input(context, context->mouse_x, context->mouse_y);
|
||||||
|
|
||||||
root->debug_string = GUI_STRING("root");
|
|
||||||
root->layout_direction = layout_direction;
|
|
||||||
root->semantic_size[GUI_AXIS2_X] = (GUI_Size)
|
|
||||||
{.size_rule = GUI_SIZERULE_PIXELS, .value = width, .strictness = 100,};
|
|
||||||
root->semantic_size[GUI_AXIS2_Y] = (GUI_Size)
|
|
||||||
{.size_rule = GUI_SIZERULE_PIXELS, .value = height, .strictness = 100,};
|
|
||||||
root->style = style;
|
|
||||||
|
|
||||||
return new_root_reference;
|
return new_root_reference;
|
||||||
}
|
}
|
||||||
void gui_context_finish_frame(
|
void gui_context_finish_frame(
|
||||||
@@ -1028,6 +1071,32 @@ bool gui_dumb_button(
|
|||||||
|
|
||||||
#undef ENABLE_DEBUG
|
#undef ENABLE_DEBUG
|
||||||
#define ENABLE_DEBUG 0
|
#define ENABLE_DEBUG 0
|
||||||
|
bool gui_mouseover_box(
|
||||||
|
GUI_Context *context,
|
||||||
|
GUI_Node_Reference *last_reference,
|
||||||
|
GUI_String text,
|
||||||
|
GUI_Style *style,
|
||||||
|
GUI_Size size[static 2])
|
||||||
|
{
|
||||||
|
GUI_Node_Reference new_reference = gui_get_node(
|
||||||
|
context, *last_reference, GUI_LAYOUT_NONE, style, size);
|
||||||
|
GUI_Node *node = new_reference.node;
|
||||||
|
node->debug_string = GUI_STRING("gui_mouseover_box");
|
||||||
|
node->text_string = text;
|
||||||
|
|
||||||
|
bool new_ref_is_top = gui_node_references_equal(
|
||||||
|
new_reference, context->top_node_under_cursor);
|
||||||
|
DEBUG(" %p\n | %p\n | %p\n",
|
||||||
|
context->top_node_under_cursor.node,
|
||||||
|
last_reference->node, new_reference.node);
|
||||||
|
bool hovered = new_ref_is_top;
|
||||||
|
|
||||||
|
*last_reference = new_reference;
|
||||||
|
return hovered;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef ENABLE_DEBUG
|
||||||
|
#define ENABLE_DEBUG 1
|
||||||
bool gui_slider(
|
bool gui_slider(
|
||||||
GUI_Context *context,
|
GUI_Context *context,
|
||||||
GUI_Node_Reference *last_reference,
|
GUI_Node_Reference *last_reference,
|
||||||
@@ -1053,10 +1122,10 @@ bool gui_slider(
|
|||||||
new_reference, context->top_node_under_cursor);
|
new_reference, context->top_node_under_cursor);
|
||||||
bool inner_ref_is_top = gui_node_references_equal(
|
bool inner_ref_is_top = gui_node_references_equal(
|
||||||
new_inner_reference, context->top_node_under_cursor);
|
new_inner_reference, context->top_node_under_cursor);
|
||||||
DEBUG("%p\n | %p %p\n | %p %p\n",
|
/*DEBUG(" %p\n | %p %p\n | %p %p\n",
|
||||||
context->top_node_under_cursor.node,
|
context->top_node_under_cursor.node,
|
||||||
last_reference->node, inner_box_reference->node,
|
last_reference->node, inner_box_reference->node,
|
||||||
new_reference.node, new_inner_reference.node);
|
new_reference.node, new_inner_reference.node);*/
|
||||||
if(new_ref_is_top || inner_ref_is_top)
|
if(new_ref_is_top || inner_ref_is_top)
|
||||||
{
|
{
|
||||||
DEBUG("\n%s: reference is the top node under cursor.\n", __func__);
|
DEBUG("\n%s: reference is the top node under cursor.\n", __func__);
|
||||||
@@ -1814,6 +1883,14 @@ void test_gui__subtree(
|
|||||||
full_gui_rectangle.y1-full_gui_rectangle.y0,
|
full_gui_rectangle.y1-full_gui_rectangle.y0,
|
||||||
GUI_LAYOUT_VERTICAL,
|
GUI_LAYOUT_VERTICAL,
|
||||||
&root_style);
|
&root_style);
|
||||||
|
static GUI_Node_Reference top_root = {0};
|
||||||
|
top_root = gui_context_prepare_layer(
|
||||||
|
context, &context->top_layer, top_root,
|
||||||
|
context->top_layer.pixel_buffer->width,
|
||||||
|
context->top_layer.pixel_buffer->height,
|
||||||
|
GUI_LAYOUT_HORIZONTAL, &outer_style);
|
||||||
|
context->top_layer.offset_x = 50;
|
||||||
|
context->top_layer.offset_y = 250;
|
||||||
|
|
||||||
|
|
||||||
static GUI_Node_Reference top = {0};
|
static GUI_Node_Reference top = {0};
|
||||||
@@ -1841,7 +1918,7 @@ void test_gui__subtree(
|
|||||||
static GUI_Node_Reference dirty_button = {0};
|
static GUI_Node_Reference dirty_button = {0};
|
||||||
static GUI_Style button_style = {0x99,0x99,0x99, 0x00222222,2,0};
|
static GUI_Style button_style = {0x99,0x99,0x99, 0x00222222,2,0};
|
||||||
static GUI_Size button_size[2] = {
|
static GUI_Size button_size[2] = {
|
||||||
{GUI_SIZERULE_PIXELS, 200, 100},
|
{GUI_SIZERULE_PIXELS, 170, 100},
|
||||||
{GUI_SIZERULE_PIXELS, 40, 100}};
|
{GUI_SIZERULE_PIXELS, 40, 100}};
|
||||||
if(gui_dumb_button(
|
if(gui_dumb_button(
|
||||||
context, &dirty_button, GUI_STRING("Dirty middle"),
|
context, &dirty_button, GUI_STRING("Dirty middle"),
|
||||||
@@ -1857,6 +1934,31 @@ void test_gui__subtree(
|
|||||||
set_pixels = true;
|
set_pixels = true;
|
||||||
printf("Setting pixels.\n");
|
printf("Setting pixels.\n");
|
||||||
}
|
}
|
||||||
|
static bool tooltip_toggle = false;
|
||||||
|
static GUI_Node_Reference dirty_button3 = {0};
|
||||||
|
if(gui_dumb_button(
|
||||||
|
context, &dirty_button3, GUI_STRING("Hover for tooltip"),
|
||||||
|
&button_style, button_size))
|
||||||
|
{
|
||||||
|
tooltip_toggle = !tooltip_toggle;
|
||||||
|
}
|
||||||
|
static GUI_Node_Reference dirty_button4 = {0};
|
||||||
|
if(
|
||||||
|
gui_mouseover_box(
|
||||||
|
context, &dirty_button4, GUI_STRING("Hover for tooltip"),
|
||||||
|
&button_style, button_size)
|
||||||
|
|| tooltip_toggle)
|
||||||
|
{
|
||||||
|
GUI_ON_LAYER(context, &context->top_layer)
|
||||||
|
{
|
||||||
|
static GUI_Size full_size[2] = {
|
||||||
|
{GUI_SIZERULE_PERCENTOFPARENT, 100, 100},
|
||||||
|
{GUI_SIZERULE_PERCENTOFPARENT, 100, 100}};
|
||||||
|
static GUI_Node_Reference top_layer_block = {0};
|
||||||
|
top_layer_block = gui_dumb_block(
|
||||||
|
context, top_layer_block, &element_style, full_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
} gui_pop_parent(context); // middle.
|
} gui_pop_parent(context); // middle.
|
||||||
|
|
||||||
middle = gui_dumb_block(context, middle, &outer_style, middle_size);
|
middle = gui_dumb_block(context, middle, &outer_style, middle_size);
|
||||||
@@ -3611,6 +3713,30 @@ void gui_layout_and_draw(GUI_Context *context)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void gui_compose_layers(
|
||||||
|
GUI_Context *context,
|
||||||
|
Pixel_Buffer *target_buffer)
|
||||||
|
{
|
||||||
|
// TODO(Zelaven): Make the layers in the context iteratable.
|
||||||
|
GUI_Layer *layers[] = {
|
||||||
|
&context->background_layer,
|
||||||
|
&context->top_layer,
|
||||||
|
};
|
||||||
|
for(
|
||||||
|
size_t i = 0;
|
||||||
|
i < ARRAYLENGTH(layers);
|
||||||
|
i++)
|
||||||
|
{
|
||||||
|
GUI_Layer *layer = layers[i];
|
||||||
|
if(layer->should_draw) {
|
||||||
|
gui_draw_image_direct(
|
||||||
|
target_buffer,
|
||||||
|
layer->pixel_buffer,
|
||||||
|
layer->offset_x,
|
||||||
|
layer->offset_y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#include <unistd.h> // usleep.
|
#include <unistd.h> // usleep.
|
||||||
@@ -3678,12 +3804,27 @@ int main(void)
|
|||||||
RDIC_Freelist subtree_freelist = {&g_gui_subtree_freelist[0].rdic_node};
|
RDIC_Freelist subtree_freelist = {&g_gui_subtree_freelist[0].rdic_node};
|
||||||
context.subtree_freelist = &subtree_freelist;
|
context.subtree_freelist = &subtree_freelist;
|
||||||
|
|
||||||
|
Pixel_Buffer background_pixel_buffer = (Pixel_Buffer){
|
||||||
|
.pixels = malloc(xwindow.pixel_buffer.width*xwindow.pixel_buffer.height*sizeof(GUI_Color)),
|
||||||
|
.width = xwindow.pixel_buffer.width,
|
||||||
|
.height = xwindow.pixel_buffer.height,
|
||||||
|
};
|
||||||
|
Pixel_Buffer top_pixel_buffer = (Pixel_Buffer){
|
||||||
|
.pixels = malloc(300*200*sizeof(GUI_Color)),
|
||||||
|
.width = 300,
|
||||||
|
.height = 200,
|
||||||
|
};
|
||||||
|
assert(background_pixel_buffer.pixels);
|
||||||
|
assert(top_pixel_buffer.pixels);
|
||||||
|
|
||||||
context.background_layer = (GUI_Layer){
|
context.background_layer = (GUI_Layer){
|
||||||
.subtree_rdic.freelist = &subtree_freelist,
|
.subtree_rdic.freelist = &subtree_freelist,
|
||||||
.pixel_buffer = &xwindow.pixel_buffer,
|
//.pixel_buffer = &xwindow.pixel_buffer,
|
||||||
|
.pixel_buffer = &background_pixel_buffer,
|
||||||
};
|
};
|
||||||
context.top_layer = (GUI_Layer){
|
context.top_layer = (GUI_Layer){
|
||||||
.subtree_rdic.freelist = &subtree_freelist,
|
.subtree_rdic.freelist = &subtree_freelist,
|
||||||
|
.pixel_buffer = &top_pixel_buffer,
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -3692,10 +3833,16 @@ int main(void)
|
|||||||
|
|
||||||
fill_pixel_buffer(
|
fill_pixel_buffer(
|
||||||
xwindow.pixel_buffer.pixels,
|
xwindow.pixel_buffer.pixels,
|
||||||
xwindow.width,
|
xwindow.width, xwindow.height,
|
||||||
xwindow.height,
|
0, 0);
|
||||||
0,
|
fill_pixel_buffer(
|
||||||
0);
|
background_pixel_buffer.pixels,
|
||||||
|
background_pixel_buffer.width, background_pixel_buffer.height,
|
||||||
|
0, 0);
|
||||||
|
fill_pixel_buffer(
|
||||||
|
top_pixel_buffer.pixels,
|
||||||
|
top_pixel_buffer.width, top_pixel_buffer.height,
|
||||||
|
0, 0);
|
||||||
GUI_Rectangle screen_rectangle = {
|
GUI_Rectangle screen_rectangle = {
|
||||||
.x0 = 0, .y0 = 0,
|
.x0 = 0, .y0 = 0,
|
||||||
.x1 = xwindow.width, .y1 = xwindow.height,
|
.x1 = xwindow.width, .y1 = xwindow.height,
|
||||||
@@ -3798,7 +3945,7 @@ int main(void)
|
|||||||
//gui_layout_nodes(&context);
|
//gui_layout_nodes(&context);
|
||||||
#if 1
|
#if 1
|
||||||
gui_layout_and_draw(&context);
|
gui_layout_and_draw(&context);
|
||||||
SET_PIXEL(&xwindow.pixel_buffer, 239, 259, 0x00ff0000);
|
gui_compose_layers(&context, &xwindow.pixel_buffer);
|
||||||
#else
|
#else
|
||||||
for(
|
for(
|
||||||
GUI_Subtree *current = (GUI_Subtree*)context.background_layer.subtree_rdic.root;
|
GUI_Subtree *current = (GUI_Subtree*)context.background_layer.subtree_rdic.root;
|
||||||
|
|||||||
Reference in new issue
Block a user