mirror of
https://github.com/kevinbentley/Descent3.git
synced 2025-01-22 19:55:23 +00:00
a4ab78192c
Join the license header with historical comments using a separator so IDEs can correctly parse the initial header. Also use .gitattributes to ensure all files are LF.
727 lines
19 KiB
C++
727 lines
19 KiB
C++
/*
|
|
* 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 ---
|
|
|
|
* $Logfile: /DescentIII/Main/ui/UIWindow.cpp $
|
|
* $Revision: 39 $
|
|
* $Date: 5/02/99 2:09a $
|
|
* $Author: Samir $
|
|
*
|
|
* Interface code.
|
|
*
|
|
* $Log: /DescentIII/Main/ui/UIWindow.cpp $
|
|
*
|
|
* 39 5/02/99 2:09a Samir
|
|
* don't process input on disabled gadgets.
|
|
*
|
|
* 38 4/26/99 9:11p Matt
|
|
* Took out saturation used by old newui.
|
|
*
|
|
* 37 4/22/99 4:28p Samir
|
|
* made gadget clip check include the right and bottom boundaries of the
|
|
* screen.
|
|
*
|
|
* 36 4/21/99 12:42p Samir
|
|
* clip gadgets on screen.
|
|
*
|
|
* 35 4/14/99 1:54a Jeff
|
|
* fixed case mismatched #includes
|
|
*
|
|
* 34 3/01/99 6:56p Samir
|
|
* saturate text for old ui menus (UIF_PROCESS_ALL)
|
|
*
|
|
* 32 3/01/99 5:00a Samir
|
|
* whenever m_GadgetCur is being NULLed, do a lose focus on it first.
|
|
*
|
|
* 31 2/26/99 2:10a Samir
|
|
* added accelerator table.
|
|
*
|
|
* 30 2/22/99 8:13p Samir
|
|
* added slave gadget system that only uses mouse input from window, but
|
|
* defers keys to its master.
|
|
*
|
|
* 29 2/21/99 6:36p Samir
|
|
* focusing changes and key input changes to ui.,
|
|
*
|
|
* 28 2/17/99 8:32p Samir
|
|
* fixed bugs in remove gadget, added callbacks for attaching and
|
|
* detaching gadgets.
|
|
*
|
|
* 27 2/16/99 11:58a Samir
|
|
* small fixes and added gadget notification.
|
|
*
|
|
* 26 10/19/98 12:18p Samir
|
|
* made tabbing between edit controls possible.
|
|
*
|
|
* 25 10/13/98 8:23p Samir
|
|
* communication between gadget and window and edit system to work
|
|
* together.
|
|
*
|
|
* 24 10/06/98 7:31p Samir
|
|
* both tab keys and arrow keys scroll through gadgets.
|
|
*
|
|
* 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.
|
|
*
|
|
* 22 8/31/98 12:36p Samir
|
|
* implemented dialogversion of window.
|
|
*
|
|
* 21 8/27/98 2:52p Samir
|
|
* changing window system to work in two modes.
|
|
*
|
|
* 20 8/26/98 12:25p Samir
|
|
* fixed the whole editbox, keyboard access mess.
|
|
*
|
|
* 19 8/25/98 7:08p Samir
|
|
* select how keys are sent to a gadget.
|
|
*
|
|
* 18 8/25/98 6:33p Kevin
|
|
* PXO screens
|
|
*
|
|
* 17 8/25/98 5:27p Samir
|
|
* new focusing rules for keyboard.
|
|
*
|
|
* 16 6/05/98 5:35p Samir
|
|
* massive improvement in UI keyboard interface.
|
|
*
|
|
* 15 3/10/98 12:48p Samir
|
|
* Added window centering ability.
|
|
*
|
|
* 14 3/09/98 2:57p Samir
|
|
* Remove gadget from window called from gadget destroy.
|
|
*
|
|
* 13 3/05/98 6:38p Samir
|
|
* Fixed key presses within windows.
|
|
*
|
|
* 12 2/15/98 7:07p Samir
|
|
* Revamped way keys like up and down are handled in window system.
|
|
*
|
|
* 11 2/13/98 6:35p Samir
|
|
* Fixed some gadget creation/destruction inconsistancies
|
|
*
|
|
* 10 2/02/98 7:36p Samir
|
|
* Added UIObject::Destroy.
|
|
*
|
|
* 9 1/30/98 7:05p Samir
|
|
* Each gadget now has their own coordinate system.
|
|
*
|
|
* 8 1/26/98 10:54a Samir
|
|
* Fixed bug in UIWindow returning -2 always.
|
|
*
|
|
* 7 1/23/98 5:45p Samir
|
|
* Call OnUserProcess after default Window Process.
|
|
*
|
|
* 6 1/18/98 4:23p Samir
|
|
* Moved object destruction code to a virtual OnDestroy function for
|
|
* gadgets. Must destroy window too.
|
|
*
|
|
* 5 1/13/98 4:26p Samir
|
|
* Changed process of setting and getting focus.
|
|
*
|
|
* 4 1/08/98 12:17p Samir
|
|
* Added TitledWindow and modified the UI interface for polling.
|
|
*
|
|
* 3 1/05/98 11:10a Jason
|
|
* FROM SAMIR: Draw background rectangle for menus
|
|
*
|
|
* 2 1/02/98 12:48p Samir
|
|
* Redid setting and releasing keyboard/mouse focus for gadgets.
|
|
*
|
|
* 1 12/30/97 4:36p Samir
|
|
* Initial revision
|
|
*
|
|
* $NoKeywords: $
|
|
*/
|
|
|
|
#include "UIlib.h"
|
|
#include "Macros.h"
|
|
|
|
// the window font for all windows
|
|
int UIWindow::m_WindowFont = 0;
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// UIWindow class
|
|
|
|
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;
|
|
}
|
|
|
|
UIWindow::~UIWindow() {
|
|
if (m_GadgetTail) {
|
|
Destroy();
|
|
}
|
|
}
|
|
|
|
// create a window at the specified coords.
|
|
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);
|
|
}
|
|
|
|
void UIWindow::Destroy() {
|
|
OnDestroy();
|
|
|
|
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;
|
|
|
|
SetBackItem(NULL);
|
|
|
|
UIObject::Destroy();
|
|
}
|
|
|
|
// interface functions
|
|
// adds a UIObject to the interface's draw list.
|
|
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();
|
|
}
|
|
|
|
// removes a UIObject from the draw list.
|
|
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;
|
|
}
|
|
|
|
// forces a particular gadget into focus, always until unlocked.
|
|
void UIWindow::LockFocusOnGadget(UIGadget *gadget) { m_LockedGadget = gadget; }
|
|
|
|
void UIWindow::UnlockFocusOnGadget() { m_LockedGadget = NULL; }
|
|
|
|
// forces all keyinput onto one gadget.
|
|
void UIWindow::LockKeyFocusOnGadget(UIGadget *gadget) {}
|
|
|
|
// Process
|
|
// run this to handle user input inside an interface
|
|
// sets focus on a control
|
|
// m_GadgetCur is gadget in focus.
|
|
|
|
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;
|
|
}
|
|
|
|
// overridable: runs after window is processed, to supplement it.
|
|
void UIWindow::OnUserProcess() {}
|
|
|
|
// behavior when key is pressed.
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// behavior when key is released.
|
|
void UIWindow::OnKeyUp(int key) {}
|
|
|
|
// redraw all gadgets
|
|
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);
|
|
|
|
// 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.
|
|
void UIWindow::Open() { ui_AddWindow(this); }
|
|
|
|
// removes window from ui list.
|
|
void UIWindow::Close() { ui_RemoveWindow(this); }
|
|
|
|
// settings
|
|
void UIWindow::SetFont(int handle) { m_FontHandle = handle; }
|
|
|
|
// overridable draws the window background before gadgets
|
|
void UIWindow::OnDraw() {
|
|
if (m_BackItem)
|
|
m_BackItem->draw(0, 0, m_W, m_H);
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
// used to mark key pressed to id numbers
|
|
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++;
|
|
}
|
|
|
|
void UIWindow::ResetAcceleratorKey() { m_naccels = 0; }
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// UITitledWindow class
|
|
|
|
UITitledWindow::UITitledWindow() {}
|
|
|
|
UITitledWindow::~UITitledWindow() {}
|
|
|
|
void UITitledWindow::Create(UITextItem &title, int x, int y, int w, int h) {
|
|
m_Title = title;
|
|
m_BorderThickness = 2;
|
|
m_CaptionColor = GR_DARKGRAY;
|
|
|
|
UIWindow::Create(x, y, w, h);
|
|
UIPrimativeItem item{GR_LIGHTGRAY};
|
|
UIWindow::SetBackItem(&item);
|
|
}
|
|
|
|
// inheritable actions
|
|
|
|
// draws the window background before gadgets
|
|
void UITitledWindow::OnDraw() {
|
|
UIWindow::OnDraw();
|
|
int m_CaptionHeight; // caption height
|
|
|
|
// set font for title.
|
|
if (m_Title.get_font() > -1)
|
|
ui_DrawSetFont(m_Title.get_font());
|
|
|
|
m_CaptionHeight = ui_GetFontHeight() + ui_GetFontHeight() / 2;
|
|
|
|
// 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);
|
|
}
|