12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412 |
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Copyright 2016 RWS Inc, All Rights Reserved
- //
- // This program is free software; you can redistribute it and/or modify
- // it under the terms of version 2 of the GNU General Public License as published by
- // the Free Software Foundation
- //
- // 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, write to the Free Software Foundation, Inc.,
- // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- //
- //////////////////////////////////////////////////////////////////////////////
- //
- // ListBox.CPP
- //
- // History:
- // 01/13/97 JMI Started.
- //
- // 01/15/97 JMI SetProp() now takes the Key parm first and the Item parm
- // second. Changed this module to reflect that.
- //
- // 01/15/97 JMI Added overrides of base class's Save/LoadChildren() to
- // implement special cases for m_sbVert, Horz, &
- // m_lcContents. List items saved and then loaded will not
- // be recognized as list items by this class. This should
- // eventually be supported so one can save a list of items.
- //
- // 01/15/97 JMI Since loading of list items does not work properly, any
- // list items in m_lcContents are destroyed immediately
- // after they are loaded.
- //
- // 01/20/97 JMI UpdateScrollBarVisibility() was not working correctly for
- // Hidden. Fixed.
- //
- // 01/21/97 JMI Added ReadMembers() and WriteMembers() overloads to read
- // and write members of this class. Note that they call the
- // base class version to read/write base class members.
- // Support exists for versions 0 and 1. Version 0 did not
- // contain other than RGuiItem members.
- //
- // 01/21/97 JMI RemoveItem() was not considering the possibly that the
- // item being removed might be the selected item.
- // No longer sizes an encapsulator/string item to
- // m_sLargestWidth until the AdjustContents() call.
- //
- // 01/21/97 JMI Changed m_frmContents (RFrame) to m_lcContents
- // (RListContents).
- //
- // 01/23/97 JMI EnsureVisible() had an error that made it think that
- // some items that were list items were not.
- //
- // 02/05/97 JMI Changed position of default: case in ReadMembers().
- // And made CreateStringItem() use m_typeEncapsulator as
- // the type of the created encapsulator.
- // Note that CreateEncapsulator() still only uses RTxts.
- //
- // 02/25/97 JMI SaveChildren() now goes through the children in reverse
- // order so they, on load, get added back to their parent in
- // the order they were originally added to this parent.
- //
- // 03/28/97 JMI Now AdjustContents() adjusts vertical scroll bar incs
- // so that the buttons will advance one item and the tray
- // will scroll visible items - 1.
- //
- // 04/10/97 JMI Now uses m_sFontCellHeight instead of GetPos() to get
- // cell height.
- //
- // 05/25/97 JMI Added GetFirst(), GetNext(), and GetPrev().
- //
- // 06/15/97 JMI List items are now at least as wide as the viewable area.
- //
- // 08/11/97 JMI Seemed like there was a potential for infinite loop in
- // GetNext() and GetPrev().
- // Also, GetFirst() returned the first item in the list
- // w/o checking if it was an encapsulator.
- //
- // 09/01/97 JMI Added MakeEncapsulator().
- //
- // 09/07/97 JMI Now EnsureVisible() accepts an optional position
- // preference so you can bias the location of your item.
- //
- // 09/24/97 JMI Calls to InsertAfter() and InsertBefore() had their
- // parameters backward.
- //
- //////////////////////////////////////////////////////////////////////////////
- //
- // This a GUI item that is based on the basic RGuiItem.
- // This overrides HotCall() to get information about where a click in its RHot
- // occurred.
- // This overrides Compose() to create the scrollable area and compose
- // the scrollbars.
- //
- // Enhancements/Uses:
- // Not yet known.
- //
- //////////////////////////////////////////////////////////////////////////////
- //////////////////////////////////////////////////////////////////////////////
- // Headers.
- //////////////////////////////////////////////////////////////////////////////
- #include "Blue.h"
- #ifdef PATHS_IN_INCLUDES
- #include "ORANGE/GUI/ListBox.h"
- #include "ORANGE/GUI/txt.h"
- #else
- #include "listbox.h"
- #include "txt.h"
- #endif // PATHS_IN_INCLUDES
- //////////////////////////////////////////////////////////////////////////////
- // Module specific macros.
- //////////////////////////////////////////////////////////////////////////////
- // Sets val to def if val is -1.
- #define DEF(val, def) ((val == -1) ? def : val)
- // Default width for vertical scrollbar and height for horizontal scrollbar.
- #define DEF_SCROLL_THICKNESS 13
- // Space between items.
- #define ITEM_SPACING m_sBorderThickness
- // Scrollbar priority is very high so it will be above other siblings.
- #define SCROLLBAR_PRIORITY ((short)0x8001)
- // Frame should be lower priority so that scrollbars are 'on top' of it.
- #define FRAME_PRIORITY ((short)0x7FFF)
- //////////////////////////////////////////////////////////////////////////////
- // Module specific typedefs.
- //////////////////////////////////////////////////////////////////////////////
- //////////////////////////////////////////////////////////////////////////////
- // Module specific (static) variables.
- //////////////////////////////////////////////////////////////////////////////
- //////////////////////////////////////////////////////////////////////////////
- // Construction/Destruction.
- //////////////////////////////////////////////////////////////////////////////
- //////////////////////////////////////////////////////////////////////////////
- //
- // Default constructor.
- //
- //////////////////////////////////////////////////////////////////////////////
- RListBox::RListBox()
- {
- // Override defaults for this.
- m_type = ListBox; // Indicates type of GUI item.
- m_sInvertedBorder = TRUE; // Want sunken look.
-
- // Override defaults for children.
- m_sbVert.m_im.m_sWidth = DEF_SCROLL_THICKNESS;
- m_sbVert.m_oOrientation = RScrollBar::Vertical;
- m_sbVert.m_upcUser = ScrollCall;
- m_sbVert.m_ulUserInstance = (ULONG)this;
- // Priority for scrollbars should be higher than any other sibling.
- m_sbVert.m_hot.SetPriority(SCROLLBAR_PRIORITY);
- m_sbHorz.m_im.m_sHeight = DEF_SCROLL_THICKNESS;
- m_sbHorz.m_oOrientation = RScrollBar::Horizontal;
- m_sbHorz.m_upcUser = ScrollCall;
- m_sbHorz.m_ulUserInstance = (ULONG)this;
- // Priority for scrollbars should be higher than any other sibling.
- m_sbHorz.m_hot.SetPriority(SCROLLBAR_PRIORITY);
- // Priority for frame is low.
- m_lcContents.m_hot.SetPriority(FRAME_PRIORITY);
- // Set defaults for direct members.
- m_sbvVert = ShownAsNeeded;
- m_sbvHorz = ShownAsNeeded;
-
- m_sLargestWidth = 0;
-
- m_pguiSel = NULL;
-
- m_typeEncapsulator = Txt;
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // Destructor.
- //
- //////////////////////////////////////////////////////////////////////////////
- RListBox::~RListBox()
- {
- // Remove all items and destroy their encapsulators.
- RemoveAll();
- }
- ////////////////////////////////////////////////////////////////////////
- // Methods.
- ////////////////////////////////////////////////////////////////////////
- //////////////////////////////////////////////////////////////////////////////
- //
- // Creates a displayable Listbox item.
- //
- //////////////////////////////////////////////////////////////////////////////
- short RListBox::Create( // Returns 0 on success.
- short sX, // X position relative to "parent" item.
- short sY, // Y position relative to "parent" item.
- short sW, // Width.
- short sH, // Height.
- short sDepth) // Color depth.
- {
- short sRes = 0; // Assume success.
- Destroy();
- m_sX = sX;
- m_sY = sY;
- if (m_im.CreateImage(sW, sH, RImage::BMP8, 0, sDepth) == 0)
- {
- // Done.
-
- // If there's an error after calling CreateImage, perhaps
- // we should destroy the RImage data here.
- if (sRes != 0)
- {
- Destroy();
- }
- }
- else
- {
- TRACE("Create(): RImage::CreateImage() failed.\n");
- sRes = -1;
- }
-
- // Get client area.
- short sClientX, sClientY, sClientW, sClientH;
- GetClient(&sClientX, &sClientY, &sClientW, &sClientH);
- // Create child items:
- CopyParms(&m_lcContents);
- m_lcContents.m_sBorderThickness = 0;
- // Frame is created in AdjustContents() call.
- m_lcContents.SetParent(this);
- CopyParms(&m_sbVert);
- if (m_sbVert.Create(
- sClientX + sClientW - m_sbVert.m_im.m_sWidth,
- sClientY,
- m_sbVert.m_im.m_sWidth,
- sClientH,
- sDepth) == 0)
- {
- m_sbVert.SetParent(this);
- }
- else
- {
- TRACE("Create(): m_sbVert.Create() failed.\n");
- // Don't use this.
- m_sbVert.SetParent(NULL);
- }
- CopyParms(&m_sbHorz);
- if (m_sbHorz.Create(
- sClientX,
- sClientY + sClientH - m_sbHorz.m_im.m_sHeight,
- sClientW - m_sbVert.m_im.m_sWidth,
- m_sbHorz.m_im.m_sHeight,
- sDepth) == 0)
- {
- m_sbHorz.SetParent(this);
- }
- else
- {
- TRACE("Create(): m_sbHorz.Create() failed.\n");
- // Don't use this.
- m_sbHorz.SetParent(NULL);
- }
-
- // Compose this item.
- Compose();
- return sRes;
- }
- ////////////////////////////////////////////////////////////////////////
- //
- // Compose item.
- //
- ////////////////////////////////////////////////////////////////////////
- void RListBox::Compose( // Returns nothing.
- RImage* pim /*= NULL*/) // Dest image, uses m_im if NULL.
- {
- if (pim == NULL)
- {
- pim = &m_im;
- }
- // Call base (draws border and background).
- RGuiItem::Compose(pim);
- // Resizes all encapsulators, m_lcContents, and sets scroll ranges.
- AdjustContents();
- // No text.
- }
- ////////////////////////////////////////////////////////////////////////
- //
- // Add a string into the list box.
- //
- ////////////////////////////////////////////////////////////////////////
- RGuiItem* RListBox::AddString( // Returns new GUI item on success.
- char* pszString, // String to add.
- RGuiItem* pguiAfter /*= NULL*/) // Gui to add after or NULL to add at
- // end.
- {
- // Create a new string item . . .
- RGuiItem* pguiRes = CreateStringItem(pszString);
- if (pguiRes != NULL)
- {
- // Reposition item.
- AddAfter(pguiRes, pguiAfter);
- }
- else
- {
- TRACE("AddString(): CreateStringItem() failed.\n");
- }
- return pguiRes;
- }
- ////////////////////////////////////////////////////////////////////////
- //
- // Insert a string into the list box.
- //
- ////////////////////////////////////////////////////////////////////////
- RGuiItem* RListBox::InsertString( // Returns new GUI item on success.
- char* pszString, // String to insert.
- RGuiItem* pguiBefore /*= NULL*/) // Gui to insert before or NULL to
- // insert at beginning.
- {
- // Create a new string item . . .
- RGuiItem* pguiRes = CreateStringItem(pszString);
- if (pguiRes != NULL)
- {
- // Reposition item.
- InsertBefore(pguiRes, pguiBefore);
- }
- else
- {
- TRACE("InsertString(): CreateStringItem() failed.\n");
- }
- return pguiRes;
- }
- ////////////////////////////////////////////////////////////////////////
- //
- // Add an item into the list box.
- //
- ////////////////////////////////////////////////////////////////////////
- RGuiItem* RListBox::AddItem( // Returns new GUI item or pgui on
- // success. Depends on sEncapsulate.
- RGuiItem* pgui, // GUI item to insert.
- short sEncapsulate /*= FALSE*/, // If TRUE, this item will be
- // encapsulated in an RGuiItem that
- // will be returned on success.
- // If FALSE, this item will be a direct
- // child of the listbox and will be
- // returned on success.
- RGuiItem* pguiAfter /*= NULL*/) // Gui to add after or NULL to add at
- // end.
- {
- RGuiItem* pguiRes = NULL; // Assume nothing.
- // If encapsulation requested . . .
- if (sEncapsulate != FALSE)
- {
- // Create encapsulator item.
- pguiRes = CreateEncapsulator(pgui);
- }
- else
- {
- // The item is the item to be placed in the listbox.
- pguiRes = pgui;
- }
- // If we have the item to be added . . .
- if (pguiRes != NULL)
- {
- // Make child of list area.
- pguiRes->SetParent(&m_lcContents);
- // Reposition item.
- AddAfter(pguiRes, pguiAfter);
- }
- else
- {
- TRACE("AddItem(): CreateEncapsulator() failed.\n");
- }
- return pguiRes;
- }
- ////////////////////////////////////////////////////////////////////////
- //
- // Insert an item into the list box.
- //
- ////////////////////////////////////////////////////////////////////////
- RGuiItem* RListBox::InsertItem( // Returns new GUI item or pgui on
- // success. Depends on sEncapsulate.
- RGuiItem* pgui, // GUI item to insert.
- short sEncapsulate /*= FALSE*/, // If TRUE, this item will be
- // encapsulated in an RGuiItem that
- // will be returned on success.
- // If FALSE, this item will be a direct
- // child of the listbox and will be
- // returned on success.
- RGuiItem* pguiBefore /*= NULL*/) // Gui to insert before or NULL to
- // insert at beginning.
- {
- RGuiItem* pguiRes = NULL; // Assume nothing.
- // If encapsulation requested . . .
- if (sEncapsulate != FALSE)
- {
- // Create encapsulator item.
- pguiRes = CreateEncapsulator(pgui);
- }
- else
- {
- // The item is the item to be placed in the listbox.
- pguiRes = pgui;
- }
- // If we have the item to be added . . .
- if (pguiRes != NULL)
- {
- // Make child of list area.
- pguiRes->SetParent(&m_lcContents);
- // Reposition item.
- InsertBefore(pguiRes, pguiBefore);
- }
- else
- {
- TRACE("AddItem(): CreateEncapsulator() failed.\n");
- }
- return pguiRes;
- }
- ////////////////////////////////////////////////////////////////////////
- //
- // Remove an item from the list box and destroy encapsulator, if an
- // encapsulator exists for that item.
- //
- ////////////////////////////////////////////////////////////////////////
- void RListBox::RemoveItem( // Returns nothing.
- RGuiItem* pgui) // Item to remove. NOTE: Any
- // encapsulating GUI item will be
- // destroyed.
- {
- // Verify item is a list item and get encapsulator, if any:
- RGuiItem* pguiParent = pgui->GetParent();
- RGuiItem* pguiRemove = NULL;
- if (pguiParent != NULL)
- {
- // If parent is the list container . . .
- if (pguiParent == &m_lcContents)
- {
- // Set item to remove.
- pguiRemove = pgui;
- }
- else
- {
- // If parent's parent is the list container . . .
- if (pguiParent->GetParent() == &m_lcContents)
- {
- // Free from encapsulator.
- pgui->SetParent(NULL);
- // Set item to remove.
- pguiRemove = pguiParent;
- }
- }
- }
- // If there is an item to remove . . .
- if (pguiRemove != NULL)
- {
- // If this item is an encapsulator . . .
- if (IsEncapsulator(pguiRemove) != FALSE)
- {
- // If this item was the selected item . . .
- if (pguiRemove == m_pguiSel)
- {
- // Clear selection.
- SetSel(NULL);
- }
- // Remove encapsulator prop.
- pguiRemove->RemoveProp(ENCAPSULATOR_PROP_KEY);
- // Destroy item.
- delete pguiRemove;
- }
- else
- {
- // If dynamic . . .
- if (pguiRemove->IsDynamic() != FALSE)
- {
- delete pguiRemove;
- }
- }
- }
- else
- {
- TRACE("RemoveItem(): Specified item is not an item of this listbox.\n");
- }
- }
- ////////////////////////////////////////////////////////////////////////
- //
- // Remove all items and encapsulators in listbox.
- // Calls RemoveItem() for each item.
- //
- ////////////////////////////////////////////////////////////////////////
- void RListBox::RemoveAll(void) // Returns nothing.
- {
- RGuiItem* pgui = m_lcContents.m_listguiChildren.GetHead();
- while (pgui != NULL)
- {
- RemoveItem(pgui);
- pgui = m_lcContents.m_listguiChildren.GetNext();
- }
- }
- ////////////////////////////////////////////////////////////////////////
- //
- // Ensure the specified item is within the client of the listbox.
- //
- ////////////////////////////////////////////////////////////////////////
- void RListBox::EnsureVisible( // Returns nothing.
- RGuiItem* pgui, // Item to ensure visibility of.
- Position posPreference /*= Top*/) // In: Preferred vertical position.
- {
- short sX = pgui->m_sX;
- short sY = pgui->m_sY;
- // Take position of item to list contents level.
- RGuiItem* pguiParent = pgui->GetParent();
- while (pguiParent != NULL && pguiParent != &m_lcContents)
- {
- sX += pguiParent->m_sX;
- sY += pguiParent->m_sY;
- pguiParent = pguiParent->GetParent();
- }
- // If we got to the list contents . . .
- if (pguiParent != NULL)
- {
- // Set new position for list contents such that item
- // is in upper left corner of client.
- short sClientX, sClientY, sClientH;
- GetClient(&sClientX, &sClientY, NULL, &sClientH);
- switch (posPreference)
- {
- case Top:
- m_lcContents.Move(-sX + sClientX, -sY + sClientY);
- break;
- case Middle:
- m_lcContents.Move(-sX + sClientX, -sY + sClientY + (sClientH - pgui->m_im.m_sHeight) / 2);
- break;
- case Bottom:
- m_lcContents.Move(-sX + sClientX, -sY + sClientY + sClientH - pgui->m_im.m_sHeight);
- break;
- }
- // Update the scrollbars.
- UpdateScrollBars();
- }
- else
- {
- TRACE("EnsureVisible(): Specified gui is not a member of this "
- "listbox.\n");
- }
- }
- ////////////////////////////////////////////////////////////////////////
- //
- // Set the selection to the specified GUI item.
- //
- ////////////////////////////////////////////////////////////////////////
- void RListBox::SetSel( // Returns nothing.
- RGuiItem* pgui) // Item to select or NULL for none.
- {
- // If new selection is different than current . . .
- if (pgui != m_pguiSel)
- {
- // Unselect item.
- SelectItem(m_pguiSel, FALSE);
- // Set new selection.
- m_pguiSel = pgui;
- // Select item.
- SelectItem(m_pguiSel, TRUE);
- }
- }
- ////////////////////////////////////////////////////////////////////////
- //
- // Update scrollbar visibility based on current listbox contents and
- // their visibility.
- //
- ////////////////////////////////////////////////////////////////////////
- void RListBox::UpdateScrollBarVisibility(void) // Returns nothing.
- {
- // Get client.
- short sClientX, sClientY, sClientW, sClientH;
- GetClient(&sClientX, &sClientY, &sClientW, &sClientH);
- // If visibility is not prohibited . . .
- if (m_sbvVert != Hidden)
- {
- // If the vertical scrollbar should be visible . . .
- if (m_lcContents.m_im.m_sHeight > sClientH - m_sbHorz.m_im.m_sHeight || m_sbvVert == Shown)
- {
- m_sbVert.m_sVisible = TRUE;
- }
- else
- {
- m_sbVert.m_sVisible = FALSE;
- }
- }
- else
- {
- m_sbVert.m_sVisible = FALSE;
- }
- // If visibility is not prohibited . . .
- if (m_sbvHorz != Hidden)
- {
- // If the horizontal scrollbar should be visible . . .
- if (m_lcContents.m_im.m_sWidth > sClientW - m_sbVert.m_im.m_sWidth || m_sbvHorz == Shown)
- {
- m_sbHorz.m_sVisible = TRUE;
- }
- else
- {
- m_sbHorz.m_sVisible = FALSE;
- }
- }
- else
- {
- m_sbHorz.m_sVisible = FALSE;
- }
- // Activate scrollbars according to their visibility and current
- // activation status of listbox.
- m_sbVert.SetActive(m_sbVert.m_sVisible && IsActivated());
- m_sbHorz.SetActive(m_sbHorz.m_sVisible && IsActivated());
- }
- ////////////////////////////////////////////////////////////////////////
- //
- // Resize encapsulators to fit the largest encapsulated item or string,
- // reposition all items to appear in the correct order, resize scrollable
- // area (m_lcContents) to fit all listbox items, and update scrollbar
- // ranges accordingly.
- //
- ////////////////////////////////////////////////////////////////////////
- void RListBox::AdjustContents(void) // Returns nothing.
- {
- // Get client.
- short sClientX, sClientY, sClientW, sClientH;
- GetClient(&sClientX, &sClientY, &sClientW, &sClientH);
- // Minimum is viewable area (when vertical scrollbar shown).
- m_sLargestWidth = sClientW - m_sbVert.m_im.m_sWidth;
- long lTotalHeight = 0; // Used for averaging heights.
- long lTotalItems = 0; // Used for averaging heights.
- // Get largest width.
- RGuiItem* pguiItem = m_lcContents.m_listguiChildren.GetHead();
- while (pguiItem != NULL)
- {
- // If width is larger than largest . . .
- if (pguiItem->m_im.m_sWidth > m_sLargestWidth)
- {
- m_sLargestWidth = pguiItem->m_im.m_sWidth;
- }
- // Get next item.
- pguiItem = m_lcContents.m_listguiChildren.GetNext();
- }
- // Go through children sizing encapsulators to m_sLargestWidth and
- // repositioning items as we go.
- short sY = 0;
- pguiItem = m_lcContents.m_listguiChildren.GetHead();
- while (pguiItem != NULL)
- {
- // Reposition.
- pguiItem->Move(pguiItem->m_sX, sY);
- // If this is an encapsulator . . .
- if (IsEncapsulator(pguiItem) != FALSE)
- {
- // If there's a change in width . . .
- if (pguiItem->m_im.m_sWidth != m_sLargestWidth)
- {
- // Recreate item . . .
- if (pguiItem->Create(
- pguiItem->m_sX,
- pguiItem->m_sY,
- m_sLargestWidth,
- pguiItem->m_im.m_sHeight,
- pguiItem->m_im.m_sDepth) == 0)
- {
- }
- else
- {
- TRACE("AdustContents(): pguiItem->Create() failed.\n");
- }
- }
- }
- // Adjust position for next item by this item's height and the
- // item spacing.
- sY += pguiItem->m_im.m_sHeight + ITEM_SPACING;
- // Keep total height so we can average it to determine scrollbar
- // increments.
- lTotalHeight += pguiItem->m_im.m_sHeight + ITEM_SPACING;
- lTotalItems++;
- // Get next item.
- pguiItem = m_lcContents.m_listguiChildren.GetNext();
- }
- // New height and/or width for container . . .
- if (m_lcContents.Create(
- m_lcContents.m_sX,
- m_lcContents.m_sY,
- m_sLargestWidth,
- sY - ITEM_SPACING,
- m_lcContents.m_im.m_sDepth) == 0)
- {
- }
- else
- {
- TRACE("AdjustContents(): m_lcContents.Create() failed.\n");
- }
- // Update scrollbar visibility.
- UpdateScrollBarVisibility();
- // Set scroll ranges:
- // The scrollable range is the length of the frame minus the size of
- // the area that can be viewed. This is subtracted from the client
- // position to so it is already mapped directly into 'this's
- // coordinate system.
- // If the horizontal scrollbar is visible . . .
- short sScrollBarH = 0;
- if (m_sbHorz.m_sVisible != FALSE)
- {
- // Compensation:
- sScrollBarH = m_sbHorz.m_im.m_sHeight;
- }
- // If viewable area is smaller than list area . . .
- if (m_lcContents.m_im.m_sHeight > sClientH - sScrollBarH)
- {
- m_sbVert.SetRange(
- -sClientY,
- (m_lcContents.m_im.m_sHeight - (sClientH - sScrollBarH)) - sClientY);
- }
- else
- {
- m_sbVert.SetRange(
- -sClientY,
- -sClientY);
- }
-
- // If the vertical scrollbar is visible . . .
- short sScrollBarW = 0;
- if (m_sbVert.m_sVisible != FALSE)
- {
- // Compensation:
- sScrollBarW = m_sbVert.m_im.m_sWidth;
- }
- // If viewable area is smaller than list area . . .
- if (m_lcContents.m_im.m_sWidth > sClientW - sScrollBarW)
- {
- m_sbHorz.SetRange(
- -sClientX,
- (m_lcContents.m_im.m_sWidth - (sClientW - sScrollBarW)) - sClientX);
- }
- else
- {
- m_sbHorz.SetRange(
- -sClientX,
- -sClientX);
- }
- // Calculate average height of item.
- long lAvgHeight = 0;
- if (lTotalItems > 0)
- {
- lAvgHeight = (short)(lTotalHeight / lTotalItems);
- }
-
- // Update vertical scroll bar increments:
-
- // Clicking buttons should scroll one item at a time.
- m_sbVert.m_lButtonIncDec = lAvgHeight;
- // Clicking tray should scroll visible items - 1 at a time.
- m_sbVert.m_lTrayIncDec = (sClientH - sScrollBarH) - lAvgHeight;
- // Safety . . .
- if (m_sbVert.m_lTrayIncDec <= 0)
- {
- m_sbVert.m_lTrayIncDec = lAvgHeight;
- }
- // Update scroll positions.
- UpdateScrollBars();
- }
- ////////////////////////////////////////////////////////////////////////
- //
- // Update scrollbars' positions. This function is called by
- // AdjustContents() and EnsureVisible(), so there is no need to call it
- // after calling one of those functions.
- //
- ////////////////////////////////////////////////////////////////////////
- void RListBox::UpdateScrollBars(void)
- {
- m_sbVert.SetPos(-m_lcContents.m_sY);
- m_sbHorz.SetPos(-m_lcContents.m_sX);
- }
- ////////////////////////////////////////////////////////////////////////
- // Querries.
- ////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////
- // Get the first child item.
- ////////////////////////////////////////////////////////////////////////
- RGuiItem* RListBox::GetFirst(void) // Returns the first child item or
- // NULL.
- {
- // Find first encapsulator.
- RGuiItem* pguiFirst = m_lcContents.m_listguiChildren.GetHead();
- while (pguiFirst != NULL)
- {
- if (IsEncapsulator(pguiFirst) != FALSE)
- {
- break;
- }
- pguiFirst = m_lcContents.m_listguiChildren.GetNext();
- }
- return pguiFirst;
- }
- ////////////////////////////////////////////////////////////////////////
- // Get the next child item after the specified item.
- ////////////////////////////////////////////////////////////////////////
- RGuiItem* RListBox::GetNext( // Returns the next child item.
- RGuiItem* pgui) // In: Child item that precedes the next.
- {
- RGuiItem* pguiNext = m_lcContents.m_listguiChildren.GetNext(pgui);
- while (pguiNext != NULL)
- {
- if (IsEncapsulator(pguiNext) != FALSE)
- {
- break;
- }
- pguiNext = m_lcContents.m_listguiChildren.GetNext();
- }
- return pguiNext;
- }
- ////////////////////////////////////////////////////////////////////////
- // Get the child item before the specified item.
- ////////////////////////////////////////////////////////////////////////
- RGuiItem* RListBox::GetPrev( // Returns the previous child item or NULL.
- RGuiItem* pgui) // In: Child item that follows the prev.
- {
- RGuiItem* pguiPrev = m_lcContents.m_listguiChildren.GetPrev(pgui);
- while (pguiPrev != NULL)
- {
- if (IsEncapsulator(pguiPrev) != FALSE)
- {
- break;
- }
- pguiPrev = m_lcContents.m_listguiChildren.GetPrev();
- }
- return pguiPrev;
- }
- ////////////////////////////////////////////////////////////////////////
- // Internals.
- ////////////////////////////////////////////////////////////////////////
- ////////////////////////////////////////////////////////////////////////
- //
- // Creates an item appropriate for the specified string and makes it
- // a child of this listbox.
- //
- ////////////////////////////////////////////////////////////////////////
- RGuiItem* RListBox::CreateStringItem( // Returns new item on success;
- // NULL, otherwise.
- char* pszString) // Text for new item.
- {
- RGuiItem* pgui = NULL; // Assume nothing.
- short sError = 0;
- // We'll need a font and a print for this.
- ASSERT(m_pprint != NULL);
- ASSERT(m_pprint->GetFont() != NULL);
- // Allocate a new item . . .
- pgui = CreateGuiItem(m_typeEncapsulator);
- if (pgui != NULL)
- {
- // Copy parms to new item.
- CopyParms(pgui);
- // Set callback.
- pgui->m_bcUser = PressedCall;
- pgui->m_ulUserInstance = (ULONG)this;
- // Get thickness of border.
- short sBorder = pgui->GetTopLeftBorderThickness()
- + pgui->GetBottomRightBorderThickness();
- // Get the width of the desired string.
- short sWidth = m_pprint->GetWidth(pszString);
- short sHeight = m_sFontCellHeight;
- // Adjust by border thickness.
- sWidth += sBorder;
- sHeight += sBorder;
- // Set text for item before Create() (Create() calls Compose()).
- pgui->SetText(pszString);
- // Create item . . .
- if (pgui->Create(0, 0, sWidth, sHeight, m_im.m_sDepth) == 0)
- {
- // Make child of list area.
- pgui->SetParent(&m_lcContents);
- // Remember to delete this item.
- MakeEncapsulator(pgui);
- // Item position is not set until the next AdjustContents() call.
- }
- else
- {
- TRACE("CreateStringItem(): ptxt->Create() failed.\n");
- sError = 2;
- }
- // If any errors occurred after allocation . . .
- if (sError != 0)
- {
- delete pgui;
- pgui = NULL;
- }
- }
- else
- {
- TRACE("CreateStringItem(): Failed to allocate encapsulator of type %s.\n",
- ms_apszTypes[m_typeEncapsulator]);
- sError = 1;
- }
- return pgui;
- }
- ////////////////////////////////////////////////////////////////////////
- //
- // Creates an encapsulator object for the specified GUI.
- //
- ////////////////////////////////////////////////////////////////////////
- RGuiItem* RListBox::CreateEncapsulator( // Returns new item on success; NULL,
- // otherwise.
- RGuiItem* pgui) // Item to encapsulate.
- {
- RGuiItem* pguiRes = NULL; // Assume nothing.
- short sError = 0;
- // Allocate a new item . . .
- pguiRes = new RGuiItem;
- if (pguiRes != NULL)
- {
- // Copy parms to new item.
- CopyParms(pguiRes);
- // Set callback.
- pguiRes->m_bcUser = PressedCall;
- pguiRes->m_ulUserInstance = (ULONG)this;
- // Get thickness of border.
- short sBorder = pguiRes->GetTopLeftBorderThickness()
- + pguiRes->GetBottomRightBorderThickness();
- // Get the width and height of the encapsulated item.
- short sWidth = pgui->m_im.m_sWidth;
- short sHeight = pgui->m_im.m_sHeight;
- // Adjust by border thickness.
- sWidth += sBorder;
- sHeight += sBorder;
- // Create item . . .
- if (pguiRes->Create(0, 0, sWidth, sHeight, m_im.m_sDepth) == 0)
- {
- // Make item a child of encapsulator.
- pgui->SetParent(pguiRes);
- // Mark item as an encapsulator.
- MakeEncapsulator(pguiRes);
- // Item position is not set until the next AdjustContents() call.
- }
- else
- {
- TRACE("CreateEncapsulator(): pguiRes->Create() failed.\n");
- sError = 2;
- }
- // If any errors occurred after allocation . . .
- if (sError != 0)
- {
- delete pguiRes;
- pguiRes = NULL;
- }
- }
- else
- {
- TRACE("CreateEncapsulator(): Failed to allocate RTxt.\n");
- sError = 1;
- }
- return pguiRes;
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // Place item at specified location in list of container's child items.
- // Under new pretenses, this should not fail.
- //
- //////////////////////////////////////////////////////////////////////////////
- void RListBox::AddAfter( // Returns nothing.
- RGuiItem* pgui, // Item to add.
- RGuiItem* pguiAfter) // Item to add after or NULL to add at
- // end.
- {
- // Reposition the new item. Under new pretenses, this SHOULD not fail.
- m_lcContents.m_listguiChildren.Remove(pgui);
- // If none specified . . .
- if (pguiAfter == NULL)
- {
- // Insert new item. Under new pretenses, this SHOULD not fail.
- m_lcContents.m_listguiChildren.AddTail(pgui);
- }
- else
- {
- // Insert new item. Under new pretenses, this SHOULD not fail.
- m_lcContents.m_listguiChildren.InsertAfter(pguiAfter, pgui);
- }
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // Place item at specified location in list of container's child items.
- // Under new pretenses, this should not fail.
- //
- //////////////////////////////////////////////////////////////////////////////
- void RListBox::InsertBefore( // Returns nothing.
- RGuiItem* pgui, // Item to insert.
- RGuiItem* pguiBefore) // Item to insert before or NULL to insert
- // at beginning.
- {
- // Reposition the new item. Under new pretenses, this SHOULD not fail.
- m_lcContents.m_listguiChildren.Remove(pgui);
- // If none specified . . .
- if (pguiBefore == NULL)
- {
- // Insert new item. Under new pretenses, this SHOULD not fail.
- m_lcContents.m_listguiChildren.InsertHead(pgui);
- }
- else
- {
- // Insert new item. Under new pretenses, this SHOULD not fail.
- m_lcContents.m_listguiChildren.InsertBefore(pguiBefore, pgui);
- }
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // [Un]Select the specified item.
- //
- //////////////////////////////////////////////////////////////////////////////
- void RListBox::SelectItem( // Returns nothing.
- RGuiItem* pguiSel, // Item to [un]select.
- short sSelect) // If TRUE, item is selected; if FALSE,
- // item is unselected.
- {
- // If there was previously a selection . . .
- if (pguiSel != NULL)
- {
- // If this is an encapsulation . . .
- if (IsEncapsulator(pguiSel) != FALSE)
- {
- // Toggle border.
- pguiSel->m_sInvertedBorder = sSelect;
- // Recompose item with new border effect.
- pguiSel->Compose();
- }
- }
- }
- ////////////////////////////////////////////////////////////////////////
- //
- // Load item's children from the specified file.
- // (virtual override).
- // (protected).
- //
- ////////////////////////////////////////////////////////////////////////
- short RListBox::LoadChildren( // Returns 0 on success.
- RFile* pfile) // File to load from.
- {
- short sRes = 0; // Assume success.
- ASSERT(pfile->IsOpen() != FALSE);
- short sNum;
- // Read number of children.
- pfile->Read(&sNum);
- // The first three are our scrollbars and frame.
- ASSERT(sNum >= 3);
- // Load directly into these special children.
- if (m_sbVert.Load(pfile) == 0)
- {
- if (m_sbHorz.Load(pfile) == 0)
- {
- // m_lcContents needs to know its parent during Load() (specifically
- // LoadChildren() needs to know).
- m_lcContents.SetParent(this);
- if (m_lcContents.Load(pfile) == 0)
- {
- // Subtract these three children from total.
- sNum -= 3;
- }
- else
- {
- TRACE("LoadChildren(): m_sbVert.Load() failed.\n");
- sRes = -3;
- }
- }
- else
- {
- TRACE("LoadChildren(): m_sbHorz.Load() failed.\n");
- sRes = -2;
- }
- }
- else
- {
- TRACE("LoadChildren(): m_lcContents.Load() failed.\n");
- sRes = -1;
- }
- // Instantiate rest of children.
- RGuiItem* pgui;
- short sCurChild;
- for ( sCurChild = 0;
- sCurChild < sNum && sRes == 0 && pfile->Error() == FALSE;
- sCurChild++)
- {
- pgui = LoadInstantiate(pfile);
- if (pgui != NULL)
- {
- pgui->SetParent(this);
- }
- else
- {
- TRACE("LoadChildren(): LoadInstantiate() failed.\n");
- sRes = -1;
- }
- }
- return sRes;
- }
- ////////////////////////////////////////////////////////////////////////
- //
- // Save item's children to the specified file.
- // (virtual override).
- // (protected).
- //
- ////////////////////////////////////////////////////////////////////////
- short RListBox::SaveChildren( // Returns 0 on success.
- RFile* pfile) // File to save to.
- {
- short sRes = 0; // Assume success.
- ASSERT(pfile->IsOpen() != FALSE);
- // Determine number of child items.
- short sNum = 0;
- RGuiItem* pgui = m_listguiChildren.GetHead();
- while (pgui != NULL)
- {
- sNum++;
- pgui = m_listguiChildren.GetNext();
- }
- // Write number of children.
- pfile->Write(sNum);
- // These should definitely be children of 'this' item.
- ASSERT(m_sbVert.GetParent() == this);
- ASSERT(m_sbHorz.GetParent() == this);
- ASSERT(m_lcContents.GetParent() == this);
- // Always write our 3 special children (scrollbars & frame) first so we know
- // where to get them on load.
- if (m_sbVert.Save(pfile) == 0)
- {
- if (m_sbHorz.Save(pfile) == 0)
- {
- if (m_lcContents.Save(pfile) == 0)
- {
- // Subtract these three children from total.
- // Currently this number is not used during save,
- // but just in case it ever is.
- sNum -= 3;
- }
- else
- {
- TRACE("SaveChildren(): m_lcContents.Save() failed.\n");
- sRes = -3;
- }
- }
- else
- {
- TRACE("SaveChildren(): m_sbHorz.Save() failed.\n");
- sRes = -2;
- }
- }
- else
- {
- TRACE("SaveChildren(): m_sbVert.Save() failed.\n");
- sRes = -1;
- }
- // Save children. Note that we go through the children in reverse
- // order so they, on load, get added back to their parent in the
- // order they were originally added to this parent.
- pgui = m_listguiChildren.GetTail();
- while (pgui != NULL && sRes == 0 && pfile->Error() == FALSE)
- {
- // Don't write these 3 again . . .
- if (pgui != &m_sbVert && pgui != &m_sbHorz && pgui != &m_lcContents)
- {
- // Save child.
- sRes = pgui->Save(pfile);
- }
- pgui = m_listguiChildren.GetPrev();
- }
- return sRes;
- }
- ////////////////////////////////////////////////////////////////////////
- //
- // Read item's members from file.
- // (virtual/protected (overriden here)).
- //
- ////////////////////////////////////////////////////////////////////////
- short RListBox::ReadMembers( // Returns 0 on success.
- RFile* pfile, // File to read from.
- U32 u32Version) // File format version to use.
- {
- short sRes = 0; // Assume success.
- // Invoke base class to read base members.
- sRes = RGuiItem::ReadMembers(pfile, u32Version);
- // If okay so far . . .
- if (sRes == 0)
- {
- ASSERT(pfile != NULL);
- ASSERT(pfile->IsOpen() != FALSE);
-
- U32 u32Temp;
-
- // Switch on version.
- switch (u32Version)
- {
- default:
- // Insert additional version numbers here!
- // case 4: // Version 4 stuff.
- // case 3: // Version 3 stuff.
- case 2: // Version 2 added encapsulator type.
- pfile->Read(&u32Temp);
- m_typeEncapsulator = (Type)u32Temp;
- case 1:
- // Read this class's members.
- pfile->Read(&u32Temp);
- m_sbvVert = (ScrollBarVisibility)u32Temp;
- pfile->Read(&u32Temp);
- m_sbvHorz = (ScrollBarVisibility)u32Temp;
- case 0: // In version 0, only base class RGuiItem members were stored.
- // If successful . . .
- if (pfile->Error() == FALSE)
- {
- // Success.
- }
- else
- {
- TRACE("ReadMembers(): Error reading RListBox members.\n");
- sRes = -1;
- }
- break;
- }
- }
- return sRes;
- }
- ////////////////////////////////////////////////////////////////////////
- //
- // Write item's members to file.
- // (virtual/protected (overriden here)).
- //
- ////////////////////////////////////////////////////////////////////////
- short RListBox::WriteMembers( // Returns 0 on success.
- RFile* pfile) // File to write to.
- {
- short sRes = 0; // Assume success.
- // Invoke base class to read base members.
- sRes = RGuiItem::WriteMembers(pfile);
- // If okay so far . . .
- if (sRes == 0)
- {
- ASSERT(pfile != NULL);
- ASSERT(pfile->IsOpen() != FALSE);
-
- // Write this class's members.
- ////////////// Version 2 ////////////////////
- pfile->Write((U32)m_typeEncapsulator);
- ////////////// Version 1 ////////////////////
- pfile->Write((U32)m_sbvVert);
- pfile->Write((U32)m_sbvHorz);
- ////////////// Version 0 ////////////////////
- // If successful . . .
- if (pfile->Error() == FALSE)
- {
- // Success.
- }
- else
- {
- TRACE("WriteMembers(): Error writing RListBox members.\n");
- sRes = -1;
- }
- }
- return sRes;
- }
- //////////////////////////////////////////////////////////////////////////////
- // EOF
- //////////////////////////////////////////////////////////////////////////////
|