Descent3/ui/UIWindow.cpp

727 lines
19 KiB
C++
Raw Normal View History

/*
* Descent 3
* Copyright (C) 2024 Parallax Software
*
* This program 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 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
--- HISTORICAL COMMENTS FOLLOW ---
2024-04-16 03:43:29 +00:00
* $Logfile: /DescentIII/Main/ui/UIWindow.cpp $
* $Revision: 39 $
* $Date: 5/02/99 2:09a $
* $Author: Samir $
*
* Interface code.
*
* $Log: /DescentIII/Main/ui/UIWindow.cpp $
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 39 5/02/99 2:09a Samir
* don't process input on disabled gadgets.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 38 4/26/99 9:11p Matt
* Took out saturation used by old newui.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 37 4/22/99 4:28p Samir
* made gadget clip check include the right and bottom boundaries of the
* screen.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 36 4/21/99 12:42p Samir
* clip gadgets on screen.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 35 4/14/99 1:54a Jeff
* fixed case mismatched #includes
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 34 3/01/99 6:56p Samir
* saturate text for old ui menus (UIF_PROCESS_ALL)
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 32 3/01/99 5:00a Samir
* whenever m_GadgetCur is being NULLed, do a lose focus on it first.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 31 2/26/99 2:10a Samir
* added accelerator table.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 30 2/22/99 8:13p Samir
* added slave gadget system that only uses mouse input from window, but
* defers keys to its master.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 29 2/21/99 6:36p Samir
* focusing changes and key input changes to ui.,
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 28 2/17/99 8:32p Samir
* fixed bugs in remove gadget, added callbacks for attaching and
* detaching gadgets.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 27 2/16/99 11:58a Samir
* small fixes and added gadget notification.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 26 10/19/98 12:18p Samir
* made tabbing between edit controls possible.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 25 10/13/98 8:23p Samir
* communication between gadget and window and edit system to work
* together.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 24 10/06/98 7:31p Samir
* both tab keys and arrow keys scroll through gadgets.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 23 9/10/98 10:20a Samir
* when removing a gadget from a window, check if it's being used by the
* user intefrace, if it is then remove it from that.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 22 8/31/98 12:36p Samir
* implemented dialogversion of window.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 21 8/27/98 2:52p Samir
* changing window system to work in two modes.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 20 8/26/98 12:25p Samir
* fixed the whole editbox, keyboard access mess.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 19 8/25/98 7:08p Samir
* select how keys are sent to a gadget.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 18 8/25/98 6:33p Kevin
* PXO screens
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 17 8/25/98 5:27p Samir
* new focusing rules for keyboard.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 16 6/05/98 5:35p Samir
* massive improvement in UI keyboard interface.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 15 3/10/98 12:48p Samir
* Added window centering ability.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 14 3/09/98 2:57p Samir
* Remove gadget from window called from gadget destroy.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 13 3/05/98 6:38p Samir
* Fixed key presses within windows.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 12 2/15/98 7:07p Samir
* Revamped way keys like up and down are handled in window system.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 11 2/13/98 6:35p Samir
* Fixed some gadget creation/destruction inconsistancies
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 10 2/02/98 7:36p Samir
* Added UIObject::Destroy.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 9 1/30/98 7:05p Samir
* Each gadget now has their own coordinate system.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 8 1/26/98 10:54a Samir
* Fixed bug in UIWindow returning -2 always.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 7 1/23/98 5:45p Samir
* Call OnUserProcess after default Window Process.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 6 1/18/98 4:23p Samir
* Moved object destruction code to a virtual OnDestroy function for
* gadgets. Must destroy window too.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 5 1/13/98 4:26p Samir
* Changed process of setting and getting focus.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 4 1/08/98 12:17p Samir
* Added TitledWindow and modified the UI interface for polling.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 3 1/05/98 11:10a Jason
* FROM SAMIR: Draw background rectangle for menus
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 2 1/02/98 12:48p Samir
* Redid setting and releasing keyboard/mouse focus for gadgets.
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* 1 12/30/97 4:36p Samir
* Initial revision
2024-04-16 18:56:40 +00:00
*
2024-04-16 03:43:29 +00:00
* $NoKeywords: $
*/
#include "UIlib.h"
#include "Macros.h"
// the window font for all windows
int UIWindow::m_WindowFont = 0;
// ----------------------------------------------------------------------------
// UIWindow class
2024-04-16 18:56:40 +00:00
UIWindow::UIWindow() : UIObject() {
m_GadgetHead = NULL;
m_GadgetTail = NULL;
m_GadgetCur = NULL;
m_BackItem = NULL;
m_HoldHotkeys = false;
m_CurGadgetInGroup = false;
m_ResetCurGadget = false;
m_naccels = 0;
2024-04-16 03:43:29 +00:00
}
2024-04-16 18:56:40 +00:00
UIWindow::~UIWindow() {
if (m_GadgetTail) {
Destroy();
}
2024-04-16 03:43:29 +00:00
}
// create a window at the specified coords.
2024-04-16 18:56:40 +00:00
void UIWindow::Create(int x, int y, int w, int h, int flags) {
m_FontHandle = m_WindowFont;
m_LockedGadget = NULL;
m_BackItem = UIPrimativeItem(TRANSPARENT_COLOR32).CopyUIItem();
m_BackColor = GR_RGB(0, 0, 0);
m_Flags = flags;
m_GadgetTail = NULL;
m_GadgetHead = NULL;
m_LastKey = 0;
m_LastKeyTime = 0.0f;
m_HoldHotkeys = false;
m_ResetCurGadget = false;
m_CurGadgetInGroup = false;
m_naccels = 0;
if (m_Flags & UIF_CENTER) {
x = UI_screen_width / 2 - w / 2;
y = UI_screen_height / 2 - h / 2;
}
UIObject::Create(x, y, w, h);
2024-04-16 03:43:29 +00:00
}
2024-04-16 18:56:40 +00:00
void UIWindow::Destroy() {
OnDestroy();
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
while (m_GadgetTail) {
UIGadget *gadget = m_GadgetTail;
gadget->Destroy(); // gadget must be destroyed AFTER it's removed from list.
}
m_GadgetTail = NULL;
m_GadgetHead = NULL;
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
SetBackItem(NULL);
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
UIObject::Destroy();
2024-04-16 03:43:29 +00:00
}
// interface functions
// adds a UIObject to the interface's draw list.
2024-04-16 18:56:40 +00:00
void UIWindow::AddGadget(UIGadget *gadget) {
ASSERT(IsCreated());
ASSERT(gadget->IsCreated());
// perform a linked list add.
if (!m_GadgetHead) {
m_GadgetHead = gadget;
m_GadgetTail = m_GadgetHead;
} else {
m_GadgetTail->m_Next = gadget;
gadget->m_Prev = m_GadgetTail;
gadget->m_Next = NULL;
m_GadgetTail = gadget;
}
if (m_GadgetCur) {
m_GadgetCur->LostFocus();
m_GadgetCur = NULL;
}
m_ResetCurGadget = true;
m_CurGadgetInGroup = false;
gadget->m_Wnd = this;
gadget->OnAttachToWindow();
2024-04-16 03:43:29 +00:00
}
// removes a UIObject from the draw list.
2024-04-16 18:56:40 +00:00
void UIWindow::RemoveGadget(UIGadget *gadget) {
if (!gadget)
return;
ASSERT(IsCreated());
ASSERT(gadget->IsCreated());
ASSERT(gadget->m_Wnd == this);
gadget->OnDetachFromWindow();
// remove object from list.
if (gadget->m_Prev)
gadget->m_Prev->m_Next = gadget->m_Next;
if (gadget->m_Next)
gadget->m_Next->m_Prev = gadget->m_Prev;
if (gadget == m_GadgetTail)
m_GadgetTail = gadget->m_Prev;
if (gadget == m_GadgetHead)
m_GadgetHead = gadget->m_Next;
if (gadget == m_GadgetCur) {
m_GadgetCur->LostFocus();
m_GadgetCur = NULL;
m_ResetCurGadget = true;
m_CurGadgetInGroup = false;
}
if (gadget == m_LockedGadget)
m_LockedGadget = NULL;
// break link.
gadget->m_Prev = NULL;
gadget->m_Next = NULL;
gadget->m_Wnd = NULL;
2024-04-16 03:43:29 +00:00
}
// forces a particular gadget into focus, always until unlocked.
2024-04-16 18:56:40 +00:00
void UIWindow::LockFocusOnGadget(UIGadget *gadget) { m_LockedGadget = gadget; }
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
void UIWindow::UnlockFocusOnGadget() { m_LockedGadget = NULL; }
2024-04-16 03:43:29 +00:00
// forces all keyinput onto one gadget.
2024-04-16 18:56:40 +00:00
void UIWindow::LockKeyFocusOnGadget(UIGadget *gadget) {}
2024-04-16 03:43:29 +00:00
// Process
// run this to handle user input inside an interface
// sets focus on a control
// m_GadgetCur is gadget in focus.
2024-04-16 18:56:40 +00:00
int UIWindow::Process() {
ASSERT(IsCreated());
bool no_process = false; // don't do input for disabled gadgets.
if (m_ResetCurGadget) {
// find first valid gadget to set focus to.
UIGadget *start_gadget, *gadget;
start_gadget = gadget = m_GadgetHead;
if (gadget) {
bool in_group = false;
do {
if (CHECK_FLAG(gadget->GetFlags(), UIF_GROUP_START)) {
in_group = true;
}
if (!gadget->IsDisabled() && !CHECK_FLAG(gadget->GetFlags(), UIF_SLAVE)) {
if (m_GadgetCur) {
m_GadgetCur->LostFocus();
}
m_GadgetCur = gadget;
m_GadgetCur->GainFocus();
m_CurGadgetInGroup = in_group;
break;
}
if (CHECK_FLAG(gadget->GetFlags(), UIF_GROUP_END)) {
in_group = false;
}
gadget = (gadget->m_Next) ? gadget->m_Next : m_GadgetHead;
} while (gadget != start_gadget);
}
m_ResetCurGadget = false;
}
// setup default output values
UI_output.gadget = NULL;
UI_output.id = -1;
// we can do focus processing if no one gadget has locked the keyboard, mouse focus.
if (!m_LockedGadget) {
UIGadget *test_gadget = NULL;
if (UI_input.b1_status == UIMSEBTN_PRESSED || UI_input.b1_status == UIMSEBTN_CLICKED) {
// start from top most gadget down for mouse focus check.
bool in_group = false;
for (test_gadget = m_GadgetTail; test_gadget != NULL; test_gadget = test_gadget->m_Prev) {
if (CHECK_FLAG(test_gadget->GetFlags(), UIF_GROUP_END)) { // going from end of list to start, so reverse
in_group = true;
}
if (PT_IN_GADGET(this, test_gadget, UI_input.mx, UI_input.my)) {
if (!CHECK_FLAG(test_gadget->GetFlags(), UIF_SLAVE)) {
if (!test_gadget->IsDisabled()) {
break;
} else {
test_gadget = NULL;
no_process = true;
break;
}
}
}
if (CHECK_FLAG(test_gadget->GetFlags(), UIF_GROUP_START)) {
in_group = false;
}
}
// switch focus from old gadget to new.
if (test_gadget) {
if (m_GadgetCur && m_GadgetCur != test_gadget) {
m_GadgetCur->LostFocus();
m_GadgetCur = NULL;
}
if (!m_GadgetCur) {
m_GadgetCur = test_gadget;
m_GadgetCur->GainFocus();
m_CurGadgetInGroup = in_group;
}
test_gadget->CheckFocusOnSlaves(UI_input.mx, UI_input.my);
}
} else {
// check for keyboard switching.
if (UI_input.key_status == UIKEY_PRESSED) {
if (TrapKey(UI_input.key)) {
OnKeyDown(UI_input.key);
}
} else if (UI_input.key_status == UIKEY_RELEASED) {
UntrapKey(UI_input.key);
OnKeyUp(UI_input.key);
} else if (UI_input.key_status == UIKEY_CLICKED) {
if (TrapKey(UI_input.key)) {
OnKeyDown(UI_input.key);
}
UntrapKey(UI_input.key);
OnKeyUp(UI_input.key);
}
}
} else {
// always assert that current gadget is locked gadget.
// if not, then m_CurGadgetInGroup can be wrong.
// ASSERT(m_GadgetCur == m_LockedGadget);
// m_GadgetCur = m_LockedGadget;
}
// process input for current gadget in focus.
if (m_LockedGadget) {
m_LockedGadget->Process(true);
} else if (m_GadgetCur && !m_GadgetCur->IsDisabled()) {
// check what slave gadget a mouse event occurs inside m_GadgetCur
if (!no_process) {
if (m_GadgetCur->m_CurrentSlave) {
m_GadgetCur->m_CurrentSlave->Process(false, true);
}
m_GadgetCur->Process(true, m_GadgetCur->m_CurrentSlave ? false : true);
}
}
// perform user processing of window input.
OnUserProcess();
return UI_output.id;
2024-04-16 03:43:29 +00:00
}
// overridable: runs after window is processed, to supplement it.
2024-04-16 18:56:40 +00:00
void UIWindow::OnUserProcess() {}
2024-04-16 03:43:29 +00:00
// behavior when key is pressed.
2024-04-16 18:56:40 +00:00
void UIWindow::OnKeyDown(int key) {
UIGadget *gadget, *start_gadget;
bool in_group;
// advance down gadget list.
if (key == KEY_TAB) {
if (!m_GadgetCur) {
m_ResetCurGadget = true;
return;
}
start_gadget = gadget = m_GadgetCur;
in_group = m_CurGadgetInGroup;
do {
if (CHECK_FLAG(gadget->GetFlags(), UIF_GROUP_START)) {
in_group = true;
}
if (CHECK_FLAG(gadget->GetFlags(), UIF_GROUP_END)) {
in_group = false;
}
gadget = (gadget->m_Next) ? gadget->m_Next : m_GadgetHead;
if (!gadget->IsDisabled() && !CHECK_FLAG(gadget->GetFlags(), UIF_SLAVE) && !in_group) {
start_gadget->LostFocus();
gadget->GainFocus();
m_CurGadgetInGroup = (CHECK_FLAG(gadget->GetFlags(), UIF_GROUP_START) > 0);
m_GadgetCur = gadget;
break;
}
} while (gadget != start_gadget);
}
if (key == (KEY_SHIFTED + KEY_TAB)) {
if (!m_GadgetCur) {
m_ResetCurGadget = true;
return;
}
start_gadget = gadget = m_GadgetCur;
in_group = m_CurGadgetInGroup;
do {
gadget = (gadget->m_Prev) ? gadget->m_Prev : m_GadgetTail;
if (CHECK_FLAG(gadget->GetFlags(), UIF_GROUP_END)) {
in_group = true;
}
if (CHECK_FLAG(gadget->GetFlags(), UIF_GROUP_START)) {
in_group = false;
}
if (!gadget->IsDisabled() && !CHECK_FLAG(gadget->GetFlags(), UIF_SLAVE) && !in_group) {
start_gadget->LostFocus();
gadget->GainFocus();
m_CurGadgetInGroup =
(CHECK_FLAG(gadget->GetFlags(), UIF_GROUP_END)) || (CHECK_FLAG(gadget->GetFlags(), UIF_GROUP_START));
m_GadgetCur = gadget;
break;
}
} while (gadget != start_gadget);
}
// handle direction keys only in a group
if (m_CurGadgetInGroup) {
if (key == KEY_UP || key == KEY_LEFT) {
if (!m_GadgetCur) {
m_ResetCurGadget = true;
return;
}
start_gadget = gadget = m_GadgetCur;
do {
if (CHECK_FLAG(gadget->GetFlags(), UIF_GROUP_START)) {
break;
}
gadget = (gadget->m_Prev) ? gadget->m_Prev : m_GadgetTail;
if (!gadget->IsDisabled() && !CHECK_FLAG(gadget->GetFlags(), UIF_SLAVE)) {
start_gadget->LostFocus();
gadget->GainFocus();
m_GadgetCur = gadget;
break;
}
} while (start_gadget != gadget);
}
if (key == KEY_DOWN || key == KEY_RIGHT) {
if (!m_GadgetCur) {
m_ResetCurGadget = true;
return;
}
start_gadget = gadget = m_GadgetCur;
do {
if (CHECK_FLAG(gadget->GetFlags(), UIF_GROUP_END)) {
break;
}
gadget = (gadget->m_Next) ? gadget->m_Next : m_GadgetHead;
if (!gadget->IsDisabled() && !CHECK_FLAG(gadget->GetFlags(), UIF_SLAVE)) {
start_gadget->LostFocus();
gadget->GainFocus();
m_GadgetCur = gadget;
break;
}
} while (start_gadget != gadget);
}
}
// determine if any hotkey was pressed
if (!m_HoldHotkeys) {
int i;
for (gadget = m_GadgetHead; gadget != NULL; gadget = gadget->m_Next) {
if (!gadget->IsDisabled()) {
if (gadget->GetID() == UID_CANCEL && key == KEY_ESC)
gadget->OnSelect();
}
}
// do hotkeys
for (gadget = m_GadgetHead; gadget != NULL; gadget = gadget->m_Next) {
if (!gadget->IsDisabled() && UI_input.key && ISKEYPRESSED(gadget->m_Hotkey))
gadget->OnSelect();
}
// do window accelerators.
for (i = 0; i < m_naccels; i++) {
if (UI_input.key && ISKEYPRESSED(m_Accelerators[i].key) && UI_output.id < 0) {
UI_output.gadget = NULL;
UI_output.id = m_Accelerators[i].id;
break;
}
}
}
2024-04-16 03:43:29 +00:00
}
// behavior when key is released.
2024-04-16 18:56:40 +00:00
void UIWindow::OnKeyUp(int key) {}
2024-04-16 03:43:29 +00:00
// redraw all gadgets
2024-04-16 18:56:40 +00:00
void UIWindow::Render() {
UIGadget *gadget = m_GadgetHead;
// draw background of window.
ui_StartDraw(m_X, m_Y, m_X + m_W, m_Y + m_H);
ui_DrawSetFont(m_FontHandle);
OnDraw();
ui_EndDraw();
while (gadget) {
int l = m_X + gadget->X();
int t = m_Y + gadget->Y();
int r = l + gadget->W();
int b = t + gadget->H();
// reformat gadget
gadget->OnFormat();
// draw gadget
if (l >= 0 && r <= UI_screen_width && t >= 0 && b <= UI_screen_height) {
ui_StartDraw(l, t, r, b);
ui_DrawSetFont(m_FontHandle);
gadget->OnDraw();
ui_EndDraw();
} else {
mprintf((0, "WINDOW: Gadget clipped on screen border (%d,%d,%d,%d)\n", l, t, r, b));
// Int3();
}
// proeceed...
gadget = gadget->m_Next;
}
UITextItem::SetSaturationFactor(0);
2024-04-16 03:43:29 +00:00
// draw ugly looking focus box around current gadget.
#if 0
if (m_GadgetCur && !CHECK_FLAG(m_GadgetCur->m_Flags, UIF_SLAVE) ) {
int l = m_X+m_GadgetCur->X();
int t = m_Y+m_GadgetCur->Y();
int r = l+m_GadgetCur->W();
int b = t+m_GadgetCur->H();
l--; t--; r++; b++;
if (l < 0) l = 0;
if (t < 0) t = 0;
if (r >(m_X+m_W)) r = m_X+m_W;
if (b >(m_Y+m_H)) b = m_Y+m_H;
ui_StartDraw(l,t,r,b);
ui_DrawBox(GR_RGB(128,128,128),0,0,(r-l),(b-t));
ui_EndDraw();
}
#endif
}
// adds window to ui list.
2024-04-16 18:56:40 +00:00
void UIWindow::Open() { ui_AddWindow(this); }
2024-04-16 03:43:29 +00:00
// removes window from ui list.
2024-04-16 18:56:40 +00:00
void UIWindow::Close() { ui_RemoveWindow(this); }
2024-04-16 03:43:29 +00:00
// settings
2024-04-16 18:56:40 +00:00
void UIWindow::SetFont(int handle) { m_FontHandle = handle; }
2024-04-16 03:43:29 +00:00
// overridable draws the window background before gadgets
2024-04-16 18:56:40 +00:00
void UIWindow::OnDraw() {
if (m_BackItem)
m_BackItem->draw(0, 0, m_W, m_H);
2024-04-16 03:43:29 +00:00
}
2024-04-16 18:56:40 +00:00
// used to manage keypresses so repeating isn't quick.
bool UIWindow::TrapKey(int key) {
float time;
time = timer_GetTime();
// take care of multiple keypresses and key down repeats. handle timing
// so it feels 'natural'
if (m_LastKey && m_LastKey == key) {
if (m_LastKeyCount == 1) {
if ((time - m_LastKeyTime) < KEYDOWN_FIRST_DELAY)
return false;
m_LastKeyCount++;
} else if ((time - m_LastKeyTime) < KEYDOWN_REPEAT_DELAY) {
return false;
}
m_LastKeyCount++;
} else {
m_LastKeyCount = 1;
}
m_LastKey = key;
m_LastKeyTime = time;
return true;
2024-04-16 03:43:29 +00:00
}
2024-04-16 18:56:40 +00:00
void UIWindow::UntrapKey(int key) {
// if the key previously pressed went up, then
// turn off key repeat management.
if (key == m_LastKey) {
m_LastKeyCount = 0;
m_LastKey = 0;
}
2024-04-16 03:43:29 +00:00
}
2024-04-16 18:56:40 +00:00
void UIWindow::SetFocusOnGadget(UIGadget *gadget, bool key) {
if (m_GadgetCur) {
m_GadgetCur->LostFocus();
}
m_GadgetCur = gadget;
if (m_GadgetCur) {
m_GadgetCur->GainFocus();
m_ResetCurGadget = false;
}
2024-04-16 03:43:29 +00:00
}
// used to mark key pressed to id numbers
2024-04-16 18:56:40 +00:00
void UIWindow::AddAcceleratorKey(int key, int id) {
if (m_naccels == N_WINDOW_ACCELS) {
// window has asked for too many accelerators. will not add this one. it's okay to continue, but tell someone
Int3();
return;
}
m_Accelerators[m_naccels].id = id;
m_Accelerators[m_naccels].key = key;
m_naccels++;
2024-04-16 03:43:29 +00:00
}
2024-04-16 18:56:40 +00:00
void UIWindow::ResetAcceleratorKey() { m_naccels = 0; }
2024-04-16 03:43:29 +00:00
// ----------------------------------------------------------------------------
// UITitledWindow class
2024-04-16 18:56:40 +00:00
UITitledWindow::UITitledWindow() {}
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
UITitledWindow::~UITitledWindow() {}
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
void UITitledWindow::Create(UITextItem &title, int x, int y, int w, int h) {
m_Title = title;
m_BorderThickness = 2;
m_CaptionColor = GR_DARKGRAY;
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
UIWindow::Create(x, y, w, h);
UIPrimativeItem item{GR_LIGHTGRAY};
UIWindow::SetBackItem(&item);
2024-04-16 03:43:29 +00:00
}
2024-04-16 18:56:40 +00:00
// inheritable actions
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
// draws the window background before gadgets
void UITitledWindow::OnDraw() {
UIWindow::OnDraw();
int m_CaptionHeight; // caption height
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
// set font for title.
if (m_Title.get_font() > -1)
ui_DrawSetFont(m_Title.get_font());
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
m_CaptionHeight = ui_GetFontHeight() + ui_GetFontHeight() / 2;
2024-04-16 03:43:29 +00:00
2024-04-16 18:56:40 +00:00
// draw border.
for (int i = 0; i < m_BorderThickness; i++)
ui_DrawBox(GR_RGB(0, 0, 0), m_X + i, m_Y + i, m_X + m_W - i, m_Y + m_H - i);
// draw caption.
int x, y;
ui_DrawRect(m_CaptionColor, m_BorderThickness, m_BorderThickness, m_W - m_BorderThickness, m_CaptionHeight);
x = m_W / 2 - ui_GetTextWidth(m_Title) / 2;
y = m_BorderThickness + m_CaptionHeight / 2 - ui_GetFontHeight() / 2;
ui_SetCharAlpha(m_Title.get_alpha());
ui_DrawString(m_Title.get_color(), x, y, m_Title);
}