mirror of
https://github.com/bearstonem/openmohaa-vr.git
synced 2026-10-21 12:00:24 +02:00
489 lines
12 KiB
C++
489 lines
12 KiB
C++
/*
|
|
===========================================================================
|
|
Copyright (C) 2015-2024 the OpenMoHAA team
|
|
|
|
This file is part of OpenMoHAA source code.
|
|
|
|
OpenMoHAA source code is free software; you can redistribute it
|
|
and/or modify it under the terms of the GNU General Public License as
|
|
published by the Free Software Foundation; either version 2 of the License,
|
|
or (at your option) any later version.
|
|
|
|
OpenMoHAA source code is distributed in the hope that it will be
|
|
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with OpenMoHAA source code; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
===========================================================================
|
|
*/
|
|
|
|
#include "ui_local.h"
|
|
#include "localization.h"
|
|
|
|
CLASS_DECLARATION(UIWidget, UIPopupMenu, NULL) {
|
|
{&W_LeftMouseUp, &UIPopupMenu::MouseReleased},
|
|
{&W_MouseMoved, &UIPopupMenu::MouseMoved },
|
|
{&W_MouseExited, &UIPopupMenu::MouseExited },
|
|
{&W_Deactivated, &UIPopupMenu::DismissEvent },
|
|
{NULL, NULL }
|
|
};
|
|
|
|
uipopup_type UI_PopupTypeStringToInt(str type)
|
|
{
|
|
if (type == "event_string") {
|
|
return UIP_EVENT_STRING;
|
|
} else if (type == "command") {
|
|
return UIP_CMD;
|
|
} else if (type == "cvar") {
|
|
return UIP_CVAR;
|
|
} else if (type == "separator") {
|
|
return UIP_SEPARATOR;
|
|
}
|
|
|
|
return UIP_NONE;
|
|
}
|
|
|
|
UIPopupMenu::UIPopupMenu()
|
|
{
|
|
m_selected = -1;
|
|
m_listener = NULL;
|
|
m_parentMenu = NULL;
|
|
m_submenu = -1;
|
|
m_marlett = UIFont("marlett");
|
|
m_autodismiss = qtrue;
|
|
m_describe = NULL;
|
|
m_submenuptr = NULL;
|
|
|
|
m_highlightFGColor = UColor(0.9f, 0.8f, 0.6f, 1.0f);
|
|
m_highlightBGColor = UColor(0.21f, 0.18f, 0.015f, 1.0f);
|
|
m_background_color = UColor(0.02f, 0.07f, 0.005f, 1.0f);
|
|
m_foreground_color = UHudColor;
|
|
|
|
m_iFontAlignmentHorizontal = FONT_JUSTHORZ_RIGHT;
|
|
}
|
|
|
|
UIPopupMenu::~UIPopupMenu()
|
|
{
|
|
if (m_parentMenu) {
|
|
m_submenu = -1;
|
|
}
|
|
|
|
if (m_submenu != -1 && m_submenuptr) {
|
|
m_submenuptr->m_parentMenu = NULL;
|
|
delete m_submenuptr;
|
|
}
|
|
}
|
|
|
|
uipopup_describe *UIPopupMenu::getDescribeFromPoint(const UIPoint2D& p)
|
|
{
|
|
// FIXME: macro or inline for this somewhere?
|
|
if (p.y < 4.0f || p.x < 2.0f || m_frame.size.width - 2.0f <= p.x) {
|
|
return NULL;
|
|
}
|
|
|
|
float top = getVirtualScale()[1] * 4.0f;
|
|
for (int i = 1; i <= m_describe->NumObjects(); i++) {
|
|
uipopup_describe *desc = m_describe->ObjectAt(i);
|
|
float height = getDescribeHeight(desc);
|
|
if (p.y >= top && p.y < top + height) {
|
|
return desc;
|
|
}
|
|
|
|
top += height;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void UIPopupMenu::MakeSubMenu(void)
|
|
{
|
|
UIRect2D place;
|
|
for (int i = 1; i <= m_submenu; i++) {
|
|
place.pos.y += getDescribeHeight(m_describe->ObjectAt(i));
|
|
}
|
|
|
|
place.size.height = getDescribeHeight(m_describe->ObjectAt(m_submenu)) + 8.0f;
|
|
place.size.width = m_frame.size.width - 40.0f;
|
|
|
|
place.pos.x = 20.0f;
|
|
if (place.size.width < 0.0f) {
|
|
place.pos.x -= place.size.width * 0.5f;
|
|
place.size.width = 0.0f;
|
|
}
|
|
|
|
place.pos.x += m_screenframe.pos.x;
|
|
place.pos.y += m_screenframe.pos.y;
|
|
|
|
UIPopupMenu *me = new UIPopupMenu();
|
|
me->Create(
|
|
(Container<uipopup_describe *> *)m_describe->ObjectAt(m_submenu)->data,
|
|
m_listener,
|
|
place,
|
|
UIP_WHERE_RIGHT,
|
|
qfalse,
|
|
-1.0f
|
|
);
|
|
|
|
me->m_parentMenu = this;
|
|
m_submenuptr = me;
|
|
}
|
|
|
|
float UIPopupMenu::getDescribeHeight(uipopup_describe *d)
|
|
{
|
|
if (d->type == UIP_SEPARATOR) {
|
|
return 8.0f * getVirtualScale()[0];
|
|
}
|
|
|
|
return m_font->getHeight(getVirtualScale());
|
|
}
|
|
|
|
float UIPopupMenu::getDescribeWidth(uipopup_describe *d)
|
|
{
|
|
return m_font->getWidth(d->title, -1) * getVirtualScale()[0];
|
|
}
|
|
|
|
bool UIPopupMenu::MouseInSubmenus(void)
|
|
{
|
|
if (m_submenu == -1) {
|
|
return false;
|
|
}
|
|
|
|
if (m_submenuptr->m_screenframe.contains(uid.mouseX, uid.mouseY)) {
|
|
return true;
|
|
}
|
|
|
|
return m_submenuptr->MouseInSubmenus();
|
|
}
|
|
|
|
void UIPopupMenu::Create(Container<uipopup_describe *> *describe, Listener *listener, const UIPoint2D& where)
|
|
{
|
|
Create(describe, listener, UIRect2D(where.x, where.y, 0.0f, 0.0f), UIP_WHERE_RIGHT, qfalse, -1.0f);
|
|
}
|
|
|
|
void UIPopupMenu::Create(
|
|
Container<uipopup_describe *> *describe,
|
|
Listener *listener,
|
|
const UIRect2D& createRect,
|
|
uipopup_where where,
|
|
qboolean bVirtualSize,
|
|
float width
|
|
)
|
|
{
|
|
m_describe = describe;
|
|
m_listener = listener;
|
|
setFont("verdana-12");
|
|
|
|
if (bVirtualSize) {
|
|
m_bVirtual = qtrue;
|
|
m_vVirtualScale[0] = (float)uid.vidWidth / SCREEN_WIDTH;
|
|
m_vVirtualScale[1] = (float)uid.vidHeight / SCREEN_HEIGHT;
|
|
}
|
|
|
|
if (!(m_describe && m_listener)) {
|
|
return;
|
|
}
|
|
|
|
UISize2D totalSize;
|
|
for (int i = 1; i <= m_describe->NumObjects(); i++) {
|
|
uipopup_describe *desc = m_describe->ObjectAt(i);
|
|
totalSize.height += getDescribeHeight(desc);
|
|
if (desc->type != UIP_SEPARATOR) {
|
|
float newWidth = getDescribeWidth(desc);
|
|
if (newWidth > totalSize.width) {
|
|
totalSize.width = newWidth;
|
|
}
|
|
}
|
|
}
|
|
|
|
totalSize.height /= getVirtualScale()[1];
|
|
|
|
if (width != -1.0f) {
|
|
totalSize.width = width;
|
|
}
|
|
|
|
if (totalSize.width == 0.0f || totalSize.height == 0.0f) {
|
|
return;
|
|
}
|
|
|
|
totalSize.width += 24.0f;
|
|
totalSize.height += 8.0f;
|
|
|
|
//if (m_bVirtual)
|
|
//{
|
|
totalSize.width *= getVirtualScale()[0];
|
|
totalSize.height *= getVirtualScale()[1];
|
|
//}
|
|
|
|
UIPoint2D place;
|
|
place.x = (where) ? createRect.pos.x : createRect.size.width + createRect.pos.x;
|
|
place.y = (where) ? createRect.size.height + createRect.pos.y : createRect.pos.y;
|
|
|
|
// FIXME: avoid code repetition, extract these checks below to an inline func
|
|
|
|
// Adjust position of menu rect if it goes beyond the screen width
|
|
if (place.x + totalSize.width > uid.vidWidth) {
|
|
place.x = (where) ? createRect.size.width + createRect.pos.x : createRect.pos.x;
|
|
|
|
if (place.x < totalSize.width) {
|
|
place.x = std::fmax(0.0f, uid.vidWidth - totalSize.width);
|
|
} else {
|
|
place.x -= totalSize.width;
|
|
}
|
|
}
|
|
|
|
// Adjust position of menu rect if it goes beyond the screen height
|
|
if (place.y + totalSize.height > uid.vidHeight) {
|
|
place.y = (where) ? createRect.pos.y : createRect.size.height + createRect.pos.y;
|
|
|
|
if (place.y < totalSize.height) {
|
|
place.y = std::fmax(0.0f, uid.vidHeight - totalSize.height);
|
|
} else {
|
|
place.y -= totalSize.height;
|
|
}
|
|
}
|
|
|
|
InitFrame(NULL, place.x, place.y, totalSize.width, totalSize.height, 1);
|
|
}
|
|
|
|
void UIPopupMenu::YouAreASubmenu(UIPopupMenu *me)
|
|
{
|
|
m_parentMenu = me;
|
|
}
|
|
|
|
void UIPopupMenu::Draw(void)
|
|
{
|
|
const float originX = getVirtualScale()[0] * 4.0f;
|
|
const float originY = getVirtualScale()[1] * 4.0f;
|
|
|
|
float fFontHeight = m_font->getHeight(getVirtualScale());
|
|
float top = originY;
|
|
for (int i = 1; i <= m_describe->NumObjects(); i++) {
|
|
uipopup_describe *desc = m_describe->ObjectAt(i);
|
|
if (desc->type == UIP_SEPARATOR) {
|
|
DrawBox(
|
|
originX * 2.0f, originY + top, m_frame.size.width - (originX * 4.0f), 1.0f, m_foreground_color, 1.0f
|
|
);
|
|
} else {
|
|
UColor textColor;
|
|
if (m_selected == i || m_submenu == i) {
|
|
DrawBox(
|
|
originX / 2.0f, top, m_frame.size.width - originX, fFontHeight, m_highlightBGColor, m_local_alpha
|
|
);
|
|
|
|
textColor = m_highlightFGColor;
|
|
} else {
|
|
textColor = m_foreground_color;
|
|
}
|
|
|
|
m_font->setColor(textColor);
|
|
m_marlett.setColor(textColor);
|
|
const char *text = Sys_LV_CL_ConvertString(desc->title);
|
|
m_font->Print(4.0f, top / getVirtualScale()[1], text, -1, getVirtualScale());
|
|
|
|
if (desc->type == UIP_SUBMENU) {
|
|
m_marlett.PrintJustified(
|
|
UIRect2D(0.0f, top, m_frame.size.width - originX, getDescribeHeight(desc)),
|
|
m_iFontAlignmentHorizontal,
|
|
m_iFontAlignmentVertical,
|
|
"4",
|
|
getVirtualScale()
|
|
);
|
|
}
|
|
}
|
|
|
|
top += getDescribeHeight(desc);
|
|
}
|
|
}
|
|
|
|
void UIPopupMenu::MouseReleased(Event *ev)
|
|
{
|
|
UIPoint2D p = MouseEventToClientPoint(ev); // unused
|
|
if (m_selected == -1 || m_selected > m_describe->NumObjects()) {
|
|
return;
|
|
}
|
|
|
|
uipopup_describe *desc = m_describe->ObjectAt(m_selected);
|
|
if (!desc || desc->type == UIP_SEPARATOR || desc->type == UIP_SUBMENU) {
|
|
return;
|
|
}
|
|
|
|
// NOTE: Dismiss() below can delete this entire instance!
|
|
// Save the m_listener pointer for later, as `this->m_listener`
|
|
// cannot be used after the instance was freed.
|
|
Listener *listener = m_listener;
|
|
|
|
if (m_autodismiss) {
|
|
Dismiss();
|
|
}
|
|
|
|
switch (desc->type) {
|
|
case UIP_EVENT:
|
|
// make sure it's passed in as an Event&, as ProcessEvent(Event*) would try to delete the static event!
|
|
listener->ProcessEvent(*(Event *)desc->data);
|
|
break;
|
|
case UIP_EVENT_STRING:
|
|
listener->ProcessEvent(new Event((const char *)desc->data));
|
|
break;
|
|
case UIP_CMD:
|
|
case UIP_CVAR:
|
|
Cbuf_AddText((const char *)desc->data);
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
|
|
void UIPopupMenu::MouseMoved(Event *ev)
|
|
{
|
|
UIPoint2D point = MouseEventToClientPoint(ev);
|
|
uipopup_describe *describe = getDescribeFromPoint(point);
|
|
if (describe) {
|
|
int index = m_describe->IndexOfObject(describe);
|
|
setSelection(index);
|
|
} else {
|
|
setSelection(-1);
|
|
}
|
|
}
|
|
|
|
void UIPopupMenu::MouseExited(Event *ev)
|
|
{
|
|
MouseMoved(ev);
|
|
}
|
|
|
|
void UIPopupMenu::Dismiss(void)
|
|
{
|
|
// navigate to the topmost menu
|
|
if (m_parentMenu) {
|
|
m_parentMenu->Dismiss();
|
|
} else {
|
|
delete this;
|
|
}
|
|
}
|
|
|
|
void UIPopupMenu::DismissEvent(Event *ev)
|
|
{
|
|
Dismiss();
|
|
}
|
|
|
|
void UIPopupMenu::setAutoDismiss(bool b)
|
|
{
|
|
m_autodismiss = b;
|
|
}
|
|
|
|
void UIPopupMenu::setNextSelection(void)
|
|
{
|
|
if (!m_describe->NumObjects()) {
|
|
return;
|
|
}
|
|
|
|
if (m_selected == -1) {
|
|
setSelection(0);
|
|
return;
|
|
}
|
|
|
|
int sel = m_selected + 1;
|
|
if (sel > m_describe->NumObjects()) {
|
|
// wrap around
|
|
sel = 0;
|
|
}
|
|
|
|
setSelection(sel);
|
|
}
|
|
|
|
void UIPopupMenu::setPrevSelection(void)
|
|
{
|
|
if (!m_describe->NumObjects()) {
|
|
return;
|
|
}
|
|
|
|
if (m_selected == -1) {
|
|
setSelection(0);
|
|
return;
|
|
}
|
|
|
|
int sel;
|
|
if (m_selected != 0) {
|
|
sel = m_selected - 1;
|
|
} else {
|
|
// wrap around
|
|
sel = m_describe->NumObjects();
|
|
}
|
|
|
|
setSelection(sel);
|
|
}
|
|
|
|
uipopup_describe *UIPopupMenu::getSelectedDescribe(void)
|
|
{
|
|
if (m_selected == -1) {
|
|
return NULL;
|
|
}
|
|
|
|
return m_describe->ObjectAt(m_selected);
|
|
}
|
|
|
|
void UIPopupMenu::setSelection(int sel)
|
|
{
|
|
int maxSel = m_describe->NumObjects();
|
|
if (sel > maxSel) {
|
|
m_selected = maxSel;
|
|
return;
|
|
}
|
|
|
|
int newSubMenu = -1;
|
|
if (sel != -1) {
|
|
uipopup_describe *desc = m_describe->ObjectAt(sel);
|
|
if (desc && desc->type == UIP_SUBMENU) {
|
|
newSubMenu = sel;
|
|
}
|
|
}
|
|
|
|
m_selected = sel;
|
|
|
|
if (newSubMenu == m_submenu) {
|
|
return;
|
|
}
|
|
|
|
if (newSubMenu == -1) {
|
|
if (m_submenuptr) {
|
|
delete m_submenuptr;
|
|
}
|
|
|
|
m_submenu = -1;
|
|
} else {
|
|
if (m_submenu != -1 && m_submenuptr) {
|
|
delete m_submenuptr;
|
|
}
|
|
|
|
m_submenu = newSubMenu;
|
|
MakeSubMenu();
|
|
}
|
|
}
|
|
|
|
void UIPopupMenu::setHighlightFGColor(UColor c)
|
|
{
|
|
m_highlightFGColor = c;
|
|
}
|
|
|
|
void UIPopupMenu::setHighlightBGColor(UColor c)
|
|
{
|
|
m_highlightBGColor = c;
|
|
}
|
|
|
|
void UIPopupMenu::setPopupHighlightBGColor(str menu, UColor c)
|
|
{
|
|
// not present in disassembly
|
|
}
|
|
|
|
void UIPopupMenu::setPopupHighlightFGColor(str menu, UColor c)
|
|
{
|
|
// not present in disassembly
|
|
}
|
|
|
|
void UIPopupMenu::getPulldown(str title)
|
|
{
|
|
// not present in disassembly
|
|
}
|