added text widgets to dev-console tabs python api

This commit is contained in:
Eric 2023-10-02 19:12:41 -07:00
parent d85ac6a160
commit 9fcc313b0b
No known key found for this signature in database
GPG Key ID: 89C93F0F8D6D5A98
9 changed files with 321 additions and 124 deletions

40
.efrocachemap generated
View File

@ -4056,26 +4056,26 @@
"build/assets/windows/Win32/ucrtbased.dll": "2def5335207d41b21b9823f6805997f1", "build/assets/windows/Win32/ucrtbased.dll": "2def5335207d41b21b9823f6805997f1",
"build/assets/windows/Win32/vc_redist.x86.exe": "b08a55e2e77623fe657bea24f223a3ae", "build/assets/windows/Win32/vc_redist.x86.exe": "b08a55e2e77623fe657bea24f223a3ae",
"build/assets/windows/Win32/vcruntime140d.dll": "865b2af4d1e26a1a8073c89acb06e599", "build/assets/windows/Win32/vcruntime140d.dll": "865b2af4d1e26a1a8073c89acb06e599",
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "5979fc1374865abb96a8ff2e3f44c166", "build/prefab/full/linux_arm64_gui/debug/ballisticakit": "53125d7d6bd34fdfe78880773272237b",
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "b389b9d4d3cac1d18dc6c04d266d444e", "build/prefab/full/linux_arm64_gui/release/ballisticakit": "804a8aa64c159a3812a31be3df3584b1",
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "9446081855fe37326f970d0ab43e2e59", "build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "655d8bc1d591917d7bbec7ffed98a5a7",
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "1527bc05d69edeb8af30c6ab25b928f0", "build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "9830f4dac6f35121b19db8e2f332d87c",
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "c57b7f45564dd7cbb3f25c28266a5a3a", "build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "7a360065ea427f2d44f1db6d550becfb",
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "54911f2b25836bf38f8a33e306dcdee2", "build/prefab/full/linux_x86_64_gui/release/ballisticakit": "dd5b6769d2e95c93aae7126c8bdd3ffe",
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "9f887dfab9eb196ee8a9ff5d7f876139", "build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "791b43e652365874eb136b7ec147f9e8",
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "7f89a9b77feb1cde4ba611f4dd8bb444", "build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "8d3fe48c1a1b601aa97ce33e892f5163",
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "b52a34026a36769640de84ae94ac94d3", "build/prefab/full/mac_arm64_gui/debug/ballisticakit": "12d92655438f34e912e1525991df1f73",
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "3c90aa7a5828921da6fa2d1b0242c76a", "build/prefab/full/mac_arm64_gui/release/ballisticakit": "e39556a0047b65919b61c740e096e967",
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "f057fa1a420d0d23e6a5ccfa29a5cd2b", "build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "ae3a622c7fe0bddc6badba38402284fd",
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "24ca0d3ddbe3c45870de1167cd92459a", "build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "1e744c3641f603e22b55882f96fb0a86",
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "eddb8691d13480b147baf732428139ca", "build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "bcbb650a041317c7788a31525a7c2d02",
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "9b276bef34a259e05c23391fa3d372a6", "build/prefab/full/mac_x86_64_gui/release/ballisticakit": "a84d2e36cb685224749f556d5ba857a5",
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "789d66ae2c844d81f3d4929cc6caf950", "build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "beeecfee397c12e4c7193391973873f7",
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "9fe031c292167461bd8790f11c1b78c6", "build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "f186772de8396573ca7daa4f765ac63a",
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "461d3623b1d047a81000bf91f2b5095d", "build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "ada072c442da241991d2de9ad35abf79",
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "57fa8e653ccd0625fa6a95ba7cbcc089", "build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "52a2e2a3bd751f941069d4d007d7bc59",
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "7c9ef4e375fcfa593ea8ebdb2cb59f8e", "build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "82d428e93227eafc8c8ffcb6e24d1ec0",
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "d6e492d84f592d0547878c7de8b60e35", "build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "567cac9a0ba532234fedb35a9bdd51a3",
"build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "6ce4983e76e1cc2d2803fe306d08ad58", "build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "6ce4983e76e1cc2d2803fe306d08ad58",
"build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "4ea0cf78901f994215f215aebb0af1dc", "build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "4ea0cf78901f994215f215aebb0af1dc",
"build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "6ce4983e76e1cc2d2803fe306d08ad58", "build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "6ce4983e76e1cc2d2803fe306d08ad58",

View File

@ -1,4 +1,4 @@
### 1.7.28 (build 21406, api 8, 2023-10-02) ### 1.7.28 (build 21407, api 8, 2023-10-02)
- Massively cleaned up code related to rendering and window systems (OpenGL, - Massively cleaned up code related to rendering and window systems (OpenGL,
SDL, etc). This code had been growing into a nasty tangle for 15 years SDL, etc). This code had been growing into a nasty tangle for 15 years
@ -37,6 +37,9 @@
etc.) etc.)
- The in-app Python console text is now sized up on phone and tablet devices, - The in-app Python console text is now sized up on phone and tablet devices,
and is generally a bit larger everywhere. and is generally a bit larger everywhere.
- Added an API to define DevConsole tabs via Python. Currently it supports basic
buttons and text, but should be easy to expand to whatever we need. See
`babase/_devconsole.py`. It should be easy to define new tabs via plugins/etc.
- Cleaned up onscreen keyboard support and generalized it to make it possible to - Cleaned up onscreen keyboard support and generalized it to make it possible to
support other things besides widgets and to make it easier to implement on support other things besides widgets and to make it easier to implement on
other platforms. other platforms.

View File

@ -49,6 +49,21 @@ class DevConsoleTab:
style, style,
) )
def text(
self,
text: str,
pos: tuple[float, float],
h_anchor: Literal['left', 'center', 'right'] = 'center',
h_align: Literal['left', 'center', 'right'] = 'center',
v_align: Literal['top', 'center', 'bottom', 'none'] = 'center',
scale: float = 1.0,
) -> None:
"""Add a button to the tab being refreshed."""
assert _babase.app.devconsole.is_refreshing
_babase.dev_console_add_text(
text, pos[0], pos[1], h_anchor, h_align, v_align, scale
)
def python_terminal(self) -> None: def python_terminal(self) -> None:
"""Add a Python Terminal to the tab being refreshed.""" """Add a Python Terminal to the tab being refreshed."""
assert _babase.app.devconsole.is_refreshing assert _babase.app.devconsole.is_refreshing
@ -95,6 +110,7 @@ class DevConsoleTabTest(DevConsoleTab):
pos=(10, 10), pos=(10, 10),
size=(100, 30), size=(100, 30),
h_anchor='left', h_anchor='left',
label_scale=0.6,
call=self.request_refresh, call=self.request_refresh,
) )
self.button( self.button(
@ -102,8 +118,17 @@ class DevConsoleTabTest(DevConsoleTab):
pos=(120, 10), pos=(120, 10),
size=(100, 30), size=(100, 30),
h_anchor='left', h_anchor='left',
label_scale=0.6,
style='dark', style='dark',
) )
self.text(
'TestText',
scale=0.8,
pos=(15, 50),
h_anchor='left',
h_align='left',
v_align='none',
)
@dataclass @dataclass
@ -115,7 +140,15 @@ class DevConsoleTabEntry:
class DevConsoleSubsystem: class DevConsoleSubsystem:
"""Wrangles the dev console.""" """Subsystem for wrangling the dev console.
The single instance of this class can be found at
babase.app.devconsole. The dev-console is a simple always-available
UI intended for use by developers; not end users. Traditionally it
is available by typing a backtick (`) key on a keyboard, but now can
be accessed via an on-screen button (see settings/advanced to enable
said button).
"""
def __init__(self) -> None: def __init__(self) -> None:
# All tabs in the dev-console. Add your own stuff here via # All tabs in the dev-console. Add your own stuff here via

View File

@ -52,7 +52,7 @@ if TYPE_CHECKING:
# Build number and version of the ballistica binary we expect to be # Build number and version of the ballistica binary we expect to be
# using. # using.
TARGET_BALLISTICA_BUILD = 21406 TARGET_BALLISTICA_BUILD = 21407
TARGET_BALLISTICA_VERSION = '1.7.28' TARGET_BALLISTICA_VERSION = '1.7.28'

View File

@ -1501,6 +1501,48 @@ static PyMethodDef PyDevConsoleAddButtonDef = {
"(internal)", "(internal)",
}; };
// ------------------------- dev_console_add_text ------------------------------
static auto PyDevConsoleAddText(PyObject* self, PyObject* args) -> PyObject* {
BA_PYTHON_TRY;
BA_PRECONDITION(g_base->InLogicThread());
auto* dev_console = g_base->ui->dev_console();
BA_PRECONDITION(dev_console);
BA_PRECONDITION(dev_console->IsActive());
const char* text;
float x;
float y;
const char* h_anchor;
const char* h_align;
const char* v_align;
float scale;
if (!PyArg_ParseTuple(args, "sffsssf", &text, &x, &y, &h_anchor, &h_align,
&v_align, &scale)) {
return nullptr;
}
dev_console->AddText(text, x, y, h_anchor, h_align, v_align, scale);
Py_RETURN_NONE;
BA_PYTHON_CATCH;
}
static PyMethodDef PyDevConsoleAddTextDef = {
"dev_console_add_text", // name
(PyCFunction)PyDevConsoleAddText, // method
METH_VARARGS, // flags
"dev_console_add_text(\n"
" text: str,\n"
" x: float,\n"
" y: float,\n"
" h_anchor: str,\n"
" h_align: str,\n"
" v_align: str,\n"
" scale: float,\n"
") -> None\n"
"\n"
"(internal)",
};
// -------------------- dev_console_add_python_terminal ------------------------ // -------------------- dev_console_add_python_terminal ------------------------
static auto PyDevConsoleAddPythonTerminal(PyObject* self, PyObject* args) static auto PyDevConsoleAddPythonTerminal(PyObject* self, PyObject* args)
@ -1673,6 +1715,7 @@ auto PythonMethodsMisc::GetMethods() -> std::vector<PyMethodDef> {
PyOpenDirExternallyDef, PyOpenDirExternallyDef,
PyFatalErrorDef, PyFatalErrorDef,
PyDevConsoleAddButtonDef, PyDevConsoleAddButtonDef,
PyDevConsoleAddTextDef,
PyDevConsoleAddPythonTerminalDef, PyDevConsoleAddPythonTerminalDef,
PyDevConsoleTabWidthDef, PyDevConsoleTabWidthDef,
PyDevConsoleTabHeightDef, PyDevConsoleTabHeightDef,

View File

@ -31,44 +31,102 @@ const int kDevConsoleActivateKey1 = SDLK_BACKQUOTE;
const int kDevConsoleActivateKey2 = SDLK_F2; const int kDevConsoleActivateKey2 = SDLK_F2;
const float kDevConsoleTabButtonCornerRadius{16.0f}; const float kDevConsoleTabButtonCornerRadius{16.0f};
const double kTransitionSeconds = 0.1; const double kTransitionSeconds = 0.15;
enum class DevButtonAttach_ { kLeft, kCenter, kRight }; enum class DevConsoleHAnchor_ { kLeft, kCenter, kRight };
enum class DevButtonStyle_ { kNormal, kDark }; enum class DevButtonStyle_ { kNormal, kDark };
static auto XOffs(DevButtonAttach_ attach) -> float { static auto DevButtonStyleFromStr_(const char* strval) {
if (!strcmp(strval, "dark")) {
return DevButtonStyle_::kDark;
}
assert(!strcmp(strval, "normal"));
return DevButtonStyle_::kNormal;
}
static auto DevConsoleHAttachFromStr_(const char* strval) {
if (!strcmp(strval, "left")) {
return DevConsoleHAnchor_::kLeft;
} else if (!strcmp(strval, "right")) {
return DevConsoleHAnchor_::kRight;
}
assert(!strcmp(strval, "center"));
return DevConsoleHAnchor_::kCenter;
}
static auto TextMeshHAlignFromStr_(const char* strval) {
if (!strcmp(strval, "left")) {
return TextMesh::HAlign::kLeft;
} else if (!strcmp(strval, "right")) {
return TextMesh::HAlign::kRight;
}
assert(!strcmp(strval, "center"));
return TextMesh::HAlign::kCenter;
}
static auto TextMeshVAlignFromStr_(const char* strval) {
if (!strcmp(strval, "top")) {
return TextMesh::VAlign::kTop;
} else if (!strcmp(strval, "bottom")) {
return TextMesh::VAlign::kBottom;
} else if (!strcmp(strval, "none")) {
return TextMesh::VAlign::kNone;
}
assert(!strcmp(strval, "center"));
return TextMesh::VAlign::kCenter;
}
static auto XOffs(DevConsoleHAnchor_ attach) -> float {
switch (attach) { switch (attach) {
case DevButtonAttach_::kLeft: case DevConsoleHAnchor_::kLeft:
return 0.0f; return 0.0f;
case DevButtonAttach_::kRight: case DevConsoleHAnchor_::kRight:
return g_base->graphics->screen_virtual_width(); return g_base->graphics->screen_virtual_width();
case DevButtonAttach_::kCenter: case DevConsoleHAnchor_::kCenter:
return g_base->graphics->screen_virtual_width() * 0.5f; return g_base->graphics->screen_virtual_width() * 0.5f;
} }
assert(false); assert(false);
return 0.0f; return 0.0f;
} }
static void DrawBasicButton(RenderPass* pass, Mesh* mesh, TextGroup* tgrp, static void DrawRect(RenderPass* pass, Mesh* mesh, float bottom, float x,
float tscale, float bottom, float x, float y, float y, float width, float height,
float width, float height, const Vector3f& fgcolor, const Vector3f& bgcolor) {
const Vector3f& bgcolor) {
SimpleComponent c(pass); SimpleComponent c(pass);
c.SetTransparent(true); c.SetTransparent(true);
c.SetColor(bgcolor.x, bgcolor.y, bgcolor.z, 1.0f); c.SetColor(bgcolor.x, bgcolor.y, bgcolor.z, 1.0f);
c.SetTexture(g_base->assets->SysTexture(SysTextureID::kCircle)); c.SetTexture(g_base->assets->SysTexture(SysTextureID::kCircle));
{ // Draw mesh bg.
if (mesh) {
auto xf = c.ScopedTransform(); auto xf = c.ScopedTransform();
c.Translate(x, y + bottom, kDevConsoleZDepth); c.Translate(x, y + bottom, kDevConsoleZDepth);
c.DrawMesh(mesh); c.DrawMesh(mesh);
} }
// Draw our text. // Draw text.
// {
// auto xf = c.ScopedTransform();
// c.Translate(x + width * 0.5f, y + bottom + height * 0.5f,
// kDevConsoleZDepth);
// c.Scale(tscale, tscale, 1.0f);
// int elem_count = tgrp->GetElementCount();
// c.SetColor(fgcolor.x, fgcolor.y, fgcolor.z, 1.0f);
// c.SetFlatness(1.0f);
// for (int e = 0; e < elem_count; e++) {
// c.SetTexture(tgrp->GetElementTexture(e));
// c.DrawMesh(tgrp->GetElementMesh(e));
// }
// }
}
static void DrawText(RenderPass* pass, TextGroup* tgrp, float tscale,
float bottom, float x, float y, const Vector3f& fgcolor) {
SimpleComponent c(pass);
c.SetTransparent(true);
// Draw text.
{ {
auto xf = c.ScopedTransform(); auto xf = c.ScopedTransform();
c.Translate(x + width * 0.5f, y + bottom + height * 0.5f, c.Translate(x, y + bottom, kDevConsoleZDepth);
kDevConsoleZDepth); c.Scale(tscale, tscale, 1.0f);
float sc{0.6f * tscale};
c.Scale(sc, sc, 1.0f);
int elem_count = tgrp->GetElementCount(); int elem_count = tgrp->GetElementCount();
c.SetColor(fgcolor.x, fgcolor.y, fgcolor.z, 1.0f); c.SetColor(fgcolor.x, fgcolor.y, fgcolor.z, 1.0f);
c.SetFlatness(1.0f); c.SetFlatness(1.0f);
@ -84,14 +142,46 @@ static void DrawBasicButton(RenderPass* pass, Mesh* mesh, TextGroup* tgrp,
class DevConsole::Widget_ { class DevConsole::Widget_ {
public: public:
virtual ~Widget_() = default; virtual ~Widget_() = default;
virtual auto HandleMouseDown(float mx, float my) -> bool = 0; virtual auto HandleMouseDown(float mx, float my) -> bool { return false; }
virtual void HandleMouseUp(float mx, float my) = 0; virtual void HandleMouseUp(float mx, float my) {}
virtual void Draw(RenderPass* pass, float bottom) = 0; virtual void Draw(RenderPass* pass, float bottom) = 0;
}; };
class DevConsole::Text_ : public DevConsole::Widget_ {
public:
DevConsoleHAnchor_ h_attach;
TextMesh::HAlign h_align;
TextMesh::VAlign v_align;
float x;
float y;
float scale;
TextGroup text_group;
DevButtonStyle_ style;
Text_(const std::string& text, float x, float y, DevConsoleHAnchor_ h_attach,
TextMesh::HAlign h_align, TextMesh::VAlign v_align, float scale)
: h_attach{h_attach},
h_align(h_align),
v_align(v_align),
x{x},
y{y},
scale{scale} {
text_group.SetText(text, h_align, v_align);
}
void Draw(RenderPass* pass, float bottom) override {
Vector3f fgcolor;
Vector3f bgcolor;
fgcolor = Vector3f{0.8f, 0.7f, 0.8f};
bgcolor = Vector3f{0.25, 0.2f, 0.3f};
DrawText(pass, &text_group, scale, bottom, x + XOffs(h_attach), y, fgcolor);
}
};
class DevConsole::Button_ : public DevConsole::Widget_ { class DevConsole::Button_ : public DevConsole::Widget_ {
public: public:
DevButtonAttach_ attach; DevConsoleHAnchor_ attach;
float x; float x;
float y; float y;
float width; float width;
@ -104,7 +194,7 @@ class DevConsole::Button_ : public DevConsole::Widget_ {
DevButtonStyle_ style; DevButtonStyle_ style;
template <typename F> template <typename F>
Button_(const std::string& label, float text_scale, DevButtonAttach_ attach, Button_(const std::string& label, float text_scale, DevConsoleHAnchor_ attach,
float x, float y, float width, float height, float corner_radius, float x, float y, float width, float height, float corner_radius,
DevButtonStyle_ style, const F& lambda) DevButtonStyle_ style, const F& lambda)
: attach{attach}, : attach{attach},
@ -165,14 +255,15 @@ class DevConsole::Button_ : public DevConsole::Widget_ {
bgcolor = bgcolor =
pressed ? Vector3f{0.8f, 0.7f, 0.8f} : Vector3f{0.25, 0.2f, 0.3f}; pressed ? Vector3f{0.8f, 0.7f, 0.8f} : Vector3f{0.25, 0.2f, 0.3f};
} }
DrawBasicButton(pass, &mesh, &text_group, text_scale, bottom, DrawRect(pass, &mesh, bottom, x + XOffs(attach), y, width, height, bgcolor);
x + XOffs(attach), y, width, height, fgcolor, bgcolor); DrawText(pass, &text_group, text_scale, bottom,
x + XOffs(attach) + width * 0.5f, y + height * 0.5f, fgcolor);
} }
}; };
class DevConsole::ToggleButton_ : public DevConsole::Widget_ { class DevConsole::ToggleButton_ : public DevConsole::Widget_ {
public: public:
DevButtonAttach_ attach; DevConsoleHAnchor_ attach;
float x; float x;
float y; float y;
float width; float width;
@ -187,7 +278,7 @@ class DevConsole::ToggleButton_ : public DevConsole::Widget_ {
template <typename F, typename G> template <typename F, typename G>
ToggleButton_(const std::string& label, float text_scale, ToggleButton_(const std::string& label, float text_scale,
DevButtonAttach_ attach, float x, float y, float width, DevConsoleHAnchor_ attach, float x, float y, float width,
float height, float corner_radius, const F& on_call, float height, float corner_radius, const F& on_call,
const G& off_call) const G& off_call)
: attach{attach}, : attach{attach},
@ -234,20 +325,22 @@ class DevConsole::ToggleButton_ : public DevConsole::Widget_ {
} }
void Draw(RenderPass* pass, float bottom) override { void Draw(RenderPass* pass, float bottom) override {
DrawBasicButton(pass, &mesh, &text_group, text_scale, bottom, DrawRect(pass, &mesh, bottom, x + XOffs(attach), y, width, height,
x + XOffs(attach), y, width, height,
pressed ? Vector3f{1.0f, 1.0f, 1.0f} pressed ? Vector3f{0.5f, 0.2f, 1.0f}
: on ? Vector3f{1.0f, 1.0f, 1.0f} : on ? Vector3f{0.5f, 0.4f, 0.6f}
: Vector3f{0.8f, 0.7f, 0.8f}, : Vector3f{0.25, 0.2f, 0.3f});
pressed ? Vector3f{0.5f, 0.2f, 1.0f} DrawText(pass, &text_group, text_scale, bottom,
: on ? Vector3f{0.5f, 0.4f, 0.6f} x + XOffs(attach) + width * 0.5f, y + height * 0.5f,
: Vector3f{0.25, 0.2f, 0.3f}); pressed ? Vector3f{1.0f, 1.0f, 1.0f}
: on ? Vector3f{1.0f, 1.0f, 1.0f}
: Vector3f{0.8f, 0.7f, 0.8f});
} }
}; };
class DevConsole::TabButton_ : public DevConsole::Widget_ { class DevConsole::TabButton_ : public DevConsole::Widget_ {
public: public:
DevButtonAttach_ attach; DevConsoleHAnchor_ attach;
float x; float x;
float y; float y;
float width; float width;
@ -261,7 +354,7 @@ class DevConsole::TabButton_ : public DevConsole::Widget_ {
template <typename F> template <typename F>
TabButton_(const std::string& label, bool selected, float text_scale, TabButton_(const std::string& label, bool selected, float text_scale,
DevButtonAttach_ attach, float x, float y, float width, DevConsoleHAnchor_ attach, float x, float y, float width,
float height, const F& call) float height, const F& call)
: attach{attach}, : attach{attach},
x{x}, x{x},
@ -308,15 +401,15 @@ class DevConsole::TabButton_ : public DevConsole::Widget_ {
} }
void Draw(RenderPass* pass, float bottom) override { void Draw(RenderPass* pass, float bottom) override {
DrawBasicButton(pass, &mesh, &text_group, text_scale, bottom, DrawRect(pass, &mesh, bottom, x + XOffs(attach), y, width, height,
x + XOffs(attach), y, width, height, pressed ? Vector3f{0.4f, 0.2f, 0.8f}
pressed ? Vector3f{1.0f, 1.0f, 1.0f} : selected ? Vector3f{0.4f, 0.3f, 0.4f}
: selected ? Vector3f{1.0f, 1.0f, 1.0f} : Vector3f{0.25, 0.2f, 0.3f});
: Vector3f{0.6f, 0.5f, 0.6f}, DrawText(pass, &text_group, text_scale, bottom,
pressed ? Vector3f{0.4f, 0.2f, 0.8f} x + XOffs(attach) + width * 0.5f, y + height * 0.5f,
: selected ? Vector3f{0.4f, 0.3f, 0.4f} pressed ? Vector3f{1.0f, 1.0f, 1.0f}
// : selected ? Vector3f{0.5f, 0.4f, 0.6f} : selected ? Vector3f{1.0f, 1.0f, 1.0f}
: Vector3f{0.25, 0.2f, 0.3f}); : Vector3f{0.6f, 0.5f, 0.6f});
} }
}; };
@ -381,13 +474,13 @@ void DevConsole::RefreshTabButtons_() {
float bs = BaseScale(); float bs = BaseScale();
float bwidth = 90.0f * bs; float bwidth = 90.0f * bs;
float bheight = 26.0f * bs; float bheight = 26.0f * bs;
float bscale = 0.8f * bs; float bscale = 0.6f * bs;
float total_width = tabs_.size() * bwidth; float total_width = tabs_.size() * bwidth;
float x = total_width * -0.5f; float x = total_width * -0.5f;
for (auto&& tab : tabs_) { for (auto&& tab : tabs_) {
tab_buttons_.emplace_back(std::make_unique<TabButton_>( tab_buttons_.emplace_back(std::make_unique<TabButton_>(
tab, active_tab_ == tab, bscale, DevButtonAttach_::kCenter, x, -bheight, tab, active_tab_ == tab, bscale, DevConsoleHAnchor_::kCenter, x,
bwidth, bheight, [this, tab] { -bheight, bwidth, bheight, [this, tab] {
active_tab_ = tab; active_tab_ = tab;
RefreshTabButtons_(); RefreshTabButtons_();
RefreshTabContents_(); RefreshTabContents_();
@ -404,7 +497,7 @@ void DevConsole::RefreshTabContents_() {
refresh_pending_ = false; refresh_pending_ = false;
// Clear to an empty slate. // Clear to an empty slate.
buttons_.clear(); widgets_.clear();
python_terminal_visible_ = false; python_terminal_visible_ = false;
// Now ask the Python layer to fill this tab in. // Now ask the Python layer to fill this tab in.
@ -414,43 +507,39 @@ void DevConsole::RefreshTabContents_() {
.Call(args); .Call(args);
} }
void DevConsole::AddText(const char* text, float x, float y,
const char* h_anchor_str, const char* h_align_str,
const char* v_align_str, float scale) {
auto h_anchor = DevConsoleHAttachFromStr_(h_anchor_str);
auto h_align = TextMeshHAlignFromStr_(h_align_str);
auto v_align = TextMeshVAlignFromStr_(v_align_str);
widgets_.emplace_back(
std::make_unique<Text_>(text, x, y, h_anchor, h_align, v_align, scale));
}
void DevConsole::AddButton(const char* label, float x, float y, float width, void DevConsole::AddButton(const char* label, float x, float y, float width,
float height, PyObject* call, const char* h_anchor, float height, PyObject* call,
float label_scale, float corner_radius, const char* h_anchor_str, float label_scale,
const char* style) { float corner_radius, const char* style_str) {
assert(g_base->InLogicThread()); assert(g_base->InLogicThread());
DevButtonStyle_ style_val; auto style = DevButtonStyleFromStr_(style_str);
if (!strcmp(style, "dark")) { auto h_anchor = DevConsoleHAttachFromStr_(h_anchor_str);
style_val = DevButtonStyle_::kDark;
} else {
style_val = DevButtonStyle_::kNormal;
}
DevButtonAttach_ anchor; widgets_.emplace_back(std::make_unique<Button_>(
if (!strcmp(h_anchor, "left")) { label, label_scale, h_anchor, x, y, width, height, corner_radius, style,
anchor = DevButtonAttach_::kLeft; [this, callref = PythonRef::Acquired(call)] {
} else if (!strcmp(h_anchor, "right")) { if (callref.Get() != Py_None) {
anchor = DevButtonAttach_::kRight; callref.Call();
} else {
assert(!strcmp(h_anchor, "center"));
anchor = DevButtonAttach_::kCenter;
}
// auto call_obj = PythonRef::Acquired(call);
buttons_.emplace_back(std::make_unique<Button_>(
label, label_scale, anchor, x, y, width, height, corner_radius, style_val,
[this, call_obj = PythonRef::Acquired(call)] {
if (call_obj.Get() != Py_None) {
call_obj.Call();
} }
})); }));
} }
void DevConsole::AddPythonTerminal() { void DevConsole::AddPythonTerminal() {
float bs = BaseScale(); float bs = BaseScale();
buttons_.emplace_back(std::make_unique<Button_>( widgets_.emplace_back(std::make_unique<Button_>(
"Exec", 0.75f * bs, DevButtonAttach_::kRight, -33.0f * bs, 15.95f * bs, "Exec", 0.5f * bs, DevConsoleHAnchor_::kRight, -33.0f * bs, 15.95f * bs,
32.0f * bs, 13.0f * bs, 2.0 * bs, DevButtonStyle_::kNormal, 32.0f * bs, 13.0f * bs, 2.0 * bs, DevButtonStyle_::kNormal,
[this] { Exec(); })); [this] { Exec(); }));
python_terminal_visible_ = true; python_terminal_visible_ = true;
@ -483,7 +572,7 @@ auto DevConsole::HandleMouseDown(int button, float x, float y) -> bool {
return true; return true;
} }
} }
for (auto&& button : buttons_) { for (auto&& button : widgets_) {
if (button->HandleMouseDown(x, y - bottom)) { if (button->HandleMouseDown(x, y - bottom)) {
return true; return true;
} }
@ -517,7 +606,7 @@ void DevConsole::HandleMouseUp(int button, float x, float y) {
for (auto&& button : tab_buttons_) { for (auto&& button : tab_buttons_) {
button->HandleMouseUp(x, y - bottom); button->HandleMouseUp(x, y - bottom);
} }
for (auto&& button : buttons_) { for (auto&& button : widgets_) {
button->HandleMouseUp(x, y - bottom); button->HandleMouseUp(x, y - bottom);
} }
} }
@ -800,6 +889,10 @@ auto DevConsole::Bottom_() const -> float {
// more important for them to be able to be written to a known hard-coded // more important for them to be able to be written to a known hard-coded
// mini-size. // mini-size.
float mini_size = 100.0f; float mini_size = 100.0f;
// Now that we have tabs and drop-shadows hanging down, we have to
// overshoot the top of the screen when transitioning out.
float top_buffer = 100.0f;
if (state_ == State_::kMini) { if (state_ == State_::kMini) {
bottom = vh - mini_size; bottom = vh - mini_size;
} else { } else {
@ -812,7 +905,7 @@ auto DevConsole::Bottom_() const -> float {
} else if (state_prev_ == State_::kFull) { } else if (state_prev_ == State_::kFull) {
from_height = vh - vh * kDevConsoleSize; from_height = vh - vh * kDevConsoleSize;
} else { } else {
from_height = vh; from_height = vh + top_buffer;
} }
float to_height; float to_height;
if (state_ == State_::kMini) { if (state_ == State_::kMini) {
@ -820,7 +913,7 @@ auto DevConsole::Bottom_() const -> float {
} else if (state_ == State_::kFull) { } else if (state_ == State_::kFull) {
to_height = vh - vh * kDevConsoleSize; to_height = vh - vh * kDevConsoleSize;
} else { } else {
to_height = vh; to_height = vh + top_buffer;
} }
bottom = to_height * ratio + from_height * (1.0 - ratio); bottom = to_height * ratio + from_height * (1.0 - ratio);
} }
@ -852,19 +945,20 @@ void DevConsole::Draw(FrameDef* frame_def) {
border_mesh_.SetPositionAndSize(0, bottom - border_height * bs, border_mesh_.SetPositionAndSize(0, bottom - border_height * bs,
kDevConsoleZDepth, pass->virtual_width(), kDevConsoleZDepth, pass->virtual_width(),
border_height * bs); border_height * bs);
SimpleComponent c(pass); {
c.SetTransparent(true); SimpleComponent c(pass);
c.SetColor(0, 0, 0.1f, 0.9f); c.SetTransparent(true);
c.DrawMesh(&bg_mesh_); c.SetColor(0, 0, 0.1f, 0.9f);
c.Submit(); c.DrawMesh(&bg_mesh_);
if (python_terminal_visible_) {
c.SetColor(1.0f, 1.0f, 1.0f, 0.1f);
c.DrawMesh(&stripe_mesh_);
c.Submit(); c.Submit();
if (python_terminal_visible_) {
c.SetColor(1.0f, 1.0f, 1.0f, 0.1f);
c.DrawMesh(&stripe_mesh_);
c.Submit();
}
c.SetColor(0.25f, 0.2f, 0.3f, 1.0f);
c.DrawMesh(&border_mesh_);
} }
c.SetColor(0.25f, 0.2f, 0.3f, 1.0f);
c.DrawMesh(&border_mesh_);
c.Submit();
} }
// Drop shadow. // Drop shadow.
@ -936,7 +1030,6 @@ void DevConsole::Draw(FrameDef* frame_def) {
c.DrawMesh(input_text_group_.GetElementMesh(e)); c.DrawMesh(input_text_group_.GetElementMesh(e));
} }
} }
c.Submit();
} }
// Carat. // Carat.
@ -956,17 +1049,16 @@ void DevConsole::Draw(FrameDef* frame_def) {
c.Scale(6.0f * bs, 12.0f * bs, 1.0f); c.Scale(6.0f * bs, 12.0f * bs, 1.0f);
c.DrawMeshAsset(g_base->assets->SysMesh(SysMeshID::kImage1x1)); c.DrawMeshAsset(g_base->assets->SysMesh(SysMeshID::kImage1x1));
} }
c.Submit();
} }
// Draw output lines. // Output lines.
{ {
float draw_scale = 0.6f;
float v_inc = 18.0f;
SimpleComponent c(pass); SimpleComponent c(pass);
c.SetTransparent(true); c.SetTransparent(true);
c.SetColor(1, 1, 1, 1); c.SetColor(1, 1, 1, 1);
c.SetFlatness(1.0f); c.SetFlatness(1.0f);
float draw_scale = 0.6f;
float v_inc = 18.0f;
float h = 0.5f float h = 0.5f
* (g_base->graphics->screen_virtual_width() * (g_base->graphics->screen_virtual_width()
- (kDevConsoleStringBreakUpSize * draw_scale)); - (kDevConsoleStringBreakUpSize * draw_scale));
@ -1007,7 +1099,6 @@ void DevConsole::Draw(FrameDef* frame_def) {
break; break;
} }
} }
c.Submit();
} }
} }
@ -1020,7 +1111,7 @@ void DevConsole::Draw(FrameDef* frame_def) {
// Buttons. // Buttons.
{ {
for (auto&& button : buttons_) { for (auto&& button : widgets_) {
button->Draw(pass, bottom); button->Draw(pass, bottom);
} }
} }
@ -1040,4 +1131,21 @@ auto DevConsole::BaseScale() const -> float {
return 1.0f; return 1.0f;
} }
void DevConsole::StepDisplayTime() {
assert(g_base->InLogicThread());
// If we're inactive, blow away all our stuff once we transition fully
// off screen. This will kill any Python stuff attached to our widgets
// so things can clean themselves up.
if (state_ == State_::kInactive && !tab_buttons_.empty()) {
if ((g_base->logic->display_time() - transition_start_)
>= kTransitionSeconds) {
// Reset to a blank slate but *don't refresh anything (that will
// happen once we get vis'ed again).
tab_buttons_.clear();
widgets_.clear();
python_terminal_visible_ = false;
}
}
}
} // namespace ballistica::base } // namespace ballistica::base

View File

@ -37,6 +37,8 @@ class DevConsole {
void Print(const std::string& s_in); void Print(const std::string& s_in);
void Draw(FrameDef* frame_def); void Draw(FrameDef* frame_def);
void StepDisplayTime();
/// Called when the console should start accepting Python command input. /// Called when the console should start accepting Python command input.
void EnableInput(); void EnableInput();
@ -53,8 +55,10 @@ class DevConsole {
void Exec(); void Exec();
void AddButton(const char* label, float x, float y, float width, float height, void AddButton(const char* label, float x, float y, float width, float height,
PyObject* call, const char* h_anchor, float label_scale, PyObject* call, const char* h_anchor_str, float label_scale,
float corner_radius, const char* style); float corner_radius, const char* style_str);
void AddText(const char* text, float x, float y, const char* h_anchor_str,
const char* h_align_str, const char* v_align_str, float scale);
void AddPythonTerminal(); void AddPythonTerminal();
auto Width() -> float; auto Width() -> float;
@ -65,6 +69,7 @@ class DevConsole {
private: private:
class Widget_; class Widget_;
class Button_; class Button_;
class Text_;
class ToggleButton_; class ToggleButton_;
class TabButton_; class TabButton_;
class OutputLine_; class OutputLine_;
@ -103,7 +108,7 @@ class DevConsole {
Object::Ref<TextGroup> last_line_mesh_group_; Object::Ref<TextGroup> last_line_mesh_group_;
std::list<std::string> input_history_; std::list<std::string> input_history_;
std::list<OutputLine_> output_lines_; std::list<OutputLine_> output_lines_;
std::vector<std::unique_ptr<Widget_> > buttons_; std::vector<std::unique_ptr<Widget_> > widgets_;
std::vector<std::unique_ptr<Widget_> > tab_buttons_; std::vector<std::unique_ptr<Widget_> > tab_buttons_;
}; };

View File

@ -49,7 +49,12 @@ UI::UI() {
} }
} }
void UI::StepDisplayTime() { assert(g_base->InLogicThread()); } void UI::StepDisplayTime() {
assert(g_base->InLogicThread());
if (dev_console_) {
dev_console_->StepDisplayTime();
}
}
void UI::OnAppStart() { void UI::OnAppStart() {
assert(g_base->InLogicThread()); assert(g_base->InLogicThread());

View File

@ -39,7 +39,7 @@ auto main(int argc, char** argv) -> int {
namespace ballistica { namespace ballistica {
// These are set automatically via script; don't modify them here. // These are set automatically via script; don't modify them here.
const int kEngineBuildNumber = 21406; const int kEngineBuildNumber = 21407;
const char* kEngineVersion = "1.7.28"; const char* kEngineVersion = "1.7.28";
const int kEngineApiVersion = 8; const int kEngineApiVersion = 8;