2017-03-19 15:41:48 -07:00
|
|
|
#include <algorithm>
|
2016-01-22 22:40:16 -08:00
|
|
|
#include <map>
|
2020-08-10 01:30:58 -07:00
|
|
|
#include <sstream>
|
2020-08-15 16:13:24 +02:00
|
|
|
|
2020-10-04 10:10:55 +02:00
|
|
|
#include "Common/System/Display.h"
|
2020-10-01 09:36:43 +02:00
|
|
|
#include "Common/Input/InputState.h"
|
|
|
|
|
#include "Common/Input/KeyCodes.h"
|
2020-10-04 00:25:21 +02:00
|
|
|
#include "Common/Math/curves.h"
|
2020-10-04 20:48:47 +02:00
|
|
|
#include "Common/UI/UIScreen.h"
|
|
|
|
|
#include "Common/UI/Context.h"
|
|
|
|
|
#include "Common/UI/Screen.h"
|
|
|
|
|
#include "Common/UI/Root.h"
|
2020-10-01 13:05:04 +02:00
|
|
|
#include "Common/Data/Text/I18n.h"
|
2020-10-04 23:24:14 +02:00
|
|
|
#include "Common/Render/DrawBuffer.h"
|
2022-08-27 17:33:37 +02:00
|
|
|
#include "Common/VR/PPSSPPVR.h"
|
2013-06-03 19:57:40 +02:00
|
|
|
|
2020-08-15 16:13:24 +02:00
|
|
|
#include "Common/Log.h"
|
2020-09-29 12:19:22 +02:00
|
|
|
#include "Common/StringUtils.h"
|
2020-08-15 16:13:24 +02:00
|
|
|
|
2015-10-31 13:43:33 +01:00
|
|
|
static const bool ClickDebug = false;
|
|
|
|
|
|
2013-06-08 22:41:17 +02:00
|
|
|
UIScreen::UIScreen()
|
2020-03-23 07:58:24 -07:00
|
|
|
: Screen() {
|
2013-06-08 22:41:17 +02:00
|
|
|
}
|
|
|
|
|
|
2013-11-26 13:56:56 +01:00
|
|
|
UIScreen::~UIScreen() {
|
|
|
|
|
delete root_;
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-21 13:30:47 +02:00
|
|
|
void UIScreen::DoRecreateViews() {
|
2013-06-08 22:41:17 +02:00
|
|
|
if (recreateViews_) {
|
2021-02-21 16:45:31 -08:00
|
|
|
std::lock_guard<std::recursive_mutex> guard(screenManager()->inputLock_);
|
|
|
|
|
|
2016-01-22 22:40:16 -08:00
|
|
|
UI::PersistMap persisted;
|
|
|
|
|
bool persisting = root_ != nullptr;
|
|
|
|
|
if (persisting) {
|
2016-01-23 01:59:25 -08:00
|
|
|
root_->PersistData(UI::PERSIST_SAVE, "root", persisted);
|
2016-01-22 22:40:16 -08:00
|
|
|
}
|
|
|
|
|
|
2013-06-03 19:57:40 +02:00
|
|
|
delete root_;
|
2016-01-22 22:40:16 -08:00
|
|
|
root_ = nullptr;
|
2013-06-03 19:57:40 +02:00
|
|
|
CreateViews();
|
2017-12-29 17:55:37 -08:00
|
|
|
UI::View *defaultView = root_ ? root_->GetDefaultFocusView() : nullptr;
|
|
|
|
|
if (defaultView && defaultView->GetVisibility() == UI::V_VISIBLE) {
|
|
|
|
|
defaultView->SetFocus();
|
2014-03-03 11:39:06 +01:00
|
|
|
}
|
2013-06-09 01:21:08 +02:00
|
|
|
recreateViews_ = false;
|
2016-01-22 22:40:16 -08:00
|
|
|
|
2016-01-23 01:59:25 -08:00
|
|
|
if (persisting && root_ != nullptr) {
|
|
|
|
|
root_->PersistData(UI::PERSIST_RESTORE, "root", persisted);
|
2016-01-23 02:23:04 -08:00
|
|
|
|
|
|
|
|
// Update layout and refocus so things scroll into view.
|
|
|
|
|
// This is for resizing down, when focused on something now offscreen.
|
2020-05-31 23:20:13 +02:00
|
|
|
UI::LayoutViewHierarchy(*screenManager()->getUIContext(), root_, ignoreInsets_);
|
2016-01-23 02:23:04 -08:00
|
|
|
UI::View *focused = UI::GetFocusedView();
|
|
|
|
|
if (focused) {
|
|
|
|
|
root_->SubviewFocused(focused);
|
|
|
|
|
}
|
2016-01-22 22:40:16 -08:00
|
|
|
}
|
2013-06-03 19:57:40 +02:00
|
|
|
}
|
2013-07-21 13:30:47 +02:00
|
|
|
}
|
|
|
|
|
|
2017-03-14 22:01:18 -07:00
|
|
|
void UIScreen::update() {
|
2013-07-21 13:30:47 +02:00
|
|
|
DoRecreateViews();
|
2013-06-03 19:57:40 +02:00
|
|
|
|
2013-07-20 12:04:24 +02:00
|
|
|
if (root_) {
|
2017-03-14 22:01:18 -07:00
|
|
|
UpdateViewHierarchy(root_);
|
2013-07-20 12:04:24 +02:00
|
|
|
}
|
2013-06-03 19:57:40 +02:00
|
|
|
}
|
|
|
|
|
|
2018-03-27 23:10:33 +02:00
|
|
|
void UIScreen::deviceLost() {
|
|
|
|
|
if (root_)
|
|
|
|
|
root_->DeviceLost();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UIScreen::deviceRestored() {
|
|
|
|
|
if (root_)
|
|
|
|
|
root_->DeviceRestored(screenManager()->getDrawContext());
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-18 14:18:35 +01:00
|
|
|
void UIScreen::preRender() {
|
2017-05-16 16:00:34 +02:00
|
|
|
using namespace Draw;
|
2017-01-30 14:33:38 +01:00
|
|
|
Draw::DrawContext *draw = screenManager()->getDrawContext();
|
|
|
|
|
if (!draw) {
|
2016-04-09 18:21:31 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2017-05-16 13:30:10 +02:00
|
|
|
draw->BeginFrame();
|
2017-05-16 16:00:34 +02:00
|
|
|
// Bind and clear the back buffer
|
2020-05-21 11:24:05 +02:00
|
|
|
draw->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::CLEAR, RPAction::CLEAR, 0xFF000000 }, "UI");
|
2018-12-18 10:23:22 +01:00
|
|
|
screenManager()->getUIContext()->BeginFrame();
|
2015-11-18 14:18:35 +01:00
|
|
|
|
2022-08-27 17:33:37 +02:00
|
|
|
if (IsVRBuild()) {
|
|
|
|
|
BindVRFramebuffer();
|
|
|
|
|
}
|
2022-07-15 21:52:34 +02:00
|
|
|
|
2016-12-25 18:52:05 +01:00
|
|
|
Draw::Viewport viewport;
|
2015-11-18 14:18:35 +01:00
|
|
|
viewport.TopLeftX = 0;
|
|
|
|
|
viewport.TopLeftY = 0;
|
|
|
|
|
viewport.Width = pixel_xres;
|
|
|
|
|
viewport.Height = pixel_yres;
|
|
|
|
|
viewport.MaxDepth = 1.0;
|
|
|
|
|
viewport.MinDepth = 0.0;
|
2017-01-30 14:33:38 +01:00
|
|
|
draw->SetViewports(1, &viewport);
|
|
|
|
|
draw->SetTargetSize(pixel_xres, pixel_yres);
|
2015-11-18 14:18:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void UIScreen::postRender() {
|
2017-05-24 12:06:02 +02:00
|
|
|
Draw::DrawContext *draw = screenManager()->getDrawContext();
|
|
|
|
|
if (!draw) {
|
2016-04-09 18:21:31 +02:00
|
|
|
return;
|
|
|
|
|
}
|
2017-05-16 13:30:10 +02:00
|
|
|
draw->EndFrame();
|
2015-11-18 14:18:35 +01:00
|
|
|
}
|
|
|
|
|
|
2013-06-03 19:57:40 +02:00
|
|
|
void UIScreen::render() {
|
2013-07-21 13:30:47 +02:00
|
|
|
DoRecreateViews();
|
|
|
|
|
|
2013-06-08 22:41:17 +02:00
|
|
|
if (root_) {
|
2017-03-19 14:28:24 -07:00
|
|
|
UIContext *uiContext = screenManager()->getUIContext();
|
2020-05-31 23:20:13 +02:00
|
|
|
UI::LayoutViewHierarchy(*uiContext, root_, ignoreInsets_);
|
2013-06-03 19:57:40 +02:00
|
|
|
|
2017-03-19 14:28:24 -07:00
|
|
|
uiContext->PushTransform({translation_, scale_, alpha_});
|
|
|
|
|
|
|
|
|
|
uiContext->Begin();
|
|
|
|
|
DrawBackground(*uiContext);
|
|
|
|
|
root_->Draw(*uiContext);
|
|
|
|
|
uiContext->Flush();
|
|
|
|
|
|
|
|
|
|
uiContext->PopTransform();
|
2013-06-08 22:41:17 +02:00
|
|
|
}
|
2013-06-03 19:57:40 +02:00
|
|
|
}
|
|
|
|
|
|
2017-03-19 14:28:24 -07:00
|
|
|
TouchInput UIScreen::transformTouch(const TouchInput &touch) {
|
|
|
|
|
TouchInput updated = touch;
|
|
|
|
|
|
|
|
|
|
float x = touch.x - translation_.x;
|
|
|
|
|
float y = touch.y - translation_.y;
|
|
|
|
|
// Scale around the center as the origin.
|
|
|
|
|
updated.x = (x - dp_xres * 0.5f) / scale_.x + dp_xres * 0.5f;
|
|
|
|
|
updated.y = (y - dp_yres * 0.5f) / scale_.y + dp_yres * 0.5f;
|
|
|
|
|
|
|
|
|
|
return updated;
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-15 13:04:10 +02:00
|
|
|
bool UIScreen::touch(const TouchInput &touch) {
|
2013-06-08 22:41:17 +02:00
|
|
|
if (root_) {
|
2015-10-31 13:43:33 +01:00
|
|
|
if (ClickDebug && (touch.flags & TOUCH_DOWN)) {
|
2020-08-15 16:13:24 +02:00
|
|
|
INFO_LOG(SYSTEM, "Touch down!");
|
2015-10-31 13:43:33 +01:00
|
|
|
std::vector<UI::View *> views;
|
|
|
|
|
root_->Query(touch.x, touch.y, views);
|
|
|
|
|
for (auto view : views) {
|
2021-02-21 12:42:56 -08:00
|
|
|
INFO_LOG(SYSTEM, "%s", view->DescribeLog().c_str());
|
2015-10-31 13:43:33 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-12 23:07:27 +02:00
|
|
|
UI::TouchEvent(touch, root_);
|
2014-06-15 13:04:10 +02:00
|
|
|
return true;
|
2013-06-08 22:41:17 +02:00
|
|
|
}
|
2014-06-15 13:04:10 +02:00
|
|
|
return false;
|
2013-06-03 19:57:40 +02:00
|
|
|
}
|
|
|
|
|
|
2014-06-15 13:04:10 +02:00
|
|
|
bool UIScreen::key(const KeyInput &key) {
|
2013-07-08 12:34:39 +02:00
|
|
|
if (root_) {
|
2014-06-15 13:04:10 +02:00
|
|
|
return UI::KeyEvent(key, root_);
|
2013-07-08 12:34:39 +02:00
|
|
|
}
|
2014-06-15 13:04:10 +02:00
|
|
|
return false;
|
2013-07-08 12:34:39 +02:00
|
|
|
}
|
|
|
|
|
|
2017-03-19 17:43:03 -07:00
|
|
|
void UIScreen::TriggerFinish(DialogResult result) {
|
|
|
|
|
screenManager()->finishDialog(this, result);
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-15 13:04:10 +02:00
|
|
|
bool UIDialogScreen::key(const KeyInput &key) {
|
2015-02-03 00:10:38 +01:00
|
|
|
bool retval = UIScreen::key(key);
|
2015-08-28 17:05:11 +02:00
|
|
|
if (!retval && (key.flags & KEY_DOWN) && UI::IsEscapeKey(key)) {
|
2013-10-28 16:05:21 +01:00
|
|
|
if (finished_) {
|
2020-08-15 16:13:24 +02:00
|
|
|
ERROR_LOG(SYSTEM, "Screen already finished");
|
2013-10-28 16:05:21 +01:00
|
|
|
} else {
|
|
|
|
|
finished_ = true;
|
2017-03-19 17:43:03 -07:00
|
|
|
TriggerFinish(DR_BACK);
|
2020-08-03 11:58:55 +02:00
|
|
|
UI::PlayUISound(UI::UISound::BACK);
|
2013-10-28 16:05:21 +01:00
|
|
|
}
|
2014-06-15 13:04:10 +02:00
|
|
|
return true;
|
2013-08-13 00:06:23 +02:00
|
|
|
}
|
2015-02-03 00:10:38 +01:00
|
|
|
return retval;
|
2013-08-13 00:06:23 +02:00
|
|
|
}
|
|
|
|
|
|
2017-12-02 11:07:27 -08:00
|
|
|
void UIDialogScreen::sendMessage(const char *msg, const char *value) {
|
|
|
|
|
Screen *screen = screenManager()->dialogParent(this);
|
|
|
|
|
if (screen) {
|
|
|
|
|
screen->sendMessage(msg, value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-15 13:04:10 +02:00
|
|
|
bool UIScreen::axis(const AxisInput &axis) {
|
2013-08-15 22:13:57 +02:00
|
|
|
if (root_) {
|
|
|
|
|
UI::AxisEvent(axis, root_);
|
2014-06-15 13:04:10 +02:00
|
|
|
return true;
|
2013-08-15 22:13:57 +02:00
|
|
|
}
|
2020-03-23 07:58:24 -07:00
|
|
|
return false;
|
2013-08-12 23:07:27 +02:00
|
|
|
}
|
|
|
|
|
|
2013-06-03 19:57:40 +02:00
|
|
|
UI::EventReturn UIScreen::OnBack(UI::EventParams &e) {
|
2017-03-19 17:43:03 -07:00
|
|
|
TriggerFinish(DR_BACK);
|
2013-06-03 19:57:40 +02:00
|
|
|
return UI::EVENT_DONE;
|
|
|
|
|
}
|
2013-07-16 00:25:08 +02:00
|
|
|
|
2013-12-05 14:15:18 +01:00
|
|
|
UI::EventReturn UIScreen::OnOK(UI::EventParams &e) {
|
2017-03-19 17:43:03 -07:00
|
|
|
TriggerFinish(DR_OK);
|
2013-12-05 14:15:18 +01:00
|
|
|
return UI::EVENT_DONE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UI::EventReturn UIScreen::OnCancel(UI::EventParams &e) {
|
2017-03-19 17:43:03 -07:00
|
|
|
TriggerFinish(DR_CANCEL);
|
2013-12-05 14:15:18 +01:00
|
|
|
return UI::EVENT_DONE;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-16 12:51:57 +02:00
|
|
|
PopupScreen::PopupScreen(std::string title, std::string button1, std::string button2)
|
2016-05-01 09:50:03 -07:00
|
|
|
: box_(0), defaultButton_(nullptr), title_(title) {
|
2020-01-26 10:43:18 -08:00
|
|
|
auto di = GetI18NCategory("Dialog");
|
2013-11-29 11:33:51 +01:00
|
|
|
if (!button1.empty())
|
2015-07-02 14:20:04 +02:00
|
|
|
button1_ = di->T(button1.c_str());
|
2013-11-29 11:33:51 +01:00
|
|
|
if (!button2.empty())
|
2015-07-02 14:20:04 +02:00
|
|
|
button2_ = di->T(button2.c_str());
|
2017-03-19 15:41:48 -07:00
|
|
|
|
|
|
|
|
alpha_ = 0.0f;
|
2013-08-31 05:33:23 +08:00
|
|
|
}
|
2013-08-20 13:03:42 +02:00
|
|
|
|
2014-06-15 13:04:10 +02:00
|
|
|
bool PopupScreen::touch(const TouchInput &touch) {
|
2021-04-17 22:33:44 +02:00
|
|
|
if (!box_ || (touch.flags & TOUCH_DOWN) == 0) {
|
2014-06-15 13:04:10 +02:00
|
|
|
return UIDialogScreen::touch(touch);
|
2013-08-20 13:03:42 +02:00
|
|
|
}
|
|
|
|
|
|
2021-04-17 12:07:40 +02:00
|
|
|
if (!box_->GetBounds().Contains(touch.x, touch.y)) {
|
2017-03-19 17:43:03 -07:00
|
|
|
TriggerFinish(DR_BACK);
|
2021-04-17 12:07:40 +02:00
|
|
|
}
|
2013-08-20 13:03:42 +02:00
|
|
|
|
2014-06-15 13:04:10 +02:00
|
|
|
return UIDialogScreen::touch(touch);
|
2013-08-20 13:03:42 +02:00
|
|
|
}
|
2013-07-16 00:25:08 +02:00
|
|
|
|
2014-07-18 12:22:33 +02:00
|
|
|
bool PopupScreen::key(const KeyInput &key) {
|
|
|
|
|
if (key.flags & KEY_DOWN) {
|
2022-06-21 08:32:57 +02:00
|
|
|
if ((key.keyCode == NKCODE_ENTER || key.keyCode == NKCODE_NUMPAD_ENTER) && defaultButton_) {
|
2017-03-21 18:34:52 -07:00
|
|
|
UI::EventParams e{};
|
2014-07-18 12:22:33 +02:00
|
|
|
defaultButton_->OnClick.Trigger(e);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return UIDialogScreen::key(key);
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-19 15:41:48 -07:00
|
|
|
void PopupScreen::update() {
|
|
|
|
|
UIDialogScreen::update();
|
|
|
|
|
|
2019-08-18 12:00:21 -07:00
|
|
|
if (defaultButton_)
|
|
|
|
|
defaultButton_->SetEnabled(CanComplete(DR_OK));
|
2019-08-17 18:24:57 -07:00
|
|
|
|
2017-03-21 18:27:57 -07:00
|
|
|
float animatePos = 1.0f;
|
|
|
|
|
|
2017-03-19 17:45:39 -07:00
|
|
|
++frames_;
|
2017-03-26 08:58:04 -07:00
|
|
|
if (finishFrame_ >= 0) {
|
2017-03-19 17:45:39 -07:00
|
|
|
float leadOut = bezierEaseInOut((frames_ - finishFrame_) * (1.0f / (float)FRAMES_LEAD_OUT));
|
2017-03-21 18:27:57 -07:00
|
|
|
animatePos = 1.0f - leadOut;
|
2017-03-19 17:45:39 -07:00
|
|
|
|
|
|
|
|
if (frames_ >= finishFrame_ + FRAMES_LEAD_OUT) {
|
|
|
|
|
// Actual finish happens here.
|
|
|
|
|
screenManager()->finishDialog(this, finishResult_);
|
|
|
|
|
}
|
2017-03-26 08:58:04 -07:00
|
|
|
} else if (frames_ < FRAMES_LEAD_IN) {
|
|
|
|
|
float leadIn = bezierEaseInOut(frames_ * (1.0f / (float)FRAMES_LEAD_IN));
|
|
|
|
|
animatePos = leadIn;
|
2017-03-21 18:27:57 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (animatePos < 1.0f) {
|
|
|
|
|
alpha_ = animatePos;
|
|
|
|
|
scale_.x = 0.9f + animatePos * 0.1f;
|
|
|
|
|
scale_.y = 0.9f + animatePos * 0.1f;
|
|
|
|
|
|
|
|
|
|
if (hasPopupOrigin_) {
|
|
|
|
|
float xoff = popupOrigin_.x - dp_xres / 2;
|
|
|
|
|
float yoff = popupOrigin_.y - dp_yres / 2;
|
|
|
|
|
|
|
|
|
|
// Pull toward the origin a bit.
|
|
|
|
|
translation_.x = xoff * (1.0f - animatePos) * 0.2f;
|
|
|
|
|
translation_.y = yoff * (1.0f - animatePos) * 0.2f;
|
|
|
|
|
} else {
|
|
|
|
|
translation_.y = -dp_yres * (1.0f - animatePos) * 0.2f;
|
|
|
|
|
}
|
2017-03-19 15:41:48 -07:00
|
|
|
} else {
|
|
|
|
|
alpha_ = 1.0f;
|
|
|
|
|
scale_.x = 1.0f;
|
|
|
|
|
scale_.y = 1.0f;
|
2017-03-21 18:27:57 -07:00
|
|
|
translation_.x = 0.0f;
|
2017-03-19 15:41:48 -07:00
|
|
|
translation_.y = 0.0f;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-21 18:27:57 -07:00
|
|
|
void PopupScreen::SetPopupOrigin(const UI::View *view) {
|
|
|
|
|
hasPopupOrigin_ = true;
|
|
|
|
|
popupOrigin_ = view->GetBounds().Center();
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-28 15:23:46 -07:00
|
|
|
void PopupScreen::SetPopupOffset(float y) {
|
|
|
|
|
offsetY_ = y;
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-19 17:45:39 -07:00
|
|
|
void PopupScreen::TriggerFinish(DialogResult result) {
|
2019-08-17 18:24:57 -07:00
|
|
|
if (CanComplete(result)) {
|
|
|
|
|
finishFrame_ = frames_;
|
|
|
|
|
finishResult_ = result;
|
2017-03-19 17:45:39 -07:00
|
|
|
|
2019-08-17 18:24:57 -07:00
|
|
|
OnCompleted(result);
|
|
|
|
|
}
|
2017-03-19 17:45:39 -07:00
|
|
|
}
|
|
|
|
|
|
2017-12-27 01:13:47 -08:00
|
|
|
void PopupScreen::resized() {
|
|
|
|
|
RecreateViews();
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-16 00:25:08 +02:00
|
|
|
void PopupScreen::CreateViews() {
|
|
|
|
|
using namespace UI;
|
2014-02-10 12:35:36 +01:00
|
|
|
UIContext &dc = *screenManager()->getUIContext();
|
|
|
|
|
|
2015-12-22 19:52:23 -08:00
|
|
|
AnchorLayout *anchor = new AnchorLayout(new LayoutParams(FILL_PARENT, FILL_PARENT));
|
|
|
|
|
anchor->Overflow(false);
|
|
|
|
|
root_ = anchor;
|
2013-08-10 23:03:12 +02:00
|
|
|
|
2014-02-10 12:35:36 +01:00
|
|
|
float yres = screenManager()->getUIContext()->GetBounds().h;
|
|
|
|
|
|
2013-10-28 16:05:21 +01:00
|
|
|
box_ = new LinearLayout(ORIENT_VERTICAL,
|
2021-08-28 15:23:46 -07:00
|
|
|
new AnchorLayoutParams(PopupWidth(), FillVertical() ? yres - 30 : WRAP_CONTENT, dc.GetBounds().centerX(), dc.GetBounds().centerY() + offsetY_, NONE, NONE, true));
|
2013-07-17 01:03:29 +02:00
|
|
|
|
2013-08-20 13:03:42 +02:00
|
|
|
root_->Add(box_);
|
2017-03-26 08:57:04 -07:00
|
|
|
box_->SetBG(dc.theme->popupStyle.background);
|
2022-02-11 18:23:56 +01:00
|
|
|
box_->SetHasDropShadow(hasDropShadow_);
|
2017-03-19 15:41:48 -07:00
|
|
|
// Since we scale a bit, make the dropshadow bleed past the edges.
|
|
|
|
|
box_->SetDropShadowExpand(std::max(dp_xres, dp_yres));
|
2013-07-16 00:25:08 +02:00
|
|
|
|
2013-08-14 23:29:27 +02:00
|
|
|
View *title = new PopupHeader(title_);
|
2013-08-20 13:03:42 +02:00
|
|
|
box_->Add(title);
|
2013-07-16 00:25:08 +02:00
|
|
|
|
2013-08-20 13:03:42 +02:00
|
|
|
CreatePopupContents(box_);
|
2014-03-03 12:55:29 +01:00
|
|
|
root_->SetDefaultFocusView(box_);
|
2013-07-16 00:25:08 +02:00
|
|
|
|
2013-11-29 11:33:51 +01:00
|
|
|
if (ShowButtons() && !button1_.empty()) {
|
2013-08-15 22:13:57 +02:00
|
|
|
// And the two buttons at the bottom.
|
2013-08-16 16:47:25 +02:00
|
|
|
LinearLayout *buttonRow = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(200, WRAP_CONTENT));
|
|
|
|
|
buttonRow->SetSpacing(0);
|
|
|
|
|
Margins buttonMargins(5, 5);
|
2013-08-16 12:51:57 +02:00
|
|
|
|
|
|
|
|
// Adjust button order to the platform default.
|
|
|
|
|
#if defined(_WIN32)
|
2014-07-18 12:22:33 +02:00
|
|
|
defaultButton_ = buttonRow->Add(new Button(button1_, new LinearLayoutParams(1.0f, buttonMargins)));
|
2017-03-19 17:45:39 -07:00
|
|
|
defaultButton_->OnClick.Handle<UIScreen>(this, &UIScreen::OnOK);
|
2013-08-16 16:47:25 +02:00
|
|
|
if (!button2_.empty())
|
2017-03-19 17:45:39 -07:00
|
|
|
buttonRow->Add(new Button(button2_, new LinearLayoutParams(1.0f, buttonMargins)))->OnClick.Handle<UIScreen>(this, &UIScreen::OnCancel);
|
2013-08-16 12:51:57 +02:00
|
|
|
#else
|
2013-08-16 16:47:25 +02:00
|
|
|
if (!button2_.empty())
|
2017-03-19 17:45:39 -07:00
|
|
|
buttonRow->Add(new Button(button2_, new LinearLayoutParams(1.0f)))->OnClick.Handle<UIScreen>(this, &UIScreen::OnCancel);
|
2014-07-18 12:22:33 +02:00
|
|
|
defaultButton_ = buttonRow->Add(new Button(button1_, new LinearLayoutParams(1.0f)));
|
2017-03-19 17:45:39 -07:00
|
|
|
defaultButton_->OnClick.Handle<UIScreen>(this, &UIScreen::OnOK);
|
2013-08-16 12:51:57 +02:00
|
|
|
#endif
|
|
|
|
|
|
2013-08-20 13:03:42 +02:00
|
|
|
box_->Add(buttonRow);
|
2013-08-15 22:13:57 +02:00
|
|
|
}
|
2013-07-16 00:25:08 +02:00
|
|
|
}
|
|
|
|
|
|
2013-08-16 12:51:57 +02:00
|
|
|
void MessagePopupScreen::CreatePopupContents(UI::ViewGroup *parent) {
|
2017-03-26 08:57:04 -07:00
|
|
|
using namespace UI;
|
|
|
|
|
UIContext &dc = *screenManager()->getUIContext();
|
|
|
|
|
|
2014-09-14 19:51:13 -04:00
|
|
|
std::vector<std::string> messageLines;
|
|
|
|
|
SplitString(message_, '\n', messageLines);
|
|
|
|
|
for (const auto& lineOfText : messageLines)
|
2017-03-26 08:57:04 -07:00
|
|
|
parent->Add(new UI::TextView(lineOfText, ALIGN_LEFT | ALIGN_VCENTER, false))->SetTextColor(dc.theme->popupStyle.fgColor);
|
2014-09-14 19:51:13 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MessagePopupScreen::OnCompleted(DialogResult result) {
|
|
|
|
|
if (result == DR_OK) {
|
|
|
|
|
if (callback_)
|
|
|
|
|
callback_(true);
|
|
|
|
|
} else {
|
|
|
|
|
if (callback_)
|
|
|
|
|
callback_(false);
|
|
|
|
|
}
|
2013-08-16 12:51:57 +02:00
|
|
|
}
|
|
|
|
|
|
2013-07-16 00:25:08 +02:00
|
|
|
void ListPopupScreen::CreatePopupContents(UI::ViewGroup *parent) {
|
|
|
|
|
using namespace UI;
|
|
|
|
|
|
2016-02-25 15:39:17 +01:00
|
|
|
listView_ = parent->Add(new ListView(&adaptor_, hidden_)); //, new LinearLayoutParams(1.0)));
|
2014-02-10 12:35:36 +01:00
|
|
|
listView_->SetMaxHeight(screenManager()->getUIContext()->GetBounds().h - 140);
|
2013-07-16 00:25:08 +02:00
|
|
|
listView_->OnChoice.Handle(this, &ListPopupScreen::OnListChoice);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
UI::EventReturn ListPopupScreen::OnListChoice(UI::EventParams &e) {
|
|
|
|
|
adaptor_.SetSelected(e.a);
|
2013-08-15 22:43:42 +02:00
|
|
|
if (callback_)
|
2013-10-25 13:07:13 +02:00
|
|
|
callback_(adaptor_.GetSelected());
|
2017-03-19 17:43:03 -07:00
|
|
|
TriggerFinish(DR_OK);
|
2013-07-16 00:25:08 +02:00
|
|
|
OnChoice.Dispatch(e);
|
|
|
|
|
return UI::EVENT_DONE;
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-07 13:38:12 +02:00
|
|
|
namespace UI {
|
|
|
|
|
|
2016-08-07 17:44:02 -07:00
|
|
|
std::string ChopTitle(const std::string &title) {
|
|
|
|
|
size_t pos = title.find('\n');
|
|
|
|
|
if (pos != title.npos) {
|
|
|
|
|
return title.substr(0, pos);
|
|
|
|
|
}
|
|
|
|
|
return title;
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-07 13:38:12 +02:00
|
|
|
UI::EventReturn PopupMultiChoice::HandleClick(UI::EventParams &e) {
|
2015-06-27 09:41:53 -07:00
|
|
|
restoreFocus_ = HasFocus();
|
|
|
|
|
|
2020-01-26 10:43:18 -08:00
|
|
|
auto category = category_ ? GetI18NCategory(category_) : nullptr;
|
2015-09-23 12:43:45 +02:00
|
|
|
|
2013-09-07 13:38:12 +02:00
|
|
|
std::vector<std::string> choices;
|
|
|
|
|
for (int i = 0; i < numChoices_; i++) {
|
2015-09-23 12:43:45 +02:00
|
|
|
choices.push_back(category ? category->T(choices_[i]) : choices_[i]);
|
2013-09-07 13:38:12 +02:00
|
|
|
}
|
|
|
|
|
|
2016-08-07 17:44:02 -07:00
|
|
|
ListPopupScreen *popupScreen = new ListPopupScreen(ChopTitle(text_), choices, *value_ - minVal_,
|
2016-10-12 11:32:24 +02:00
|
|
|
std::bind(&PopupMultiChoice::ChoiceCallback, this, std::placeholders::_1));
|
2016-02-25 15:39:17 +01:00
|
|
|
popupScreen->SetHiddenChoices(hidden_);
|
2017-03-21 18:27:57 -07:00
|
|
|
if (e.v)
|
|
|
|
|
popupScreen->SetPopupOrigin(e.v);
|
2013-09-07 13:38:12 +02:00
|
|
|
screenManager_->push(popupScreen);
|
|
|
|
|
return UI::EVENT_DONE;
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-14 22:01:18 -07:00
|
|
|
void PopupMultiChoice::Update() {
|
2014-07-22 09:54:24 +02:00
|
|
|
UpdateText();
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-07 13:38:12 +02:00
|
|
|
void PopupMultiChoice::UpdateText() {
|
2018-04-15 09:56:37 +02:00
|
|
|
if (!choices_)
|
|
|
|
|
return;
|
2020-01-26 10:43:18 -08:00
|
|
|
auto category = GetI18NCategory(category_);
|
2013-09-11 22:20:30 +02:00
|
|
|
// Clamp the value to be safe.
|
|
|
|
|
if (*value_ < minVal_ || *value_ > minVal_ + numChoices_ - 1) {
|
|
|
|
|
valueText_ = "(invalid choice)"; // Shouldn't happen. Should be no need to translate this.
|
|
|
|
|
} else {
|
2015-09-23 12:43:45 +02:00
|
|
|
valueText_ = category ? category->T(choices_[*value_ - minVal_]) : choices_[*value_ - minVal_];
|
2013-09-11 22:20:30 +02:00
|
|
|
}
|
2013-09-07 13:38:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PopupMultiChoice::ChoiceCallback(int num) {
|
|
|
|
|
if (num != -1) {
|
|
|
|
|
*value_ = num + minVal_;
|
|
|
|
|
UpdateText();
|
|
|
|
|
|
2017-03-21 18:34:52 -07:00
|
|
|
UI::EventParams e{};
|
2013-09-07 13:38:12 +02:00
|
|
|
e.v = this;
|
|
|
|
|
e.a = num;
|
|
|
|
|
OnChoice.Trigger(e);
|
2015-06-27 09:41:53 -07:00
|
|
|
|
|
|
|
|
if (restoreFocus_) {
|
|
|
|
|
SetFocusedView(this);
|
|
|
|
|
}
|
2018-04-15 09:56:37 +02:00
|
|
|
PostChoiceCallback(num);
|
2013-09-07 13:38:12 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-24 08:09:56 -07:00
|
|
|
std::string PopupMultiChoice::ValueText() const {
|
|
|
|
|
return valueText_;
|
2013-09-07 13:38:12 +02:00
|
|
|
}
|
|
|
|
|
|
2015-11-06 17:55:40 +10:30
|
|
|
PopupSliderChoice::PopupSliderChoice(int *value, int minValue, int maxValue, const std::string &text, ScreenManager *screenManager, const std::string &units, LayoutParams *layoutParams)
|
2021-09-24 08:09:56 -07:00
|
|
|
: AbstractChoiceWithValueDisplay(text, layoutParams), value_(value), minValue_(minValue), maxValue_(maxValue), step_(1), units_(units), screenManager_(screenManager) {
|
2015-12-20 12:58:24 -08:00
|
|
|
fmt_ = "%i";
|
2013-12-02 16:50:03 +01:00
|
|
|
OnClick.Handle(this, &PopupSliderChoice::HandleClick);
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-06 17:55:40 +10:30
|
|
|
PopupSliderChoice::PopupSliderChoice(int *value, int minValue, int maxValue, const std::string &text, int step, ScreenManager *screenManager, const std::string &units, LayoutParams *layoutParams)
|
2021-09-24 08:09:56 -07:00
|
|
|
: AbstractChoiceWithValueDisplay(text, layoutParams), value_(value), minValue_(minValue), maxValue_(maxValue), step_(step), units_(units), screenManager_(screenManager) {
|
2015-12-20 12:58:24 -08:00
|
|
|
fmt_ = "%i";
|
2014-05-05 23:39:57 -04:00
|
|
|
OnClick.Handle(this, &PopupSliderChoice::HandleClick);
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-26 22:43:16 +09:30
|
|
|
PopupSliderChoiceFloat::PopupSliderChoiceFloat(float *value, float minValue, float maxValue, const std::string &text, ScreenManager *screenManager, const std::string &units, LayoutParams *layoutParams)
|
2021-09-24 08:09:56 -07:00
|
|
|
: AbstractChoiceWithValueDisplay(text, layoutParams), value_(value), minValue_(minValue), maxValue_(maxValue), step_(1.0f), units_(units), screenManager_(screenManager) {
|
2015-12-20 12:58:24 -08:00
|
|
|
fmt_ = "%2.2f";
|
2013-12-02 16:50:03 +01:00
|
|
|
OnClick.Handle(this, &PopupSliderChoiceFloat::HandleClick);
|
|
|
|
|
}
|
2013-09-07 13:38:12 +02:00
|
|
|
|
2015-09-26 22:43:16 +09:30
|
|
|
PopupSliderChoiceFloat::PopupSliderChoiceFloat(float *value, float minValue, float maxValue, const std::string &text, float step, ScreenManager *screenManager, const std::string &units, LayoutParams *layoutParams)
|
2021-09-24 08:09:56 -07:00
|
|
|
: AbstractChoiceWithValueDisplay(text, layoutParams), value_(value), minValue_(minValue), maxValue_(maxValue), step_(step), units_(units), screenManager_(screenManager) {
|
2015-12-20 12:58:24 -08:00
|
|
|
fmt_ = "%2.2f";
|
2014-08-16 15:07:06 -04:00
|
|
|
OnClick.Handle(this, &PopupSliderChoiceFloat::HandleClick);
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-07 13:38:12 +02:00
|
|
|
EventReturn PopupSliderChoice::HandleClick(EventParams &e) {
|
2015-06-27 09:48:24 -07:00
|
|
|
restoreFocus_ = HasFocus();
|
|
|
|
|
|
2016-08-07 17:44:02 -07:00
|
|
|
SliderPopupScreen *popupScreen = new SliderPopupScreen(value_, minValue_, maxValue_, ChopTitle(text_), step_, units_);
|
2018-06-16 20:06:00 -07:00
|
|
|
if (!negativeLabel_.empty())
|
|
|
|
|
popupScreen->SetNegativeDisable(negativeLabel_);
|
2013-12-02 16:50:03 +01:00
|
|
|
popupScreen->OnChange.Handle(this, &PopupSliderChoice::HandleChange);
|
2017-03-21 18:27:57 -07:00
|
|
|
if (e.v)
|
|
|
|
|
popupScreen->SetPopupOrigin(e.v);
|
2013-09-07 13:38:12 +02:00
|
|
|
screenManager_->push(popupScreen);
|
|
|
|
|
return EVENT_DONE;
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-02 16:50:03 +01:00
|
|
|
EventReturn PopupSliderChoice::HandleChange(EventParams &e) {
|
|
|
|
|
e.v = this;
|
|
|
|
|
OnChange.Trigger(e);
|
2015-06-27 09:48:24 -07:00
|
|
|
|
|
|
|
|
if (restoreFocus_) {
|
|
|
|
|
SetFocusedView(this);
|
|
|
|
|
}
|
2013-12-02 16:50:03 +01:00
|
|
|
return EVENT_DONE;
|
|
|
|
|
}
|
2013-09-07 13:38:12 +02:00
|
|
|
|
2021-09-24 08:09:56 -07:00
|
|
|
std::string PopupSliderChoice::ValueText() const {
|
2018-06-16 20:06:00 -07:00
|
|
|
// Always good to have space for Unicode.
|
|
|
|
|
char temp[256];
|
2015-12-20 12:58:24 -08:00
|
|
|
if (zeroLabel_.size() && *value_ == 0) {
|
|
|
|
|
strcpy(temp, zeroLabel_.c_str());
|
2018-06-16 20:06:00 -07:00
|
|
|
} else if (negativeLabel_.size() && *value_ < 0) {
|
|
|
|
|
strcpy(temp, negativeLabel_.c_str());
|
2015-12-20 12:58:24 -08:00
|
|
|
} else {
|
|
|
|
|
sprintf(temp, fmt_, *value_);
|
|
|
|
|
}
|
2016-08-07 11:39:15 -07:00
|
|
|
|
2021-09-24 08:09:56 -07:00
|
|
|
return temp;
|
2013-09-07 13:38:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EventReturn PopupSliderChoiceFloat::HandleClick(EventParams &e) {
|
2015-06-27 09:48:24 -07:00
|
|
|
restoreFocus_ = HasFocus();
|
|
|
|
|
|
2022-02-11 15:12:52 +01:00
|
|
|
SliderFloatPopupScreen *popupScreen = new SliderFloatPopupScreen(value_, minValue_, maxValue_, ChopTitle(text_), step_, units_, liveUpdate_);
|
2013-12-02 16:50:03 +01:00
|
|
|
popupScreen->OnChange.Handle(this, &PopupSliderChoiceFloat::HandleChange);
|
2022-02-11 18:23:56 +01:00
|
|
|
popupScreen->SetHasDropShadow(hasDropShadow_);
|
2017-03-21 18:27:57 -07:00
|
|
|
if (e.v)
|
|
|
|
|
popupScreen->SetPopupOrigin(e.v);
|
2013-09-07 13:38:12 +02:00
|
|
|
screenManager_->push(popupScreen);
|
|
|
|
|
return EVENT_DONE;
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-02 16:50:03 +01:00
|
|
|
EventReturn PopupSliderChoiceFloat::HandleChange(EventParams &e) {
|
|
|
|
|
e.v = this;
|
|
|
|
|
OnChange.Trigger(e);
|
2015-06-27 09:48:24 -07:00
|
|
|
|
|
|
|
|
if (restoreFocus_) {
|
|
|
|
|
SetFocusedView(this);
|
|
|
|
|
}
|
2013-12-02 16:50:03 +01:00
|
|
|
return EVENT_DONE;
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-24 08:09:56 -07:00
|
|
|
std::string PopupSliderChoiceFloat::ValueText() const {
|
2018-06-16 20:06:00 -07:00
|
|
|
char temp[256];
|
2015-12-20 12:58:24 -08:00
|
|
|
if (zeroLabel_.size() && *value_ == 0.0f) {
|
|
|
|
|
strcpy(temp, zeroLabel_.c_str());
|
|
|
|
|
} else {
|
|
|
|
|
sprintf(temp, fmt_, *value_);
|
|
|
|
|
}
|
2016-08-07 11:39:15 -07:00
|
|
|
|
2021-09-24 08:09:56 -07:00
|
|
|
return temp;
|
2013-09-07 13:38:12 +02:00
|
|
|
}
|
|
|
|
|
|
2013-12-06 15:01:34 +01:00
|
|
|
EventReturn SliderPopupScreen::OnDecrease(EventParams ¶ms) {
|
2015-11-06 17:55:40 +10:30
|
|
|
if (sliderValue_ > minValue_ && sliderValue_ < maxValue_) {
|
|
|
|
|
sliderValue_ = step_ * floor((sliderValue_ / step_) + 0.5f);
|
|
|
|
|
}
|
2014-05-05 23:39:57 -04:00
|
|
|
sliderValue_ -= step_;
|
2013-12-06 15:01:34 +01:00
|
|
|
slider_->Clamp();
|
2015-11-06 17:55:40 +10:30
|
|
|
changing_ = true;
|
|
|
|
|
char temp[64];
|
|
|
|
|
sprintf(temp, "%d", sliderValue_);
|
|
|
|
|
edit_->SetText(temp);
|
|
|
|
|
changing_ = false;
|
2018-06-16 20:06:00 -07:00
|
|
|
disabled_ = false;
|
2013-12-06 15:01:34 +01:00
|
|
|
return EVENT_DONE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EventReturn SliderPopupScreen::OnIncrease(EventParams ¶ms) {
|
2015-11-06 17:55:40 +10:30
|
|
|
if (sliderValue_ > minValue_ && sliderValue_ < maxValue_) {
|
|
|
|
|
sliderValue_ = step_ * floor((sliderValue_ / step_) + 0.5f);
|
|
|
|
|
}
|
2014-05-05 23:39:57 -04:00
|
|
|
sliderValue_ += step_;
|
2013-12-06 15:01:34 +01:00
|
|
|
slider_->Clamp();
|
2015-11-06 17:55:40 +10:30
|
|
|
changing_ = true;
|
|
|
|
|
char temp[64];
|
|
|
|
|
sprintf(temp, "%d", sliderValue_);
|
|
|
|
|
edit_->SetText(temp);
|
|
|
|
|
changing_ = false;
|
2018-06-16 20:06:00 -07:00
|
|
|
disabled_ = false;
|
2015-11-06 17:55:40 +10:30
|
|
|
return EVENT_DONE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EventReturn SliderPopupScreen::OnSliderChange(EventParams ¶ms) {
|
|
|
|
|
changing_ = true;
|
|
|
|
|
char temp[64];
|
|
|
|
|
sprintf(temp, "%d", sliderValue_);
|
|
|
|
|
edit_->SetText(temp);
|
|
|
|
|
changing_ = false;
|
2018-06-16 20:06:00 -07:00
|
|
|
disabled_ = false;
|
2015-11-06 17:55:40 +10:30
|
|
|
return EVENT_DONE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EventReturn SliderPopupScreen::OnTextChange(EventParams ¶ms) {
|
|
|
|
|
if (!changing_) {
|
|
|
|
|
sliderValue_ = atoi(edit_->GetText().c_str());
|
2018-06-16 20:06:00 -07:00
|
|
|
disabled_ = false;
|
2015-11-06 17:55:40 +10:30
|
|
|
slider_->Clamp();
|
|
|
|
|
}
|
2013-12-06 15:01:34 +01:00
|
|
|
return EVENT_DONE;
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-18 10:25:30 +02:00
|
|
|
void SliderPopupScreen::CreatePopupContents(UI::ViewGroup *parent) {
|
|
|
|
|
using namespace UI;
|
2017-03-26 08:57:04 -07:00
|
|
|
UIContext &dc = *screenManager()->getUIContext();
|
|
|
|
|
|
2013-08-14 23:29:27 +02:00
|
|
|
sliderValue_ = *value_;
|
2018-06-16 20:06:00 -07:00
|
|
|
if (disabled_ && sliderValue_ < 0)
|
|
|
|
|
sliderValue_ = 0;
|
2015-11-06 17:55:40 +10:30
|
|
|
LinearLayout *vert = parent->Add(new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(UI::Margins(10, 10))));
|
|
|
|
|
slider_ = new Slider(&sliderValue_, minValue_, maxValue_, new LinearLayoutParams(UI::Margins(10, 10)));
|
2015-11-12 19:25:11 +01:00
|
|
|
slider_->OnChange.Handle(this, &SliderPopupScreen::OnSliderChange);
|
2015-11-06 17:55:40 +10:30
|
|
|
vert->Add(slider_);
|
2017-03-26 08:57:04 -07:00
|
|
|
|
2015-11-06 17:55:40 +10:30
|
|
|
LinearLayout *lin = vert->Add(new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(UI::Margins(10, 10))));
|
2013-12-06 15:01:34 +01:00
|
|
|
lin->Add(new Button(" - "))->OnClick.Handle(this, &SliderPopupScreen::OnDecrease);
|
|
|
|
|
lin->Add(new Button(" + "))->OnClick.Handle(this, &SliderPopupScreen::OnIncrease);
|
2017-03-26 08:57:04 -07:00
|
|
|
|
2015-11-06 17:55:40 +10:30
|
|
|
char temp[64];
|
|
|
|
|
sprintf(temp, "%d", sliderValue_);
|
2021-02-21 16:38:02 -08:00
|
|
|
edit_ = new TextEdit(temp, Title(), "", new LinearLayoutParams(10.0f));
|
2015-11-06 17:55:40 +10:30
|
|
|
edit_->SetMaxLen(16);
|
2017-03-26 08:57:04 -07:00
|
|
|
edit_->SetTextColor(dc.theme->popupStyle.fgColor);
|
2017-11-22 22:14:06 +01:00
|
|
|
edit_->SetTextAlign(FLAG_DYNAMIC_ASCII);
|
2015-11-06 17:55:40 +10:30
|
|
|
edit_->OnTextChange.Handle(this, &SliderPopupScreen::OnTextChange);
|
|
|
|
|
changing_ = false;
|
|
|
|
|
lin->Add(edit_);
|
2017-03-26 08:57:04 -07:00
|
|
|
|
2015-12-23 15:26:29 -08:00
|
|
|
if (!units_.empty())
|
2017-03-26 08:57:04 -07:00
|
|
|
lin->Add(new TextView(units_, new LinearLayoutParams(10.0f)))->SetTextColor(dc.theme->popupStyle.fgColor);
|
2013-12-06 15:01:34 +01:00
|
|
|
|
2018-06-16 20:06:00 -07:00
|
|
|
if (!negativeLabel_.empty())
|
|
|
|
|
vert->Add(new CheckBox(&disabled_, negativeLabel_));
|
|
|
|
|
|
2015-11-12 19:25:11 +01:00
|
|
|
if (IsFocusMovementEnabled())
|
|
|
|
|
UI::SetFocusedView(slider_);
|
2013-07-18 10:25:30 +02:00
|
|
|
}
|
2013-07-20 13:54:09 +02:00
|
|
|
|
|
|
|
|
void SliderFloatPopupScreen::CreatePopupContents(UI::ViewGroup *parent) {
|
|
|
|
|
using namespace UI;
|
2017-03-26 08:57:04 -07:00
|
|
|
UIContext &dc = *screenManager()->getUIContext();
|
|
|
|
|
|
2013-08-14 23:29:27 +02:00
|
|
|
sliderValue_ = *value_;
|
2015-09-26 22:43:16 +09:30
|
|
|
LinearLayout *vert = parent->Add(new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(UI::Margins(10, 10))));
|
|
|
|
|
slider_ = new SliderFloat(&sliderValue_, minValue_, maxValue_, new LinearLayoutParams(UI::Margins(10, 10)));
|
2015-11-12 19:25:11 +01:00
|
|
|
slider_->OnChange.Handle(this, &SliderFloatPopupScreen::OnSliderChange);
|
2015-09-26 22:43:16 +09:30
|
|
|
vert->Add(slider_);
|
2017-03-26 08:57:04 -07:00
|
|
|
|
2015-09-26 22:43:16 +09:30
|
|
|
LinearLayout *lin = vert->Add(new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(UI::Margins(10, 10))));
|
2014-08-16 15:07:06 -04:00
|
|
|
lin->Add(new Button(" - "))->OnClick.Handle(this, &SliderFloatPopupScreen::OnDecrease);
|
|
|
|
|
lin->Add(new Button(" + "))->OnClick.Handle(this, &SliderFloatPopupScreen::OnIncrease);
|
2017-03-26 08:57:04 -07:00
|
|
|
|
2015-09-26 22:43:16 +09:30
|
|
|
char temp[64];
|
|
|
|
|
sprintf(temp, "%0.3f", sliderValue_);
|
2021-02-21 16:38:02 -08:00
|
|
|
edit_ = new TextEdit(temp, Title(), "", new LinearLayoutParams(10.0f));
|
2015-09-26 22:43:16 +09:30
|
|
|
edit_->SetMaxLen(16);
|
2017-03-26 08:57:04 -07:00
|
|
|
edit_->SetTextColor(dc.theme->popupStyle.fgColor);
|
2017-11-22 22:14:06 +01:00
|
|
|
edit_->SetTextAlign(FLAG_DYNAMIC_ASCII);
|
2015-09-26 22:43:16 +09:30
|
|
|
edit_->OnTextChange.Handle(this, &SliderFloatPopupScreen::OnTextChange);
|
|
|
|
|
changing_ = false;
|
|
|
|
|
lin->Add(edit_);
|
2015-12-23 15:26:29 -08:00
|
|
|
if (!units_.empty())
|
2017-03-26 08:57:04 -07:00
|
|
|
lin->Add(new TextView(units_, new LinearLayoutParams(10.0f)))->SetTextColor(dc.theme->popupStyle.fgColor);
|
2015-09-26 22:43:16 +09:30
|
|
|
|
2014-08-16 15:07:06 -04:00
|
|
|
// slider_ = parent->Add(new SliderFloat(&sliderValue_, minValue_, maxValue_, new LinearLayoutParams(UI::Margins(10, 5))));
|
2015-11-12 19:25:11 +01:00
|
|
|
if (IsFocusMovementEnabled())
|
|
|
|
|
UI::SetFocusedView(slider_);
|
2013-08-14 23:29:27 +02:00
|
|
|
}
|
|
|
|
|
|
2014-08-16 15:07:06 -04:00
|
|
|
EventReturn SliderFloatPopupScreen::OnDecrease(EventParams ¶ms) {
|
2015-09-26 22:43:16 +09:30
|
|
|
if (sliderValue_ > minValue_ && sliderValue_ < maxValue_) {
|
|
|
|
|
sliderValue_ = step_ * floor((sliderValue_ / step_) + 0.5f);
|
|
|
|
|
}
|
2014-08-16 15:07:06 -04:00
|
|
|
sliderValue_ -= step_;
|
|
|
|
|
slider_->Clamp();
|
2015-09-26 22:43:16 +09:30
|
|
|
changing_ = true;
|
|
|
|
|
char temp[64];
|
|
|
|
|
sprintf(temp, "%0.3f", sliderValue_);
|
|
|
|
|
edit_->SetText(temp);
|
|
|
|
|
changing_ = false;
|
2022-02-11 19:13:44 +01:00
|
|
|
if (liveUpdate_) {
|
|
|
|
|
*value_ = sliderValue_;
|
|
|
|
|
}
|
2014-08-16 15:07:06 -04:00
|
|
|
return EVENT_DONE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EventReturn SliderFloatPopupScreen::OnIncrease(EventParams ¶ms) {
|
2015-09-26 22:43:16 +09:30
|
|
|
if (sliderValue_ > minValue_ && sliderValue_ < maxValue_) {
|
|
|
|
|
sliderValue_ = step_ * floor((sliderValue_ / step_) + 0.5f);
|
|
|
|
|
}
|
2014-08-16 15:07:06 -04:00
|
|
|
sliderValue_ += step_;
|
|
|
|
|
slider_->Clamp();
|
2015-09-26 22:43:16 +09:30
|
|
|
changing_ = true;
|
|
|
|
|
char temp[64];
|
|
|
|
|
sprintf(temp, "%0.3f", sliderValue_);
|
|
|
|
|
edit_->SetText(temp);
|
|
|
|
|
changing_ = false;
|
2022-02-11 19:13:44 +01:00
|
|
|
if (liveUpdate_) {
|
|
|
|
|
*value_ = sliderValue_;
|
|
|
|
|
}
|
2015-09-26 22:43:16 +09:30
|
|
|
return EVENT_DONE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EventReturn SliderFloatPopupScreen::OnSliderChange(EventParams ¶ms) {
|
|
|
|
|
changing_ = true;
|
|
|
|
|
char temp[64];
|
|
|
|
|
sprintf(temp, "%0.3f", sliderValue_);
|
|
|
|
|
edit_->SetText(temp);
|
|
|
|
|
changing_ = false;
|
2022-02-11 15:12:52 +01:00
|
|
|
if (liveUpdate_) {
|
|
|
|
|
*value_ = sliderValue_;
|
|
|
|
|
}
|
2015-09-26 22:43:16 +09:30
|
|
|
return EVENT_DONE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EventReturn SliderFloatPopupScreen::OnTextChange(EventParams ¶ms) {
|
|
|
|
|
if (!changing_) {
|
|
|
|
|
sliderValue_ = atof(edit_->GetText().c_str());
|
|
|
|
|
slider_->Clamp();
|
2022-02-11 19:13:44 +01:00
|
|
|
if (liveUpdate_) {
|
|
|
|
|
*value_ = sliderValue_;
|
|
|
|
|
}
|
2015-09-26 22:43:16 +09:30
|
|
|
}
|
2014-08-16 15:07:06 -04:00
|
|
|
return EVENT_DONE;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-16 12:51:57 +02:00
|
|
|
void SliderPopupScreen::OnCompleted(DialogResult result) {
|
2013-12-02 16:50:03 +01:00
|
|
|
if (result == DR_OK) {
|
2018-06-16 20:06:00 -07:00
|
|
|
*value_ = disabled_ ? -1 : sliderValue_;
|
2017-03-21 18:34:52 -07:00
|
|
|
EventParams e{};
|
|
|
|
|
e.v = nullptr;
|
2013-12-02 16:50:03 +01:00
|
|
|
e.a = *value_;
|
|
|
|
|
OnChange.Trigger(e);
|
|
|
|
|
}
|
2013-08-14 23:29:27 +02:00
|
|
|
}
|
|
|
|
|
|
2013-08-16 12:51:57 +02:00
|
|
|
void SliderFloatPopupScreen::OnCompleted(DialogResult result) {
|
2013-12-02 16:50:03 +01:00
|
|
|
if (result == DR_OK) {
|
2013-08-16 12:51:57 +02:00
|
|
|
*value_ = sliderValue_;
|
2017-03-21 18:34:52 -07:00
|
|
|
EventParams e{};
|
|
|
|
|
e.v = nullptr;
|
2013-12-02 16:50:03 +01:00
|
|
|
e.a = (int)*value_;
|
|
|
|
|
e.f = *value_;
|
|
|
|
|
OnChange.Trigger(e);
|
2022-02-11 15:12:52 +01:00
|
|
|
} else {
|
|
|
|
|
*value_ = originalValue_;
|
2013-12-02 16:50:03 +01:00
|
|
|
}
|
2013-07-20 13:54:09 +02:00
|
|
|
}
|
2013-09-07 13:38:12 +02:00
|
|
|
|
2014-07-21 11:59:05 +02:00
|
|
|
PopupTextInputChoice::PopupTextInputChoice(std::string *value, const std::string &title, const std::string &placeholder, int maxLen, ScreenManager *screenManager, LayoutParams *layoutParams)
|
2021-09-24 08:09:56 -07:00
|
|
|
: AbstractChoiceWithValueDisplay(title, layoutParams), screenManager_(screenManager), value_(value), placeHolder_(placeholder), maxLen_(maxLen) {
|
2014-07-18 11:03:18 +02:00
|
|
|
OnClick.Handle(this, &PopupTextInputChoice::HandleClick);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EventReturn PopupTextInputChoice::HandleClick(EventParams &e) {
|
2015-06-27 09:48:24 -07:00
|
|
|
restoreFocus_ = HasFocus();
|
|
|
|
|
|
2016-08-07 17:44:02 -07:00
|
|
|
TextEditPopupScreen *popupScreen = new TextEditPopupScreen(value_, placeHolder_, ChopTitle(text_), maxLen_);
|
2014-07-18 11:03:18 +02:00
|
|
|
popupScreen->OnChange.Handle(this, &PopupTextInputChoice::HandleChange);
|
2017-03-21 18:27:57 -07:00
|
|
|
if (e.v)
|
|
|
|
|
popupScreen->SetPopupOrigin(e.v);
|
2014-07-18 11:03:18 +02:00
|
|
|
screenManager_->push(popupScreen);
|
|
|
|
|
return EVENT_DONE;
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-24 08:09:56 -07:00
|
|
|
std::string PopupTextInputChoice::ValueText() const {
|
|
|
|
|
return *value_;
|
2014-07-18 11:03:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EventReturn PopupTextInputChoice::HandleChange(EventParams &e) {
|
|
|
|
|
e.v = this;
|
|
|
|
|
OnChange.Trigger(e);
|
2015-06-27 09:48:24 -07:00
|
|
|
|
|
|
|
|
if (restoreFocus_) {
|
|
|
|
|
SetFocusedView(this);
|
|
|
|
|
}
|
2014-07-18 11:03:18 +02:00
|
|
|
return EVENT_DONE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TextEditPopupScreen::CreatePopupContents(UI::ViewGroup *parent) {
|
|
|
|
|
using namespace UI;
|
2017-03-26 08:57:04 -07:00
|
|
|
UIContext &dc = *screenManager()->getUIContext();
|
2014-07-18 11:03:18 +02:00
|
|
|
|
|
|
|
|
textEditValue_ = *value_;
|
|
|
|
|
LinearLayout *lin = parent->Add(new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams((UI::Size)300, WRAP_CONTENT)));
|
2021-02-21 16:38:02 -08:00
|
|
|
edit_ = new TextEdit(textEditValue_, Title(), placeholder_, new LinearLayoutParams(1.0f));
|
2014-07-21 11:59:05 +02:00
|
|
|
edit_->SetMaxLen(maxLen_);
|
2017-03-26 08:57:04 -07:00
|
|
|
edit_->SetTextColor(dc.theme->popupStyle.fgColor);
|
2014-07-18 11:03:18 +02:00
|
|
|
lin->Add(edit_);
|
|
|
|
|
|
2022-06-07 17:16:06 +02:00
|
|
|
UI::SetFocusedView(edit_);
|
2014-07-18 11:03:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TextEditPopupScreen::OnCompleted(DialogResult result) {
|
|
|
|
|
if (result == DR_OK) {
|
2017-08-08 16:42:05 +02:00
|
|
|
*value_ = StripSpaces(edit_->GetText());
|
2017-03-21 18:34:52 -07:00
|
|
|
EventParams e{};
|
2014-07-18 11:03:18 +02:00
|
|
|
e.v = edit_;
|
|
|
|
|
OnChange.Trigger(e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-24 08:09:56 -07:00
|
|
|
void AbstractChoiceWithValueDisplay::GetContentDimensionsBySpec(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert, float &w, float &h) const {
|
|
|
|
|
const std::string valueText = ValueText();
|
|
|
|
|
int paddingX = 12;
|
|
|
|
|
// Assume we want at least 20% of the size for the label, at a minimum.
|
|
|
|
|
float availWidth = (horiz.size - paddingX * 2) * 0.8f;
|
|
|
|
|
if (availWidth < 0) {
|
|
|
|
|
availWidth = 65535.0f;
|
|
|
|
|
}
|
|
|
|
|
float scale = CalculateValueScale(dc, valueText, availWidth);
|
|
|
|
|
Bounds availBounds(0, 0, availWidth, vert.size);
|
|
|
|
|
|
|
|
|
|
float valueW, valueH;
|
|
|
|
|
dc.MeasureTextRect(dc.theme->uiFont, scale, scale, valueText.c_str(), (int)valueText.size(), availBounds, &valueW, &valueH, ALIGN_RIGHT | ALIGN_VCENTER | FLAG_WRAP_TEXT);
|
|
|
|
|
valueW += paddingX;
|
|
|
|
|
|
|
|
|
|
// Give the choice itself less space to grow in, so it shrinks if needed.
|
|
|
|
|
MeasureSpec horizLabel = horiz;
|
|
|
|
|
horizLabel.size -= valueW;
|
|
|
|
|
Choice::GetContentDimensionsBySpec(dc, horiz, vert, w, h);
|
|
|
|
|
|
|
|
|
|
w += valueW;
|
|
|
|
|
h = std::max(h, valueH);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AbstractChoiceWithValueDisplay::Draw(UIContext &dc) {
|
2014-07-18 18:42:41 -04:00
|
|
|
Style style = dc.theme->itemStyle;
|
2016-08-07 11:39:15 -07:00
|
|
|
if (!IsEnabled()) {
|
|
|
|
|
style = dc.theme->itemDisabledStyle;
|
|
|
|
|
}
|
2022-02-14 15:07:33 +01:00
|
|
|
if (HasFocus()) {
|
|
|
|
|
style = dc.theme->itemFocusedStyle;
|
|
|
|
|
}
|
|
|
|
|
if (down_) {
|
|
|
|
|
style = dc.theme->itemDownStyle;
|
|
|
|
|
}
|
2016-08-07 11:39:15 -07:00
|
|
|
int paddingX = 12;
|
2014-07-18 18:42:41 -04:00
|
|
|
dc.SetFontStyle(dc.theme->uiFont);
|
|
|
|
|
|
2021-09-24 07:13:56 -07:00
|
|
|
const std::string valueText = ValueText();
|
2021-09-24 07:38:39 -07:00
|
|
|
// Assume we want at least 20% of the size for the label, at a minimum.
|
|
|
|
|
float availWidth = (bounds_.w - paddingX * 2) * 0.8f;
|
|
|
|
|
float scale = CalculateValueScale(dc, valueText, availWidth);
|
2021-09-24 07:13:56 -07:00
|
|
|
|
2021-09-25 07:59:18 -07:00
|
|
|
float w, h;
|
2021-09-24 07:38:39 -07:00
|
|
|
Bounds availBounds(0, 0, availWidth, bounds_.h);
|
2021-09-25 07:59:18 -07:00
|
|
|
dc.MeasureTextRect(dc.theme->uiFont, scale, scale, valueText.c_str(), (int)valueText.size(), availBounds, &w, &h, ALIGN_RIGHT | ALIGN_VCENTER | FLAG_WRAP_TEXT);
|
|
|
|
|
textPadding_.right = w + paddingX;
|
2021-09-24 07:13:56 -07:00
|
|
|
|
|
|
|
|
Choice::Draw(dc);
|
2021-09-24 07:38:39 -07:00
|
|
|
dc.SetFontScale(scale, scale);
|
2021-09-25 07:59:18 -07:00
|
|
|
Bounds valueBounds(bounds_.x2() - textPadding_.right, bounds_.y, w, bounds_.h);
|
2021-09-24 07:38:39 -07:00
|
|
|
dc.DrawTextRect(valueText.c_str(), valueBounds, style.fgColor, ALIGN_RIGHT | ALIGN_VCENTER | FLAG_WRAP_TEXT);
|
|
|
|
|
dc.SetFontScale(1.0f, 1.0f);
|
2021-09-24 07:13:56 -07:00
|
|
|
}
|
|
|
|
|
|
2021-09-24 08:09:56 -07:00
|
|
|
float AbstractChoiceWithValueDisplay::CalculateValueScale(const UIContext &dc, const std::string &valueText, float availWidth) const {
|
2021-09-24 07:38:39 -07:00
|
|
|
float actualWidth, actualHeight;
|
|
|
|
|
Bounds availBounds(0, 0, availWidth, bounds_.h);
|
|
|
|
|
dc.MeasureTextRect(dc.theme->uiFont, 1.0f, 1.0f, valueText.c_str(), (int)valueText.size(), availBounds, &actualWidth, &actualHeight);
|
|
|
|
|
if (actualWidth > availWidth) {
|
|
|
|
|
return std::max(0.8f, availWidth / actualWidth);
|
|
|
|
|
}
|
|
|
|
|
return 1.0f;
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-24 07:13:56 -07:00
|
|
|
std::string ChoiceWithValueDisplay::ValueText() const {
|
2020-01-26 10:43:18 -08:00
|
|
|
auto category = GetI18NCategory(category_);
|
2016-08-07 11:39:15 -07:00
|
|
|
std::ostringstream valueText;
|
2018-03-25 14:26:44 +02:00
|
|
|
if (translateCallback_ && sValue_) {
|
|
|
|
|
valueText << translateCallback_(sValue_->c_str());
|
|
|
|
|
} else if (sValue_ != nullptr) {
|
2015-09-23 12:43:45 +02:00
|
|
|
if (category)
|
|
|
|
|
valueText << category->T(*sValue_);
|
2014-07-21 18:42:25 +02:00
|
|
|
else
|
|
|
|
|
valueText << *sValue_;
|
2014-07-18 18:42:41 -04:00
|
|
|
} else if (iValue_ != nullptr) {
|
|
|
|
|
valueText << *iValue_;
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-24 07:13:56 -07:00
|
|
|
return valueText.str();
|
2014-07-18 18:42:41 -04:00
|
|
|
}
|
|
|
|
|
|
2013-10-19 14:24:46 -07:00
|
|
|
} // namespace UI
|