From 9fcc313b0b1d197aa46171273a77087379bce5d6 Mon Sep 17 00:00:00 2001 From: Eric Date: Mon, 2 Oct 2023 19:12:41 -0700 Subject: [PATCH] added text widgets to dev-console tabs python api --- .efrocachemap | 40 +-- CHANGELOG.md | 5 +- .../ba_data/python/babase/_devconsole.py | 35 +- src/assets/ba_data/python/baenv.py | 2 +- .../python/methods/python_methods_misc.cc | 43 +++ src/ballistica/base/ui/dev_console.cc | 300 ++++++++++++------ src/ballistica/base/ui/dev_console.h | 11 +- src/ballistica/base/ui/ui.cc | 7 +- src/ballistica/shared/ballistica.cc | 2 +- 9 files changed, 321 insertions(+), 124 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 77adb16b..5c396610 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4056,26 +4056,26 @@ "build/assets/windows/Win32/ucrtbased.dll": "2def5335207d41b21b9823f6805997f1", "build/assets/windows/Win32/vc_redist.x86.exe": "b08a55e2e77623fe657bea24f223a3ae", "build/assets/windows/Win32/vcruntime140d.dll": "865b2af4d1e26a1a8073c89acb06e599", - "build/prefab/full/linux_arm64_gui/debug/ballisticakit": "5979fc1374865abb96a8ff2e3f44c166", - "build/prefab/full/linux_arm64_gui/release/ballisticakit": "b389b9d4d3cac1d18dc6c04d266d444e", - "build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "9446081855fe37326f970d0ab43e2e59", - "build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "1527bc05d69edeb8af30c6ab25b928f0", - "build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "c57b7f45564dd7cbb3f25c28266a5a3a", - "build/prefab/full/linux_x86_64_gui/release/ballisticakit": "54911f2b25836bf38f8a33e306dcdee2", - "build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "9f887dfab9eb196ee8a9ff5d7f876139", - "build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "7f89a9b77feb1cde4ba611f4dd8bb444", - "build/prefab/full/mac_arm64_gui/debug/ballisticakit": "b52a34026a36769640de84ae94ac94d3", - "build/prefab/full/mac_arm64_gui/release/ballisticakit": "3c90aa7a5828921da6fa2d1b0242c76a", - "build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "f057fa1a420d0d23e6a5ccfa29a5cd2b", - "build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "24ca0d3ddbe3c45870de1167cd92459a", - "build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "eddb8691d13480b147baf732428139ca", - "build/prefab/full/mac_x86_64_gui/release/ballisticakit": "9b276bef34a259e05c23391fa3d372a6", - "build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "789d66ae2c844d81f3d4929cc6caf950", - "build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "9fe031c292167461bd8790f11c1b78c6", - "build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "461d3623b1d047a81000bf91f2b5095d", - "build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "57fa8e653ccd0625fa6a95ba7cbcc089", - "build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "7c9ef4e375fcfa593ea8ebdb2cb59f8e", - "build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "d6e492d84f592d0547878c7de8b60e35", + "build/prefab/full/linux_arm64_gui/debug/ballisticakit": "53125d7d6bd34fdfe78880773272237b", + "build/prefab/full/linux_arm64_gui/release/ballisticakit": "804a8aa64c159a3812a31be3df3584b1", + "build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "655d8bc1d591917d7bbec7ffed98a5a7", + "build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "9830f4dac6f35121b19db8e2f332d87c", + "build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "7a360065ea427f2d44f1db6d550becfb", + "build/prefab/full/linux_x86_64_gui/release/ballisticakit": "dd5b6769d2e95c93aae7126c8bdd3ffe", + "build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "791b43e652365874eb136b7ec147f9e8", + "build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "8d3fe48c1a1b601aa97ce33e892f5163", + "build/prefab/full/mac_arm64_gui/debug/ballisticakit": "12d92655438f34e912e1525991df1f73", + "build/prefab/full/mac_arm64_gui/release/ballisticakit": "e39556a0047b65919b61c740e096e967", + "build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "ae3a622c7fe0bddc6badba38402284fd", + "build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "1e744c3641f603e22b55882f96fb0a86", + "build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "bcbb650a041317c7788a31525a7c2d02", + "build/prefab/full/mac_x86_64_gui/release/ballisticakit": "a84d2e36cb685224749f556d5ba857a5", + "build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "beeecfee397c12e4c7193391973873f7", + "build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "f186772de8396573ca7daa4f765ac63a", + "build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "ada072c442da241991d2de9ad35abf79", + "build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "52a2e2a3bd751f941069d4d007d7bc59", + "build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "82d428e93227eafc8c8ffcb6e24d1ec0", + "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/release/libballisticaplus.a": "4ea0cf78901f994215f215aebb0af1dc", "build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "6ce4983e76e1cc2d2803fe306d08ad58", diff --git a/CHANGELOG.md b/CHANGELOG.md index a37f4ff8..a5227f63 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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, SDL, etc). This code had been growing into a nasty tangle for 15 years @@ -37,6 +37,9 @@ etc.) - The in-app Python console text is now sized up on phone and tablet devices, 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 support other things besides widgets and to make it easier to implement on other platforms. diff --git a/src/assets/ba_data/python/babase/_devconsole.py b/src/assets/ba_data/python/babase/_devconsole.py index 40d76c23..9e0ca0cd 100644 --- a/src/assets/ba_data/python/babase/_devconsole.py +++ b/src/assets/ba_data/python/babase/_devconsole.py @@ -49,6 +49,21 @@ class DevConsoleTab: 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: """Add a Python Terminal to the tab being refreshed.""" assert _babase.app.devconsole.is_refreshing @@ -95,6 +110,7 @@ class DevConsoleTabTest(DevConsoleTab): pos=(10, 10), size=(100, 30), h_anchor='left', + label_scale=0.6, call=self.request_refresh, ) self.button( @@ -102,8 +118,17 @@ class DevConsoleTabTest(DevConsoleTab): pos=(120, 10), size=(100, 30), h_anchor='left', + label_scale=0.6, style='dark', ) + self.text( + 'TestText', + scale=0.8, + pos=(15, 50), + h_anchor='left', + h_align='left', + v_align='none', + ) @dataclass @@ -115,7 +140,15 @@ class DevConsoleTabEntry: 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: # All tabs in the dev-console. Add your own stuff here via diff --git a/src/assets/ba_data/python/baenv.py b/src/assets/ba_data/python/baenv.py index 999a1b60..52a2646f 100644 --- a/src/assets/ba_data/python/baenv.py +++ b/src/assets/ba_data/python/baenv.py @@ -52,7 +52,7 @@ if TYPE_CHECKING: # Build number and version of the ballistica binary we expect to be # using. -TARGET_BALLISTICA_BUILD = 21406 +TARGET_BALLISTICA_BUILD = 21407 TARGET_BALLISTICA_VERSION = '1.7.28' diff --git a/src/ballistica/base/python/methods/python_methods_misc.cc b/src/ballistica/base/python/methods/python_methods_misc.cc index b3487fa4..ff46fa8b 100644 --- a/src/ballistica/base/python/methods/python_methods_misc.cc +++ b/src/ballistica/base/python/methods/python_methods_misc.cc @@ -1501,6 +1501,48 @@ static PyMethodDef PyDevConsoleAddButtonDef = { "(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 ------------------------ static auto PyDevConsoleAddPythonTerminal(PyObject* self, PyObject* args) @@ -1673,6 +1715,7 @@ auto PythonMethodsMisc::GetMethods() -> std::vector { PyOpenDirExternallyDef, PyFatalErrorDef, PyDevConsoleAddButtonDef, + PyDevConsoleAddTextDef, PyDevConsoleAddPythonTerminalDef, PyDevConsoleTabWidthDef, PyDevConsoleTabHeightDef, diff --git a/src/ballistica/base/ui/dev_console.cc b/src/ballistica/base/ui/dev_console.cc index 05c2c12d..0f6c11aa 100644 --- a/src/ballistica/base/ui/dev_console.cc +++ b/src/ballistica/base/ui/dev_console.cc @@ -31,44 +31,102 @@ const int kDevConsoleActivateKey1 = SDLK_BACKQUOTE; const int kDevConsoleActivateKey2 = SDLK_F2; 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 }; -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) { - case DevButtonAttach_::kLeft: + case DevConsoleHAnchor_::kLeft: return 0.0f; - case DevButtonAttach_::kRight: + case DevConsoleHAnchor_::kRight: return g_base->graphics->screen_virtual_width(); - case DevButtonAttach_::kCenter: + case DevConsoleHAnchor_::kCenter: return g_base->graphics->screen_virtual_width() * 0.5f; } assert(false); return 0.0f; } -static void DrawBasicButton(RenderPass* pass, Mesh* mesh, TextGroup* tgrp, - float tscale, float bottom, float x, float y, - float width, float height, const Vector3f& fgcolor, - const Vector3f& bgcolor) { +static void DrawRect(RenderPass* pass, Mesh* mesh, float bottom, float x, + float y, float width, float height, + const Vector3f& bgcolor) { SimpleComponent c(pass); c.SetTransparent(true); c.SetColor(bgcolor.x, bgcolor.y, bgcolor.z, 1.0f); c.SetTexture(g_base->assets->SysTexture(SysTextureID::kCircle)); - { + // Draw mesh bg. + if (mesh) { auto xf = c.ScopedTransform(); c.Translate(x, y + bottom, kDevConsoleZDepth); 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(); - c.Translate(x + width * 0.5f, y + bottom + height * 0.5f, - kDevConsoleZDepth); - float sc{0.6f * tscale}; - c.Scale(sc, sc, 1.0f); + c.Translate(x, y + bottom, 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); @@ -84,14 +142,46 @@ static void DrawBasicButton(RenderPass* pass, Mesh* mesh, TextGroup* tgrp, class DevConsole::Widget_ { public: virtual ~Widget_() = default; - virtual auto HandleMouseDown(float mx, float my) -> bool = 0; - virtual void HandleMouseUp(float mx, float my) = 0; + virtual auto HandleMouseDown(float mx, float my) -> bool { return false; } + virtual void HandleMouseUp(float mx, float my) {} 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_ { public: - DevButtonAttach_ attach; + DevConsoleHAnchor_ attach; float x; float y; float width; @@ -104,7 +194,7 @@ class DevConsole::Button_ : public DevConsole::Widget_ { DevButtonStyle_ style; template - 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, DevButtonStyle_ style, const F& lambda) : attach{attach}, @@ -165,14 +255,15 @@ class DevConsole::Button_ : public DevConsole::Widget_ { bgcolor = pressed ? Vector3f{0.8f, 0.7f, 0.8f} : Vector3f{0.25, 0.2f, 0.3f}; } - DrawBasicButton(pass, &mesh, &text_group, text_scale, bottom, - x + XOffs(attach), y, width, height, fgcolor, bgcolor); + DrawRect(pass, &mesh, bottom, x + XOffs(attach), y, width, height, 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_ { public: - DevButtonAttach_ attach; + DevConsoleHAnchor_ attach; float x; float y; float width; @@ -187,7 +278,7 @@ class DevConsole::ToggleButton_ : public DevConsole::Widget_ { template 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, const G& off_call) : attach{attach}, @@ -234,20 +325,22 @@ class DevConsole::ToggleButton_ : public DevConsole::Widget_ { } void Draw(RenderPass* pass, float bottom) override { - DrawBasicButton(pass, &mesh, &text_group, text_scale, bottom, - x + XOffs(attach), y, width, height, - pressed ? Vector3f{1.0f, 1.0f, 1.0f} - : on ? Vector3f{1.0f, 1.0f, 1.0f} - : Vector3f{0.8f, 0.7f, 0.8f}, - pressed ? Vector3f{0.5f, 0.2f, 1.0f} - : on ? Vector3f{0.5f, 0.4f, 0.6f} - : Vector3f{0.25, 0.2f, 0.3f}); + DrawRect(pass, &mesh, bottom, x + XOffs(attach), y, width, height, + + pressed ? Vector3f{0.5f, 0.2f, 1.0f} + : on ? Vector3f{0.5f, 0.4f, 0.6f} + : Vector3f{0.25, 0.2f, 0.3f}); + DrawText(pass, &text_group, text_scale, bottom, + x + XOffs(attach) + width * 0.5f, y + height * 0.5f, + 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_ { public: - DevButtonAttach_ attach; + DevConsoleHAnchor_ attach; float x; float y; float width; @@ -261,7 +354,7 @@ class DevConsole::TabButton_ : public DevConsole::Widget_ { template 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) : attach{attach}, x{x}, @@ -308,15 +401,15 @@ class DevConsole::TabButton_ : public DevConsole::Widget_ { } void Draw(RenderPass* pass, float bottom) override { - DrawBasicButton(pass, &mesh, &text_group, text_scale, bottom, - x + XOffs(attach), y, width, height, - pressed ? Vector3f{1.0f, 1.0f, 1.0f} - : selected ? Vector3f{1.0f, 1.0f, 1.0f} - : Vector3f{0.6f, 0.5f, 0.6f}, - pressed ? Vector3f{0.4f, 0.2f, 0.8f} - : selected ? Vector3f{0.4f, 0.3f, 0.4f} - // : selected ? Vector3f{0.5f, 0.4f, 0.6f} - : Vector3f{0.25, 0.2f, 0.3f}); + DrawRect(pass, &mesh, bottom, x + XOffs(attach), y, width, height, + pressed ? Vector3f{0.4f, 0.2f, 0.8f} + : selected ? Vector3f{0.4f, 0.3f, 0.4f} + : Vector3f{0.25, 0.2f, 0.3f}); + DrawText(pass, &text_group, text_scale, bottom, + x + XOffs(attach) + width * 0.5f, y + height * 0.5f, + pressed ? Vector3f{1.0f, 1.0f, 1.0f} + : selected ? Vector3f{1.0f, 1.0f, 1.0f} + : Vector3f{0.6f, 0.5f, 0.6f}); } }; @@ -381,13 +474,13 @@ void DevConsole::RefreshTabButtons_() { float bs = BaseScale(); float bwidth = 90.0f * bs; float bheight = 26.0f * bs; - float bscale = 0.8f * bs; + float bscale = 0.6f * bs; float total_width = tabs_.size() * bwidth; float x = total_width * -0.5f; for (auto&& tab : tabs_) { tab_buttons_.emplace_back(std::make_unique( - tab, active_tab_ == tab, bscale, DevButtonAttach_::kCenter, x, -bheight, - bwidth, bheight, [this, tab] { + tab, active_tab_ == tab, bscale, DevConsoleHAnchor_::kCenter, x, + -bheight, bwidth, bheight, [this, tab] { active_tab_ = tab; RefreshTabButtons_(); RefreshTabContents_(); @@ -404,7 +497,7 @@ void DevConsole::RefreshTabContents_() { refresh_pending_ = false; // Clear to an empty slate. - buttons_.clear(); + widgets_.clear(); python_terminal_visible_ = false; // Now ask the Python layer to fill this tab in. @@ -414,43 +507,39 @@ void DevConsole::RefreshTabContents_() { .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, x, y, h_anchor, h_align, v_align, scale)); +} + void DevConsole::AddButton(const char* label, float x, float y, float width, - float height, PyObject* call, const char* h_anchor, - float label_scale, float corner_radius, - const char* style) { + float height, PyObject* call, + const char* h_anchor_str, float label_scale, + float corner_radius, const char* style_str) { assert(g_base->InLogicThread()); - DevButtonStyle_ style_val; - if (!strcmp(style, "dark")) { - style_val = DevButtonStyle_::kDark; - } else { - style_val = DevButtonStyle_::kNormal; - } + auto style = DevButtonStyleFromStr_(style_str); + auto h_anchor = DevConsoleHAttachFromStr_(h_anchor_str); - DevButtonAttach_ anchor; - if (!strcmp(h_anchor, "left")) { - anchor = DevButtonAttach_::kLeft; - } else if (!strcmp(h_anchor, "right")) { - anchor = DevButtonAttach_::kRight; - } else { - assert(!strcmp(h_anchor, "center")); - anchor = DevButtonAttach_::kCenter; - } - - // auto call_obj = PythonRef::Acquired(call); - buttons_.emplace_back(std::make_unique( - 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(); + widgets_.emplace_back(std::make_unique( + label, label_scale, h_anchor, x, y, width, height, corner_radius, style, + [this, callref = PythonRef::Acquired(call)] { + if (callref.Get() != Py_None) { + callref.Call(); } })); } void DevConsole::AddPythonTerminal() { float bs = BaseScale(); - buttons_.emplace_back(std::make_unique( - "Exec", 0.75f * bs, DevButtonAttach_::kRight, -33.0f * bs, 15.95f * bs, + widgets_.emplace_back(std::make_unique( + "Exec", 0.5f * bs, DevConsoleHAnchor_::kRight, -33.0f * bs, 15.95f * bs, 32.0f * bs, 13.0f * bs, 2.0 * bs, DevButtonStyle_::kNormal, [this] { Exec(); })); python_terminal_visible_ = true; @@ -483,7 +572,7 @@ auto DevConsole::HandleMouseDown(int button, float x, float y) -> bool { return true; } } - for (auto&& button : buttons_) { + for (auto&& button : widgets_) { if (button->HandleMouseDown(x, y - bottom)) { return true; } @@ -517,7 +606,7 @@ void DevConsole::HandleMouseUp(int button, float x, float y) { for (auto&& button : tab_buttons_) { button->HandleMouseUp(x, y - bottom); } - for (auto&& button : buttons_) { + for (auto&& button : widgets_) { 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 // mini-size. 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) { bottom = vh - mini_size; } else { @@ -812,7 +905,7 @@ auto DevConsole::Bottom_() const -> float { } else if (state_prev_ == State_::kFull) { from_height = vh - vh * kDevConsoleSize; } else { - from_height = vh; + from_height = vh + top_buffer; } float to_height; if (state_ == State_::kMini) { @@ -820,7 +913,7 @@ auto DevConsole::Bottom_() const -> float { } else if (state_ == State_::kFull) { to_height = vh - vh * kDevConsoleSize; } else { - to_height = vh; + to_height = vh + top_buffer; } 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, kDevConsoleZDepth, pass->virtual_width(), border_height * bs); - SimpleComponent c(pass); - c.SetTransparent(true); - c.SetColor(0, 0, 0.1f, 0.9f); - c.DrawMesh(&bg_mesh_); - c.Submit(); - if (python_terminal_visible_) { - c.SetColor(1.0f, 1.0f, 1.0f, 0.1f); - c.DrawMesh(&stripe_mesh_); + { + SimpleComponent c(pass); + c.SetTransparent(true); + c.SetColor(0, 0, 0.1f, 0.9f); + c.DrawMesh(&bg_mesh_); 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. @@ -936,7 +1030,6 @@ void DevConsole::Draw(FrameDef* frame_def) { c.DrawMesh(input_text_group_.GetElementMesh(e)); } } - c.Submit(); } // Carat. @@ -956,17 +1049,16 @@ void DevConsole::Draw(FrameDef* frame_def) { c.Scale(6.0f * bs, 12.0f * bs, 1.0f); 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); c.SetTransparent(true); c.SetColor(1, 1, 1, 1); c.SetFlatness(1.0f); + float draw_scale = 0.6f; + float v_inc = 18.0f; float h = 0.5f * (g_base->graphics->screen_virtual_width() - (kDevConsoleStringBreakUpSize * draw_scale)); @@ -1007,7 +1099,6 @@ void DevConsole::Draw(FrameDef* frame_def) { break; } } - c.Submit(); } } @@ -1020,7 +1111,7 @@ void DevConsole::Draw(FrameDef* frame_def) { // Buttons. { - for (auto&& button : buttons_) { + for (auto&& button : widgets_) { button->Draw(pass, bottom); } } @@ -1040,4 +1131,21 @@ auto DevConsole::BaseScale() const -> float { 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 diff --git a/src/ballistica/base/ui/dev_console.h b/src/ballistica/base/ui/dev_console.h index 72f6f191..a2ffe55a 100644 --- a/src/ballistica/base/ui/dev_console.h +++ b/src/ballistica/base/ui/dev_console.h @@ -37,6 +37,8 @@ class DevConsole { void Print(const std::string& s_in); void Draw(FrameDef* frame_def); + void StepDisplayTime(); + /// Called when the console should start accepting Python command input. void EnableInput(); @@ -53,8 +55,10 @@ class DevConsole { void Exec(); void AddButton(const char* label, float x, float y, float width, float height, - PyObject* call, const char* h_anchor, float label_scale, - float corner_radius, const char* style); + PyObject* call, const char* h_anchor_str, float label_scale, + 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(); auto Width() -> float; @@ -65,6 +69,7 @@ class DevConsole { private: class Widget_; class Button_; + class Text_; class ToggleButton_; class TabButton_; class OutputLine_; @@ -103,7 +108,7 @@ class DevConsole { Object::Ref last_line_mesh_group_; std::list input_history_; std::list output_lines_; - std::vector > buttons_; + std::vector > widgets_; std::vector > tab_buttons_; }; diff --git a/src/ballistica/base/ui/ui.cc b/src/ballistica/base/ui/ui.cc index e02e7343..66bb00de 100644 --- a/src/ballistica/base/ui/ui.cc +++ b/src/ballistica/base/ui/ui.cc @@ -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() { assert(g_base->InLogicThread()); diff --git a/src/ballistica/shared/ballistica.cc b/src/ballistica/shared/ballistica.cc index dec8499b..fcf49cad 100644 --- a/src/ballistica/shared/ballistica.cc +++ b/src/ballistica/shared/ballistica.cc @@ -39,7 +39,7 @@ auto main(int argc, char** argv) -> int { namespace ballistica { // 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 int kEngineApiVersion = 8;