more untangling

This commit is contained in:
Eric 2023-06-02 14:14:45 -07:00
parent 3ef807890f
commit 91cfa632c8
No known key found for this signature in database
GPG Key ID: 89C93F0F8D6D5A98
19 changed files with 390 additions and 327 deletions

View File

@ -4072,26 +4072,26 @@
"build/assets/workspace/ninjafightplug.py": "https://files.ballistica.net/cache/ba1/c5/09/4f10b8a21ba87aa5509cff7a164b",
"build/assets/workspace/onslaughtplug.py": "https://files.ballistica.net/cache/ba1/ff/0a/a354984f9c074dab0676ac7e4877",
"build/assets/workspace/runaroundplug.py": "https://files.ballistica.net/cache/ba1/2a/1c/9ee5db6d1bceca7fa6638fb8abde",
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/58/ee/1ae7013ce43f284e1037e4d6d919",
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/ab/c7/667fbfbddf1633be04f3216e0643",
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/26/27/837e81d734fd600e258c02b9dccf",
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/6a/b5/0f025731ba6077489aeb2fd177d0",
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/27/38/e8add26cb151502314c1b63f17a9",
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/85/49/10aa68593cab2a1e8157d08f01b7",
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/86/3a/497b582b67614ee0dbca984ec355",
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/32/a6/dbd29464c7b8a0939db43f50f05f",
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/7a/39/e06e47cbe35b9191a8d01d634690",
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/dc/03/292c24cc1576db602d5abef25021",
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/7f/d1/ac412a5e2c13c1ff65ba745fe71a",
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/b4/ad/78a018863d2aa19c2c75bbc0507a",
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/d4/b4/6e407209943bfcbe595bb646d0ec",
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/33/56/7ba169a200619cbd84c7f0ce2d05",
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/d2/02/4e009574cce072d6a20a2ab29a70",
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/af/71/1979797270010b09d88fcb4cbf38",
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "https://files.ballistica.net/cache/ba1/bd/ed/1c0eccb11e438a2b1e9106464187",
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "https://files.ballistica.net/cache/ba1/81/0c/1f834b3e710f788748bdeb0f7e21",
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "https://files.ballistica.net/cache/ba1/43/c1/fb11c149f9a8b34cdaad76eec2c3",
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "https://files.ballistica.net/cache/ba1/30/f5/3964913ed145b96629055623e1f1",
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/4f/46/80f41faa8a51075c2472d7429b77",
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/30/cb/93ac10daaf9475d01f5d1064d358",
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/34/4e/e2bf216edcd7d6a9a1bee3b55b69",
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/5e/2b/c22b17ffa90f65bc906ae9e477d6",
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/cf/ac/1485911ed48dac0c430b18687917",
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/0d/99/2b9a15fa962b5ea354f8de27fe6c",
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/03/e1/e795c72de227173711da1a162632",
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/80/26/b82964ce5a5bb8509ca6d7516b71",
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/2e/c8/67482dedb186c9dbca2dc66f7699",
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/18/fa/c42a603705d7453279689706d2ee",
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/bc/d2/89526b59dee86888c628028a406c",
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/1d/e5/7425978a2c0112a46192a76563ce",
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "https://files.ballistica.net/cache/ba1/ff/cd/21d36a06bbc2322d8e944f392ef0",
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "https://files.ballistica.net/cache/ba1/97/ee/e2c3b4a6ee9abb170bd98f38c7de",
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/be/13/229e4c027d0ca4b037dbf67134bd",
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "https://files.ballistica.net/cache/ba1/53/bb/acf5f4b58a156c53e6ff8f0b58ad",
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "https://files.ballistica.net/cache/ba1/f3/d7/426c5cd3ec71438a98474f39ba2c",
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "https://files.ballistica.net/cache/ba1/90/79/74d6111711d655963a1e9a2728c5",
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "https://files.ballistica.net/cache/ba1/c1/f7/95ff199637a86fe138309e3a5275",
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "https://files.ballistica.net/cache/ba1/61/f0/9447fe7637ed96ce1840aa277271",
"build/prefab/lib/linux_arm64_gui/debug/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/d4/6a/dd303a200b98a56ba3b100277057",
"build/prefab/lib/linux_arm64_gui/release/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/fc/2c/2996c558fb408a548fdd37398c9a",
"build/prefab/lib/linux_arm64_server/debug/libballistica_plus.a": "https://files.ballistica.net/cache/ba1/ed/28/b7a72be7ae1bd2b58dda4b6902a0",

View File

@ -1,4 +1,4 @@
### 1.7.20 (build 21040, api 8, 2023-06-02)
### 1.7.20 (build 21041, api 8, 2023-06-02)
- This seems like a good time for a `refactoring` release in anticipation of
changes coming in 1.8. Basically this means that a lot of things will be

View File

@ -30,7 +30,7 @@ if TYPE_CHECKING:
# Build number and version of the ballistica binary we expect to be
# using.
TARGET_BALLISTICA_BUILD = 21040
TARGET_BALLISTICA_BUILD = 21041
TARGET_BALLISTICA_VERSION = '1.7.20'
_g_env_config: EnvConfig | None = None

View File

@ -1180,7 +1180,7 @@ void Graphics::BuildAndPushFrameDef() {
// drawing/blitting the 2d UI buffer during gameplay for efficiency).
if (g_core->IsVRMode()) {
if (frame_def->GetOverlayFlatPass()->HasDrawCommands()) {
if (!g_base->ui->IsWindowPresent()) {
if (!g_base->ui->MainMenuVisible()) {
BA_LOG_ONCE(LogLevel::kError,
"Drawing in overlay pass in VR mode with no UI present; "
"shouldn't happen!");

View File

@ -350,7 +350,7 @@ void TouchInput::UpdateDPad() {
void TouchInput::Draw(FrameDef* frame_def) {
assert(g_base->InLogicThread());
bool active = (!g_base->ui->IsWindowPresent());
bool active = (!g_base->ui->MainMenuVisible());
millisecs_t real_time = frame_def->real_time();
// Update our action center whenever possible in case screen is resized.
@ -915,7 +915,7 @@ auto TouchInput::HandleTouchDown(void* touch, float x, float y) -> bool {
// Normal in-game operation:
// Normal operation is disabled while a UI is up.
if (g_base->ui->IsWindowPresent()) {
if (g_base->ui->MainMenuVisible()) {
return false;
}
@ -1038,7 +1038,7 @@ auto TouchInput::HandleTouchMoved(void* touch, float x, float y) -> bool {
}
// Ignore button/pad touches while gui is up.
if (g_base->ui->IsWindowPresent()) {
if (g_base->ui->MainMenuVisible()) {
return false;
}
if (touch == buttons_touch_) {

View File

@ -16,7 +16,6 @@
#include "ballistica/base/ui/ui.h"
#include "ballistica/shared/foundation/event_loop.h"
#include "ballistica/shared/generic/utils.h"
#include "ballistica/ui_v1/widget/root_widget.h"
namespace ballistica::base {
@ -1038,7 +1037,7 @@ void Input::HandleKeyPress(const SDL_Keysym* keysym) {
g_base->ui->PushMainMenuPressCall(keyboard_input_);
} else {
// Ok there *is* a main menu up. Send it a cancel message.
g_base->ui->root_widget()->HandleMessage(
g_base->ui->SendWidgetMessage(
WidgetMessage(WidgetMessage::Type::kCancel));
}
handled = true;
@ -1144,16 +1143,15 @@ void Input::HandleMouseScroll(const Vector2f& amount) {
}
mark_input_active();
ui_v1::Widget* root_widget = g_base->ui->root_widget();
if (std::abs(amount.y) > 0.0001f && root_widget) {
root_widget->HandleMessage(WidgetMessage(WidgetMessage::Type::kMouseWheel,
nullptr, cursor_pos_x_,
cursor_pos_y_, amount.y));
if (std::abs(amount.y) > 0.0001f) {
g_base->ui->SendWidgetMessage(
WidgetMessage(WidgetMessage::Type::kMouseWheel, nullptr, cursor_pos_x_,
cursor_pos_y_, amount.y));
}
if (std::abs(amount.x) > 0.0001f && root_widget) {
root_widget->HandleMessage(WidgetMessage(WidgetMessage::Type::kMouseWheelH,
nullptr, cursor_pos_x_,
cursor_pos_y_, amount.x));
if (std::abs(amount.x) > 0.0001f) {
g_base->ui->SendWidgetMessage(
WidgetMessage(WidgetMessage::Type::kMouseWheelH, nullptr, cursor_pos_x_,
cursor_pos_y_, amount.x));
}
mouse_move_count_++;
@ -1180,15 +1178,13 @@ void Input::HandleSmoothMouseScroll(const Vector2f& velocity, bool momentum) {
mark_input_active();
bool handled = false;
ui_v1::Widget* root_widget = g_base->ui->root_widget();
if (root_widget) {
handled = root_widget->HandleMessage(
WidgetMessage(WidgetMessage::Type::kMouseWheelVelocity, nullptr,
cursor_pos_x_, cursor_pos_y_, velocity.y, momentum));
root_widget->HandleMessage(
WidgetMessage(WidgetMessage::Type::kMouseWheelVelocityH, nullptr,
cursor_pos_x_, cursor_pos_y_, velocity.x, momentum));
}
handled = g_base->ui->SendWidgetMessage(
WidgetMessage(WidgetMessage::Type::kMouseWheelVelocity, nullptr,
cursor_pos_x_, cursor_pos_y_, velocity.y, momentum));
g_base->ui->SendWidgetMessage(
WidgetMessage(WidgetMessage::Type::kMouseWheelVelocityH, nullptr,
cursor_pos_x_, cursor_pos_y_, velocity.x, momentum));
last_mouse_move_time_ = g_core->GetAppTimeMillisecs();
mouse_move_count_++;
@ -1233,11 +1229,11 @@ void Input::HandleMouseMotion(const Vector2f& position) {
}
// UI interaction.
ui_v1::Widget* root_widget = g_base->ui->root_widget();
if (root_widget && !IsInputLocked())
handled = root_widget->HandleMessage(
if (!IsInputLocked()) {
handled = g_base->ui->SendWidgetMessage(
WidgetMessage(WidgetMessage::Type::kMouseMove, nullptr, cursor_pos_x_,
cursor_pos_y_));
}
// Manual camera motion.
Camera* camera = g_base->graphics->camera();
@ -1259,6 +1255,7 @@ void Input::PushMouseDownEvent(int button, const Vector2f& position) {
}
void Input::HandleMouseDown(int button, const Vector2f& position) {
assert(g_base);
assert(g_base->graphics);
assert(g_base->InLogicThread());
@ -1266,7 +1263,7 @@ void Input::HandleMouseDown(int button, const Vector2f& position) {
return;
}
if (g_base == nullptr || g_base->ui->screen_root_widget() == nullptr) {
if (!g_base->ui->MainMenuVisible()) {
return;
}
@ -1286,7 +1283,7 @@ void Input::HandleMouseDown(int button, const Vector2f& position) {
last_click_time_ = click_time;
bool handled{};
auto* root_widget = g_base->ui->root_widget();
// auto* root_widget = g_base->ui->root_widget();
// If we have a touch-input in editing mode, pass along events to it.
// (it usually handles its own events but here we want it to play nice
@ -1302,8 +1299,8 @@ void Input::HandleMouseDown(int button, const Vector2f& position) {
}
}
if (root_widget && !handled) {
handled = root_widget->HandleMessage(
if (!handled) {
handled = g_base->ui->SendWidgetMessage(
WidgetMessage(WidgetMessage::Type::kMouseDown, nullptr, cursor_pos_x_,
cursor_pos_y_, double_click ? 2 : 1));
}
@ -1353,11 +1350,11 @@ void Input::HandleMouseUp(int button, const Vector2f& position) {
cursor_pos_y_);
}
ui_v1::Widget* root_widget = g_base->ui->root_widget();
if (root_widget) {
handled = root_widget->HandleMessage(WidgetMessage(
WidgetMessage::Type::kMouseUp, nullptr, cursor_pos_x_, cursor_pos_y_));
}
// ui_v1::Widget* root_widget = g_base->ui->root_widget();
// if (root_widget) {
handled = g_base->ui->SendWidgetMessage(WidgetMessage(
WidgetMessage::Type::kMouseUp, nullptr, cursor_pos_x_, cursor_pos_y_));
// }
Camera* camera = g_base->graphics->camera();
if (!handled && camera) {
@ -1484,7 +1481,6 @@ auto Input::IsCursorVisible() const -> bool {
if (!g_base->ui) {
return false;
}
ui_v1::ContainerWidget* screen_root_widget = g_base->ui->screen_root_widget();
// Keeps mouse hidden to start with..
if (mouse_move_count_ < 2) {
@ -1494,7 +1490,7 @@ auto Input::IsCursorVisible() const -> bool {
// Show our cursor if any dialogs/windows are up or else if its been
// moved very recently.
if (screen_root_widget && screen_root_widget->GetChildCount() > 0) {
if (g_base->ui->MainMenuVisible()) {
val = (g_core->GetAppTimeMillisecs() - last_mouse_move_time_ < 5000);
} else {
val = (g_core->GetAppTimeMillisecs() - last_mouse_move_time_ < 1000);

View File

@ -5,15 +5,15 @@
#include "ballistica/base/app/app.h"
#include "ballistica/base/app/app_mode.h"
#include "ballistica/base/graphics/graphics_server.h"
#include "ballistica/base/logic/logic.h"
#include "ballistica/base/python/base_python.h"
#include "ballistica/base/python/support/python_context_call_runnable.h"
#include "ballistica/base/ui/ui.h"
#include "ballistica/scene_v1/assets/scene_texture.h"
#include "ballistica/scene_v1/python/class/python_class_activity_data.h"
#include "ballistica/scene_v1/support/scene.h"
#include "ballistica/core/platform/core_platform.h"
#include "ballistica/shared/foundation/event_loop.h"
#include "ballistica/shared/foundation/logging.h"
#include "ballistica/shared/python/python.h"
#include "ballistica/shared/python/python_sys.h"
namespace ballistica::base {

View File

@ -3,10 +3,13 @@
#ifndef BALLISTICA_BASE_SUPPORT_UI_V1_SOFT_H_
#define BALLISTICA_BASE_SUPPORT_UI_V1_SOFT_H_
#include "ballistica/base/ui/ui.h"
// Predeclare some types we use.
namespace ballistica::ui_v1 {
class RootUI;
}
class Widget;
} // namespace ballistica::ui_v1
namespace ballistica::base {
@ -26,6 +29,14 @@ class UIV1SoftInterface {
virtual void HandleLegacyRootUIMouseMotion(float x, float y) = 0;
virtual auto HandleLegacyRootUIMouseDown(float x, float y) -> bool = 0;
virtual void HandleLegacyRootUIMouseUp(float x, float y) = 0;
virtual void Draw(FrameDef* frame_def) = 0;
virtual void OnAppStart() = 0;
virtual auto PartyWindowOpen() -> bool = 0;
virtual void Reset() = 0;
virtual void OnScreenSizeChange() = 0;
virtual void OnLanguageChange() = 0;
virtual auto GetRootWidget() -> ui_v1::Widget* = 0;
virtual auto SendWidgetMessage(const WidgetMessage& m) -> int = 0;
};
} // namespace ballistica::base

View File

@ -4,7 +4,6 @@
#include "ballistica/base/app/app_config.h"
#include "ballistica/base/audio/audio.h"
#include "ballistica/base/graphics/component/empty_component.h"
#include "ballistica/base/input/device/keyboard_input.h"
#include "ballistica/base/input/input.h"
#include "ballistica/base/logic/logic.h"
@ -12,8 +11,6 @@
#include "ballistica/base/ui/console.h"
#include "ballistica/shared/foundation/event_loop.h"
#include "ballistica/shared/generic/utils.h"
#include "ballistica/ui_v1/python/ui_v1_python.h"
#include "ballistica/ui_v1/support/root_ui.h"
#include "ballistica/ui_v1/widget/root_widget.h"
#include "ballistica/ui_v1/widget/stack_widget.h"
#include "ballistica/ui_v1/widget/text_widget.h"
@ -58,9 +55,11 @@ void UI::StepDisplayTime() { assert(g_base->InLogicThread()); }
void UI::OnAppStart() {
assert(g_base->InLogicThread());
root_ui_ = g_base->ui_v1()->NewRootUI();
if (g_base->HaveUIV1()) {
g_base->ui_v1()->OnAppStart();
}
// Make sure we know when forced-ui-scale is enabled.
// Make sure user knows when forced-ui-scale is enabled.
if (force_scale_) {
if (scale_ == UIScale::kSmall) {
ScreenMessage("FORCING SMALL UI FOR TESTING", Vector3f(1, 0, 0));
@ -93,13 +92,20 @@ void UI::ApplyAppConfig() {
AppConfig::BoolID::kAlwaysUseInternalKeyboard));
}
auto UI::MainMenuVisible() -> bool {
auto UI::MainMenuVisible() const -> bool {
if (g_base->HaveUIV1()) {
return g_base->ui_v1()->MainMenuVisible();
}
return false;
}
// FIXME should be same as MainMenuVisible.
// auto UI::IsWindowPresent() const -> bool {
// return ((screen_root_widget_.Exists() && screen_root_widget_->HasChildren())
// || (overlay_root_widget_.Exists()
// && overlay_root_widget_->HasChildren()));
//}
auto UI::PartyIconVisible() -> bool {
if (g_base->HaveUIV1()) {
return g_base->ui_v1()->PartyIconVisible();
@ -113,6 +119,13 @@ void UI::ActivatePartyIcon() {
}
}
auto UI::PartyWindowOpen() -> bool {
if (g_base->HaveUIV1()) {
g_base->ui_v1()->PartyWindowOpen();
}
return false;
}
void UI::HandleLegacyRootUIMouseMotion(float x, float y) {
if (g_base->HaveUIV1()) {
g_base->ui_v1()->HandleLegacyRootUIMouseMotion(x, y);
@ -136,15 +149,10 @@ void UI::PushBackButtonCall(InputDevice* input_device) {
g_base->logic->event_loop()->PushCall([this, input_device] {
assert(g_base->InLogicThread());
// Ignore if UI isn't up yet.
if (!overlay_root_widget() || !screen_root_widget()) {
return;
}
// If there's a UI up, send along a cancel message.
if (overlay_root_widget()->GetChildCount() != 0
|| screen_root_widget()->GetChildCount() != 0) {
root_widget()->HandleMessage(WidgetMessage(WidgetMessage::Type::kCancel));
if (g_base->ui->MainMenuVisible()) {
g_base->ui->SendWidgetMessage(
WidgetMessage(WidgetMessage::Type::kCancel));
} else {
// If there's no main screen or overlay windows, ask for a menu owned by
// this device.
@ -168,12 +176,6 @@ void UI::MainMenuPress(InputDevice* device) {
}
}
auto UI::IsWindowPresent() const -> bool {
return ((screen_root_widget_.Exists() && screen_root_widget_->HasChildren())
|| (overlay_root_widget_.Exists()
&& overlay_root_widget_->HasChildren()));
}
void UI::SetUIInputDevice(InputDevice* input_device) {
assert(g_base->InLogicThread());
@ -202,82 +204,27 @@ UI::UILock::~UILock() {
}
void UI::Reset() {
// Hmm; technically we don't need to recreate these each time we reset.
root_widget_.Clear();
// Kill our screen-root widget.
screen_root_widget_.Clear();
// (Re)create our screen-root widget.
auto sw(Object::New<ui_v1::StackWidget>());
sw->set_is_main_window_stack(true);
sw->SetWidth(g_base->graphics->screen_virtual_width());
sw->SetHeight(g_base->graphics->screen_virtual_height());
sw->set_translate(0, 0);
screen_root_widget_ = sw;
// (Re)create our screen-overlay widget.
auto ow(Object::New<ui_v1::StackWidget>());
ow->set_is_overlay_window_stack(true);
ow->SetWidth(g_base->graphics->screen_virtual_width());
ow->SetHeight(g_base->graphics->screen_virtual_height());
ow->set_translate(0, 0);
overlay_root_widget_ = ow;
// (Re)create our abs-root widget.
auto rw(Object::New<ui_v1::RootWidget>());
root_widget_ = rw;
rw->SetWidth(g_base->graphics->screen_virtual_width());
rw->SetHeight(g_base->graphics->screen_virtual_height());
rw->SetScreenWidget(sw.Get());
rw->Setup();
rw->SetOverlayWidget(ow.Get());
sw->GlobalSelect();
if (g_base->HaveUIV1()) {
g_base->ui_v1()->Reset();
}
}
auto UI::ShouldHighlightWidgets() const -> bool {
// Show selection highlights only if we've got controllers connected and only
// when the main UI is visible (dont want a selection highlight for toolbar
// buttons during a game).
return (
g_base->input->have_non_touch_inputs()
&& ((screen_root_widget_.Exists() && screen_root_widget_->HasChildren())
|| (overlay_root_widget_.Exists()
&& overlay_root_widget_->HasChildren())));
return (g_base->input->have_non_touch_inputs() && MainMenuVisible());
}
auto UI::ShouldShowButtonShortcuts() const -> bool {
return g_base->input->have_non_touch_inputs();
}
void UI::AddWidget(ui_v1::Widget* w, ui_v1::ContainerWidget* parent) {
assert(g_base->InLogicThread());
BA_PRECONDITION(parent != nullptr);
// If they're adding an initial window/dialog to our screen-stack
// or overlay stack, send a reset-local-input message so that characters
// who have lost focus will not get stuck running or whatnot.
// We should come up with a more generalized way to track this sort of
// focus as this is a bit hacky, but it works for now.
auto* screen_root_widget = screen_root_widget_.Get();
auto* overlay_root_widget = overlay_root_widget_.Get();
if ((screen_root_widget && !screen_root_widget->HasChildren()
&& parent == screen_root_widget)
|| (overlay_root_widget && !overlay_root_widget->HasChildren()
&& parent == overlay_root_widget)) {
g_base->input->ResetHoldStates();
}
parent->AddWidget(w);
}
auto UI::SendWidgetMessage(const WidgetMessage& m) -> int {
if (!root_widget_.Exists()) {
return false;
if (g_base->HaveUIV1()) {
return g_base->ui_v1()->SendWidgetMessage(m);
}
return root_widget_->HandleMessage(m);
return false;
}
void UI::DeleteWidget(ui_v1::Widget* widget) {
@ -291,16 +238,14 @@ void UI::DeleteWidget(ui_v1::Widget* widget) {
}
void UI::OnScreenSizeChange() {
if (root_widget_.Exists()) {
root_widget_->SetWidth(g_base->graphics->screen_virtual_width());
root_widget_->SetHeight(g_base->graphics->screen_virtual_height());
if (g_base->HaveUIV1()) {
g_base->ui_v1()->OnScreenSizeChange();
}
}
void UI::LanguageChanged() {
// As well as existing UI stuff.
if (ui_v1::Widget* root_widget = g_base->ui->root_widget()) {
root_widget->OnLanguageChange();
if (g_base->HaveUIV1()) {
g_base->ui_v1()->OnLanguageChange();
}
}
@ -315,9 +260,7 @@ auto UI::GetWidgetForInput(InputDevice* input_device) -> ui_v1::Widget* {
// We only allow input-devices to control the UI when there's a window/dialog
// on the screen (even though our top/bottom bars still exist).
if ((!screen_root_widget_.Exists() || (!screen_root_widget_->HasChildren()))
&& (!overlay_root_widget_.Exists()
|| (!overlay_root_widget_->HasChildren()))) {
if (!MainMenuVisible()) {
return nullptr;
}
@ -332,15 +275,20 @@ auto UI::GetWidgetForInput(InputDevice* input_device) -> ui_v1::Widget* {
// However, if no events are received by that device for a long time,
// it is up for grabs to the next device that requests it.
if ((GetUIInputDevice() == nullptr) || (input_device == GetUIInputDevice())
|| (time - last_input_device_use_time_ > (1000 * kUIOwnerTimeoutSeconds))
|| !g_base->input->HaveManyLocalActiveInputDevices()) {
if (!g_base->HaveUIV1()) {
ret_val = nullptr;
} else if ((GetUIInputDevice() == nullptr)
|| (input_device == GetUIInputDevice())
|| (time - last_input_device_use_time_
> (1000 * kUIOwnerTimeoutSeconds))
|| !g_base->input->HaveManyLocalActiveInputDevices()) {
// Don't actually assign yet; only update times and owners if there's a
// widget to be had (we don't want some guy who moved his character 3
// seconds ago to automatically own a newly created widget).
last_input_device_use_time_ = time;
ui_input_device_ = input_device;
ret_val = screen_root_widget_.Get();
// ret_val = screen_root_widget_.Get();
ret_val = g_base->ui_v1()->GetRootWidget();
} else {
// For rejected input devices, play error sounds sometimes so they know
// they're not the chosen one.
@ -397,55 +345,8 @@ auto UI::GetWidgetForInput(InputDevice* input_device) -> ui_v1::Widget* {
}
void UI::Draw(FrameDef* frame_def) {
RenderPass* overlay_flat_pass = frame_def->GetOverlayFlatPass();
// Draw interface elements.
auto* root_widget = root_widget_.Get();
if (root_widget && root_widget->HasChildren()) {
// Draw our opaque and transparent parts separately.
// This way we can draw front-to-back for opaque and back-to-front for
// transparent.
g_base->graphics->set_drawing_opaque_only(true);
// Do a wee bit of shifting based on tilt just for fun.
Vector3f tilt = 0.1f * g_base->graphics->tilt();
{
EmptyComponent c(overlay_flat_pass);
c.SetTransparent(false);
c.PushTransform();
c.Translate(-tilt.y, tilt.x, -0.5f);
// We want our widgets to cover 0.1f in z space.
c.Scale(1.0f, 1.0f, 0.1f);
c.Submit();
root_widget->Draw(overlay_flat_pass, false);
c.PopTransform();
c.Submit();
}
g_base->graphics->set_drawing_opaque_only(false);
g_base->graphics->set_drawing_transparent_only(true);
{
EmptyComponent c(overlay_flat_pass);
c.SetTransparent(true);
c.PushTransform();
c.Translate(-tilt.y, tilt.x, -0.5f);
// We want our widgets to cover 0.1f in z space.
c.Scale(1.0f, 1.0f, 0.1f);
c.Submit();
root_widget->Draw(overlay_flat_pass, true);
c.PopTransform();
c.Submit();
}
g_base->graphics->set_drawing_transparent_only(false);
}
if (root_ui_) {
root_ui_->Draw(frame_def);
if (g_base->HaveUIV1()) {
g_base->ui_v1()->Draw(frame_def);
}
}

View File

@ -60,30 +60,19 @@ class UI {
/// This can be called from any thread.
void ConfirmQuit();
auto MainMenuVisible() -> bool;
/// Return whether there is UI present in either the main or overlay
/// stacks. Generally this implies the focus should be on the UI.
auto MainMenuVisible() const -> bool;
auto PartyIconVisible() -> bool;
void ActivatePartyIcon();
void HandleLegacyRootUIMouseMotion(float x, float y);
auto HandleLegacyRootUIMouseDown(float x, float y) -> bool;
void HandleLegacyRootUIMouseUp(float x, float y);
// Return the root widget containing all windows & dialogs
// Whenever this contains children, the UI is considered to be in focus
auto screen_root_widget() -> ui_v1::ContainerWidget* {
return screen_root_widget_.Get();
}
auto overlay_root_widget() -> ui_v1::ContainerWidget* {
return overlay_root_widget_.Get();
}
auto PartyWindowOpen() -> bool;
/// Return whether there is UI present in either the main or overlay
/// stacks. Generally this implies the focus should be on the UI.
auto IsWindowPresent() const -> bool;
// Return the absolute root widget; this includes persistent UI
// bits such as the top/bottom bars
auto root_widget() -> ui_v1::RootWidget* { return root_widget_.Get(); }
// auto IsWindowPresent() const -> bool;
void Draw(FrameDef* frame_def);
@ -92,11 +81,6 @@ class UI {
// so only call this if you intend on sending a message to that widget.
auto GetWidgetForInput(InputDevice* input_device) -> ui_v1::Widget*;
// Add a widget to a container.
// If a parent is provided, the widget is added to it; otherwise it is added
// to the root widget.
void AddWidget(ui_v1::Widget* w, ui_v1::ContainerWidget* to);
// Send message to the active widget.
auto SendWidgetMessage(const WidgetMessage& msg) -> int;
@ -130,11 +114,6 @@ class UI {
BA_DISALLOW_CLASS_COPIES(UILock);
};
auto root_ui() const -> ui_v1::RootUI* {
assert(root_ui_);
return root_ui_;
}
auto scale() const { return scale_; }
/// Push a generic 'menu press' event, optionally associated with an
@ -145,13 +124,9 @@ class UI {
private:
void MainMenuPress(InputDevice* device);
ui_v1::RootUI* root_ui_{};
Object::WeakRef<InputDevice> ui_input_device_;
millisecs_t last_input_device_use_time_{};
millisecs_t last_widget_input_reject_err_sound_time_{};
Object::Ref<ui_v1::ContainerWidget> screen_root_widget_;
Object::Ref<ui_v1::ContainerWidget> overlay_root_widget_;
Object::Ref<ui_v1::RootWidget> root_widget_;
int ui_lock_count_{};
UIScale scale_{UIScale::kLarge};
bool force_scale_{};

View File

@ -42,8 +42,8 @@ void CoreFeatureSet::DoImport(const CoreConfig& config) {
g_core = new CoreFeatureSet(config);
g_core->PostInit();
// Slightly hacky: have to report our begin time after the fact since
// core didn't exist before. Can at least add an offset to give an accurate
// Slightly hacky: have to report our begin time after the fact since core
// didn't exist before. Can at least add an offset to give an accurate
// time though.
auto seconds_since_actual_start =
static_cast<double>(CorePlatform::GetCurrentMillisecs() - start_millisecs)
@ -67,14 +67,14 @@ void CoreFeatureSet::PostInit() {
// Some of this stuff accesses g_core so we need to run it *after*
// assigning our singleton.
// Test our static-type-name functionality.
// This code runs at compile time and extracts human readable type names using
// __PRETTY_FUNCTION__ type functionality. However, it is dependent on
// specific compiler output and so could break easily if anything changes.
// Here we add some compile-time checks to alert us if that happens.
// Test our static-type-name functionality. This code runs at compile time
// and extracts human readable type names using __PRETTY_FUNCTION__ type
// functionality. However, it is dependent on specific compiler output and
// so could break easily if anything changes. Here we add some
// compile-time checks to alert us if that happens.
// Remember that results can vary per compiler; make sure we match
// any one of the expected formats.
// Remember that results can vary per compiler; make sure we match any one
// of the expected formats.
static_assert(static_type_name_constexpr<decltype(g_core)>()
== "ballistica::core::CoreFeatureSet *"
|| static_type_name_constexpr<decltype(g_core)>()
@ -94,13 +94,10 @@ void CoreFeatureSet::PostInit() {
|| static_type_name_constexpr<decltype(testrunnable)>()
== "Object::Ref<Runnable>");
// int testint{};
// static_assert(static_type_name_constexpr<decltype(testint)>() == "int");
// If anything above breaks, enable this code to debug/fix it.
// This will print a calculated type name as well as the full string
// it was parsed from. Use this to adjust the filtering as necessary so
// the resulting type name matches what is expected.
// If anything above breaks, enable this code to debug/fix it. This will
// print a calculated type name as well as the full string it was parsed
// from. Use this to adjust the filtering as necessary so the resulting
// type name matches what is expected.
if (explicit_bool(false)) {
Log(LogLevel::kError, "static_type_name check; name is '"
+ static_type_name<decltype(g_core)>()

View File

@ -1117,7 +1117,7 @@ void SceneV1AppMode::LocalDisplayChatMessage(
// Show it on the screen if they don't have their chat window open
// (and don't have chat muted).
if (!g_base->ui->root_ui()->party_window_open()) {
if (!g_base->ui->PartyWindowOpen()) {
if (!chat_muted_) {
ScreenMessage(final_message, {0.7f, 1.0f, 0.7f});
}

View File

@ -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 = 21040;
const int kEngineBuildNumber = 21041;
const char* kEngineVersion = "1.7.20";
auto MonolithicMain(const core::CoreConfig& core_config) -> int {

View File

@ -263,7 +263,7 @@ static auto PyButtonWidget(PyObject* self, PyObject* args, PyObject* keywds)
}
} else {
parent_widget = parent_obj == Py_None
? g_base->ui->screen_root_widget()
? g_ui_v1->screen_root_widget()
: dynamic_cast<ContainerWidget*>(
UIV1Python::GetPyWidget(parent_obj));
if (parent_widget == nullptr) {
@ -445,7 +445,7 @@ static auto PyButtonWidget(PyObject* self, PyObject* args, PyObject* keywds)
// If making a new widget add it at the end.
if (edit_obj == Py_None) {
g_base->ui->AddWidget(b.Get(), parent_widget);
g_ui_v1->AddWidget(b.Get(), parent_widget);
}
return b->NewPyRef();
@ -566,7 +566,7 @@ static auto PyCheckBoxWidget(PyObject* self, PyObject* args, PyObject* keywds)
}
} else {
parent_widget = parent_obj == Py_None
? g_base->ui->screen_root_widget()
? g_ui_v1->screen_root_widget()
: dynamic_cast<ContainerWidget*>(
UIV1Python::GetPyWidget(parent_obj));
if (parent_widget == nullptr) {
@ -634,7 +634,7 @@ static auto PyCheckBoxWidget(PyObject* self, PyObject* args, PyObject* keywds)
// if making a new widget add it at the end
if (edit_obj == Py_None) {
g_base->ui->AddWidget(widget.Get(), parent_widget);
g_ui_v1->AddWidget(widget.Get(), parent_widget);
}
return widget->NewPyRef();
@ -738,7 +738,7 @@ static auto PyImageWidget(PyObject* self, PyObject* args, PyObject* keywds)
PyExcType::kWidgetNotFound);
} else {
parent_widget = parent_obj == Py_None
? g_base->ui->screen_root_widget()
? g_ui_v1->screen_root_widget()
: dynamic_cast<ContainerWidget*>(
UIV1Python::GetPyWidget(parent_obj));
if (parent_widget == nullptr) {
@ -822,7 +822,7 @@ static auto PyImageWidget(PyObject* self, PyObject* args, PyObject* keywds)
// if making a new widget add it at the end
if (edit_obj == Py_None) {
g_base->ui->AddWidget(b.Get(), parent_widget);
g_ui_v1->AddWidget(b.Get(), parent_widget);
}
return b->NewPyRef();
@ -928,7 +928,7 @@ static auto PyColumnWidget(PyObject* self, PyObject* args, PyObject* keywds)
}
} else {
parent_widget = parent_obj == Py_None
? g_base->ui->screen_root_widget()
? g_ui_v1->screen_root_widget()
: dynamic_cast<ContainerWidget*>(
UIV1Python::GetPyWidget(parent_obj));
if (!parent_widget) {
@ -992,7 +992,7 @@ static auto PyColumnWidget(PyObject* self, PyObject* args, PyObject* keywds)
// if making a new widget add it at the end
if (edit_obj == Py_None) {
g_base->ui->AddWidget(widget.Get(), parent_widget);
g_ui_v1->AddWidget(widget.Get(), parent_widget);
}
return widget->NewPyRef();
@ -1134,11 +1134,10 @@ static auto PyContainerWidget(PyObject* self, PyObject* args, PyObject* keywds)
}
} else {
if (parent_obj == Py_None) {
BA_PRECONDITION(g_base && g_base->ui
&& g_base->ui->screen_root_widget() != nullptr);
BA_PRECONDITION(g_ui_v1 && g_ui_v1->screen_root_widget() != nullptr);
}
parent_widget = parent_obj == Py_None
? g_base->ui->screen_root_widget()
? g_ui_v1->screen_root_widget()
: dynamic_cast<ContainerWidget*>(
UIV1Python::GetPyWidget(parent_obj));
if (!parent_widget) {
@ -1146,7 +1145,7 @@ static auto PyContainerWidget(PyObject* self, PyObject* args, PyObject* keywds)
PyExcType::kWidgetNotFound);
}
widget = Object::New<ContainerWidget>();
g_base->ui->AddWidget(widget.Get(), parent_widget);
g_ui_v1->AddWidget(widget.Get(), parent_widget);
}
// Set applicable values.
@ -1402,7 +1401,7 @@ static auto PyRowWidget(PyObject* self, PyObject* args, PyObject* keywds)
}
} else {
parent_widget = parent_obj == Py_None
? g_base->ui->screen_root_widget()
? g_ui_v1->screen_root_widget()
: dynamic_cast<ContainerWidget*>(
UIV1Python::GetPyWidget(parent_obj));
if (!parent_widget) {
@ -1445,7 +1444,7 @@ static auto PyRowWidget(PyObject* self, PyObject* args, PyObject* keywds)
// If making a new widget, add it to the parent.
if (edit_obj == Py_None) {
g_base->ui->AddWidget(widget.Get(), parent_widget);
g_ui_v1->AddWidget(widget.Get(), parent_widget);
}
return widget->NewPyRef();
@ -1547,7 +1546,7 @@ static auto PyScrollWidget(PyObject* self, PyObject* args, PyObject* keywds)
}
} else {
parent_widget = parent_obj == Py_None
? g_base->ui->screen_root_widget()
? g_ui_v1->screen_root_widget()
: dynamic_cast<ContainerWidget*>(
UIV1Python::GetPyWidget(parent_obj));
if (!parent_widget) {
@ -1618,7 +1617,7 @@ static auto PyScrollWidget(PyObject* self, PyObject* args, PyObject* keywds)
// If making a new widget add it at the end.
if (edit_obj == Py_None) {
g_base->ui->AddWidget(widget.Get(), parent_widget);
g_ui_v1->AddWidget(widget.Get(), parent_widget);
}
return widget->NewPyRef();
@ -1725,7 +1724,7 @@ static auto PyHScrollWidget(PyObject* self, PyObject* args, PyObject* keywds)
}
} else {
parent_widget = parent_obj == Py_None
? g_base->ui->screen_root_widget()
? g_ui_v1->screen_root_widget()
: dynamic_cast<ContainerWidget*>(
UIV1Python::GetPyWidget(parent_obj));
if (!parent_widget) {
@ -1791,7 +1790,7 @@ static auto PyHScrollWidget(PyObject* self, PyObject* args, PyObject* keywds)
// if making a new widget add it at the end
if (edit_obj == Py_None) {
g_base->ui->AddWidget(widget.Get(), parent_widget);
g_ui_v1->AddWidget(widget.Get(), parent_widget);
}
return widget->NewPyRef();
@ -1943,7 +1942,7 @@ static auto PyTextWidget(PyObject* self, PyObject* args, PyObject* keywds)
}
} else {
parent_widget = parent_obj == Py_None
? g_base->ui->screen_root_widget()
? g_ui_v1->screen_root_widget()
: dynamic_cast<ContainerWidget*>(
UIV1Python::GetPyWidget(parent_obj));
if (!parent_widget) {
@ -2099,7 +2098,7 @@ static auto PyTextWidget(PyObject* self, PyObject* args, PyObject* keywds)
// if making a new widget add it at the end
if (edit_obj == Py_None) {
g_base->ui->AddWidget(widget.Get(), parent_widget);
g_ui_v1->AddWidget(widget.Get(), parent_widget);
}
return widget->NewPyRef();
@ -2545,7 +2544,7 @@ static auto PySetPartyIconAlwaysVisible(PyObject* self, PyObject* args,
return nullptr;
}
assert(g_base->input);
g_base->ui->root_ui()->set_always_draw_party_icon(static_cast<bool>(value));
g_ui_v1->root_ui()->set_always_draw_party_icon(static_cast<bool>(value));
Py_RETURN_NONE;
BA_PYTHON_CATCH;
}
@ -2572,7 +2571,7 @@ static auto PySetPartyWindowOpen(PyObject* self, PyObject* args,
return nullptr;
}
assert(g_base->input);
g_base->ui->root_ui()->set_party_window_open(static_cast<bool>(value));
g_ui_v1->root_ui()->set_party_window_open(static_cast<bool>(value));
Py_RETURN_NONE;
BA_PYTHON_CATCH;
}
@ -2600,7 +2599,7 @@ static auto PyGetSpecialWidget(PyObject* self, PyObject* args, PyObject* keywds)
return nullptr;
}
BA_PRECONDITION(g_base->InLogicThread());
RootWidget* root_widget = g_base->ui->root_widget();
RootWidget* root_widget = g_ui_v1->root_widget();
BA_PRECONDITION(root_widget);
Widget* w = root_widget->GetSpecialWidget(name);
if (w == nullptr) {
@ -2872,10 +2871,9 @@ static PyMethodDef PyConsolePrintDef = {
static auto PyIsPartyIconVisible(PyObject* self, PyObject* args,
PyObject* keywds) -> PyObject* {
BA_PYTHON_TRY;
bool party_button_active =
(g_base->app_mode()->HasConnectionToClients()
|| g_base->app_mode()->HasConnectionToHost()
|| g_base->ui->root_ui()->always_draw_party_icon());
bool party_button_active = (g_base->app_mode()->HasConnectionToClients()
|| g_base->app_mode()->HasConnectionToHost()
|| g_ui_v1->root_ui()->always_draw_party_icon());
if (party_button_active) {
Py_RETURN_TRUE;
} else {

View File

@ -59,8 +59,8 @@ void RootUI::ActivatePartyIcon() const {
- menu_button_size_ * 0.5f;
float icon_pos_v = g_base->graphics->screen_virtual_height() * 0.5f
- menu_button_size_ * 0.5f;
bool menu_active = !(g_base->ui && g_base->ui->screen_root_widget()
&& g_base->ui->screen_root_widget()->HasChildren());
bool menu_active = !(g_ui_v1 && g_ui_v1->screen_root_widget()
&& g_ui_v1->screen_root_widget()->HasChildren());
if (menu_active) {
icon_pos_h -= menu_button_size_;
}
@ -71,8 +71,8 @@ void RootUI::ActivatePartyIcon() const {
auto RootUI::HandleMouseButtonDown(float x, float y) -> bool {
// Whether the menu button is visible/active.
bool menu_active = !(g_base->ui && g_base->ui->screen_root_widget()
&& g_base->ui->screen_root_widget()->HasChildren());
bool menu_active = !(g_ui_v1 && g_ui_v1->screen_root_widget()
&& g_ui_v1->screen_root_widget()->HasChildren());
// Handle party button presses (need to do this before UI since it
// floats over the top). Party button is to the left of menu button.
@ -150,8 +150,8 @@ void RootUI::Draw(base::FrameDef* frame_def) {
// Menu button.
// Update time-dependent stuff to this point.
bool active = !(g_base->ui && g_base->ui->screen_root_widget()
&& g_base->ui->screen_root_widget()->HasChildren());
bool active = !(g_ui_v1 && g_ui_v1->screen_root_widget()
&& g_ui_v1->screen_root_widget()->HasChildren());
if (real_time - menu_update_time_ > 500) {
menu_update_time_ = real_time - 500;
}

View File

@ -3,10 +3,15 @@
#include "ballistica/ui_v1/ui_v1.h"
#include "ballistica/base/app/app_mode.h"
#include "ballistica/base/graphics/component/empty_component.h"
#include "ballistica/base/graphics/graphics.h"
#include "ballistica/base/input/input.h"
#include "ballistica/base/ui/ui.h"
#include "ballistica/ui_v1/python/ui_v1_python.h"
#include "ballistica/ui_v1/support/root_ui.h"
#include "ballistica/ui_v1/widget/container_widget.h"
#include "ballistica/ui_v1/widget/root_widget.h"
#include "ballistica/ui_v1/widget/stack_widget.h"
namespace ballistica::ui_v1 {
@ -77,8 +82,8 @@ RootUI* UIV1FeatureSet::NewRootUI() { return new RootUI(); }
bool UIV1FeatureSet::MainMenuVisible() {
// We consider anything on our screen or overlay stacks to be a 'main menu'.
// Probably need a better name than 'main menu' though.
auto* screen_root = g_base->ui->screen_root_widget();
auto* overlay_root = g_base->ui->overlay_root_widget();
auto* screen_root = screen_root_widget();
auto* overlay_root = overlay_root_widget();
return ((screen_root && screen_root->HasChildren())
|| (overlay_root && overlay_root->HasChildren()));
}
@ -86,35 +91,180 @@ bool UIV1FeatureSet::MainMenuVisible() {
bool UIV1FeatureSet::PartyIconVisible() {
int party_size = g_base->app_mode()->GetPartySize();
if (party_size > 1 || g_base->app_mode()->HasConnectionToHost()
|| g_base->ui->root_ui()->always_draw_party_icon()) {
|| root_ui()->always_draw_party_icon()) {
return true;
}
return false;
}
void UIV1FeatureSet::ActivatePartyIcon() {
if (auto* root_ui = g_base->ui->root_ui()) {
root_ui->ActivatePartyIcon();
if (auto* r = root_ui()) {
r->ActivatePartyIcon();
}
}
bool UIV1FeatureSet::PartyWindowOpen() {
if (auto* r = root_ui()) {
return r->party_window_open();
}
return false;
}
void UIV1FeatureSet::HandleLegacyRootUIMouseMotion(float x, float y) {
if (auto* root_ui = g_base->ui->root_ui()) {
root_ui->HandleMouseMotion(x, y);
if (auto* r = root_ui()) {
r->HandleMouseMotion(x, y);
}
}
auto UIV1FeatureSet::HandleLegacyRootUIMouseDown(float x, float y) -> bool {
if (auto* root_ui = g_base->ui->root_ui()) {
return root_ui->HandleMouseButtonDown(x, y);
if (auto* r = root_ui()) {
return r->HandleMouseButtonDown(x, y);
}
return false;
}
void UIV1FeatureSet::HandleLegacyRootUIMouseUp(float x, float y) {
if (auto* root_ui = g_base->ui->root_ui()) {
root_ui->HandleMouseButtonUp(x, y);
if (auto* r = root_ui()) {
r->HandleMouseButtonUp(x, y);
}
}
void UIV1FeatureSet::Draw(base::FrameDef* frame_def) {
base::RenderPass* overlay_flat_pass = frame_def->GetOverlayFlatPass();
// Draw interface elements.
auto* root_widget = root_widget_.Get();
if (root_widget && root_widget->HasChildren()) {
// Draw our opaque and transparent parts separately.
// This way we can draw front-to-back for opaque and back-to-front for
// transparent.
g_base->graphics->set_drawing_opaque_only(true);
// Do a wee bit of shifting based on tilt just for fun.
Vector3f tilt = 0.1f * g_base->graphics->tilt();
{
base::EmptyComponent c(overlay_flat_pass);
c.SetTransparent(false);
c.PushTransform();
c.Translate(-tilt.y, tilt.x, -0.5f);
// We want our widgets to cover 0.1f in z space.
c.Scale(1.0f, 1.0f, 0.1f);
c.Submit();
root_widget->Draw(overlay_flat_pass, false);
c.PopTransform();
c.Submit();
}
g_base->graphics->set_drawing_opaque_only(false);
g_base->graphics->set_drawing_transparent_only(true);
{
base::EmptyComponent c(overlay_flat_pass);
c.SetTransparent(true);
c.PushTransform();
c.Translate(-tilt.y, tilt.x, -0.5f);
// We want our widgets to cover 0.1f in z space.
c.Scale(1.0f, 1.0f, 0.1f);
c.Submit();
root_widget->Draw(overlay_flat_pass, true);
c.PopTransform();
c.Submit();
}
g_base->graphics->set_drawing_transparent_only(false);
}
if (auto* r = root_ui()) {
r->Draw(frame_def);
}
}
void UIV1FeatureSet::OnAppStart() {
assert(g_base->InLogicThread());
root_ui_ = g_base->ui_v1()->NewRootUI();
}
void UIV1FeatureSet::Reset() {
// Hmm; technically we don't need to recreate these each time we reset.
root_widget_.Clear();
// Kill our screen-root widget.
screen_root_widget_.Clear();
// (Re)create our screen-root widget.
auto sw(Object::New<ui_v1::StackWidget>());
sw->set_is_main_window_stack(true);
sw->SetWidth(g_base->graphics->screen_virtual_width());
sw->SetHeight(g_base->graphics->screen_virtual_height());
sw->set_translate(0, 0);
screen_root_widget_ = sw;
// (Re)create our screen-overlay widget.
auto ow(Object::New<ui_v1::StackWidget>());
ow->set_is_overlay_window_stack(true);
ow->SetWidth(g_base->graphics->screen_virtual_width());
ow->SetHeight(g_base->graphics->screen_virtual_height());
ow->set_translate(0, 0);
overlay_root_widget_ = ow;
// (Re)create our abs-root widget.
auto rw(Object::New<ui_v1::RootWidget>());
root_widget_ = rw;
rw->SetWidth(g_base->graphics->screen_virtual_width());
rw->SetHeight(g_base->graphics->screen_virtual_height());
rw->SetScreenWidget(sw.Get());
rw->Setup();
rw->SetOverlayWidget(ow.Get());
sw->GlobalSelect();
}
void UIV1FeatureSet::AddWidget(Widget* w, ContainerWidget* parent) {
assert(g_base->InLogicThread());
BA_PRECONDITION(parent != nullptr);
// If they're adding an initial window/dialog to our screen-stack
// or overlay stack, send a reset-local-input message so that characters
// who have lost focus will not get stuck running or whatnot.
// We should come up with a more generalized way to track this sort of
// focus as this is a bit hacky, but it works for now.
auto* screen_root_widget = screen_root_widget_.Get();
auto* overlay_root_widget = overlay_root_widget_.Get();
if ((screen_root_widget && !screen_root_widget->HasChildren()
&& parent == screen_root_widget)
|| (overlay_root_widget && !overlay_root_widget->HasChildren()
&& parent == overlay_root_widget)) {
g_base->input->ResetHoldStates();
}
parent->AddWidget(w);
}
void UIV1FeatureSet::OnScreenSizeChange() {
if (root_widget_.Exists()) {
root_widget_->SetWidth(g_base->graphics->screen_virtual_width());
root_widget_->SetHeight(g_base->graphics->screen_virtual_height());
}
}
void UIV1FeatureSet::OnLanguageChange() {
// As well as existing UI stuff.
if (auto* r = root_widget()) {
r->OnLanguageChange();
}
}
Widget* UIV1FeatureSet::GetRootWidget() { return root_widget(); }
auto UIV1FeatureSet::SendWidgetMessage(const base::WidgetMessage& m) -> int {
if (!root_widget_.Exists()) {
return false;
}
return root_widget_->HandleMessage(m);
}
} // namespace ballistica::ui_v1

View File

@ -18,7 +18,8 @@ class CoreFeatureSet;
}
namespace ballistica::base {
class BaseFeatureSet;
}
class WidgetMessage;
} // namespace ballistica::base
namespace ballistica::ui_v1 {
@ -64,11 +65,48 @@ class UIV1FeatureSet : public FeatureSetNativeComponent,
void HandleLegacyRootUIMouseMotion(float x, float y) override;
auto HandleLegacyRootUIMouseDown(float x, float y) -> bool override;
void HandleLegacyRootUIMouseUp(float x, float y) override;
void Draw(base::FrameDef* frame_def) override;
UIV1Python* const python;
auto root_ui() const -> ui_v1::RootUI* {
assert(root_ui_);
return root_ui_;
}
void OnAppStart() override;
auto PartyWindowOpen() -> bool override;
// Return the root widget containing all windows & dialogs
// Whenever this contains children, the UI is considered to be in focus
auto screen_root_widget() -> ui_v1::ContainerWidget* {
return screen_root_widget_.Get();
}
auto overlay_root_widget() -> ui_v1::ContainerWidget* {
return overlay_root_widget_.Get();
}
// Return the absolute root widget; this includes persistent UI
// bits such as the top/bottom bars
auto root_widget() -> ui_v1::RootWidget* { return root_widget_.Get(); }
void Reset() override;
// Add a widget to a container.
// If a parent is provided, the widget is added to it; otherwise it is added
// to the root widget.
void AddWidget(Widget* w, ContainerWidget* to);
void OnScreenSizeChange() override;
void OnLanguageChange() override;
auto GetRootWidget() -> ui_v1::Widget* override;
auto SendWidgetMessage(const base::WidgetMessage& m) -> int override;
private:
UIV1FeatureSet();
RootUI* root_ui_{};
Object::Ref<ContainerWidget> screen_root_widget_;
Object::Ref<ContainerWidget> overlay_root_widget_;
Object::Ref<RootWidget> root_widget_;
};
} // namespace ballistica::ui_v1

View File

@ -1086,7 +1086,7 @@ void ContainerWidget::AddWidget(Widget* w) {
// direct selected child (which may not affect the global selection).
if (is_window_stack_
&& (is_overlay_window_stack_
|| !g_base->ui->root_widget()
|| !g_ui_v1->root_widget()
->overlay_window_stack()
->HasChildren())) {
w->GlobalSelect();
@ -1094,7 +1094,7 @@ void ContainerWidget::AddWidget(Widget* w) {
// Special case for the main window stack; whenever a window is added,
// update the toolbar state for the topmost living container.
if (is_main_window_stack_) {
g_base->ui->root_widget()->UpdateForFocusedWindow();
g_ui_v1->root_widget()->UpdateForFocusedWindow();
}
} else {
SelectWidget(w);
@ -1232,7 +1232,7 @@ void ContainerWidget::SetTransition(TransitionType t) {
// *immediately* (otherwise we'd have to wait for our transition to complete
// before the toolbar switches).
if (transitioning_ && transitioning_out_ && parent->is_main_window_stack_) {
g_base->ui->root_widget()->UpdateForFocusedWindow();
g_ui_v1->root_widget()->UpdateForFocusedWindow();
}
}
@ -1275,7 +1275,7 @@ void ContainerWidget::DeleteWidget(Widget* w) {
if (is_overlay_window_stack_) {
if (widgets_.empty()) {
// Eww this logic should be in some sort of controller.
g_base->ui->root_widget()->ReselectLastSelectedWidget();
g_ui_v1->root_widget()->ReselectLastSelectedWidget();
return;
}
}
@ -1293,7 +1293,7 @@ void ContainerWidget::DeleteWidget(Widget* w) {
// direct selected child (which may not affect the global selection).
if (is_window_stack_
&& (is_overlay_window_stack_
|| !g_base->ui->root_widget()
|| !g_ui_v1->root_widget()
->overlay_window_stack()
->HasChildren())) {
(**i).GlobalSelect();
@ -1308,7 +1308,7 @@ void ContainerWidget::DeleteWidget(Widget* w) {
// Special case: if we're the main window stack,
// update the active toolbar/etc.
if (is_main_window_stack_) {
g_base->ui->root_widget()->UpdateForFocusedWindow();
g_ui_v1->root_widget()->UpdateForFocusedWindow();
}
}
@ -1559,8 +1559,7 @@ auto ContainerWidget::GetClosestDownWidget(float our_x, float our_y,
void ContainerWidget::SelectDownWidget() {
BA_DEBUG_UI_READ_LOCK;
if (!g_base->ui || !g_base->ui->root_widget()
|| !g_base->ui->screen_root_widget()) {
if (!g_ui_v1 || !g_ui_v1->root_widget() || !g_ui_v1->screen_root_widget()) {
BA_LOG_ONCE(LogLevel::kError, "SelectDownWidget called before UI init.");
return;
}
@ -1581,9 +1580,9 @@ void ContainerWidget::SelectDownWidget() {
float x = our_x;
float y = our_y;
WidgetPointToScreen(&x, &y);
g_base->ui->root_widget()->ScreenPointToWidget(&x, &y);
w = g_base->ui->root_widget()->GetClosestDownWidget(
x, y, g_base->ui->screen_root_widget());
g_ui_v1->root_widget()->ScreenPointToWidget(&x, &y);
w = g_ui_v1->root_widget()->GetClosestDownWidget(
x, y, g_ui_v1->screen_root_widget());
}
// When we find no viable targets for an autoselect widget we do
// nothing.
@ -1625,8 +1624,7 @@ void ContainerWidget::SelectDownWidget() {
void ContainerWidget::SelectUpWidget() {
BA_DEBUG_UI_READ_LOCK;
if (!g_base->ui || !g_base->ui->root_widget()
|| !g_base->ui->screen_root_widget()) {
if (!g_ui_v1 || !g_ui_v1->root_widget() || !g_ui_v1->screen_root_widget()) {
BA_LOG_ONCE(LogLevel::kError, "SelectUpWidget called before UI init.");
return;
}
@ -1647,9 +1645,9 @@ void ContainerWidget::SelectUpWidget() {
float x = our_x;
float y = our_y;
WidgetPointToScreen(&x, &y);
g_base->ui->root_widget()->ScreenPointToWidget(&x, &y);
w = g_base->ui->root_widget()->GetClosestUpWidget(
x, y, g_base->ui->screen_root_widget());
g_ui_v1->root_widget()->ScreenPointToWidget(&x, &y);
w = g_ui_v1->root_widget()->GetClosestUpWidget(
x, y, g_ui_v1->screen_root_widget());
}
// When we find no viable targets for an autoselect widget we do
// nothing.
@ -1691,8 +1689,7 @@ void ContainerWidget::SelectUpWidget() {
void ContainerWidget::SelectLeftWidget() {
BA_DEBUG_UI_READ_LOCK;
if (!g_base->ui || !g_base->ui->root_widget()
|| !g_base->ui->screen_root_widget()) {
if (!g_ui_v1 || !g_ui_v1->root_widget() || !g_ui_v1->screen_root_widget()) {
BA_LOG_ONCE(LogLevel::kError, "SelectLeftWidget called before UI init.");
return;
}
@ -1743,8 +1740,8 @@ void ContainerWidget::SelectLeftWidget() {
void ContainerWidget::SelectRightWidget() {
BA_DEBUG_UI_READ_LOCK;
if (!g_base->ui || !g_base->ui->root_widget()
|| !g_base->ui->screen_root_widget()) {
if (!g_base->ui || !g_ui_v1->root_widget()
|| !g_ui_v1->screen_root_widget()) {
BA_LOG_ONCE(LogLevel::kError, "SelectRightWidget called before UI init.");
return;
}
@ -1797,8 +1794,8 @@ void ContainerWidget::SelectRightWidget() {
void ContainerWidget::SelectNextWidget() {
BA_DEBUG_UI_READ_LOCK;
if (!g_base->ui || !g_base->ui->root_widget()
|| !g_base->ui->screen_root_widget()) {
if (!g_base->ui || !g_ui_v1->root_widget()
|| !g_ui_v1->screen_root_widget()) {
BA_LOG_ONCE(LogLevel::kError, "SelectNextWidget called before UI init.");
return;
}

View File

@ -33,7 +33,7 @@ void Widget::SetToolbarVisibility(ToolbarVisibility v) {
// Most widgets can never influence the global toolbar so we can
// do a quick out.
if (parent_widget_ != nullptr && parent_widget_->is_window_stack()) {
g_base->ui->root_widget()->UpdateForFocusedWindow();
g_ui_v1->root_widget()->UpdateForFocusedWindow();
}
}
@ -52,7 +52,7 @@ auto Widget::IsInMainStack() const -> bool {
}
// Navigate up to the top of the hierarchy and see if the
// screen-root widget is in there somewhere.
ContainerWidget* screen_root = g_base->ui->screen_root_widget();
ContainerWidget* screen_root = g_ui_v1->screen_root_widget();
assert(screen_root);
if (!screen_root) {
return false;
@ -70,7 +70,7 @@ auto Widget::IsInMainStack() const -> bool {
auto Widget::IsInOverlayStack() const -> bool {
// Navigate up to the top of the hierarchy and see if the overlay-root widget
// is in there somewhere.
ContainerWidget* overlay_root = g_base->ui->overlay_root_widget();
ContainerWidget* overlay_root = g_ui_v1->overlay_root_widget();
assert(overlay_root);
ContainerWidget* parent = parent_widget_;
while (parent != nullptr) {
@ -99,7 +99,7 @@ auto Widget::IsHierarchySelected() const -> bool {
return false;
}
p = p->GetOwnerWidget();
if (!p || p == g_base->ui->root_widget()) {
if (!p || p == g_ui_v1->root_widget()) {
break;
}
}