/* * 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 . */ /* * $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 "UIlib.h" #include #include #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) { mprintf((0, "UIListBox:: Didn't find item to remove!\n")); 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) { mprintf((0, "UIListBox::SelectItem item not found!\n")); } } // 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; ubyte 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((ubyte)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; }