mirror of
https://github.com/kevinbentley/Descent3.git
synced 2025-01-22 19:55:23 +00:00
885 lines
24 KiB
C++
885 lines
24 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/UIListBox.cpp $
|
|
* $Revision: 42 $
|
|
* $Date: 4/30/99 6:49p $
|
|
* $Author: Samir $
|
|
*
|
|
* Listbox code
|
|
*
|
|
* $Log: /DescentIII/Main/ui/UIListBox.cpp $
|
|
*
|
|
* 42 4/30/99 6:49p Samir
|
|
* fixed bug when scroll down with keyboard in last visible item of
|
|
* listbox.
|
|
*
|
|
* 41 4/14/99 1:53a Jeff
|
|
* fixed case mismatched #includes
|
|
*
|
|
* 40 3/22/99 1:55p Jeff
|
|
* fixed more crashes
|
|
*
|
|
* 39 3/22/99 12:47p Jeff
|
|
* oops...fixed some listbox crashes
|
|
*
|
|
* 38 3/19/99 9:21p Jeff
|
|
* fixed some listbox sorting issues
|
|
*
|
|
* 37 2/24/99 1:14p Jeff
|
|
* fixed sorting bug when you have 2 identical items
|
|
*
|
|
* 36 2/21/99 6:36p Samir
|
|
* focusing changes and key input changes to ui.,
|
|
*
|
|
* 35 2/04/99 12:10p Jeff
|
|
* fixed SelectItem
|
|
*
|
|
* 34 1/27/99 10:26p Jeff
|
|
* fixed sorting bug, very odd it hasn't cropped up before, only happened
|
|
* when allocating a new buffer of indices
|
|
*
|
|
* 32 10/19/98 6:30p Jeff
|
|
* changes made for detail variables. Put in preset values. Preset
|
|
* options. Removed terrain_cast from detail. Put new callbacks in
|
|
* UIListBox and UISlider
|
|
*
|
|
* 31 10/06/98 8:05p Samir
|
|
* added page up and page down!
|
|
*
|
|
* 30 10/06/98 7:30p Samir
|
|
* scrolling listbox is cleaner.
|
|
*
|
|
* 29 9/30/98 4:33p Samir
|
|
* listbox broke for keyboard for now.
|
|
*
|
|
* 28 9/22/98 3:57p Samir
|
|
* listbox prob fixed again.
|
|
*
|
|
* 27 9/10/98 6:32p Samir
|
|
* changed some visual characteristics of listboxes.
|
|
*
|
|
* 26 9/02/98 6:50p Samir
|
|
* fixed some double clicking issues for listboxes.
|
|
*
|
|
* 25 8/31/98 12:37p Samir
|
|
* SetSelectedIndex modifies visible index as well, and dblclick works
|
|
* again.
|
|
*
|
|
* 24 8/25/98 5:27p Samir
|
|
* new focusing rules for keyboard.
|
|
*
|
|
* 23 8/24/98 3:12p Samir
|
|
* fixed text clipping
|
|
*
|
|
* 22 8/11/98 11:38a Samir
|
|
* fixed listbox probs yet again. arrows on side this time.
|
|
*
|
|
* 21 7/29/98 3:26p Samir
|
|
* fixed some listbox mouse problems.
|
|
*
|
|
* 20 7/28/98 7:13p Samir
|
|
* reset index when removing all items.
|
|
*
|
|
* 19 7/15/98 2:26p Samir
|
|
* may have fixed something with arrows.
|
|
*
|
|
* 18 6/22/98 2:15p Samir
|
|
* implemented border flag.
|
|
*
|
|
* 17 6/05/98 5:36p Samir
|
|
* cleaner keyboard inteface for listboxes.
|
|
*
|
|
* 16 4/29/98 1:04p Jeff
|
|
* fixed up the UIListBox a bit (color control and scroll buttons)
|
|
*
|
|
* 15 4/29/98 11:55a Samir
|
|
* allow user to change color of selected listbox item.
|
|
*
|
|
* 14 4/13/98 7:02p Samir
|
|
* made some things protected.
|
|
*
|
|
* 13 3/16/98 11:43a Brent
|
|
* (Jeff) fixed UIListBox so it doesn't draw arrows if nothing in the box
|
|
*
|
|
* 12 3/13/98 5:19p Jeff
|
|
* added scroll button code
|
|
*
|
|
* 11 3/09/98 5:08p Samir
|
|
* fixed bug.
|
|
*
|
|
* 10 3/09/98 5:05p Samir
|
|
* Added callback to selection change function.
|
|
*
|
|
* 9 3/09/98 3:43p Samir
|
|
* Single clicks should select an item in a listbox.
|
|
*
|
|
* 8 2/24/98 3:05p Samir
|
|
* don't set listindex when selecting.
|
|
*
|
|
* 7 2/15/98 7:07p Samir
|
|
* Listbox now supports up and down arrow keys.
|
|
*
|
|
* 6 2/13/98 6:36p Samir
|
|
* Double click to select.
|
|
*
|
|
* 5 2/10/98 4:56p Samir
|
|
* Listbox with alphas and a selection bar.
|
|
*
|
|
* 4 2/10/98 3:45p Samir
|
|
* Fixed bug in drawing items over the boundaries of the listbox.
|
|
*
|
|
* 3 1/30/98 7:07p Samir
|
|
* Simple box containing items. Must be handled by a parent.
|
|
*
|
|
* 2 1/13/98 4:28p Samir
|
|
* Fixed typo.
|
|
*
|
|
* 1 1/09/98 12:00p Samir
|
|
* Initial revision
|
|
*
|
|
* $NoKeywords: $
|
|
*/
|
|
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
|
|
#include "UIlib.h"
|
|
#include "log.h"
|
|
|
|
#define SCROLL_BUTTON_GAP 4
|
|
|
|
// Construction and destruction
|
|
|
|
UIListBox::UIListBox() {
|
|
m_NumItems = 0;
|
|
m_SelectedIndex = 0;
|
|
m_Index = 0;
|
|
m_ItemList = NULL;
|
|
m_Virt2Real = NULL;
|
|
m_Real2Virt = NULL;
|
|
m_MouseState = 0;
|
|
selectchange_fn = NULL;
|
|
selectchange_id_fn = NULL;
|
|
m_callbackptr = NULL;
|
|
m_TextOffX = 4;
|
|
m_TextOffY = 4;
|
|
}
|
|
|
|
UIListBox::~UIListBox() {}
|
|
|
|
void UIListBox::Create(UIWindow *parent, int id, int x, int y, int w, int h, int flags) {
|
|
m_NumItems = 0;
|
|
m_ItemList = NULL;
|
|
m_Virt2Real = NULL;
|
|
m_Real2Virt = NULL;
|
|
m_SelectedIndex = 0;
|
|
m_Index = 0;
|
|
m_MouseState = 0;
|
|
m_ClickTime = 0;
|
|
selectchange_fn = NULL;
|
|
selectchange_id_fn = NULL;
|
|
m_callbackptr = NULL;
|
|
m_ShowDown = false;
|
|
m_ShowUp = false;
|
|
m_SelectColor = GR_WHITE;
|
|
m_HiliteColor = GR_DARKGRAY;
|
|
m_NumVisibleItems = 0;
|
|
m_Alpha = 192;
|
|
|
|
UIGadget::Create(parent, id, x, y, w, h, flags);
|
|
m_CX = 1;
|
|
m_CY = 1;
|
|
m_CX2 = m_W - 1;
|
|
m_CY2 = m_H - 1;
|
|
}
|
|
|
|
// settings
|
|
|
|
// adds an item to the list, no sorting
|
|
void UIListBox::AddItem(const UIItem *item) {
|
|
UIItem **temp;
|
|
int i;
|
|
int *tempvirt2real, *tempreal2virt;
|
|
int real_index = -1;
|
|
|
|
if (m_Flags & UILB_NOSORT) {
|
|
// insert without sort
|
|
|
|
if ((m_NumItems % LISTBOX_BUFFER_SIZE) == 0) {
|
|
// dynamically allocated memory for listbox, expand as needed.
|
|
temp = new UIItem *[m_NumItems + LISTBOX_BUFFER_SIZE];
|
|
tempvirt2real = new int[m_NumItems + LISTBOX_BUFFER_SIZE];
|
|
tempreal2virt = new int[m_NumItems + LISTBOX_BUFFER_SIZE];
|
|
|
|
if (m_ItemList) {
|
|
for (i = 0; i < m_NumItems; i++) {
|
|
temp[i] = m_ItemList[i];
|
|
tempvirt2real[i] = m_Virt2Real[i];
|
|
tempreal2virt[i] = m_Real2Virt[i];
|
|
}
|
|
|
|
delete[] m_ItemList;
|
|
delete[] m_Virt2Real;
|
|
delete[] m_Real2Virt;
|
|
}
|
|
m_ItemList = temp;
|
|
m_Virt2Real = tempvirt2real;
|
|
m_Real2Virt = tempreal2virt;
|
|
}
|
|
|
|
real_index = m_NumItems;
|
|
|
|
} else {
|
|
// only text item listboxes!
|
|
|
|
// insert with sorting
|
|
if ((m_NumItems % LISTBOX_BUFFER_SIZE) == 0) {
|
|
// dynamically allocated memory for listbox, expand as needed.
|
|
temp = new UIItem *[m_NumItems + LISTBOX_BUFFER_SIZE];
|
|
tempvirt2real = new int[m_NumItems + LISTBOX_BUFFER_SIZE];
|
|
tempreal2virt = new int[m_NumItems + LISTBOX_BUFFER_SIZE];
|
|
int oidx = 0, cidx = 0;
|
|
int pidx = 0;
|
|
real_index = -1;
|
|
int result;
|
|
|
|
if (m_ItemList) {
|
|
while (oidx <= m_NumItems) {
|
|
if (oidx == m_NumItems) {
|
|
if (real_index == -1) {
|
|
real_index = oidx;
|
|
} else {
|
|
temp[cidx] = m_ItemList[pidx];
|
|
tempreal2virt[cidx] = m_Real2Virt[pidx];
|
|
}
|
|
oidx++;
|
|
continue;
|
|
}
|
|
|
|
if (m_Flags & UILB_CASESENSITIVE)
|
|
result = strcmp(((UITextItem *)m_ItemList[cidx])->GetBuffer(), ((UITextItem *)item)->GetBuffer());
|
|
else
|
|
result = stricmp(((UITextItem *)m_ItemList[cidx])->GetBuffer(), ((UITextItem *)item)->GetBuffer());
|
|
if (result < 0) {
|
|
// copy old
|
|
temp[cidx] = m_ItemList[pidx];
|
|
tempreal2virt[cidx] = m_Real2Virt[pidx];
|
|
cidx++;
|
|
pidx++;
|
|
} else if (result >= 0) {
|
|
// see if we need to insert, if not just keep copying
|
|
if (real_index == -1) {
|
|
real_index = cidx;
|
|
cidx++;
|
|
} else {
|
|
temp[cidx] = m_ItemList[pidx];
|
|
tempreal2virt[cidx] = m_Real2Virt[pidx];
|
|
cidx++;
|
|
pidx++;
|
|
}
|
|
}
|
|
oidx++;
|
|
}
|
|
ASSERT(real_index != -1);
|
|
|
|
// now we need to fix m_Virt2Real to represent the new structure,
|
|
// all values>=real_index must be incremented
|
|
for (oidx = 0; oidx <= m_NumItems; oidx++) {
|
|
if (oidx < m_NumItems) {
|
|
tempvirt2real[oidx] = m_Virt2Real[oidx];
|
|
|
|
// if(oidx!=real_index){
|
|
if (tempvirt2real[oidx] >= real_index)
|
|
tempvirt2real[oidx]++;
|
|
}
|
|
}
|
|
|
|
delete[] m_ItemList;
|
|
delete[] m_Virt2Real;
|
|
delete[] m_Real2Virt;
|
|
} else {
|
|
real_index = 0;
|
|
}
|
|
|
|
m_ItemList = temp;
|
|
m_Virt2Real = tempvirt2real;
|
|
m_Real2Virt = tempreal2virt;
|
|
} else {
|
|
// find where to insert, without allocating memory
|
|
int oidx = 0, cidx = 0;
|
|
real_index = -1;
|
|
int result;
|
|
|
|
int old_r2v;
|
|
UIItem *old_item = NULL;
|
|
|
|
while (oidx <= m_NumItems) {
|
|
|
|
if (oidx == m_NumItems) {
|
|
// we're past the slot of the old buffer
|
|
if (real_index == -1) {
|
|
// we haven't set the real index yet, so it has to go here
|
|
real_index = m_NumItems;
|
|
} else {
|
|
// the real index has been set, we're still pulling back
|
|
m_Real2Virt[cidx] = old_r2v;
|
|
m_ItemList[cidx] = old_item;
|
|
}
|
|
oidx++;
|
|
continue;
|
|
} else {
|
|
if (m_Flags & UILB_CASESENSITIVE)
|
|
result = strcmp(((UITextItem *)m_ItemList[cidx])->GetBuffer(), ((UITextItem *)item)->GetBuffer());
|
|
else
|
|
result = stricmp(((UITextItem *)m_ItemList[cidx])->GetBuffer(), ((UITextItem *)item)->GetBuffer());
|
|
}
|
|
|
|
if (result < 0) {
|
|
// we haven't gotten to the string yet, keep as they are
|
|
cidx++;
|
|
} else if (result >= 0) {
|
|
// see if we need to insert, if not just keep copying
|
|
if (real_index == -1) {
|
|
// we need to insert here
|
|
real_index = cidx;
|
|
old_item = m_ItemList[cidx];
|
|
old_r2v = m_Real2Virt[cidx];
|
|
cidx++;
|
|
} else {
|
|
// old_item and old_r2v should be set!
|
|
ASSERT(old_item);
|
|
UIItem *oi;
|
|
int or2v;
|
|
|
|
or2v = m_Real2Virt[cidx];
|
|
oi = m_ItemList[cidx];
|
|
|
|
m_Real2Virt[cidx] = old_r2v;
|
|
m_ItemList[cidx] = old_item;
|
|
old_r2v = or2v;
|
|
old_item = oi;
|
|
|
|
cidx++;
|
|
}
|
|
}
|
|
|
|
// continue on
|
|
oidx++;
|
|
}
|
|
|
|
ASSERT(real_index != -1);
|
|
|
|
// now we need to fix m_Virt2Real to represent the new structure,
|
|
// all values>=real_index must be incremented
|
|
cidx = 0;
|
|
for (oidx = 0; oidx <= m_NumItems; oidx++) {
|
|
if (oidx != real_index) {
|
|
if (m_Virt2Real[cidx] >= real_index)
|
|
m_Virt2Real[cidx]++;
|
|
cidx++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// copy item passed to list.
|
|
m_ItemList[real_index] = (UIItem *)item;
|
|
m_Virt2Real[m_NumItems] = real_index;
|
|
m_Real2Virt[real_index] = m_NumItems;
|
|
m_NumItems++;
|
|
|
|
if (real_index <= m_SelectedIndex) {
|
|
// adjust selected index
|
|
if (m_SelectedIndex < m_NumItems - 1)
|
|
m_SelectedIndex++;
|
|
}
|
|
}
|
|
|
|
// removes an item from the list.
|
|
void UIListBox::RemoveItem(const UIItem *item) {
|
|
int i, j, found = -1;
|
|
|
|
for (i = 0; i < m_NumItems; i++) {
|
|
if (item == m_ItemList[i]) {
|
|
found = i;
|
|
break;
|
|
}
|
|
}
|
|
if (found == -1) {
|
|
LOG_DEBUG << "UIListBox:: Didn't find item to remove!";
|
|
return;
|
|
}
|
|
|
|
// found is the real index to remove
|
|
// go through virt2real and subtract one from values of found or higher
|
|
// go through real2virt and move everything from index found on down, and subtract
|
|
// 1 from those with value of found or higher
|
|
int real_index = found; // index to remove
|
|
int virt_index = m_Real2Virt[found]; // index to remove
|
|
int real_thresh = virt_index;
|
|
int virt_thresh = real_index;
|
|
|
|
for (j = 0; j < (m_NumItems - 1); j++) {
|
|
if (j >= real_index) {
|
|
m_ItemList[j] = m_ItemList[j + 1];
|
|
m_Real2Virt[j] = m_Real2Virt[j + 1];
|
|
}
|
|
|
|
if (j >= virt_index) {
|
|
m_Virt2Real[j] = m_Virt2Real[j + 1];
|
|
}
|
|
|
|
if (m_Real2Virt[j] >= real_thresh)
|
|
m_Real2Virt[j]--;
|
|
|
|
if (m_Virt2Real[j] >= virt_thresh)
|
|
m_Virt2Real[j]--;
|
|
}
|
|
m_NumItems--;
|
|
|
|
if (real_index <= m_SelectedIndex) {
|
|
// adjust selected index
|
|
if (m_SelectedIndex > 0)
|
|
m_SelectedIndex--;
|
|
}
|
|
}
|
|
|
|
// empties listbox
|
|
void UIListBox::RemoveAll() {
|
|
m_Index = m_SelectedIndex = m_NumItems = 0;
|
|
if (m_ItemList)
|
|
delete[] m_ItemList;
|
|
if (m_Virt2Real)
|
|
delete[] m_Virt2Real;
|
|
if (m_Real2Virt)
|
|
delete[] m_Real2Virt;
|
|
m_ItemList = NULL;
|
|
m_Virt2Real = NULL;
|
|
m_Real2Virt = NULL;
|
|
}
|
|
|
|
// selects the given item in the list.
|
|
void UIListBox::SelectItem(const UIItem *item) {
|
|
int i, found = 0;
|
|
|
|
for (i = 0; i < m_NumItems; i++) {
|
|
if (item == m_ItemList[i]) {
|
|
SetSelectedIndex(m_Real2Virt[i]);
|
|
found = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (!found) {
|
|
LOG_DEBUG << "UIListBox::SelectItem item not found!";
|
|
}
|
|
}
|
|
|
|
// returns the item at listbox index given.
|
|
UIItem *UIListBox::GetItem(int index) const {
|
|
if (m_NumItems == 0)
|
|
return NULL;
|
|
|
|
if (index >= 0 && index < m_NumItems) {
|
|
int real_index = m_Virt2Real[index];
|
|
ASSERT(real_index >= 0 && real_index < m_NumItems);
|
|
return m_ItemList[real_index];
|
|
} else
|
|
return NULL;
|
|
}
|
|
|
|
// returns the current listbox index
|
|
int UIListBox::GetListIndex() const {
|
|
if (m_NumItems == 0)
|
|
return 0;
|
|
|
|
if (m_Index < 0)
|
|
return m_Index;
|
|
|
|
if (!m_Real2Virt)
|
|
return 0;
|
|
|
|
int virt_index = m_Real2Virt[m_Index];
|
|
ASSERT(virt_index >= 0 && virt_index < m_NumItems);
|
|
|
|
return virt_index;
|
|
}
|
|
|
|
// sets the index of a listbox
|
|
void UIListBox::SetListIndex(int index) {
|
|
if (m_NumItems == 0)
|
|
return;
|
|
|
|
if (index >= 0 && index < m_NumItems) {
|
|
int real_index = m_Virt2Real[index];
|
|
ASSERT(real_index >= 0 && real_index < m_NumItems);
|
|
m_Index = real_index;
|
|
}
|
|
}
|
|
|
|
// returns which item index is selected
|
|
int UIListBox::GetSelectedIndex() const {
|
|
if (m_NumItems == 0)
|
|
return 0;
|
|
|
|
if (m_SelectedIndex < 0)
|
|
return m_SelectedIndex;
|
|
|
|
if (!m_Real2Virt)
|
|
return 0;
|
|
|
|
int virt_index = m_Real2Virt[m_SelectedIndex];
|
|
ASSERT(virt_index >= 0 && virt_index < m_NumItems);
|
|
return virt_index;
|
|
}
|
|
|
|
// sets the selected index.
|
|
void UIListBox::SetSelectedIndex(int index) {
|
|
if (m_NumItems == 0)
|
|
return;
|
|
|
|
if (index >= 0 && index < m_NumItems) {
|
|
int real_index = m_Virt2Real[index];
|
|
ASSERT(real_index >= 0 && real_index < m_NumItems);
|
|
|
|
int i, y = m_TextOffY;
|
|
m_SelectedIndex = real_index;
|
|
for (i = 0; i < m_NumItems; i++) {
|
|
y += m_ItemList[i]->height() + 2;
|
|
if (y > (m_H - m_TextOffY))
|
|
break;
|
|
}
|
|
|
|
m_Index = m_SelectedIndex - i;
|
|
if (m_Index < 0)
|
|
m_Index = 0;
|
|
|
|
if (selectchange_fn)
|
|
(*selectchange_fn)(index);
|
|
if (selectchange_id_fn)
|
|
(*selectchange_id_fn)(GetID(), m_callbackptr);
|
|
}
|
|
}
|
|
|
|
void UIListBox::SetInternalSelectedIndex(int index) {
|
|
if (m_NumItems == 0)
|
|
return;
|
|
|
|
if (index >= 0 && index < m_NumItems) {
|
|
int real_index = m_Virt2Real[index];
|
|
ASSERT(real_index >= 0 && real_index < m_NumItems);
|
|
m_SelectedIndex = real_index;
|
|
|
|
if (selectchange_fn)
|
|
(*selectchange_fn)(index);
|
|
if (selectchange_id_fn)
|
|
(*selectchange_id_fn)(GetID(), m_callbackptr);
|
|
}
|
|
}
|
|
|
|
void UIListBox::SetSelectChangeCallback(void (*fn)(int)) { selectchange_fn = fn; }
|
|
|
|
void UIListBox::SetSelectChangeCallback(void (*fn)(int, void *), void *ptr) {
|
|
selectchange_id_fn = fn;
|
|
m_callbackptr = ptr;
|
|
}
|
|
|
|
// called from outside gadget hierarchy.
|
|
|
|
void UIListBox::OnDestroy() {
|
|
UIGadget::OnDestroy();
|
|
|
|
if (m_ItemList)
|
|
delete[] m_ItemList;
|
|
if (m_Real2Virt)
|
|
delete[] m_Real2Virt;
|
|
if (m_Virt2Real)
|
|
delete[] m_Virt2Real;
|
|
|
|
m_ItemList = NULL;
|
|
m_Real2Virt = NULL;
|
|
m_Virt2Real = NULL;
|
|
}
|
|
|
|
// behavior when gadget is being drawn.
|
|
void UIListBox::OnDraw() {
|
|
bool use_scroll = !(m_Flags & UILB_NOSCROLL);
|
|
bool auto_select = ((m_Flags & UILB_AUTOSELECT) > 0);
|
|
UITextItem uarrow;
|
|
UITextItem darrow;
|
|
char arrowbuf[2];
|
|
|
|
if (m_Flags & UIF_BORDER)
|
|
ui_DrawBox(GR_WHITE, 0, 0, m_W, m_H);
|
|
|
|
ui_SetTextClip(m_CX, m_CY, m_CX2, m_CY2);
|
|
|
|
// draw all items in box that can be visible.
|
|
int x, y, i;
|
|
uint8_t alpha;
|
|
|
|
x = m_TextOffX;
|
|
y = m_TextOffY;
|
|
|
|
if (m_NumItems) {
|
|
snprintf(arrowbuf, sizeof(arrowbuf), "%c", UI_UP_ARROW_CHAR);
|
|
uarrow = UITextItem(arrowbuf, m_ItemList[m_Index]->get_color(), 255);
|
|
snprintf(arrowbuf, sizeof(arrowbuf), "%c", UI_DOWN_ARROW_CHAR);
|
|
darrow = UITextItem(arrowbuf, m_ItemList[m_Index]->get_color(), 255);
|
|
|
|
// reset these
|
|
m_ShowUp = m_ShowDown = false;
|
|
|
|
if (use_scroll) {
|
|
m_UpArrowY0 = y;
|
|
m_UpArrowY1 = y + uarrow.height();
|
|
if (m_Index > 0)
|
|
uarrow.draw(m_TextOffX, m_UpArrowY0, IsDisabled() ? uiDrawFaded : uiDrawNormal);
|
|
m_ShowUp = true;
|
|
m_ArrowWidth = uarrow.width() + 2;
|
|
x = x + m_ArrowWidth;
|
|
} else
|
|
m_ArrowWidth = 0;
|
|
}
|
|
|
|
alpha = m_Alpha;
|
|
|
|
for (i = m_Index; i < m_NumItems; i++) {
|
|
// check to see if scroll arrow down needs to be drawn.
|
|
// if (m_SelectedIndex == i) {
|
|
// ui_DrawSetAlpha((alpha/4)+1);
|
|
// ui_DrawRect(m_HiliteColor, x,y,m_W-m_TextOffX,y+m_ItemList[i]->height()+2);
|
|
// }
|
|
|
|
m_ItemList[i]->set_alpha((uint8_t)alpha);
|
|
if (m_SelectedIndex == i) {
|
|
ddgr_color old_color = m_ItemList[i]->get_color();
|
|
m_ItemList[i]->set_color(m_SelectColor);
|
|
m_ItemList[i]->draw(x + 1, y + 1, IsDisabled() ? uiDrawFaded : uiDrawNormal);
|
|
if (!IsDisabled())
|
|
m_ItemList[i]->draw(x + 1, y + 1, uiDrawAlphaSaturate);
|
|
m_ItemList[i]->set_color(old_color);
|
|
} else {
|
|
m_ItemList[i]->draw(x + 1, y + 1, IsDisabled() ? uiDrawFaded : uiDrawNormal);
|
|
}
|
|
|
|
if (use_scroll && (i < m_NumItems)) {
|
|
if ((y + m_ItemList[i]->height()) > (m_H - m_TextOffY - darrow.height() + 1)) {
|
|
if (i < (m_NumItems - 1)) {
|
|
m_DownArrowY0 = m_H - m_TextOffY - darrow.height() + 1;
|
|
m_DownArrowY1 = m_H - m_TextOffY;
|
|
darrow.draw(m_TextOffX, m_DownArrowY0, IsDisabled() ? uiDrawFaded : uiDrawNormal);
|
|
m_ShowDown = true;
|
|
}
|
|
break;
|
|
}
|
|
} else if ((y + m_ItemList[i]->height() + 2) > (m_H - m_TextOffY)) {
|
|
break;
|
|
}
|
|
|
|
y += m_ItemList[i]->height() + 2;
|
|
}
|
|
|
|
if (m_NumItems) {
|
|
if (use_scroll && auto_select) {
|
|
if (m_SelectedIndex < m_Index)
|
|
UIListBox::SetSelectedIndex(m_Real2Virt[m_Index]);
|
|
if (m_SelectedIndex > i)
|
|
UIListBox::SetSelectedIndex(m_Real2Virt[i]);
|
|
}
|
|
}
|
|
|
|
m_NumVisibleItems = i - m_Index;
|
|
|
|
ui_ResetTextClip();
|
|
}
|
|
|
|
// behavior when key is pressed.
|
|
void UIListBox::OnKeyDown(int key) {
|
|
UIGadget *gadget = this;
|
|
|
|
if (key == KEY_UP) {
|
|
if (m_SelectedIndex > 0) {
|
|
if (m_SelectedIndex == m_Index)
|
|
m_Index--;
|
|
m_SelectedIndex--;
|
|
|
|
UIListBox::SetInternalSelectedIndex((m_Real2Virt) ? m_Real2Virt[m_SelectedIndex] : 0);
|
|
}
|
|
} else if (key == KEY_DOWN) {
|
|
if (m_SelectedIndex < (m_NumItems - 1)) {
|
|
if (m_SelectedIndex >= (m_Index + m_NumVisibleItems))
|
|
m_Index++;
|
|
m_SelectedIndex++;
|
|
UIListBox::SetInternalSelectedIndex((m_Real2Virt) ? m_Real2Virt[m_SelectedIndex] : 0);
|
|
}
|
|
} else if (key == KEY_PAGEDOWN) {
|
|
if (m_Index < (m_NumItems - m_NumVisibleItems))
|
|
m_Index = m_Index + m_NumVisibleItems;
|
|
if (m_Index > (m_NumItems - m_NumVisibleItems))
|
|
m_Index = m_NumItems - m_NumVisibleItems;
|
|
m_SelectedIndex = m_Index;
|
|
UIListBox::SetInternalSelectedIndex((m_Real2Virt) ? m_Real2Virt[m_SelectedIndex] : 0);
|
|
} else if (key == KEY_PAGEUP) {
|
|
m_Index = m_Index - m_NumVisibleItems;
|
|
if (m_Index < 0)
|
|
m_Index = 0;
|
|
m_SelectedIndex = m_Index;
|
|
|
|
UIListBox::SetInternalSelectedIndex((m_Real2Virt) ? m_Real2Virt[m_SelectedIndex] : 0);
|
|
}
|
|
}
|
|
|
|
// behavior when key is released.
|
|
void UIListBox::OnKeyUp(int key) {}
|
|
|
|
// behavior when mouse button is pressed.
|
|
void UIListBox::OnMouseBtnDown(int btn) {
|
|
// One day, this system needs a complete rewrite, for all this stuff is a HACK!!!!
|
|
if (btn == UILMSEBTN) {
|
|
if (m_MouseState == 1 || m_MouseState == 2) { // single click pass or double clicking
|
|
// handle first slow delay scrolling (like keyboard input)
|
|
if ((m_ClickTime + KEYDOWN_FIRST_DELAY) > UI_TIME()) {
|
|
// mprintf(0, "old=%.3f cur=%.3f\n", m_ClickTime, UI_TIME());
|
|
return;
|
|
} else
|
|
m_MouseState = 3;
|
|
} else if (m_MouseState == 3) {
|
|
// handle repeat scrolling (note this is if the user has scrolled once already.
|
|
if ((m_ClickTime + KEYDOWN_REPEAT_DELAY) > UI_TIME()) {
|
|
// mprintf(0, "old=%.3f cur=%.3f\n", m_ClickTime, UI_TIME());
|
|
return;
|
|
}
|
|
} else if (m_MouseState == 0) {
|
|
m_MouseState = 1;
|
|
m_MouseX = SCREEN_TO_GAD_X(this, UI_input.mx);
|
|
m_MouseY = SCREEN_TO_GAD_Y(this, UI_input.my);
|
|
|
|
MseCheckSelect(m_MouseX, m_MouseY);
|
|
|
|
if (UI_TIME() < (m_ClickTime + UI_DBLCLICK_DELAY)) {
|
|
if (abs(m_LastMseX - m_MouseX) < UI_DBLCLICK_MSEDELTA && abs(m_LastMseY - m_MouseY) < UI_DBLCLICK_MSEDELTA) {
|
|
|
|
if (MseCheckSelect(m_MouseX, m_MouseY))
|
|
OnSelect();
|
|
m_MouseState = 2;
|
|
}
|
|
}
|
|
LOCK_FOCUS(this);
|
|
}
|
|
|
|
m_ClickTime = UI_TIME(); // use for scroll timing, this should be reset on button release
|
|
// mprintf(0, "new=%.3f\n", m_ClickTime);
|
|
|
|
// code here should allow for continuous scrolling on mouse down.
|
|
// we need to add timing so scrolling isn't do damn quick.
|
|
m_LastMseX = m_MouseX;
|
|
m_LastMseY = m_MouseY;
|
|
|
|
if (m_ShowUp && m_MouseY >= m_UpArrowY0 && m_MouseY <= m_UpArrowY1) {
|
|
if (m_MouseX < (m_TextOffX + m_ArrowWidth)) {
|
|
if (m_Index > 0)
|
|
m_Index--;
|
|
}
|
|
} else if (m_ShowDown && m_MouseY >= m_DownArrowY0 && m_MouseY <= m_DownArrowY1) {
|
|
if (m_MouseX < (m_TextOffX + m_ArrowWidth)) {
|
|
if (m_Index < (m_NumItems - m_NumVisibleItems))
|
|
m_Index++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// behavior when mouse button is released.
|
|
void UIListBox::OnMouseBtnUp(int btn) {
|
|
if (btn == UILMSEBTN) {
|
|
if (m_MouseState == 0)
|
|
return;
|
|
if (m_MouseState == 2) // double clicked.
|
|
m_ClickTime = -2.0f;
|
|
else if (m_MouseState == 1 || m_MouseState == 3) // single clicked or prolonged single click.
|
|
m_ClickTime = UI_TIME();
|
|
m_MouseState = 0;
|
|
UNLOCK_FOCUS(this);
|
|
}
|
|
}
|
|
|
|
void UIListBox::OnSelect() { UIGadget::OnSelect(); }
|
|
|
|
void UIListBox::SetSelectedColor(ddgr_color col) { m_SelectColor = col; }
|
|
|
|
void UIListBox::SetHiliteColor(ddgr_color col) { m_HiliteColor = col; }
|
|
|
|
// override: behavior when gadget loses input focus.
|
|
void UIListBox::OnLostFocus() {
|
|
m_Alpha = 192;
|
|
|
|
UIGadget::OnLostFocus();
|
|
}
|
|
|
|
// override: behavior when gadget gains input focus.
|
|
void UIListBox::OnGainFocus() {
|
|
m_Alpha = 255;
|
|
UIGadget::OnGainFocus();
|
|
}
|
|
|
|
// override: behavior when gadget is processed
|
|
void UIListBox::OnUserProcess() {
|
|
// if mouse is outside listbox, unlock the focus on this listbox.
|
|
// if (this->IsLocked()) {
|
|
// if (!m_Wnd->HasKeyFocus() && !PT_IN_GADGET(UIGadget::m_Wnd, this, UI_input.mx, UI_input.my)) {
|
|
// UNLOCK_FOCUS(this);
|
|
// this->LostFocus();
|
|
// }
|
|
// }
|
|
}
|
|
|
|
// check if x and y selection hits a selected item.
|
|
bool UIListBox::MseCheckSelect(int x, int y) {
|
|
int i, ty;
|
|
bool use_scroll = !(m_Flags & UILB_NOSCROLL);
|
|
|
|
if (!m_NumItems)
|
|
return false;
|
|
|
|
if (m_ShowUp)
|
|
ty = m_UpArrowY0;
|
|
else
|
|
ty = m_TextOffY;
|
|
|
|
for (i = m_Index; i < m_NumItems; i++) {
|
|
// check if mouse down event occurred within this item.
|
|
if (y >= ty && y < (ty + m_ItemList[i]->height() + 2)) {
|
|
if (x > (m_ArrowWidth + m_TextOffX)) {
|
|
UIListBox::SetInternalSelectedIndex((m_Real2Virt) ? m_Real2Virt[i] : 0);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (m_ShowDown && (ty + m_ItemList[i]->height()) > m_DownArrowY1)
|
|
return false;
|
|
else if ((ty + m_ItemList[i]->height()) > (m_H - m_TextOffY))
|
|
return false;
|
|
|
|
ty += m_ItemList[i]->height() + 2;
|
|
}
|
|
|
|
return false;
|
|
}
|