openmohaa/code/uilib/uilist.cpp
smallmodel 6fe1e86b31
Automatically scale UI elements for high resolutions
This fixes UI elements being tiny on high resolutions like 4K. Now most UI elements will scale automatically with resolutions above 1920x1080.
2024-11-30 22:40:00 +01:00

380 lines
6.6 KiB
C++

/*
===========================================================================
Copyright (C) 2023 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, UIList, NULL )
{
{ &W_LeftMouseDown, &UIList::Pressed },
{ &W_LeftMouseUp, &UIList::Released },
{ &EV_Layout_AddListItem, &UIList::LayoutAddListItem },
{ NULL, NULL }
};
UIList::UIList()
{
m_arrow_width = 15.0;
m_arrow_width = 0.0;
m_currentItem = 0;
m_next_arrow_region = 0;
m_prev_arrow_region = 0;
m_prev_arrow_depressed = 0;
m_next_arrow_depressed = 0;
AllowActivate(true);
m_prev_arrow = uWinMan.RegisterShader("gfx/2d/arrow_left.tga");
if (!m_prev_arrow) {
uii.Sys_Printf("UIList::Ulist : Could not register shader gfx/2d/arrow_left.tga");
}
m_next_arrow = uWinMan.RegisterShader("gfx/2d/arrow_right.tga");
if (!m_next_arrow) {
uii.Sys_Printf("UIList::Ulist : Could not register shader gfx/2d/arrow_right.tga");
}
}
UIList::~UIList()
{
for (int i = m_itemlist.NumObjects(); i > 0; i--)
{
UIListItem* item = m_itemlist.ObjectAt(i);
m_itemlist.RemoveObjectAt(i);
delete item;
}
if (m_prev_arrow_region) delete m_prev_arrow_region;
if (m_next_arrow_region) delete m_next_arrow_region;
}
void UIList::Draw
(
void
)
{
UpdateUIElement();
// draw the item text
if (m_currentItem)
{
str itemText;
UIListItem *item = m_itemlist.ObjectAt(m_currentItem);
if (item->itemalias)
{
itemText = item->itemalias;
}
else if (item->itemname)
{
itemText = item->itemname;
}
float textX = 0.5f * m_frame.size.width - 0.5f * m_font->getWidth(itemText, -1);
float textY = 0.5f * (m_frame.size.height - m_font->getHeight(m_bVirtual ? m_vVirtualScale : uid.scaleRes)) - 1.0f;
m_font->setColor(m_foreground_color);
const char *text = Sys_LV_CL_ConvertString(itemText);
m_font->Print(textX, textY, text, -1, m_bVirtual ? m_vVirtualScale : NULL);
}
// draw the previous arrow
Draw3DBox(
0.0f,
0.0f,
m_arrow_width,
m_frame.size.height,
m_prev_arrow_depressed,
m_border_color,
m_local_alpha);
float height = m_frame.size.height - 4.0;
float width = m_arrow_width - 4.0;
uii.Rend_DrawPicStretched(
2.0f,
2.0f,
width,
height,
0.0f,
0.0f,
1.0f,
1.0f,
m_prev_arrow->GetMaterial());
// draw the next arrow
float x = m_frame.size.width - m_arrow_width;
float y = 0.0f;
Draw3DBox(
x,
y,
m_arrow_width,
m_frame.size.height,
m_next_arrow_depressed,
m_border_color,
m_local_alpha);
uii.Rend_DrawPicStretched(
x + 2.0f,
y + 2.0f,
width,
height,
0.0f,
0.0f,
1.0f,
1.0f,
m_next_arrow->GetMaterial());
}
qboolean UIList::KeyEvent
(
int key,
unsigned int time
)
{
switch (key)
{
case K_RIGHTARROW:
ScrollNext();
UpdateData();
if (m_commandhandler) {
m_commandhandler(m_itemlist.ObjectAt(m_currentItem)->itemname.c_str(), NULL);
}
return qtrue;
case K_LEFTARROW:
ScrollPrev();
UpdateData();
if (m_commandhandler) {
m_commandhandler(m_itemlist.ObjectAt(m_currentItem)->itemname.c_str(), NULL);
}
return qtrue;
default:
return qfalse;
}
}
void UIList::CharEvent
(
int ch
)
{
}
void UIList::Pressed
(
Event *ev
)
{
m_held = qtrue;
m_depressed = qtrue;
float mouse_xpos = ev->GetFloat(1);
float mouse_ypos = ev->GetFloat(2);
int buttons = ev->GetInteger(3); // unused
FrameInitialized();
// previous arrow is clicked
if (m_prev_arrow_region->contains(mouse_xpos, mouse_ypos))
{
m_prev_arrow_depressed = qtrue;
ScrollPrev();
UpdateData();
return;
}
// next arrow is clicked
if (m_next_arrow_region->contains(mouse_xpos, mouse_ypos))
{
m_next_arrow_depressed = qtrue;
ScrollNext();
UpdateData();
}
}
void UIList::Released
(
Event *ev
)
{
m_held = qfalse;
m_depressed = qfalse;
m_prev_arrow_depressed = qfalse;
m_next_arrow_depressed = qfalse;
}
void UIList::ScrollNext
(
void
)
{
m_currentItem++;
if (m_currentItem > m_itemlist.NumObjects()) {
m_currentItem = m_itemlist.NumObjects();
}
}
void UIList::ScrollPrev
(
void
)
{
m_currentItem--;
if (m_currentItem < 1) {
m_currentItem = 1;
}
}
void UIList::FrameInitialized
(
void
)
{
m_prev_arrow_region = new UIRect2D(m_clippedframe.pos.x, m_clippedframe.pos.y, m_arrow_width, m_frame.size.height);
m_next_arrow_region = new UIRect2D(m_clippedframe.size.width - m_arrow_width + m_clippedframe.pos.x, m_clippedframe.pos.y, m_arrow_width, m_frame.size.height);
}
void UIList::LayoutAddListItem
(
Event *ev
)
{
str item = ev->GetString(1);
str alias;
if (ev->NumArgs() > 1)
{
alias = ev->GetString(2);
}
AddItem(item, alias);
}
void UIList::AddItem
(
str item,
str alias
)
{
UIListItem *listItem = new UIListItem();
listItem->itemname = item;
listItem->itemalias = alias;
m_itemlist.AddObject(listItem);
m_currentItem = 1;
}
void UIList::UpdateUIElement
(
void
)
{
if (!m_cvarname)
{
return;
}
const char *cvarstring = UI_GetCvarString(m_cvarname, NULL);
if (!cvarstring)
{
m_currentItem = 1;
UpdateData();
return;
}
for (int i = 1; i <= m_itemlist.NumObjects(); i++)
{
UIListItem *obj = m_itemlist.ObjectAt(i);
if (obj->itemname == cvarstring)
{
m_currentItem = i;
break;
}
}
}
void UIList::UpdateData
(
void
)
{
if (!m_currentItem)
{
return;
}
if (m_cvarname)
{
UIListItem *item = m_itemlist.ObjectAt(m_currentItem);
if (item->itemname)
{
uii.Cvar_Set(m_cvarname, item->itemname);
}
}
if (m_command)
{
UIListItem *item = m_itemlist.ObjectAt(m_currentItem);
m_command.append(' ');
m_command.append(item->itemname);
m_command.append('\n');
Cbuf_AddText(m_command.c_str());
}
}
CLASS_DECLARATION( UIList, UIListIndex, NULL )
{
{ NULL, NULL }
};
qboolean UIListIndex::KeyEvent
(
int key,
unsigned int time
)
{
switch (key)
{
case K_RIGHTARROW:
ScrollNext();
UpdateData();
return qtrue;
case K_LEFTARROW:
ScrollPrev();
UpdateData();
return qtrue;
default:
return qfalse;
}
}