Implement Path render API into drawlist
Add some new drawing functions (need to make Rectangle -> RectFilled
Add Menu Border
ReSetup the Menu Input and Rendering API to fix flickering when moving
This commit is contained in:
tobid7 2025-03-21 16:23:17 +01:00
parent 6738fda55c
commit dbffb7f316
11 changed files with 320 additions and 75 deletions

View File

@ -52,7 +52,7 @@ execute_process(
)
# Set Project
project(palladium LANGUAGES C CXX VERSION 0.3.1)
project(palladium LANGUAGES C CXX VERSION 0.3.2)
option(PD_BUILD_TESTS "Sets if TestApp and TestBench get build" OFF)

View File

@ -25,6 +25,7 @@ SOFTWARE.
#include <pd/core/common.hpp>
#include <pd/lithium/renderer.hpp>
#include <pd/ui7/flags.hpp>
#include <pd/ui7/theme.hpp>
namespace PD {
@ -39,6 +40,15 @@ class DrawList : public SmartCtor<DrawList> {
DrawList(LI::Renderer::Ref r) { ren = r; }
~DrawList() = default;
/**
* Draw a Rectangle (LINED)
* @param pos position of the rect
* @param size Size of the rect
* @param clr Color of the rect
* @param thickness Thickness of the lines
*/
void AddRect(const vec2& pos, const vec2& size, const UI7Color& clr,
int thickness = 1);
/**
* Render a Rectangle
* @param pos Position
@ -48,12 +58,43 @@ class DrawList : public SmartCtor<DrawList> {
void AddRectangle(vec2 pos, vec2 szs, const UI7Color& clr);
/**
* Render a Triangle
* @param pos0 Position a
* @param pos1 Position b
* @param pos2 Position c
* @param a Position a
* @param b Position b
* @param c Position c
* @param clr Color
* @param thickness Thickness of the lines
*/
void AddTriangle(const vec2& a, const vec2& b, const vec2& c,
const UI7Color& clr, int thickness = 1);
/**
* Render a Filled Triangle
* @param a Position a
* @param b Position b
* @param c Position c
* @param clr Color
*/
void AddTriangle(vec2 pos0, vec2 pos1, vec2 pos2, const UI7Color& clr);
void AddTriangleFilled(const vec2& a, const vec2& b, const vec2& c,
const UI7Color& clr);
/**
* Add a Lined Circle
* @param pos Center position
* @param rad radius of the circle
* @param col Color of the Circle
* @param num_segments Number of Segments (0 = auto)
* @param thickness thickness of the line
*/
void AddCircle(const vec2& pos, float rad, UI7Color col, int num_segments = 0,
int thickness = 1);
/**
* Add a Circle
* @param pos Center position
* @param rad radius of the circle
* @param col Color of the Circle
* @param num_segments Number of Segments (0 = auto)
*/
void AddCircleFilled(const vec2& pos, float rad, UI7Color col,
int num_segments = 0);
/**
* Render a Text
* @param pos Position
@ -82,6 +123,24 @@ class DrawList : public SmartCtor<DrawList> {
*/
void AddLine(const vec2& a, const vec2& b, const UI7Color& clr, int t = 1);
/**
* Take list of points and display it as a line on screen
* @param points List of Positions
* @param clr Color of the Line
* @param flags Additional Flags (Close for go back to starting point)
* @param thickness Thickness of the Line
*/
void AddPolyLine(const std::vector<vec2>& points, const UI7Color& clr,
UI7DrawFlags flags = 0, int thickness = 1);
/**
* Take a List ofpoints and display it as Filled Shape
* @note Keep in mind to setup the list of points clockwise
* @param points List of Points
* @param clr Color of the shape
*/
void AddConvexPolyFilled(const std::vector<vec2>& points,
const UI7Color& clr);
/** Clear the Drawlist */
void Clear();
/** Process [Render] the Drawlist */
@ -98,6 +157,61 @@ class DrawList : public SmartCtor<DrawList> {
/** Setter fot the Layer */
void Layer(int v) { layer = v; }
/** Path API */
/**
* Function to reserve Memory to prevent overhead on
* pusing a lot of points with PathNext
* @param num_points Number of Positions you want to add
*/
void PathReserve(size_t num_points) {
Path.reserve(Path.size() + num_points);
}
/**
* Clear current Path
* @note PathStroke and PathFill will automatically clear
*/
void PathClear() { Path.clear(); }
/**
* Add a Point to the Path
* @note Keep in mind that this function is used for
* setting the starting point
* @param v Position to add
*/
void PathNext(const vec2& v) { Path.push_back(v); }
/**
* Path Stroke Create Line from point to point
* @note For Primitives like Rect or Triangle mak sure to use
* UI7DrawFlags_Close to add a line back to the starting point
* @param clr Color od the line
* @param thickness Thickness of the line
* @param flags Additional Drawflags
*/
void PathStroke(const UI7Color& clr, int thickness = 1,
UI7DrawFlags flags = 0) {
AddPolyLine(Path, clr, flags, thickness);
Path.clear();
}
/**
* Fill a Path with a Color
* @note **IMPORTANT: ** Paths need to be setup clockwise
* to be rendered correctly
* @param clr Fill Color
*/
void PathFill(const UI7Color& clr) {
AddConvexPolyFilled(Path, clr);
Path.clear();
}
void PathArcToN(const vec2& c, float radius, float a_min, float a_max,
int segments);
/// @brief Create a Path Rect (uses to Positions instead of Pos/Size)
/// @param a Top Left Position
/// @param b Bottom Right Position
/// @param rounding rounding
/// @param flags DrawFlags (for special rounding rules)
void PathRect(vec2 a, vec2 b, float rounding = 0.f, UI7DrawFlags flags = 0);
private:
/** Base Layer offset (Internal Used) */
int BaseLayer() const { return base; }
@ -114,6 +228,7 @@ class DrawList : public SmartCtor<DrawList> {
std::stack<vec4> clip_rects; ///< Stack containing Scissor Areas
u32 num_vertices; ///< Number of Vertices
u32 num_indices; ///< Number of Indices
std::vector<vec2> Path;
// Map for Auto Static Text
std::unordered_map<u32, LI::StaticText::Ref> static_text;
// List of Drawcommands generated

View File

@ -31,6 +31,8 @@ using UI7Align = unsigned int;
using UI7IOFlags = unsigned int;
/** 32Bit Value for Layout Flags */
using UI7LayoutFlags = unsigned int;
/** 32Bit value for DrawFlags */
using UI7DrawFlags = unsigned int;
/** Menu Flags */
enum UI7MenuFlags_ {
@ -56,6 +58,12 @@ enum UI7LayoutFlags_ {
UI7LayoutFlags_UseClipRect = 1 << 0, ///< Enable ClipRect
};
enum UI7DrawFlags_ {
UI7DrawFlags_None = 0,
UI7DrawFlags_Close = 1 << 0, ///< Close a PolyLine
UI7DrawFlags_AALines = 1 << 1, ///< Anti aliased Lines
};
/** UI7 Context Flags */
enum UI7IOFlags_ {
UI7IOFlags_None = 0, ///< No Additional Config available

View File

@ -71,6 +71,8 @@ class IO : public SmartCtor<IO> {
vec2 FramePadding = 5.f;
vec2 ItemSpace = vec2(5.f, 2.f);
vec2 MinSliderDragSize = 10.f; // Min height (Vt) and Min Width (Hz)
bool ShowMenuBorder = true;
bool ShowFrameBorder = false; // not implemented yet
float OverScrollMod = 0.15f;
u64 DoubleClickTime = 500; // Milliseconds
std::vector<std::pair<UI7::ID, DrawList::Ref>> DrawListRegestry;

View File

@ -290,6 +290,9 @@ class Menu : public SmartCtor<Menu> {
// Layout API
PD::UI7::Layout::Ref Layout;
UI7Color clr_close_btn = UI7Color_FrameBackground;
UI7Color clr_collapse_tri = UI7Color_FrameBackground;
};
} // namespace UI7
} // namespace PD

View File

@ -34,6 +34,7 @@ using UI7Color = PD::u32;
/** Theme Color */
enum UI7Color_ {
UI7Color_Background, ///< UI7 Menu Background
UI7Color_Border, ///< Menu/Frame Border Color
UI7Color_Button, ///< UI7 Button Idle Color
UI7Color_ButtonDead, ///< UI7 Disabled Button Color
UI7Color_ButtonActive, ///< UI7 Pressed Button Color

View File

@ -37,7 +37,7 @@ SOFTWARE.
* Major Minor Patch Build
* 0x01010000 -> 1.1.0-0
*/
#define UI7_VERSION 0x00030101
#define UI7_VERSION 0x00030200
namespace PD {
namespace UI7 {

View File

@ -26,40 +26,88 @@ SOFTWARE.
namespace PD {
namespace UI7 {
void DrawList::PathArcToN(const vec2& c, float radius, float a_min, float a_max,
int segments) {
// Path.push_back(c);
PathReserve(segments + 1);
for (int i = 0; i < segments; i++) {
float a = a_min + ((float)i / (float)segments) * (a_max - a_min);
PathNext(vec2(c.x() + std::cos(a) * radius, c.y() + std::sin(a) * radius));
}
}
void DrawList::PathRect(vec2 a, vec2 b, float rounding, UI7DrawFlags flags) {
if (rounding == 0.f) {
PathNext(a);
PathNext(vec2(b.x(), a.y()));
PathNext(b);
PathNext(vec2(a.x(), b.y()));
} else {
PathArcToN(vec2(a.x() + rounding, a.y() + rounding), rounding, 4*6, 4*9, 21);
PathArcToN(vec2(b.x() - rounding, a.y() + rounding), rounding, 4*9, 4*12, 21);
PathArcToN(vec2(b.x() - rounding, b.y() - rounding), rounding, 4*0, 4*3, 21);
PathArcToN(vec2(a.x() + rounding, b.y() - rounding), rounding, 4*3, 4*6, 21);
}
}
void DrawList::AddRect(const vec2& pos, const vec2& size, const UI7Color& clr,
int thickness) {
if (!ren->InBox(pos, size, ren->GetViewport())) {
return;
}
ren->UseTex();
PathRect(pos, pos + size);
PathStroke(clr, thickness, UI7DrawFlags_Close);
}
void DrawList::AddRectangle(vec2 pos, vec2 szs, const UI7Color& clr) {
if (!ren->InBox(pos, szs, ren->GetViewport())) {
return;
}
auto rect = ren->CreateRect(pos, szs, 0.f);
auto cmd = LI::Command::New();
ren->UseTex();
ren->SetupCommand(cmd);
cmd->Layer(layer);
if (!clip_rects.empty()) {
cmd->SetScissorMode(LI::ScissorMode_Normal);
cmd->ScissorRect(clip_rects.top());
}
ren->QuadCommand(cmd, rect, vec4(0.f, 1.f, 1.f, 0.f), clr);
commands.push_back(std::make_pair(
ren->CurrentScreen()->ScreenType() == Screen::Bottom, cmd));
PathRect(pos, pos + szs);
PathFill(clr);
}
void DrawList::AddTriangle(vec2 pos0, vec2 pos1, vec2 pos2,
const UI7Color& clr) {
if (!ren->InBox(pos0, pos1, pos2, ren->GetViewport())) {
return;
}
auto cmd = LI::Command::New();
void DrawList::AddTriangle(const vec2& a, const vec2& b, const vec2& c,
const UI7Color& clr, int thickness) {
ren->UseTex();
ren->SetupCommand(cmd);
cmd->Layer(layer);
if (!clip_rects.empty()) {
cmd->SetScissorMode(LI::ScissorMode_Normal);
cmd->ScissorRect(clip_rects.top());
PathNext(a);
PathNext(b);
PathNext(c);
PathStroke(clr, thickness, UI7DrawFlags_Close);
}
void DrawList::AddTriangleFilled(const vec2& a, const vec2& b, const vec2& c,
const UI7Color& clr) {
ren->UseTex();
PathNext(a);
PathNext(b);
PathNext(c);
PathFill(clr);
}
void DrawList::AddCircle(const vec2& pos, float rad, UI7Color col,
int num_segments, int thickness) {
if (num_segments <= 0) {
// Auto Segment
} else {
float am = (M_PI * 2.0f) * ((float)num_segments) / (float)num_segments;
PathArcToN(pos, rad, 0.f, am, num_segments);
}
ren->TriangleCommand(cmd, pos0, pos1, pos2, clr);
commands.push_back(std::make_pair(
ren->CurrentScreen()->ScreenType() == Screen::Bottom, cmd));
ren->UseTex();
PathStroke(col, thickness, UI7DrawFlags_Close);
}
void DrawList::AddCircleFilled(const vec2& pos, float rad, UI7Color col,
int num_segments) {
if (num_segments <= 0) {
// Auto Segment
} else {
float am = (M_PI * 2.0f) * ((float)num_segments) / (float)num_segments;
PathArcToN(pos, rad, 0.f, am, num_segments);
}
ren->UseTex();
PathFill(col);
}
void DrawList::AddText(vec2 pos, const std::string& text, const UI7Color& clr,
@ -123,16 +171,62 @@ void DrawList::AddLine(const vec2& a, const vec2& b, const UI7Color& clr,
!ren->InBox(b, ren->GetViewport())) {
return;
}
auto line = ren->CreateLine(a, b, t);
auto cmd = LI::Command::New();
ren->UseTex();
PathNext(a);
PathNext(b);
PathStroke(clr, t);
}
// TODO: Don't render OOS
void DrawList::AddPolyLine(const std::vector<vec2>& points, const UI7Color& clr,
UI7DrawFlags flags, int thickness) {
if (points.size() < 2) {
return;
}
auto cmd = LI::Command::New();
ren->SetupCommand(cmd);
cmd->Layer(layer);
if (!clip_rects.empty()) {
cmd->SetScissorMode(LI::ScissorMode_Normal);
cmd->ScissorRect(clip_rects.top());
}
ren->QuadCommand(cmd, line, vec4(0.f, 1.f, 1.f, 0.f), clr);
bool close = (flags & UI7DrawFlags_Close);
int num_points = close ? (int)points.size() : (int)points.size() - 1;
if (flags & UI7DrawFlags_AALines) {
// TODO: Find a way to draw less garbage looking lines
} else {
// Non antialiased lines look awful when rendering with thickness != 1
for (int i = 0; i < num_points; i++) {
int j = (i + 1) == (int)points.size() ? 0 : (i + 1);
auto line = ren->CreateLine(points[i], points[j], thickness);
ren->QuadCommand(cmd, line, vec4(0.f, 1.f, 1.f, 0.f), clr);
}
}
commands.push_back(std::make_pair(
ren->CurrentScreen()->ScreenType() == Screen::Bottom, cmd));
}
// TODO: Don't render OOS (Probably make it with a define as it
// would probably be faster to render out of screen than checking if
// it could be skipped)
void DrawList::AddConvexPolyFilled(const std::vector<vec2>& points,
const UI7Color& clr) {
if (points.size() < 3) {
return; // Need at least three points
}
auto cmd = LI::Command::New();
ren->SetupCommand(cmd);
cmd->Layer(layer);
if (!clip_rects.empty()) {
cmd->SetScissorMode(LI::ScissorMode_Normal);
cmd->ScissorRect(clip_rects.top());
}
for (int i = 2; i < (int)points.size(); i++) {
cmd->PushIndex(0).PushIndex(i).PushIndex(i - 1);
}
for (int i = 0; i < (int)points.size(); i++) {
cmd->PushVertex(LI::Vertex(points[i], vec2(0, 0), clr));
}
commands.push_back(std::make_pair(
ren->CurrentScreen()->ScreenType() == Screen::Bottom, cmd));
}

View File

@ -166,14 +166,12 @@ void UI7::Menu::PreHandler(UI7MenuFlags flags) {
this->flags = flags;
Layout->Scrolling[1] = flags & UI7MenuFlags_VtScrolling;
has_touch = io->Ren->CurrentScreen()->ScreenType() == Screen::Bottom;
if (!(flags & UI7MenuFlags_NoBackground) && is_open) {
list->Layer(0);
list->AddRectangle(Layout->Pos + vec2(0, tbh), Layout->Size - vec2(0, tbh),
io->Theme->Get(UI7Color_Background));
}
if (!(flags & UI7MenuFlags_NoTitlebar)) {
// Title bar setup and Rendering
tbh = io->Ren->TextScale() * 30.f;
CollapseHandler();
CloseButtonHandler();
MoveHandler();
list->Layer(20);
list->AddRectangle(Layout->Pos, vec2(Layout->Size.x(), tbh),
io->Theme->Get(header));
@ -201,11 +199,48 @@ void UI7::Menu::PreHandler(UI7MenuFlags flags) {
if (!(flags & UI7MenuFlags_NoClipRect)) {
Layout->DrawList->PopClipRect();
}
/// Close Button Rendering
if (!(flags & UI7MenuFlags_NoClose) && is_shown) {
vec2 cpos =
vec2(Layout->Pos.x() + Layout->Size.x() - 12 - io->FramePadding.x(),
Layout->Pos.y() + io->FramePadding.y());
Layout->GetDrawList()->AddLine(cpos, cpos + 12,
io->Theme->Get(clr_close_btn), 2);
Layout->GetDrawList()->AddLine(cpos + vec2(0, 12), cpos + vec2(12, 0),
io->Theme->Get(clr_close_btn), 2);
}
/// Collapse Triangle Rendering
if (!(flags & UI7MenuFlags_NoCollapse)) {
vec2 cpos = Layout->Pos + io->FramePadding;
vec2 positions[2] = {
vec2(12, 6),
vec2(0, 12),
};
if (is_open) {
float t = positions[0].y();
positions[0].y() = positions[1].x();
positions[1].x() = t;
}
Layout->GetDrawList()->AddTriangleFilled(
cpos, cpos + positions[0], cpos + positions[1],
io->Theme->Get(clr_collapse_tri));
}
Layout->WorkRect[1] = io->MenuPadding[1] + tbh;
Layout->CursorInit();
CollapseHandler();
CloseButtonHandler();
MoveHandler();
}
if (!(flags & UI7MenuFlags_NoBackground) && is_open) {
list->Layer(0);
list->AddRectangle(Layout->Pos + vec2(0, tbh), Layout->Size - vec2(0, tbh),
io->Theme->Get(UI7Color_Background));
}
if (io->ShowMenuBorder) {
vec2 bsize = Layout->Size;
if (!is_open) {
bsize[1] = tbh;
}
list->Layer(20);
list->AddRect(Layout->Pos, bsize, io->Theme->Get(UI7Color_Border));
}
// Add a clip Rect for Separators
if (!(flags & UI7MenuFlags_NoClipRect)) {
@ -221,6 +256,10 @@ void UI7::Menu::PreHandler(UI7MenuFlags flags) {
void UI7::Menu::PostHandler() {
TT::Scope st("MPOS_" + name);
TT::End("MUSR_" + name);
// Remove the Clip Rect
if (!(flags & UI7MenuFlags_NoClipRect)) {
Layout->DrawList->PopClipRect();
}
ResizeHandler();
if (Layout->Scrolling[1]) {
scroll_allowed[1] =
@ -317,10 +356,6 @@ void UI7::Menu::PostHandler() {
vec2(slider_w, vslider_h), io->Theme->Get(sldr_drag));
}
}
// Remove the Clip Rect
if (!(flags & UI7MenuFlags_NoClipRect)) {
Layout->DrawList->PopClipRect();
}
}
void UI7::Menu::Separator() {
@ -445,8 +480,9 @@ bool UI7::Menu::BeginTreeNode(const UI7::ID& id) {
positions[0].y() = positions[1].x();
positions[1].x() = t;
}
Layout->GetDrawList()->AddTriangle(ts, ts + positions[0], ts + positions[1],
io->Theme->Get(UI7Color_FrameBackground));
Layout->GetDrawList()->AddTriangleFilled(
ts, ts + positions[0], ts + positions[1],
io->Theme->Get(UI7Color_FrameBackground));
Layout->GetDrawList()->AddText(
Layout->Pos + pos + vec2(10 + io->ItemSpace[0], 0), id.GetName(),
io->Theme->Get(UI7Color_Text));
@ -478,17 +514,14 @@ void UI7::Menu::CloseButtonHandler() {
vec2(Layout->Pos.x() + Layout->Size.x() - 12 - io->FramePadding.x(),
Layout->Pos.y() + io->FramePadding.y());
UI7Color clr = UI7Color_FrameBackground;
clr_close_btn = UI7Color_FrameBackground;
if (has_touch &&
io->DragObject(UI7::ID(name + "clse"), vec4(cpos, vec2(12)))) {
if (io->DragReleased) {
*is_shown = !(*is_shown);
}
clr = UI7Color_FrameBackgroundHovered;
clr_close_btn = UI7Color_FrameBackgroundHovered;
}
Layout->GetDrawList()->AddLine(cpos, cpos + 12, io->Theme->Get(clr), 2);
Layout->GetDrawList()->AddLine(cpos + vec2(0, 12), cpos + vec2(12, 0),
io->Theme->Get(clr), 2);
}
}
@ -502,16 +535,11 @@ void UI7::Menu::ResizeHandler() {
if (szs.y() < 30) szs[1] = 30;
Layout->Size = szs;
}
Layout->DrawList->AddTriangle(Layout->Pos + Layout->Size,
Layout->Pos + Layout->Size - vec2(0, 10),
Layout->Pos + Layout->Size - vec2(10, 0),
Layout->DrawList->Layer(21);
Layout->DrawList->AddTriangleFilled(Layout->Pos + Layout->Size,
Layout->Pos + Layout->Size - vec2(0, 15),
Layout->Pos + Layout->Size - vec2(15, 0),
io->Theme->Get(UI7Color_FrameBackground));
// front->AddRectangle(Layout->Pos + Layout->Size - 20, 20,
// 0xffffffff); Not vidible dor some reason
// int l = front->Layer();
// front->Layer(l + 1);
// front->AddTriangle(10, vec2(10, 0), vec2(10, 0), 0xffffffff);
// front->Layer(l);
}
}
@ -533,25 +561,14 @@ void UI7::Menu::CollapseHandler() {
// Collapse logic
if (!(flags & UI7MenuFlags_NoCollapse)) {
vec2 cpos = Layout->Pos + io->FramePadding;
UI7Color clr = UI7Color_FrameBackground;
clr_collapse_tri = UI7Color_FrameBackground;
if (has_touch &&
io->DragObject(UI7::ID(name + "clbse"), vec4(cpos, vec2(18, tbh)))) {
if (io->DragReleased) {
is_open = !is_open;
}
clr = UI7Color_FrameBackgroundHovered;
clr_collapse_tri = UI7Color_FrameBackgroundHovered;
}
vec2 positions[2] = {
vec2(12, 6),
vec2(0, 12),
};
if (is_open) {
float t = positions[0].y();
positions[0].y() = positions[1].x();
positions[1].x() = t;
}
Layout->GetDrawList()->AddTriangle(
cpos, cpos + positions[0], cpos + positions[1], io->Theme->Get(clr));
}
}

View File

@ -30,6 +30,7 @@ void Theme::Default(Theme& theme) {
theme.Set(UI7Color_Text, Color("#FFFFFFFF"));
theme.Set(UI7Color_TextDead, Color("#AAAAAAFF"));
theme.Set(UI7Color_Background, Color("#222222ff"));
theme.Set(UI7Color_Border, Color("#999999ff"));
theme.Set(UI7Color_Button, Color("#111111FF"));
theme.Set(UI7Color_ButtonDead, Color("#080808FF"));
theme.Set(UI7Color_ButtonActive, Color("#2A2A2AFF"));
@ -49,6 +50,7 @@ void Theme::Flashbang(Theme& theme) {
theme.Set(UI7Color_Text, Color("#000000FF"));
theme.Set(UI7Color_TextDead, Color("#333333FF"));
theme.Set(UI7Color_Background, Color("#eeeeeeFF"));
theme.Set(UI7Color_Border, Color("#777777ff"));
theme.Set(UI7Color_Button, Color("#ccccccFF"));
theme.Set(UI7Color_ButtonDead, Color("#bbbbbbFF"));
theme.Set(UI7Color_ButtonActive, Color("#ccccccFF"));

View File

@ -262,6 +262,8 @@ void UI7::Context::StyleEditor(bool* show) {
m->DragData("MinSliderSize", (float*)&io->MinSliderDragSize, 2, 1.f, 100.f);
m->DragData("OverScroll Modifier", &io->OverScrollMod, 1, 0.01f,
std::numeric_limits<float>::max(), 0.01f, 2);
m->Checkbox("Menu Border", io->ShowMenuBorder);
m->Checkbox("Frame Border", io->ShowFrameBorder);
m->SeparatorText("Theme");
if (m->Button("Dark")) {
UI7::Theme::Default(*io->Theme.get());
@ -276,6 +278,7 @@ void UI7::Context::StyleEditor(bool* show) {
m->DragData(std::string(#x).substr(9), (u8*)&io->Theme->GetRef(x), 4, (u8)0, \
(u8)255);
ts2(UI7Color_Background);
ts2(UI7Color_Border);
ts2(UI7Color_Button);
ts2(UI7Color_ButtonDead);
ts2(UI7Color_ButtonActive);