_HORIZONTALLY SCROLLABLE LISTBOXES_ by Ted Faison [LISTING ONE] #ifndef __HLBOX_HPP #define __HLBOX_HPP #include #include #include class THorizontalListBox: public TListBox { class Extent { int value; public: Extent(int i) {value = i;} Extent() {value = 0;} Extent(Extent& i) {value = (int) i;} int operator==(Extent& i) const {return value == (int) i;} int operator<(Extent& i) const {return value < (int) i;} operator int() {return value;} virtual int isSortable() {return 1;} }; typedef BI_SArrayAsVector Extents; Extents textExtents; int TextExtent(LPSTR); void UpdateHorizontalExtent(); public: THorizontalListBox(PTWindowsObject, int, PTModule = NULL); int AddString(LPSTR); int InsertString(LPSTR, int); int DeleteString(int); void ClearList(); void InsertExtent(LPSTR); virtual WORD Transfer(void*, WORD); }; #endif [LISTING TWO] #include "hlbox.hpp" THorizontalListBox::THorizontalListBox(TWindowsObject* AParent, int id, TModule* module):TListBox(AParent, id, module),textExtents(20, 0, 20) { } static void AddTextExtent(Object& AString, void* P) { THorizontalListBox* listBox = (THorizontalListBox*) P; LPSTR string = (char*)(const char*)(RString)AString; if (AString != NOOBJECT) listBox->InsertExtent(string); } WORD THorizontalListBox::Transfer(void* DataPtr, WORD TransferFlag) { WORD value = TListBox::Transfer(DataPtr, TransferFlag); if (TransferFlag == TF_SETDATA) { // for each string in the transfer buffer, // add its extent to the extent container TListBoxData* ListBoxData = *(PTListBoxData*) DataPtr; ListBoxData->Strings->forEach(AddTextExtent, this); } return value; } int THorizontalListBox::AddString(LPSTR AString) { InsertExtent(AString); return TListBox::AddString(AString); } int THorizontalListBox::InsertString(LPSTR AString, int Index) { InsertExtent(AString); return TListBox::InsertString(AString, Index); } void THorizontalListBox::InsertExtent(LPSTR AString) { // store the extent of each string in sorted order in a container int length = TextExtent(AString); Extent extent = *new Extent(length); textExtents.add(extent); // update the ListBox horizontal extent UpdateHorizontalExtent(); } int THorizontalListBox::DeleteString(int Index) { // find the text extent of the string to be deleted char string [256]; GetString(string, Index); // remove the extent from the container Extent extent = Extent(TextExtent(string) ); for (int i = 0; i < textExtents.getItemsInContainer(); i++) { if (extent == textExtents [i]) { textExtents.detach(extent, TShouldDelete::Delete); break; } } // update the ListBox horizontal extent UpdateHorizontalExtent(); return TListBox::DeleteString(Index); } void THorizontalListBox::ClearList() { // delete all the text extents in the container textExtents.flush(); // update the ListBox horizontal extent UpdateHorizontalExtent(); // Call DeleteString, to force Windows 3.0 to remove // the horizontal scrollbar. Windows 3.1 doesn't need this call DeleteString(0); // clear out the remaining strings in the ListBox TListBox::ClearList(); } // find the extent of a ListBox string int THorizontalListBox::TextExtent(LPSTR AString) { int extent; // select the ListBox into the device context HDC hdc = GetDC(HWindow); HFONT hfont = (HFONT) SendMessage(HWindow, WM_GETFONT, 0, 0); if (hfont) { // non-system font being used: select it into the // ListBox's device context before calling GetTextExtent HGDIOBJ oldObject = SelectObject(hdc, hfont); // find the text extent of the string extent = GetTextExtent(hdc, AString, _fstrlen(AString) ); // release resources used SelectObject(hdc, oldObject); ReleaseDC(HWindow, hdc); } else { // system font in use: no font selection necessary, // because GetTextExtent will use the system font by default extent = GetTextExtent(hdc, AString, _fstrlen(AString) ); ReleaseDC(HWindow, hdc); } return extent; } void THorizontalListBox::UpdateHorizontalExtent() { int greatestExtent; // find the extent of the longest string in the // ListBox, and set the horizontal extent accordingly int lastElement = textExtents.getItemsInContainer() - 1; if (lastElement < 0) // no more strings in the ListBox greatestExtent = 0; else greatestExtent = textExtents [lastElement]; // add a small amount of space, so that when ListBox is completely scrolled // to the right, the last character is completely visible HDC hdc = GetDC(HWindow); greatestExtent += GetTextExtent(hdc, "X", 1); ReleaseDC(HWindow, hdc); // if the longest string fits completely in the ListBox, then scroll the box // completely to the left, so Windows will hide the scrollbar RECT rect; GetClientRect(HWindow, (LPRECT) &rect); int listWidth = rect.right - rect.left; if (listWidth >= greatestExtent) SendMessage(HWindow, WM_HSCROLL, SB_TOP, 0); // set the extent SendMessage(HWindow, LB_SETHORIZONTALEXTENT, greatestExtent, 0); } Figure 1: Required member functions for objects inserted into a sorted container Default constructor Copy constructor Operator == Operator < isSortable() Figure 2: Adding an extetent to the Extent container int length = TextExtent(AString); Extent extent = *new Extent(length); textExtents.add(extent); Figure 2: Adding an extetent to the Extent container int length = TextExtent(AString); Extent extent = *new Extent(length); textExtents.add(extent);