You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-05 12:10:55 +00:00
Add option for a touch-friendly drag handle in SplitContainer
This commit is contained in:
@@ -53,6 +53,9 @@
|
|||||||
<member name="split_offset" type="int" setter="set_split_offset" getter="get_split_offset" default="0">
|
<member name="split_offset" type="int" setter="set_split_offset" getter="get_split_offset" default="0">
|
||||||
The initial offset of the splitting between the two [Control]s, with [code]0[/code] being at the end of the first [Control].
|
The initial offset of the splitting between the two [Control]s, with [code]0[/code] being at the end of the first [Control].
|
||||||
</member>
|
</member>
|
||||||
|
<member name="touch_dragger_enabled" type="bool" setter="set_touch_dragger_enabled" getter="is_touch_dragger_enabled" default="false">
|
||||||
|
If [code]true[/code], a touch-friendly drag handle will be enabled for better usability on smaller screens. Unlike the standard grabber, this drag handle overlaps the [SplitContainer]'s children and does not affect their minimum separation. The standard grabber will no longer be drawn when this option is enabled.
|
||||||
|
</member>
|
||||||
<member name="vertical" type="bool" setter="set_vertical" getter="is_vertical" default="false">
|
<member name="vertical" type="bool" setter="set_vertical" getter="is_vertical" default="false">
|
||||||
If [code]true[/code], the [SplitContainer] will arrange its children vertically, rather than horizontally.
|
If [code]true[/code], the [SplitContainer] will arrange its children vertically, rather than horizontally.
|
||||||
Can't be changed when using [HSplitContainer] and [VSplitContainer].
|
Can't be changed when using [HSplitContainer] and [VSplitContainer].
|
||||||
@@ -102,14 +105,23 @@
|
|||||||
[b]Note:[/b] To obtain [theme_item separation] values less than the size of the grabber icon, for example a [code]1 px[/code] hairline, set [theme_item h_grabber] or [theme_item v_grabber] to a new [ImageTexture], which effectively sets the grabber icon size to [code]0 px[/code].
|
[b]Note:[/b] To obtain [theme_item separation] values less than the size of the grabber icon, for example a [code]1 px[/code] hairline, set [theme_item h_grabber] or [theme_item v_grabber] to a new [ImageTexture], which effectively sets the grabber icon size to [code]0 px[/code].
|
||||||
</theme_item>
|
</theme_item>
|
||||||
<theme_item name="grabber" data_type="icon" type="Texture2D">
|
<theme_item name="grabber" data_type="icon" type="Texture2D">
|
||||||
The icon used for the grabber drawn in the middle area.
|
The icon used for the grabber drawn in the middle area. This is only used in [HSplitContainer] and [VSplitContainer]. For [SplitContainer], see [theme_item h_grabber] and [theme_item v_grabber] instead.
|
||||||
</theme_item>
|
</theme_item>
|
||||||
<theme_item name="h_grabber" data_type="icon" type="Texture2D">
|
<theme_item name="h_grabber" data_type="icon" type="Texture2D">
|
||||||
The icon used for the grabber drawn in the middle area when [member vertical] is [code]false[/code].
|
The icon used for the grabber drawn in the middle area when [member vertical] is [code]false[/code].
|
||||||
</theme_item>
|
</theme_item>
|
||||||
|
<theme_item name="h_touch_dragger" data_type="icon" type="Texture2D">
|
||||||
|
The icon used for the drag handle when [member touch_dragger_enabled] is [code]true[/code] and [member vertical] is [code]false[/code].
|
||||||
|
</theme_item>
|
||||||
|
<theme_item name="touch_dragger" data_type="icon" type="Texture2D">
|
||||||
|
The icon used for the drag handle when [member touch_dragger_enabled] is [code]true[/code]. This is only used in [HSplitContainer] and [VSplitContainer]. For [SplitContainer], see [theme_item h_touch_dragger] and [theme_item v_touch_dragger] instead.
|
||||||
|
</theme_item>
|
||||||
<theme_item name="v_grabber" data_type="icon" type="Texture2D">
|
<theme_item name="v_grabber" data_type="icon" type="Texture2D">
|
||||||
The icon used for the grabber drawn in the middle area when [member vertical] is [code]true[/code].
|
The icon used for the grabber drawn in the middle area when [member vertical] is [code]true[/code].
|
||||||
</theme_item>
|
</theme_item>
|
||||||
|
<theme_item name="v_touch_dragger" data_type="icon" type="Texture2D">
|
||||||
|
The icon used for the drag handle when [member touch_dragger_enabled] is [code]true[/code] and [member vertical] is [code]true[/code].
|
||||||
|
</theme_item>
|
||||||
<theme_item name="split_bar_background" data_type="style" type="StyleBox">
|
<theme_item name="split_bar_background" data_type="style" type="StyleBox">
|
||||||
Determines the background of the split bar if its thickness is greater than zero.
|
Determines the background of the split bar if its thickness is greater than zero.
|
||||||
</theme_item>
|
</theme_item>
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
|
|
||||||
#include "split_container.h"
|
#include "split_container.h"
|
||||||
|
|
||||||
|
#include "scene/gui/texture_rect.h"
|
||||||
#include "scene/main/viewport.h"
|
#include "scene/main/viewport.h"
|
||||||
#include "scene/theme/theme_db.h"
|
#include "scene/theme/theme_db.h"
|
||||||
|
|
||||||
@@ -161,7 +162,7 @@ void SplitContainerDragger::_notification(int p_what) {
|
|||||||
case NOTIFICATION_DRAW: {
|
case NOTIFICATION_DRAW: {
|
||||||
SplitContainer *sc = Object::cast_to<SplitContainer>(get_parent());
|
SplitContainer *sc = Object::cast_to<SplitContainer>(get_parent());
|
||||||
draw_style_box(sc->theme_cache.split_bar_background, split_bar_rect);
|
draw_style_box(sc->theme_cache.split_bar_background, split_bar_rect);
|
||||||
if (sc->dragger_visibility == sc->DRAGGER_VISIBLE && (dragging || mouse_inside || !sc->theme_cache.autohide)) {
|
if (sc->dragger_visibility == sc->DRAGGER_VISIBLE && (dragging || mouse_inside || !sc->theme_cache.autohide) && !sc->touch_dragger_enabled) {
|
||||||
Ref<Texture2D> tex = sc->_get_grabber_icon();
|
Ref<Texture2D> tex = sc->_get_grabber_icon();
|
||||||
float available_size = sc->vertical ? (sc->get_size().x - tex->get_size().x) : (sc->get_size().y - tex->get_size().y);
|
float available_size = sc->vertical ? (sc->get_size().x - tex->get_size().x) : (sc->get_size().y - tex->get_size().y);
|
||||||
if (available_size - sc->drag_area_margin_begin - sc->drag_area_margin_end > 0) { // Draw the grabber only if it fits.
|
if (available_size - sc->drag_area_margin_begin - sc->drag_area_margin_end > 0) { // Draw the grabber only if it fits.
|
||||||
@@ -208,10 +209,26 @@ Ref<Texture2D> SplitContainer::_get_grabber_icon() const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ref<Texture2D> SplitContainer::_get_touch_dragger_icon() const {
|
||||||
|
if (is_fixed) {
|
||||||
|
return theme_cache.touch_dragger_icon;
|
||||||
|
} else {
|
||||||
|
if (vertical) {
|
||||||
|
return theme_cache.touch_dragger_icon_v;
|
||||||
|
} else {
|
||||||
|
return theme_cache.touch_dragger_icon_h;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int SplitContainer::_get_separation() const {
|
int SplitContainer::_get_separation() const {
|
||||||
if (dragger_visibility == DRAGGER_HIDDEN_COLLAPSED) {
|
if (dragger_visibility == DRAGGER_HIDDEN_COLLAPSED) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (touch_dragger_enabled) {
|
||||||
|
return theme_cache.separation;
|
||||||
|
}
|
||||||
// DRAGGER_VISIBLE or DRAGGER_HIDDEN.
|
// DRAGGER_VISIBLE or DRAGGER_HIDDEN.
|
||||||
Ref<Texture2D> g = _get_grabber_icon();
|
Ref<Texture2D> g = _get_grabber_icon();
|
||||||
return MAX(theme_cache.separation, vertical ? g->get_height() : g->get_width());
|
return MAX(theme_cache.separation, vertical ? g->get_height() : g->get_width());
|
||||||
@@ -267,6 +284,9 @@ void SplitContainer::_resort() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dragging_area_control->set_visible(!collapsed);
|
dragging_area_control->set_visible(!collapsed);
|
||||||
|
if (touch_dragger_enabled) {
|
||||||
|
touch_dragger->set_visible(dragging_enabled);
|
||||||
|
}
|
||||||
|
|
||||||
_compute_split_offset(false); // This recalculates and sets computed_split_offset.
|
_compute_split_offset(false); // This recalculates and sets computed_split_offset.
|
||||||
|
|
||||||
@@ -406,7 +426,15 @@ bool SplitContainer::is_collapsed() const {
|
|||||||
|
|
||||||
void SplitContainer::set_vertical(bool p_vertical) {
|
void SplitContainer::set_vertical(bool p_vertical) {
|
||||||
ERR_FAIL_COND_MSG(is_fixed, "Can't change orientation of " + get_class() + ".");
|
ERR_FAIL_COND_MSG(is_fixed, "Can't change orientation of " + get_class() + ".");
|
||||||
|
if (vertical == p_vertical) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
vertical = p_vertical;
|
vertical = p_vertical;
|
||||||
|
if (touch_dragger) {
|
||||||
|
touch_dragger->set_texture(_get_touch_dragger_icon());
|
||||||
|
touch_dragger->set_anchors_and_offsets_preset(Control::PRESET_CENTER);
|
||||||
|
touch_dragger->set_default_cursor_shape(vertical ? CURSOR_VSPLIT : CURSOR_HSPLIT);
|
||||||
|
}
|
||||||
update_minimum_size();
|
update_minimum_size();
|
||||||
_resort();
|
_resort();
|
||||||
}
|
}
|
||||||
@@ -504,6 +532,59 @@ bool SplitContainer::is_show_drag_area_enabled() const {
|
|||||||
return show_drag_area;
|
return show_drag_area;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SplitContainer::set_touch_dragger_enabled(bool p_enabled) {
|
||||||
|
if (touch_dragger_enabled == p_enabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
touch_dragger_enabled = p_enabled;
|
||||||
|
if (p_enabled) {
|
||||||
|
touch_dragger = memnew(TextureRect);
|
||||||
|
touch_dragger->set_texture(_get_touch_dragger_icon());
|
||||||
|
touch_dragger->set_anchors_and_offsets_preset(Control::PRESET_CENTER);
|
||||||
|
touch_dragger->set_default_cursor_shape(vertical ? CURSOR_VSPLIT : CURSOR_HSPLIT);
|
||||||
|
touch_dragger->set_modulate(Color(1, 1, 1, 0.3));
|
||||||
|
touch_dragger->connect(SceneStringName(gui_input), callable_mp(this, &SplitContainer::_touch_dragger_gui_input));
|
||||||
|
touch_dragger->connect(SceneStringName(mouse_exited), callable_mp(this, &SplitContainer::_touch_dragger_mouse_exited));
|
||||||
|
dragging_area_control->add_child(touch_dragger, false, Node::INTERNAL_MODE_FRONT);
|
||||||
|
} else {
|
||||||
|
if (touch_dragger) {
|
||||||
|
touch_dragger->queue_free();
|
||||||
|
touch_dragger = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dragging_area_control->queue_redraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SplitContainer::is_touch_dragger_enabled() const {
|
||||||
|
return touch_dragger_enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SplitContainer::_touch_dragger_mouse_exited() {
|
||||||
|
if (!dragging_area_control->dragging) {
|
||||||
|
touch_dragger->set_modulate(Color(1, 1, 1, 0.3));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SplitContainer::_touch_dragger_gui_input(const Ref<InputEvent> &p_event) {
|
||||||
|
if (!touch_dragger_enabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Ref<InputEventMouseMotion> mm = p_event;
|
||||||
|
Ref<InputEventMouseButton> mb = p_event;
|
||||||
|
|
||||||
|
if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT) {
|
||||||
|
if (mb->is_pressed()) {
|
||||||
|
touch_dragger->set_modulate(Color(1, 1, 1, 1));
|
||||||
|
} else {
|
||||||
|
touch_dragger->set_modulate(Color(1, 1, 1, 0.3));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mm.is_valid() && !dragging_area_control->dragging) {
|
||||||
|
touch_dragger->set_modulate(Color(1, 1, 1, 0.6));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SplitContainer::_bind_methods() {
|
void SplitContainer::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("set_split_offset", "offset"), &SplitContainer::set_split_offset);
|
ClassDB::bind_method(D_METHOD("set_split_offset", "offset"), &SplitContainer::set_split_offset);
|
||||||
ClassDB::bind_method(D_METHOD("get_split_offset"), &SplitContainer::get_split_offset);
|
ClassDB::bind_method(D_METHOD("get_split_offset"), &SplitContainer::get_split_offset);
|
||||||
@@ -535,6 +616,9 @@ void SplitContainer::_bind_methods() {
|
|||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("get_drag_area_control"), &SplitContainer::get_drag_area_control);
|
ClassDB::bind_method(D_METHOD("get_drag_area_control"), &SplitContainer::get_drag_area_control);
|
||||||
|
|
||||||
|
ClassDB::bind_method(D_METHOD("set_touch_dragger_enabled", "enabled"), &SplitContainer::set_touch_dragger_enabled);
|
||||||
|
ClassDB::bind_method(D_METHOD("is_touch_dragger_enabled"), &SplitContainer::is_touch_dragger_enabled);
|
||||||
|
|
||||||
ADD_SIGNAL(MethodInfo("dragged", PropertyInfo(Variant::INT, "offset")));
|
ADD_SIGNAL(MethodInfo("dragged", PropertyInfo(Variant::INT, "offset")));
|
||||||
ADD_SIGNAL(MethodInfo("drag_started"));
|
ADD_SIGNAL(MethodInfo("drag_started"));
|
||||||
ADD_SIGNAL(MethodInfo("drag_ended"));
|
ADD_SIGNAL(MethodInfo("drag_ended"));
|
||||||
@@ -544,6 +628,7 @@ void SplitContainer::_bind_methods() {
|
|||||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dragging_enabled"), "set_dragging_enabled", "is_dragging_enabled");
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dragging_enabled"), "set_dragging_enabled", "is_dragging_enabled");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "dragger_visibility", PROPERTY_HINT_ENUM, "Visible,Hidden,Hidden and Collapsed"), "set_dragger_visibility", "get_dragger_visibility");
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "dragger_visibility", PROPERTY_HINT_ENUM, "Visible,Hidden,Hidden and Collapsed"), "set_dragger_visibility", "get_dragger_visibility");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "vertical"), "set_vertical", "is_vertical");
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "vertical"), "set_vertical", "is_vertical");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "touch_dragger_enabled"), "set_touch_dragger_enabled", "is_touch_dragger_enabled");
|
||||||
|
|
||||||
ADD_GROUP("Drag Area", "drag_area_");
|
ADD_GROUP("Drag Area", "drag_area_");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "drag_area_margin_begin", PROPERTY_HINT_NONE, "suffix:px"), "set_drag_area_margin_begin", "get_drag_area_margin_begin");
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "drag_area_margin_begin", PROPERTY_HINT_NONE, "suffix:px"), "set_drag_area_margin_begin", "get_drag_area_margin_begin");
|
||||||
@@ -558,6 +643,9 @@ void SplitContainer::_bind_methods() {
|
|||||||
BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, SplitContainer, separation);
|
BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, SplitContainer, separation);
|
||||||
BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, SplitContainer, minimum_grab_thickness);
|
BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, SplitContainer, minimum_grab_thickness);
|
||||||
BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, SplitContainer, autohide);
|
BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, SplitContainer, autohide);
|
||||||
|
BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, SplitContainer, touch_dragger_icon, "touch_dragger");
|
||||||
|
BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, SplitContainer, touch_dragger_icon_h, "h_touch_dragger");
|
||||||
|
BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, SplitContainer, touch_dragger_icon_v, "v_touch_dragger");
|
||||||
BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, SplitContainer, grabber_icon, "grabber");
|
BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, SplitContainer, grabber_icon, "grabber");
|
||||||
BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, SplitContainer, grabber_icon_h, "h_grabber");
|
BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, SplitContainer, grabber_icon_h, "h_grabber");
|
||||||
BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, SplitContainer, grabber_icon_v, "v_grabber");
|
BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, SplitContainer, grabber_icon_v, "v_grabber");
|
||||||
|
|||||||
@@ -32,6 +32,8 @@
|
|||||||
|
|
||||||
#include "scene/gui/container.h"
|
#include "scene/gui/container.h"
|
||||||
|
|
||||||
|
class TextureRect;
|
||||||
|
|
||||||
class SplitContainerDragger : public Control {
|
class SplitContainerDragger : public Control {
|
||||||
GDCLASS(SplitContainerDragger, Control);
|
GDCLASS(SplitContainerDragger, Control);
|
||||||
friend class SplitContainer;
|
friend class SplitContainer;
|
||||||
@@ -82,10 +84,16 @@ private:
|
|||||||
|
|
||||||
SplitContainerDragger *dragging_area_control = nullptr;
|
SplitContainerDragger *dragging_area_control = nullptr;
|
||||||
|
|
||||||
|
bool touch_dragger_enabled = false;
|
||||||
|
TextureRect *touch_dragger = nullptr;
|
||||||
|
|
||||||
struct ThemeCache {
|
struct ThemeCache {
|
||||||
int separation = 0;
|
int separation = 0;
|
||||||
int minimum_grab_thickness = 0;
|
int minimum_grab_thickness = 0;
|
||||||
bool autohide = false;
|
bool autohide = false;
|
||||||
|
Ref<Texture2D> touch_dragger_icon;
|
||||||
|
Ref<Texture2D> touch_dragger_icon_h;
|
||||||
|
Ref<Texture2D> touch_dragger_icon_v;
|
||||||
Ref<Texture2D> grabber_icon;
|
Ref<Texture2D> grabber_icon;
|
||||||
Ref<Texture2D> grabber_icon_h;
|
Ref<Texture2D> grabber_icon_h;
|
||||||
Ref<Texture2D> grabber_icon_v;
|
Ref<Texture2D> grabber_icon_v;
|
||||||
@@ -94,6 +102,9 @@ private:
|
|||||||
} theme_cache;
|
} theme_cache;
|
||||||
|
|
||||||
Ref<Texture2D> _get_grabber_icon() const;
|
Ref<Texture2D> _get_grabber_icon() const;
|
||||||
|
Ref<Texture2D> _get_touch_dragger_icon() const;
|
||||||
|
void _touch_dragger_mouse_exited();
|
||||||
|
void _touch_dragger_gui_input(const Ref<InputEvent> &p_event);
|
||||||
void _compute_split_offset(bool p_clamp);
|
void _compute_split_offset(bool p_clamp);
|
||||||
int _get_separation() const;
|
int _get_separation() const;
|
||||||
void _resort();
|
void _resort();
|
||||||
@@ -142,6 +153,9 @@ public:
|
|||||||
|
|
||||||
Control *get_drag_area_control() { return dragging_area_control; }
|
Control *get_drag_area_control() { return dragging_area_control; }
|
||||||
|
|
||||||
|
void set_touch_dragger_enabled(bool p_enabled);
|
||||||
|
bool is_touch_dragger_enabled() const;
|
||||||
|
|
||||||
SplitContainer(bool p_vertical = false);
|
SplitContainer(bool p_vertical = false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1184,6 +1184,10 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
|
|||||||
|
|
||||||
// Containers
|
// Containers
|
||||||
|
|
||||||
|
theme->set_icon("h_touch_dragger", "SplitContainer", icons["h_dragger"]);
|
||||||
|
theme->set_icon("v_touch_dragger", "SplitContainer", icons["v_dragger"]);
|
||||||
|
theme->set_icon("touch_dragger", "VSplitContainer", icons["v_dragger"]);
|
||||||
|
theme->set_icon("touch_dragger", "HSplitContainer", icons["h_dragger"]);
|
||||||
theme->set_icon("h_grabber", "SplitContainer", icons["hsplitter"]);
|
theme->set_icon("h_grabber", "SplitContainer", icons["hsplitter"]);
|
||||||
theme->set_icon("v_grabber", "SplitContainer", icons["vsplitter"]);
|
theme->set_icon("v_grabber", "SplitContainer", icons["vsplitter"]);
|
||||||
theme->set_icon("grabber", "VSplitContainer", icons["vsplitter"]);
|
theme->set_icon("grabber", "VSplitContainer", icons["vsplitter"]);
|
||||||
|
|||||||
1
scene/theme/icons/h_dragger.svg
Normal file
1
scene/theme/icons/h_dragger.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="30" height="60"><rect width="28" height="58" x="1" y="1" fill="#e0e0e0" fill-opacity=".6" stroke="#000" stroke-width=".8" rx="7"/></svg>
|
||||||
|
After Width: | Height: | Size: 184 B |
1
scene/theme/icons/v_dragger.svg
Normal file
1
scene/theme/icons/v_dragger.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="60" height="30"><rect width="58" height="28" x="1" y="1" fill="#e0e0e0" fill-opacity=".6" stroke="#000" stroke-width=".8" rx="7"/></svg>
|
||||||
|
After Width: | Height: | Size: 184 B |
Reference in New Issue
Block a user