cclistga.cpp

Go to the documentation of this file.
00001 // $Id: cclistga.cpp 751 2006-03-31 15:43:49Z alex $
00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00003 ================================XARAHEADERSTART===========================
00004  
00005                Xara LX, a vector drawing and manipulation program.
00006                     Copyright (C) 1993-2006 Xara Group Ltd.
00007        Copyright on certain contributions may be held in joint with their
00008               respective authors. See AUTHORS file for details.
00009 
00010 LICENSE TO USE AND MODIFY SOFTWARE
00011 ----------------------------------
00012 
00013 This file is part of Xara LX.
00014 
00015 Xara LX is free software; you can redistribute it and/or modify it
00016 under the terms of the GNU General Public License version 2 as published
00017 by the Free Software Foundation.
00018 
00019 Xara LX and its component source files are distributed in the hope
00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License along
00025 with Xara LX (see the file GPL in the root directory of the
00026 distribution); if not, write to the Free Software Foundation, Inc., 51
00027 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00028 
00029 
00030 ADDITIONAL RIGHTS
00031 -----------------
00032 
00033 Conditional upon your continuing compliance with the GNU General Public
00034 License described above, Xara Group Ltd grants to you certain additional
00035 rights. 
00036 
00037 The additional rights are to use, modify, and distribute the software
00038 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00039 library and any other such library that any version of Xara LX relased
00040 by Xara Group Ltd requires in order to compile and execute, including
00041 the static linking of that library to XaraLX. In the case of the
00042 "CDraw" library, you may satisfy obligation under the GNU General Public
00043 License to provide source code by providing a binary copy of the library
00044 concerned and a copy of the license accompanying it.
00045 
00046 Nothing in this section restricts any of the rights you have under
00047 the GNU General Public License.
00048 
00049 
00050 SCOPE OF LICENSE
00051 ----------------
00052 
00053 This license applies to this program (XaraLX) and its constituent source
00054 files only, and does not necessarily apply to other Xara products which may
00055 in part share the same code base, and are subject to their own licensing
00056 terms.
00057 
00058 This license does not apply to files in the wxXtra directory, which
00059 are built into a separate library, and are subject to the wxWindows
00060 license contained within that directory in the file "WXXTRA-LICENSE".
00061 
00062 This license does not apply to the binary libraries (if any) within
00063 the "libs" directory, which are subject to a separate license contained
00064 within that directory in the file "LIBS-LICENSE".
00065 
00066 
00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00068 ----------------------------------------------
00069 
00070 Subject to the terms of the GNU Public License (see above), you are
00071 free to do whatever you like with your modifications. However, you may
00072 (at your option) wish contribute them to Xara's source tree. You can
00073 find details of how to do this at:
00074   http://www.xaraxtreme.org/developers/
00075 
00076 Prior to contributing your modifications, you will need to complete our
00077 contributor agreement. This can be found at:
00078   http://www.xaraxtreme.org/developers/contribute/
00079 
00080 Please note that Xara will not accept modifications which modify any of
00081 the text between the start and end of this header (marked
00082 XARAHEADERSTART and XARAHEADEREND).
00083 
00084 
00085 MARKS
00086 -----
00087 
00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00089 designs are registered or unregistered trademarks, design-marks, and/or
00090 service marks of Xara Group Ltd. All rights in these marks are reserved.
00091 
00092 
00093       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00094                         http://www.xara.com/
00095 
00096 =================================XARAHEADEREND============================
00097  */
00098 
00099 //****************************************************************************************************
00100 //  File contents: implementation of the Win95 list control
00101 //  Created: 06/08/96 (Adrian)
00102 //****************************************************************************************************
00103 
00104 #include "camtypes.h" 
00105 
00106 #include "bitmpinf.h"
00107 #include "camelot.h"
00108 #include "cclistga.h"
00109 #include "gbrush.h"
00110 #include "palman.h"
00111 #include "wbitmap.h"
00112 
00113 
00114 CC_IMPLEMENT_MEMDUMP(CCListGadget, CC_CLASS_MEMDUMP);
00115 
00116 // This must go after all CC_IMPLEMENT macros.
00117 #define new CAM_DEBUG_NEW
00118 
00119 
00120 
00121 #define USE_CUSTOM_ENABLER // undef this if you want to stick with the Windows one
00122 
00123 CTypedPtrArray<CObArray, CCListGadget::ListEntry*> CCListGadget::GadgetList;
00124 
00125 CCListGadget* CCListGadget::Create(CWindowID parentID, CGadgetID gadgetID)
00126 {
00127     CCListGadget* pListGadget = new CCListGadget(parentID, gadgetID);
00128     if (pListGadget)
00129     {
00130         if (IsWindows31()) // on Win32s we have to set the font to MS Sans Serif - the system font won't work properly 
00131         {
00132             pListGadget->gadgetFont.CreatePointFont(80, "MS Sans Serif");
00133             ::SendDlgItemMessage((HWND) parentID, gadgetID, WM_SETFONT, (WPARAM) (HFONT)  pListGadget->gadgetFont, (LPARAM) NULL);
00134             HWND hGadget = GetDlgItem((HWND) parentID, gadgetID);
00135             DWORD dwStyle = GetWindowLong(hGadget, GWL_STYLE);
00136             dwStyle |= LVS_NOSCROLL;
00137             SetWindowLong(hGadget, GWL_STYLE, dwStyle);
00138         }
00139         return  (pListGadget->AddToList()) ? pListGadget : (CCListGadget*) NULL;
00140     }
00141     else return (CCListGadget*) NULL;
00142 }
00143 
00144 
00145 //private constructor
00146 CCListGadget::CCListGadget(CWindowID parentID, CGadgetID gadgetID)
00147 {
00148     listID = gadgetID;
00149     formID = parentID;
00150     hHeader = 0;
00151     hHeaderBitmap = 0;
00152     columns = 0; 
00153     switches = 0; // no switches by default
00154     switchColumnWidth = 0;
00155     hStateEnabled = 0;
00156     hStateDisabled = 0;
00157     hImageListEnabled = 0;
00158     hImageListDisabled = 0;
00159     isEnabled = TRUE;
00160     isColourList = FALSE;
00161     for (INT32 i = 0; i < SWITCHES_SUPPORTED; i++)
00162         SwitchLeftCoord[i] = 0;
00163 }
00164 
00165 
00166 
00167 /******************************************************************************************
00168 
00169 >   CCListGadget::~CClistGadget()
00170 
00171     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00172     Created:    20/9/96
00173 
00174     Purpose:    Destructor. Makes sure any used resources are cleaned up
00175 
00176 ******************************************************************************************/
00177 
00178 CCListGadget::~CCListGadget()
00179 {
00180     ERROR3IF(hHeader != NULL || hHeaderBitmap != NULL ||
00181             hStateEnabled != NULL || hStateDisabled != NULL ||
00182             hImageListEnabled != NULL || hImageListDisabled != NULL,
00183             "CCListGadget object probably leaked");
00184 }
00185 
00186 
00187 
00188 //function to add this gadget to the global list
00189 CCListGadget::AddToList()
00190 {
00191     ListEntry* pListEntry = new ListEntry(formID, listID, this);
00192     if (pListEntry) 
00193     {
00194         GadgetList.Add(pListEntry);
00195         return TRUE;
00196     }
00197     else return FALSE;
00198 }
00199 
00200 void CCListGadget::OnDialogClose(CWindowID dialogID)
00201 {
00202     for (INT32 i = 0; i < CCListGadget::GadgetList.GetSize(); i++)
00203     {
00204         ListEntry* listIterator = CCListGadget::GadgetList.GetAt(i);
00205         if (listIterator)
00206         {
00207             if ((listIterator->parentID == dialogID) || (::IsChild((HWND) dialogID, (HWND) listIterator->parentID)))
00208             // the list is either on the dialog's form or on one of its tabs, so we kill it
00209                 listIterator->pListGadget->DestroyGadget();
00210         }
00211     }
00212 }
00213 
00214 
00215 CCListGadget* CCListGadget::GetGadget(CWindowID parentID, CGadgetID gadgetID)
00216 {
00217     ListEntry* pListEntry = NULL;
00218     for (INT32 i = 0; i < CCListGadget::GadgetList.GetSize(); i++)
00219     {
00220         ListEntry* listIterator = CCListGadget::GadgetList.GetAt(i);
00221         if (listIterator)
00222         {
00223             if ((parentID == listIterator->parentID) && (gadgetID == listIterator->gadgetID))
00224                 pListEntry = listIterator;
00225         }
00226     }
00227     if (pListEntry) return pListEntry->pListGadget;
00228     else return (CCListGadget*) (void*) NULL;
00229 }
00230 
00231 void CCListGadget::DestroyGadget()
00232 {
00233     //first find this object's entry in the global list and delete it
00234     ListEntry* pListEntry = NULL;
00235     for (INT32 i = 0; i < CCListGadget::GadgetList.GetSize(); i++)
00236     {
00237         ListEntry* listIterator = CCListGadget::GadgetList.GetAt(i);
00238         if (listIterator)
00239         {
00240             if ((formID == listIterator->parentID) && (listID == listIterator->gadgetID))
00241                 GadgetList.RemoveAt(i);
00242         }
00243     }
00244     
00245     // Destroy the image lists, if any
00246     if (hImageListEnabled && !ImageList_Destroy(hImageListEnabled))
00247         ERROR3("Error deleting image list");
00248     hImageListEnabled = NULL;
00249 
00250     if (hImageListDisabled && !ImageList_Destroy(hImageListDisabled))
00251         ERROR3("Error deleting image list");
00252     hImageListDisabled = NULL;
00253 
00254     if (hStateEnabled && !ImageList_Destroy(hStateEnabled))
00255         ERROR3("Error deleting image list");
00256     hStateEnabled = NULL;
00257 
00258     if (hStateDisabled && !ImageList_Destroy(hStateDisabled))
00259         ERROR3("Error deleting image list");
00260     hStateDisabled = NULL;
00261 
00262     // Destroy the header window
00263     if (hHeader != NULL)
00264     {
00265         ::DestroyWindow(hHeader);
00266         hHeader = NULL;
00267     }
00268 
00269     // Destroy the header bitmap
00270     if (hHeaderBitmap != NULL)
00271     {
00272         ::DeleteObject(hHeaderBitmap);
00273         hHeaderBitmap = NULL;
00274     }
00275 
00276     //now delete the object itself
00277     delete this;
00278 }
00279 
00280 BOOL CCListGadget::CreateCustomHeader(UINT32 bitmapID)
00281 {
00282     //The listview control has a built-in header, but we will create our own as we want it to display bitmaps
00283     //First get control's coordinates, so that we know where to place the header
00284 
00285     RECT listviewRect;
00286     HWND hGadget = GetDlgItem((HWND) formID, listID);
00287     GetWindowRect(hGadget, &listviewRect);
00288     POINT listviewOrigin = { listviewRect.left, listviewRect.top };
00289     ScreenToClient((HWND) formID, &listviewOrigin);
00290 
00291     hHeaderBitmap = LoadBitmap(AfxGetResourceHandle(), MAKEINTRESOURCE(bitmapID)); 
00292     ERROR2IF(!hHeaderBitmap, FALSE, "Failed to load header bitmap");
00293 
00294     //Get the height of the bitmap so we can figure out the height of the header
00295     BITMAP bitmap;
00296     if (!GetObject(hHeaderBitmap, sizeof(bitmap), &bitmap))
00297     {
00298         ERROR2RAW("Failed to get header bitmap data");
00299         return(FALSE);
00300     }
00301     //Change the background colour of the bitmap to the one used by dialog backgrounds, in case the colour scheme used is not the default 
00302     SetBitmapBkgToSystem(hHeaderBitmap);
00303     //Create the header
00304     hHeader = CreateWindowEx(
00305                 0L,                         // No extended styles.
00306                 WC_HEADER,                  // A header class window.
00307                 (LPCTSTR) NULL,             // No default text.
00308                 WS_CHILD | /*WS_BORDER | */ HDS_BUTTONS | HDS_HORZ, 
00309                 listviewOrigin.x, listviewOrigin.y - bitmap.bmHeight + 1,
00310                 listviewRect.right - listviewRect.left, bitmap.bmHeight,
00311                 GetParent(hGadget),         // Handle to the parent window.
00312                 (HMENU) _R(ID_HEADER),          // ID for the header window.
00313                 AfxGetInstanceHandle(),     // Current instance.
00314                 (LPVOID) NULL);
00315 
00316     if (hHeader)
00317     {
00318         ShowWindow(hHeader, SW_SHOW);
00319         ::EnableWindow(hHeader, FALSE); // We disable it so that clicking on it has no effect
00320         //SetWindowPos(hGadget, HWND_TOPMOST, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
00321         HD_ITEM hdi;  // Header item.
00322         hdi.mask = HDI_FORMAT | HDI_WIDTH | HDI_BITMAP; // the header only contains a bitmap 
00323         hdi.fmt = HDF_LEFT | HDF_BITMAP;  // Left-justify the item.
00324         hdi.cxy = listviewRect.right - listviewRect.left;           // Make it as wide as the window.
00325         hdi.hbm = hHeaderBitmap;
00326         return (Header_InsertItem(hHeader, 0, &hdi) != -1);
00327     }
00328 
00329     return FALSE; // we failed
00330 }
00331 
00332 BOOL CCListGadget::OnSysColorChange(CWindowID dialogID)
00333 {
00334     // search the global list of gadgets to find if there are any on the current dialog form or one of its tabs
00335     for (INT32 i = 0; i < CCListGadget::GadgetList.GetSize(); i++)
00336     {
00337         ListEntry* listIterator = CCListGadget::GadgetList.GetAt(i);
00338         if (listIterator)
00339         {
00340             if ((listIterator->parentID == dialogID) || (::IsChild((HWND) dialogID, (HWND) listIterator->parentID)))
00341             // the list is either on the dialog's form or on one of its tabs, so forward the message to it
00342             {
00343                 CCListGadget* pList = listIterator->pListGadget;
00344                 SendDlgItemMessage(pList->formID, pList->listID, WM_SYSCOLORCHANGE, NULL, NULL);
00345                 // if the list is got a header, we need to send the message to it and additionally to change the background of the header bitmap to COLOR_3DFACE        
00346                 if (pList->hHeader && pList->hHeaderBitmap)
00347                 {
00348                     SendDlgItemMessage(pList->formID, _R(ID_HEADER), WM_SYSCOLORCHANGE, NULL, NULL);
00349                     HD_ITEM hdi;  // Header item.
00350                     hdi.mask = HDI_BITMAP;
00351                     if (!Header_GetItem(pList->hHeader, 0, &hdi))
00352                     {
00353                         ERROR2RAW("Failed to update list header colours");
00354                         return(FALSE);
00355                     }
00356                     pList->SetBitmapBkgToSystem(hdi.hbm);
00357                     InvalidateRect(pList->hHeader, NULL, TRUE);
00358                     UpdateWindow(pList->hHeader);
00359                 }
00360             }
00361         }
00362     }
00363     return TRUE;
00364 }
00365         
00366 
00367 BOOL CCListGadget::SetBitmapBkgToSystem(HBITMAP hBitmap)
00368 {
00369     BITMAP bitmap;
00370     HDC hBitmapDC = CreateCompatibleDC(NULL);
00371     if (!GetObject(hBitmap, sizeof(bitmap), &bitmap) || !hBitmapDC)
00372     {
00373         ERROR2RAW("Non-fatal GDI error");
00374         return(FALSE);
00375     }
00376     SelectObject(hBitmapDC, hBitmap);
00377     // We make the assumption that the pixel in the lower right corner has the background colour 
00378     DWORD currentBkColour = (DWORD) GetPixel(hBitmapDC, bitmap.bmWidth - 1, bitmap.bmHeight -1); 
00379     DWORD sysBkColour = GetSysColor(COLOR_3DFACE);
00380     for (INT32 i = 0; i < bitmap.bmWidth; i++)
00381     {
00382         for (INT32 j = 0; j < bitmap.bmHeight; j++)
00383         {
00384             if ((DWORD) GetPixel(hBitmapDC, i, j) == currentBkColour)
00385                 SetPixelV(hBitmapDC, i, j, (COLORREF) sysBkColour);
00386         }
00387     }
00388     DeleteDC(hBitmapDC);
00389     return TRUE;
00390 }
00391 
00392 
00393 BOOL CCListGadget::SetSwitches(UINT32 noOfSwitches, UINT32 idBitmapOn, UINT32 idBitmapOff, UINT32 idDisabledBitmapOn, UINT32 idDisabledBitmapOff)
00394 {
00395     if (switches != 0)
00396     {
00397         ERROR3("Switches have already been set for this list gadget");
00398         return FALSE;
00399     }
00400     if ((noOfSwitches < 1) || (noOfSwitches > SWITCHES_SUPPORTED))
00401     {
00402         ERROR3("Incorrect number of switches");
00403         return FALSE;
00404     }
00405     switches = noOfSwitches;
00406 
00407     //Create two arrays of bitmaps, one for each possible state of the listview (enabled/disabled) 
00408     INT32 noOfBitmaps = 1 << noOfSwitches;
00409     HBITMAP bitmaps[1 << SWITCHES_SUPPORTED];
00410     HBITMAP disabledBitmaps[1 << SWITCHES_SUPPORTED];
00411 
00412     for (INT32 i = 0; i < (1 << SWITCHES_SUPPORTED); i++)
00413     {
00414         bitmaps[i] = NULL;
00415         disabledBitmaps[i] = NULL;
00416     }
00417 
00418     const INT32 bitmapHeight = SWITCH_HEIGHT + 2;
00419 
00420     // BLOCK
00421     {
00422         HBITMAP hBitmapOn =  LoadBitmap(AfxGetResourceHandle(), MAKEINTRESOURCE(idBitmapOn));
00423         HBITMAP hBitmapOff =  LoadBitmap(AfxGetResourceHandle(), MAKEINTRESOURCE(idBitmapOff));
00424         ERROR2IF(!((hBitmapOn) && (hBitmapOff)), FALSE, "Error loading bitmaps");
00425 
00426         HBITMAP hDisabledBitmapOn =  LoadBitmap(AfxGetResourceHandle(), MAKEINTRESOURCE(idDisabledBitmapOn));
00427         HBITMAP hDisabledBitmapOff =  LoadBitmap(AfxGetResourceHandle(), MAKEINTRESOURCE(idDisabledBitmapOff));
00428         ERROR2IF(!((hDisabledBitmapOn) && (hDisabledBitmapOff)), FALSE, "Error loading bitmaps");
00429 
00430         BOOL ok = TRUE;
00431         
00432         //Ensure that the bitmaps have correct dimmensions (we only check the enabled bitmaps) 
00433         // BLOCK
00434         {
00435             BITMAP bitmapOn;
00436             BITMAP bitmapOff;
00437             ok = GetObject(hBitmapOn, sizeof(bitmapOn), &bitmapOn);
00438             ERROR3IF(!ok, "Can't get 'ON' switch bitmap data");
00439             ERROR3IF(!((bitmapOn.bmHeight == SWITCH_HEIGHT) && (bitmapOn.bmWidth == SWITCH_WIDTH)),
00440                 "'ON' switch bitmap is not the size defined in cclistga.h (SWITCH_WIDTH x SWITCH_HEIGHT)");
00441             ok = GetObject(hBitmapOff, sizeof(bitmapOff), &bitmapOff);
00442             ERROR3IF(!ok, "Can't get 'OFF' switch bitmap data");
00443             ERROR3IF(!((bitmapOff.bmHeight == SWITCH_HEIGHT) && (bitmapOff.bmWidth == SWITCH_WIDTH)),
00444                 "'OFF' switch bitmap is not the size defined in cclistga.h (SWITCH_WIDTH x SWITCH_HEIGHT)");
00445         }
00446 
00447         //Make sure that this width is always even, or CreateBitmapIndirect() - which is used to create the bitmap inside CreateScreenCompatibleBitmap() - will fail !!!
00448         switchColumnWidth = SWITCH_MARGIN + noOfSwitches * (SWITCH_WIDTH + SWITCH_SEPARATOR);
00449         for (INT32 i = 0; i < noOfBitmaps; i++)
00450         {
00451             bitmaps[i] = CreateScreenCompatibleBitmap(switchColumnWidth,bitmapHeight);
00452             disabledBitmaps[i] = CreateScreenCompatibleBitmap(switchColumnWidth,bitmapHeight);
00453             HDC hSwitchBitmapDC = CreateCompatibleDC(NULL);
00454             HDC hDisabledBitmapDC = CreateCompatibleDC(NULL);
00455 
00456             HBITMAP OldSwitchBitmap = (HBITMAP) SelectObject(hSwitchBitmapDC, bitmaps[i]);
00457             HBITMAP OldDSwitchBitmap = (HBITMAP) SelectObject(hDisabledBitmapDC, disabledBitmaps[i]);
00458 
00459 #ifdef USE_CUSTOM_ENABLER
00460             PatBlt(hDisabledBitmapDC, 0, 0, switchColumnWidth, bitmapHeight, WHITENESS);
00461 #else
00462             HBRUSH OldBrush = SelectObject(hDisabledBitmapDC, (HBRUSH) GetStockObject(LTGRAY_BRUSH));
00463             PatBlt(hDisabledBitmapDC, 0, 0, switchColumnWidth, bitmapHeight, PATCOPY);// when disabled switches will be gray
00464 #endif
00465             PatBlt(hSwitchBitmapDC, 0, 0, switchColumnWidth, bitmapHeight, WHITENESS);// blit a white background
00466 
00467             //Combine the on/off bitmaps to create a composite state bitmap
00468             HDC hBitmapOnDC = CreateCompatibleDC(NULL);
00469             HDC hBitmapOffDC = CreateCompatibleDC(NULL);
00470 
00471             HBITMAP OldBitmapOn = (HBITMAP) SelectObject(hBitmapOnDC, hBitmapOn);
00472             HBITMAP OldBitmapOff = (HBITMAP) SelectObject(hBitmapOffDC, hBitmapOff);
00473 
00474             HDC hDisabledBitmapOnDC = CreateCompatibleDC(NULL);
00475             HDC hDisabledBitmapOffDC = CreateCompatibleDC(NULL);
00476 
00477             HBITMAP OldDisBitmapOn = (HBITMAP) SelectObject(hDisabledBitmapOnDC, hDisabledBitmapOn);
00478             HBITMAP OldDisBitmapOff = (HBITMAP) SelectObject(hDisabledBitmapOffDC, hDisabledBitmapOff);
00479 
00480             for (UINT32 j = 0; j < noOfSwitches; j++)
00481             {
00482                 // we blit the switches from right to left
00483                 if ( i & (1 << j)) // so this bit is 1
00484                 {
00485                     ok = BitBlt(hSwitchBitmapDC,
00486                     switchColumnWidth - (j + 1) * (SWITCH_WIDTH + SWITCH_SEPARATOR),  // x-coordinate of switch's upper-left corner
00487                     1, // we leave a 1 pixel border
00488                     SWITCH_WIDTH,
00489                     SWITCH_HEIGHT,
00490                     hBitmapOnDC,
00491                     0,
00492                     0,
00493                     SRCCOPY);
00494                     ERROR3IF(!ok, "GDI Error (most likely invalid bitmap handle)");
00495 #ifdef USE_CUSTOM_ENABLER
00496                     ok = BitBlt(hDisabledBitmapDC,
00497                     switchColumnWidth - (j + 1) * (SWITCH_WIDTH + SWITCH_SEPARATOR),  // x-coordinate of switch's upper-left corner
00498                     1, // we leave a 1 pixel border
00499                     SWITCH_WIDTH,
00500                     SWITCH_HEIGHT,
00501                     hDisabledBitmapOnDC,
00502                     0,
00503                     0,
00504                     SRCCOPY);
00505                     ERROR3IF(!ok, "GDI Error (most likely invalid bitmap handle)");
00506 #endif
00507                 }
00508                 else // so this bit is OFF
00509                 {
00510                     ok = BitBlt(hSwitchBitmapDC,
00511                     switchColumnWidth - (j + 1) * (SWITCH_WIDTH + SWITCH_SEPARATOR),  // x-coordinate of switch's upper-left corner
00512                     1, // we leave a 1 pixel border
00513                     SWITCH_WIDTH,
00514                     SWITCH_HEIGHT,
00515                     hBitmapOffDC,
00516                     0,
00517                     0,
00518                     SRCCOPY);
00519                     ERROR3IF(!ok, "GDI Error (most likely invalid bitmap handle)");
00520 #ifdef USE_CUSTOM_ENABLER
00521                     ok = BitBlt(hDisabledBitmapDC,
00522                     switchColumnWidth - (j + 1) * (SWITCH_WIDTH + SWITCH_SEPARATOR),  // x-coordinate of switch's upper-left corner
00523                     1, // we leave a 1 pixel border
00524                     SWITCH_WIDTH,
00525                     SWITCH_HEIGHT,
00526                     hDisabledBitmapOffDC,
00527                     0,
00528                     0,
00529                     SRCCOPY);
00530                     ERROR3IF(!ok, "GDI Error (most likely invalid bitmap handle)");
00531 #endif
00532                 }
00533                 if (!SwitchLeftCoord[noOfSwitches - 1 - j])
00534                     SwitchLeftCoord[noOfSwitches - 1 - j] = switchColumnWidth - (j + 1) * (SWITCH_WIDTH + SWITCH_SEPARATOR);
00535             }   // End for (j)
00536 
00537             // Restore the DCs
00538             SelectObject(hBitmapOnDC, OldBitmapOn);
00539             SelectObject(hBitmapOffDC, OldBitmapOff);
00540 
00541             SelectObject(hDisabledBitmapOnDC, OldDisBitmapOn);
00542             SelectObject(hDisabledBitmapOffDC, OldDisBitmapOff);
00543 
00544             SelectObject(hSwitchBitmapDC, OldSwitchBitmap);
00545             SelectObject(hDisabledBitmapDC, OldDSwitchBitmap);
00546 
00547 #ifndef USE_CUSTOM_ENABLER
00548             SelectObject(hDisabledBitmapDC, OldBrush);
00549 #endif
00550             // And then delete the DCs
00551             DeleteDC(hSwitchBitmapDC);
00552             DeleteDC(hBitmapOnDC);
00553             DeleteDC(hBitmapOffDC);
00554             DeleteDC(hDisabledBitmapDC);
00555             DeleteDC(hDisabledBitmapOnDC);
00556             DeleteDC(hDisabledBitmapOffDC);
00557         }   // End for (i)
00558 
00559         // And delete our temporary bitmaps
00560         ::DeleteObject(hBitmapOn);
00561         ::DeleteObject(hBitmapOff);
00562 
00563         ::DeleteObject(hDisabledBitmapOn);
00564         ::DeleteObject(hDisabledBitmapOff);
00565     } // End block
00566 
00567 
00568     //Create two state image list from our arrays and attach them to the control
00569     hStateEnabled = CreateImageList(switchColumnWidth, bitmapHeight);
00570     hStateDisabled = CreateImageList(switchColumnWidth, bitmapHeight);
00571     for (INT32 k = 0; k < noOfBitmaps; k++)
00572     {
00573         if (hStateEnabled != NULL)
00574             ImageList_Add(hStateEnabled, bitmaps[k], NULL);
00575 
00576         if (hStateDisabled != NULL)
00577             ImageList_Add(hStateDisabled, disabledBitmaps[k], NULL);
00578     
00579         DeleteObject(bitmaps[k]);
00580         DeleteObject(disabledBitmaps[k]);
00581     }
00582 
00583     HWND hListGadget = GetDlgItem((HWND) formID, listID);
00584     ERROR2IF(!hListGadget, FALSE, "Invalid control handle");
00585 
00586     if (IsWindowEnabled(hListGadget))
00587     {
00588         if (hStateEnabled != NULL)
00589             ListView_SetImageList(hListGadget, hStateEnabled, LVSIL_STATE);
00590     }
00591     else
00592     {
00593         if (hStateDisabled != NULL)
00594             ListView_SetImageList(hListGadget, hStateDisabled, LVSIL_STATE);
00595     }
00596 
00597     // If the columns have ben set, we need to resize them to accomodate the new switches
00598     if (columns)
00599     {
00600         RECT gadgetRect;
00601         GetWindowRect(hListGadget, &gadgetRect);
00602         // By default all columns will be the same width
00603         UINT32 columnWidth = (gadgetRect.right - gadgetRect.left - switchColumnWidth)/columns;
00604         for (UINT32 i = 0; i < columns; i++)
00605         {
00606             if (i)
00607                 ListView_SetColumnWidth(hListGadget, i, columnWidth);
00608             else
00609                 ListView_SetColumnWidth(hListGadget, i, columnWidth + switchColumnWidth);
00610         }
00611     }
00612 
00613     //Check that we have been successful - i.e. we have an image list
00614 //  return (BOOL) ListView_GetImageList( hListGadget, LVSIL_STATE); 
00615 
00616     // we now gracefully degrade if the imagelist is unavailable, so return TRUE
00617     return TRUE;
00618 }
00619 
00620 BOOL CCListGadget::SetEnabled(BOOL enabled)
00621 {
00622     //Currently we are using our own enabler
00623     HWND hListGadget = GetDlgItem((HWND) formID, listID);
00624     ERROR2IF(!hListGadget, FALSE, "Invalid control handle");
00625     if (!enabled && isEnabled) // disable the list then
00626     {
00627         //Change the following to: ListView_SetCallbackMask(hListGadget, NULL) if you want to use ::EnableWindow()
00628         ListView_SetCallbackMask(hListGadget, LVIS_FOCUSED | LVIS_SELECTED);
00629         isEnabled = FALSE;
00630 
00631         if (hStateDisabled)
00632             ListView_SetImageList(hListGadget, hStateDisabled, LVSIL_STATE);
00633 
00634         if (hImageListDisabled)
00635             ListView_SetImageList(hListGadget, hImageListDisabled, LVSIL_SMALL);
00636 
00637         ListView_SetTextColor(hListGadget, (COLORREF) GetSysColor(COLOR_GRAYTEXT));
00638         ListView_RedrawItems(hListGadget, 0, GetItemCount() - 1);
00639         UpdateWindow(hListGadget);
00640     }
00641     else if (enabled && !isEnabled) // OK to enable
00642     {
00643         ListView_SetCallbackMask(hListGadget, NULL);
00644         isEnabled = TRUE;
00645 
00646         if (hStateEnabled)
00647             ListView_SetImageList(hListGadget, hStateEnabled, LVSIL_STATE); 
00648 
00649         if (hImageListEnabled)
00650             ListView_SetImageList(hListGadget, hImageListEnabled, LVSIL_SMALL);
00651 
00652         ListView_SetTextColor(hListGadget, (COLORREF) GetSysColor(COLOR_WINDOWTEXT));
00653         ListView_RedrawItems(hListGadget, 0, GetItemCount() - 1);
00654         UpdateWindow(hListGadget);
00655     }
00656     return TRUE;
00657 }
00658 
00659 BOOL CCListGadget::SetColumnWidth(INT32 colIndex, INT32 width)
00660 {
00661     HWND hListGadget = GetDlgItem((HWND) formID, listID);
00662     ERROR2IF(!hListGadget, FALSE, "Invalid control handle");
00663     return ListView_SetColumnWidth(hListGadget, colIndex, width);
00664 }
00665 
00666 INT32 CCListGadget::GetColumnWidth(INT32 colIndex)
00667 {
00668     HWND hListGadget = GetDlgItem((HWND) formID, listID);
00669     ERROR2IF(!hListGadget, FALSE, "Invalid control handle");
00670     return ListView_GetColumnWidth(hListGadget, colIndex);
00671 }
00672 
00673 UINT32 CCListGadget::GetNumberOfSwitches()
00674 {
00675     return switches;
00676 }
00677 
00678 BOOL CCListGadget::SetHeaderString(StringBase& string, UINT32 colIndex)
00679 {
00680     if (!columns)   columns = 1;// the columns have not been set, so we default to 1 column
00681     if (colIndex > (columns - 1))
00682     {
00683         ERROR3("Invalid column index");
00684         return FALSE;
00685     }
00686     LV_COLUMN lvc;
00687     lvc.mask = LVCF_FMT | LVCF_SUBITEM | LVCF_TEXT;
00688     if (columns == 1) lvc.mask |= LVCF_WIDTH;
00689     lvc.fmt     = LVCFMT_LEFT; // text will be left-aligned
00690     lvc.cchTextMax = sizeof((TCHAR*) string);
00691     if (columns == 1)
00692     {
00693         RECT gadgetRect;
00694         GetWindowRect( GetDlgItem((HWND) formID, listID), &gadgetRect);
00695         lvc.cx = gadgetRect.right - gadgetRect.left;
00696     }
00697     lvc.iSubItem = colIndex;
00698     lvc.pszText = (TCHAR*) string;
00699     if (columns == 1) return (ListView_InsertColumn( GetDlgItem((HWND) formID, listID), colIndex, &lvc) != -1);
00700     else return ListView_SetColumn( GetDlgItem((HWND) formID, listID), colIndex, &lvc);
00701 }
00702 
00703 BOOL CCListGadget::SetNumberOfColumns(UINT32 nColumns)
00704 {
00705     HWND hListGadget = GetDlgItem((HWND) formID, listID);
00706     ERROR2IF(!hListGadget, FALSE, "Invalid gadget handle");
00707     if (!nColumns) 
00708     {
00709         ERROR3("Invalid number of columns");
00710         return FALSE;
00711     }
00712     BOOL success = TRUE;
00713     if (columns) 
00714     {
00715         ERROR3("Columns already set for list gadget");
00716         return FALSE;
00717     }
00718     //All columns will have the same width
00719     RECT gadgetRect;
00720     GetWindowRect(hListGadget, &gadgetRect);
00721     UINT32 columnWidth = (gadgetRect.right - gadgetRect.left - switchColumnWidth)/nColumns;
00722     for (UINT32 i = 0; i < nColumns; i++)
00723     {
00724         LV_COLUMN lvc;
00725         lvc.mask = LVCF_FMT | LVCF_SUBITEM | LVCF_WIDTH;
00726         lvc.fmt     = LVCFMT_LEFT; // text will be left-aligned
00727         lvc.iSubItem = i;
00728         if (i)
00729             lvc.cx = columnWidth;
00730         else
00731             lvc.cx = columnWidth + switchColumnWidth;
00732         if  (ListView_InsertColumn( hListGadget, i, &lvc) == -1)
00733             success = FALSE;
00734     }
00735     if (success)
00736         columns = nColumns;// if we're fine, update the columns variable  
00737     return success;
00738 }
00739 
00740 UINT32 CCListGadget::GetNumberOfColumns()
00741 {
00742     //easy one...
00743     return columns;
00744 }
00745 
00746 BOOL CCListGadget::SetSwitchState(BOOL state, UINT32 itemIndex, UINT32 switchIndex)
00747 {
00748     HWND hwndLV = GetDlgItem((HWND) formID, listID);
00749     if (itemIndex >= (UINT32) ListView_GetItemCount(hwndLV))
00750     {
00751         ERROR3("Invalid item index");
00752         return FALSE;
00753     }
00754     if (switchIndex >= switches)
00755     {
00756         ERROR3("Invalid switch index");
00757         return FALSE;
00758     }
00759     //If we get this far the index is correct, so let's get the state bits for the item
00760     //The state bits are actually a 1-based index into the state image list, shifted 12 places to the right (!!!!!!!)  
00761     UINT32 itemState = ListView_GetItemState(hwndLV, itemIndex,  LVIS_STATEIMAGEMASK);
00762     itemState >>= 12;
00763     itemState--;
00764     if (state) itemState |= (1 << (switches - switchIndex -1));
00765     else itemState &= ~(1 << (switches - switchIndex -1));
00766     itemState++;
00767     itemState <<= 12;
00768     ListView_SetItemState(hwndLV, itemIndex, itemState, LVIS_STATEIMAGEMASK);
00769     return TRUE;
00770 }
00771 
00772 BOOL CCListGadget::GetSwitchState(UINT32 itemIndex, UINT32 switchIndex)
00773 {
00774     HWND hwndLV = GetDlgItem((HWND) formID, listID);
00775     if (itemIndex >= (UINT32) ListView_GetItemCount(hwndLV))
00776     {
00777         ERROR3("Invalid item index");
00778         return FALSE;
00779     }
00780     if (switchIndex >= switches)
00781     {
00782         ERROR3("Invalid switch index");
00783         return FALSE;
00784     }
00785     UINT32 itemState = ListView_GetItemState(hwndLV, itemIndex,  LVIS_STATEIMAGEMASK);
00786     itemState >>= 12;
00787     itemState--;
00788     return (itemState & (1 << (switches - switchIndex -1)));
00789 }
00790 
00791 BOOL CCListGadget::AddItem(StringBase& itemString, KernelBitmap* pItemImage)
00792 {
00793     ERROR3IF(isColourList, "This is a colour list - use AddColourListItem()");
00794     if (!columns)
00795     {
00796         ERROR3("Columns not set for list gadget");
00797         return FALSE;
00798     }
00799         
00800     HWND hwndLV = GetDlgItem((HWND) formID, listID);
00801     //Check if the insertion will cause the list to scroll  - if yes, we will have to resize the last column
00802     BOOL resize = (ListView_GetItemCount(hwndLV) == ListView_GetCountPerPage(hwndLV)) ? TRUE : FALSE;
00803     if (pItemImage) //first set the item image, if any 
00804     {
00805         //Check if we have an imagelist
00806         HIMAGELIST hImgList = ListView_GetImageList(hwndLV, LVSIL_SMALL);
00807         WinBitmap* pWinBmp = (WinBitmap*) pItemImage->ActualBitmap;
00808         ERROR2IF(!pWinBmp, FALSE, "Illegal NULL bitmap");
00809         if (!ListView_GetItemCount(hwndLV)) //this is the first item so we have to create an image list
00810         {
00811             //Get the colour depth of our bitmap
00812             BitmapInfo Info;
00813             pWinBmp->GetInfo(&Info);
00814             UINT32 colorFlag = 0;
00815             switch (Info.PixelDepth)
00816             {
00817             case 4:
00818                 colorFlag = ILC_COLOR4;
00819                 break;
00820             case 8:
00821                 colorFlag = ILC_COLOR8;
00822                 break;
00823             case 16:
00824                 colorFlag = ILC_COLOR16;
00825                 break;
00826             case 24:
00827                 colorFlag = ILC_COLOR24;
00828                 break;
00829             case 32:
00830                 colorFlag = ILC_COLOR32;
00831                 break;
00832             default:
00833                 ERROR3("Unsupported bitmap colour depth");
00834                 return FALSE;
00835             }
00836             //Create the image list and attach it to the control
00837             hImgList = ImageList_Create(
00838                 pWinBmp->GetWidth(),
00839                 pWinBmp->GetHeight(),   
00840                 colorFlag,
00841                 16,
00842                 MAX_NO_ITEMS);
00843         }
00844 //      ERROR2IF(!hImgList, FALSE, "Cannot find image list"); //if we still have a null handle, something is badly wrong...
00845 
00846         if (hImgList)
00847         {
00848             ListView_SetImageList(hwndLV, hImgList, LVSIL_SMALL);
00849 
00850             //Create a temporary bitmap from the data in WinBmp
00851             HBITMAP hTempBmp = CreateBitmap(
00852                 pWinBmp->GetWidth(), 
00853                 pWinBmp->GetHeight(),
00854                 pWinBmp->GetBPP(),
00855                 1,
00856                 pWinBmp->BMBytes);
00857             if (ImageList_Add(hImgList, hTempBmp, NULL) == -1)
00858             {
00859                 ERROR3("Failed to update image list");
00860             }
00861             DeleteObject(hTempBmp);
00862         }
00863     }
00864     //Set the item text
00865     LV_ITEM itemData;
00866     INT32 itemIndex = ListView_GetItemCount(hwndLV);
00867     itemData.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE;
00868 
00869     //The state value is a 1-based index into the state image list shifted 12 bits to the left 
00870     //All switches will be OFF initially
00871     itemData.state = 0x01;
00872     itemData.state <<= 12; 
00873     itemData.stateMask   = LVIS_STATEIMAGEMASK;
00874     itemData.iItem = itemIndex;
00875     itemData.iSubItem = 0;
00876     itemData.pszText = (TCHAR*) itemString;
00877     itemData.cchTextMax  = sizeof(itemString);
00878     itemData.iImage = itemIndex;
00879     if (ListView_InsertItem(hwndLV, &itemData) == -1)
00880     {
00881         ERROR3("Failed to add list item");
00882         return FALSE;
00883     }
00884     // Check if the insertion will cause the list to scroll  - if yes, we have to resize the last column
00885     if (resize) // so we need to resize the last column
00886     {
00887         ListView_SetColumnWidth(
00888             hwndLV,
00889             columns - 1,
00890             ListView_GetColumnWidth(hwndLV, columns - 1) - GetSystemMetrics(SM_CXVSCROLL));
00891     }
00892     return TRUE;
00893 }
00894 
00895 
00896 
00897 
00898 BOOL CCListGadget::AddItem(StringBase& itemString, UINT32 bitmapEnabledID, UINT32 bitmapDisabledID)
00899 {
00900     ERROR3IF(isColourList, "This is a colour list - use AddColourListItem()");
00901     if (!columns)
00902     {
00903         ERROR3("Columns not set for list gadget");
00904         return FALSE;
00905     }
00906     
00907     HWND hwndLV = GetDlgItem((HWND) formID, listID);
00908     //Check if the insertion will cause the list to scroll  - if yes, we will have to resize the last column
00909     BOOL resize = (ListView_GetItemCount(hwndLV) == ListView_GetCountPerPage(hwndLV)) ? TRUE : FALSE;
00910     HBITMAP hItemBitmapEnabled = LoadBitmap (AfxGetResourceHandle(),MAKEINTRESOURCE(bitmapEnabledID));
00911     HBITMAP hItemBitmapDisabled = LoadBitmap (AfxGetResourceHandle(),MAKEINTRESOURCE(bitmapDisabledID));
00912     if (!(hItemBitmapEnabled && hItemBitmapDisabled))
00913     {
00914         ERROR3("Failed to load item bitmaps");
00915         return FALSE;
00916     }
00917     if (!ListView_GetItemCount(hwndLV)) //this is the first item so we have to create the image lists
00918     {
00919         //Get  a BITMAP struct for our bitmap
00920         BITMAP bitmapData;
00921         GetObject(hItemBitmapEnabled, sizeof(BITMAP), &bitmapData); // the two bitmaps, obviously, have to be the same size
00922         //Create the image lists and attach it to the control
00923         hImageListEnabled = CreateImageList(bitmapData.bmWidth, bitmapData.bmHeight);
00924         hImageListDisabled = CreateImageList(bitmapData.bmWidth, bitmapData.bmHeight);
00925     }
00926 //  ERROR2IF(!(hImageListEnabled && hImageListDisabled), FALSE, "Cannot find image list"); //if we still have a null handle, something is badly wrong...
00927     if (isEnabled)
00928     {
00929         if (hImageListEnabled)
00930             ListView_SetImageList(hwndLV, hImageListEnabled, LVSIL_SMALL);
00931     }
00932     else
00933     {
00934         if (hImageListDisabled)
00935             ListView_SetImageList(hwndLV, hImageListDisabled, LVSIL_SMALL);
00936     }
00937 
00938     BOOL Failed = FALSE;
00939 
00940     if (hImageListEnabled && ImageList_Add(hImageListEnabled, hItemBitmapEnabled, NULL) == -1)
00941     {
00942         ERROR3("Failed to update image list");
00943         Failed = TRUE;
00944     }
00945 
00946 
00947     if (hImageListDisabled && ImageList_Add(hImageListDisabled, hItemBitmapDisabled, NULL) == -1)
00948     {
00949         ERROR3("Failed to update image list");
00950         Failed = TRUE;
00951     }
00952 
00953     DeleteObject(hItemBitmapEnabled);
00954     DeleteObject(hItemBitmapDisabled);
00955 
00956     if (Failed)
00957         return(FALSE);
00958 
00959     //Set the item text
00960     LV_ITEM itemData;
00961     INT32 itemIndex = ListView_GetItemCount(hwndLV);
00962     itemData.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE;
00963     //The state value is a 1-based index into the state image list shifted 12 bits to the left 
00964     //All switches will be OFF initially
00965     itemData.state = 0x01;
00966     itemData.state <<= 12; 
00967     itemData.stateMask   = LVIS_STATEIMAGEMASK;
00968     itemData.iItem = itemIndex;
00969     itemData.iSubItem = 0;
00970     itemData.pszText = (TCHAR*) itemString;
00971     itemData.cchTextMax  = sizeof((TCHAR*) itemString);
00972     itemData.iImage = itemIndex;
00973     if (ListView_InsertItem(hwndLV, &itemData) == -1)
00974     {
00975         ERROR3("Failed to add list item");
00976         return FALSE;
00977     }
00978     if (resize) // so we need to resize the last column
00979     {
00980         ListView_SetColumnWidth(
00981             hwndLV,
00982             columns - 1,
00983             ListView_GetColumnWidth(hwndLV, columns - 1) - GetSystemMetrics(SM_CXVSCROLL));
00984     }
00985     return TRUE;
00986 }
00987 
00988 
00989 HBITMAP CCListGadget::CreateScreenCompatibleBitmap( INT32 width, INT32 height)
00990 {
00991     HDC hProbeDC = ::CreateCompatibleDC(NULL); // device context used to probe the current screen mode
00992     ERROR3IF(hProbeDC == NULL, "Couldn't create probe DC");
00993     const BITMAP bitmapData = 
00994     { 
00995         0,
00996         width,
00997         height,
00998         width * GetDeviceCaps(hProbeDC, BITSPIXEL) * GetDeviceCaps(hProbeDC, PLANES) / 8 ,
00999         GetDeviceCaps(hProbeDC, PLANES),
01000         GetDeviceCaps(hProbeDC, BITSPIXEL),
01001         0L
01002     };
01003     DeleteDC(hProbeDC);
01004     return CreateBitmapIndirect(&bitmapData);
01005 }
01006     
01007 
01008 HIMAGELIST CCListGadget::CreateImageList(INT32 imageWidth, INT32 imageHeight)
01009 {
01010     UINT32 colourFlag = ILC_COLOR;
01011 
01012     if (IsWindows31())
01013     {
01014         // Under Win32s, setting an explicit colour depth means it uses a DIB, and many
01015         // Win3.1 machines fail to create the bitmaps. However, using ILC_COLOR uses a DDB
01016         // which works, at least in 8bpp scren modes.
01017         colourFlag = ILC_COLOR;
01018     }
01019     else
01020     {
01021         HDC hProbeDC = ::CreateCompatibleDC(NULL); // device context used to probe the current screen mode
01022         ERROR3IF(hProbeDC == NULL, "Couldn't create probe DC");
01023 
01024         switch (GetDeviceCaps(hProbeDC, BITSPIXEL))
01025         {
01026             case 4:
01027                 colourFlag = ILC_COLOR4;
01028                 break;
01029             case 8:
01030                 colourFlag = ILC_COLOR8;
01031                 break;
01032             case 16:
01033                 colourFlag = ILC_COLOR16;
01034                 break;
01035             case 24:
01036                 colourFlag = ILC_COLOR24;
01037                 break;
01038             case 32:
01039                 colourFlag = ILC_COLOR32;
01040                 break;
01041             default:
01042                 colourFlag = ILC_COLOR;
01043                 break;
01044         }
01045 
01046         DeleteDC(hProbeDC);
01047     }
01048     HIMAGELIST hImageList = NULL;
01049     if (hImageList = ImageList_Create(imageWidth, imageHeight, colourFlag, 16, 1)) 
01050         return hImageList;
01051     else if (hImageList = ImageList_Create(imageWidth, imageHeight, ILC_COLORDDB, 16, 1)) // try a DDB
01052         return hImageList;
01053     else if (hImageList = ImageList_Create(imageWidth, imageHeight, ILC_PALETTE, 16, 1)) // try a palette
01054         return hImageList;
01055     else return (HIMAGELIST) NULL; // it failed, there's nothing we can do
01056 } 
01057 
01058 
01059 
01060 
01061 /******************************************************************************************
01062 
01063 >   BOOL CCListGadget::AddColourListItem(StringBase& colourName,
01064                                         INT32 red, INT32 green, INT32 blue,
01065                                         BOOL IsSpotColour = FALSE)
01066     Author:     Adrian_Stoicar (Xara Group Ltd) <camelotdev@xara.com> (patch rendering upgraded to use GBrush by Jason)
01067     Created:    6/8/96?
01068 
01069     Inputs:     colourName - The colour plate name
01070                 red, green, blue - The RGB definition (0..255) of the colour patch
01071                 IsSpotColour - TRUE if the colour is a spot colour (should be drawn
01072                         as a circle), FALSE to draw it as a normal colour square.
01073 
01074     Returns:    TRUE for success
01075 
01076     Purpose:    Adds a colour plate list item to the list - this is a special case for
01077                 the separations dialogue tab. Adds a colour plate name and colour patch
01078                 to the appropriate column of the control
01079 
01080 ******************************************************************************************/
01081 
01082 BOOL CCListGadget::AddColourListItem(StringBase& colourName, INT32 red, INT32 green, INT32 blue, BOOL IsSpotColour)
01083 {
01084     //ERROR3("Entering AddColourListItem()"); //Win32s "breakpoint" 
01085     HWND hwndLV = GetDlgItem((HWND) formID, listID);
01086     if (ListView_GetItemCount(hwndLV) && !isColourList)
01087     {
01088         ERROR3("This is not a colour list - use AddItem()");
01089     }
01090 
01091     if (!columns)
01092     {
01093         ERROR3("Columns not set for list gadget");
01094         return FALSE;
01095     }
01096 
01097     //Check if the insertion will cause the list to scroll  - if yes, we will have to resize the last column
01098     BOOL resize;
01099     if (IsWindows31())
01100          resize = (ListView_GetItemCount(hwndLV) == (ListView_GetCountPerPage(hwndLV) - 1)) ? TRUE : FALSE;
01101     else
01102         resize = (ListView_GetItemCount(hwndLV) == ListView_GetCountPerPage(hwndLV)) ? TRUE : FALSE;
01103 
01104 
01105     if (!ListView_GetItemCount(hwndLV)) //this is the first item so we have to create the image lists
01106     {
01107         hImageListEnabled = CreateImageList(COLOUR_PATCH_WIDTH, COLOUR_PATCH_HEIGHT); 
01108         hImageListDisabled = CreateImageList(COLOUR_PATCH_WIDTH, COLOUR_PATCH_HEIGHT); 
01109     }
01110 //  ERROR2IF(!(hImageListEnabled && hImageListDisabled), FALSE, "Cannot find image list"); //if we still have a null handle, something is badly wrong...
01111     if (isEnabled)
01112     {
01113         if (hImageListEnabled)
01114             ListView_SetImageList(hwndLV, hImageListEnabled, LVSIL_SMALL);
01115     }
01116     else
01117     {
01118         if (hImageListDisabled)
01119             ListView_SetImageList(hwndLV, hImageListDisabled, LVSIL_SMALL);
01120     }
01121 
01122     //First create and insert the colour patch associated with the item
01123     //Create a memory DC and 2 bitmaps (enbled/disabled) compatible with the screen 
01124     HDC hDC = ::CreateCompatibleDC(NULL);
01125     ERROR3IF(hDC == NULL, "Couldn't create rendering DC");
01126 
01127     HBITMAP bitmaps[2];
01128     bitmaps[0] = CreateScreenCompatibleBitmap(COLOUR_PATCH_WIDTH,   COLOUR_PATCH_HEIGHT);
01129     bitmaps[1] = CreateScreenCompatibleBitmap(COLOUR_PATCH_WIDTH,   COLOUR_PATCH_HEIGHT);
01130 
01131     ERROR2IF(!(bitmaps[0] && bitmaps[1]), FALSE, "GDI Error");
01132 
01133     // And draw the colour patch into the bitmap, using GBrush to get semi-decent dithering
01134     for (INT32 i = 0; i <= 1; i++)
01135     {
01136         if (hDC != NULL)
01137         {
01138             HBITMAP OldBitmap = (HBITMAP) ::SelectObject(hDC, bitmaps[i]);
01139 
01140     /*  --- GBrush doesn't work into this bitmap - there are palette problems
01141             which need to be sorted out.
01142 
01143             // Set up palette and GBrush for Spiffy redraw
01144             HPALETTE OldPal = NULL;
01145             if (PaletteManager::UsePalette())
01146                 OldPal = PaletteManager::StartPaintPalette(hDC, (HPALETTE *)NULL, TRUE);
01147 
01148             GBrush GDrawBrush;
01149             if (GDrawBrush.Init(hDC))
01150                 GDrawBrush.Start();
01151     */
01152             HBRUSH Brush;
01153 
01154             COLORREF Colour = RGB(red, green, blue);
01155             if (i != 0)
01156             {
01157                 // Convert the colour to a greyscale
01158                 BYTE Grey = BYTE((red * 0.305) + (green * 0.586) + (blue * 0.109));
01159                 Colour = RGB(Grey, Grey, Grey);
01160             }
01161 
01162     /*
01163             if (GDrawBrush.Available())
01164             {
01165                 LOGBRUSH LogBrush;
01166                 GDrawBrush.GetLogBrush(Colour, &LogBrush);
01167                 Brush = ::CreateBrushIndirect(&LogBrush);
01168             }
01169             else    */
01170             {
01171                 Brush = ::CreateSolidBrush(Colour);
01172             }
01173 
01174             ERROR3IF(Brush == NULL, "Couldn't create brush");
01175 
01176             HPEN BlackPen = (HPEN) ::GetStockObject(BLACK_PEN);
01177 
01178             HPEN OldPen = NULL;
01179             HBRUSH OldBrush = NULL;
01180 
01181             if (IsSpotColour)
01182             {
01183                 // Spot colours are drawn as circles - but first, fill the bitmap with white,
01184                 // so that the un-covered corners of the square are a sensible colour.
01185                 HBRUSH WhiteBrush = (HBRUSH) ::GetStockObject(WHITE_BRUSH);
01186                 HPEN NullPen = (HPEN) ::GetStockObject(NULL_PEN);
01187                 OldPen = (HPEN) ::SelectObject(hDC, NullPen);
01188                 OldBrush = (HBRUSH) ::SelectObject(hDC, WhiteBrush);
01189                 ::Rectangle(hDC, 0, 0, COLOUR_PATCH_WIDTH+1, COLOUR_PATCH_HEIGHT+1);
01190 
01191                 ::SelectObject(hDC, BlackPen);
01192                 ::SelectObject(hDC, Brush);
01193                 ::Ellipse(hDC, 0, 0, COLOUR_PATCH_WIDTH, COLOUR_PATCH_HEIGHT);
01194             }
01195             else
01196             {
01197                 // Process colours are shown as rectangles
01198                 OldPen = (HPEN) ::SelectObject(hDC, BlackPen);
01199                 OldBrush = (HBRUSH) ::SelectObject(hDC, Brush);
01200                 ::Rectangle(hDC, 0, 0, COLOUR_PATCH_WIDTH, COLOUR_PATCH_HEIGHT);
01201             }
01202 
01203             ::SelectObject(hDC, OldPen);
01204             ::SelectObject(hDC, OldBrush);
01205             ::SelectObject(hDC, OldBitmap);
01206 
01207             ::DeleteObject(Brush);
01208 
01209             // Finish with GBrush
01210     /*
01211             GDrawBrush.Stop();
01212             if (OldPal)
01213                 PaletteManager::StopPaintPalette(hDC, OldPal);
01214     */
01215         }
01216     }
01217 
01218     if (hImageListEnabled && ImageList_Add(hImageListEnabled, bitmaps[0], NULL) == -1)
01219     {
01220         ERROR3("Failed to update image list for listview control");
01221     }
01222     if (hImageListDisabled && ImageList_Add(hImageListDisabled, bitmaps[1], NULL) == -1)
01223     {
01224         ERROR3("Failed to update image list for SysListView32 control");
01225     }
01226 
01227     DeleteObject(bitmaps[0]);// the bitmap has been copied to an internal buffer, so we can safely delete the original 
01228     DeleteObject(bitmaps[1]);
01229     DeleteDC(hDC);
01230 
01231     //Set the item text
01232     LV_ITEM itemData;
01233     INT32 itemIndex = ListView_GetItemCount(hwndLV);
01234     itemData.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE;
01235     //The state value is a 1-based index into the state image list shifted 12 bits to the left 
01236     //All switches will be OFF initially
01237     itemData.state = 0x01;
01238     itemData.state <<= 12; 
01239     itemData.stateMask   = LVIS_STATEIMAGEMASK;
01240     itemData.iItem = itemIndex;
01241     itemData.iSubItem = 0;
01242     itemData.pszText = (TCHAR*) colourName;
01243     itemData.cchTextMax  = sizeof(colourName);
01244     itemData.iImage = itemIndex;
01245     if (ListView_InsertItem(hwndLV, &itemData) == -1)
01246     {
01247         ERROR3("Failed to add list item");
01248         return FALSE;
01249     }
01250     isColourList = TRUE;
01251     if (resize) // so we need to resize the last column
01252     {
01253         if (IsWindows31())
01254         {
01255             DWORD dwStyle = GetWindowLong(hwndLV, GWL_STYLE);
01256             dwStyle &= ~LVS_NOSCROLL;
01257             SetWindowLong(hwndLV, GWL_STYLE, dwStyle);
01258         }
01259         else
01260         {
01261             ListView_SetColumnWidth(
01262                 hwndLV,
01263                 columns - 1,
01264                 ListView_GetColumnWidth(hwndLV, columns - 1) - GetSystemMetrics(SM_CXVSCROLL));
01265         }
01266     }
01267     //ERROR3("Exiting AddColourListItem()"); // Win32s "breakpoint" 
01268     return TRUE;
01269 }
01270 
01271 
01272 BOOL CCListGadget::SetItemString(StringBase& itemString, UINT32 itemIndex, UINT32 columnIndex)
01273 {
01274     HWND hLV = GetDlgItem((HWND) formID, listID);
01275     if (columnIndex >= columns)
01276     {
01277         ERROR3("Invalid column index");
01278         return FALSE;
01279     }
01280     if (itemIndex >= (UINT32) ListView_GetItemCount(hLV))
01281     {
01282         ERROR3("Invalid item index");
01283         return FALSE;
01284     }
01285     ListView_SetItemText(hLV, itemIndex, columnIndex, (TCHAR*)  itemString);    
01286     return TRUE;
01287 }
01288 
01289 BOOL CCListGadget::GetItemString(StringBase& itemString, UINT32 itemIndex, UINT32 columnIndex)
01290 {
01291     HWND hLV = GetDlgItem((HWND) formID, listID);
01292     if (columnIndex >= columns)
01293     {
01294         ERROR3("Invalid column index");
01295         return FALSE;
01296     }
01297     if (itemIndex >= (UINT32) ListView_GetItemCount(hLV))
01298     {
01299         ERROR3("Invalid item index");
01300         return FALSE;
01301     }
01302     TCHAR buffer[64];
01303     ListView_GetItemText(hLV, itemIndex, columnIndex, buffer, sizeof(buffer));  
01304     itemString = buffer;
01305     return TRUE;
01306 }
01307 
01308 
01309 BOOL CCListGadget::DeleteAllItems()
01310 {
01311     HWND hLV = GetDlgItem((HWND) formID, listID);
01312     //This will only delete the item strings, we will have to destroy the image list ourselves
01313     ListView_DeleteAllItems(hLV);
01314     //ERROR3("About to delete image lists"); // Win32s "breakpoint"
01315     if ((hImageListEnabled && (!ImageList_Destroy(hImageListEnabled)) && ImageList_GetImageCount(hImageListEnabled)) ||
01316         (hImageListDisabled && (!ImageList_Destroy(hImageListDisabled)) && ImageList_GetImageCount(hImageListDisabled)))
01317     {
01318         ERROR3("Error deleting image list");
01319         return FALSE;
01320     }
01321     //ERROR3("Image lists deleted now"); // Win32s "breakpoint"
01322 
01323     hImageListEnabled = NULL;
01324     hImageListDisabled = NULL;
01325 
01326     ListView_SetImageList(hLV, (HIMAGELIST) NULL, LVSIL_SMALL);
01327     return TRUE;
01328 }
01329 
01330 
01331 INT32 CCListGadget::GetSelectedItemIndex()
01332 {
01333     HWND hLV = GetDlgItem((HWND) formID, listID);
01334     for (INT32 i = 0; i < ListView_GetItemCount(hLV);i++)
01335     {
01336 //      if (ListView_GetItemState(hLV, i, 0x000F) & LVIS_SELECTED)
01337         if (ListView_GetItemState(hLV, i, LVIS_SELECTED) != 0)
01338             return(i);
01339     }
01340     return -1;
01341 }
01342 
01343 
01344 
01345 /******************************************************************************************
01346 
01347 >   void CCListGadget::SetSelectedItemIndex(INT32 NewSel)
01348 
01349     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01350     Created:    23/8/96 (er.. actually, it's 24/8/96 now...
01351                         Maybe I should go to bed soon...)
01352 
01353     Inputs:     NewSel - The index of the row to select (0 .. NumItems-1)
01354 
01355     Purpose:    Selects (and scrolls to show) the given item (row) in the list.
01356 
01357     Notes:      ** IMPORTANT **
01358                 Your ListView MUST have the LVS_SHOWSELALWAYS style set, or else
01359                 the selection will only be/become visible when the control has the
01360                 keyboard input focus. Absence of this style can make it _appear_
01361                 that the selection process has failed, but it has not!
01362 
01363 ******************************************************************************************/
01364 
01365 void CCListGadget::SetSelectedItemIndex(INT32 NewSel)
01366 {
01367     // Find the window
01368     HWND hLV = GetDlgItem((HWND) formID, listID);
01369 
01370     // Setting the selected item only has a visible effect when the control has
01371     // the input focus, unless LVS_SHOWSELALWAYS is set on the control.
01372     // It is preferable that we set that style rather than grabbing the input 
01373     // focus, so we expect that our control has this style set, and we don't
01374     // force the focus into our window.
01375 //  SetFocus(hLV);
01376 
01377     // Set the selection, and make this the active line (put the keyboard focus
01378     // box around this item, if the control has the focus)
01379     UINT32 Mask = LVIS_SELECTED | LVIS_FOCUSED;
01380 
01381     // Set the states of all items to ensure only the one item is selected
01382     INT32 ItemCount = ListView_GetItemCount(hLV);
01383     for (INT32 i = 0; i < ItemCount; i++)
01384     {
01385         UINT32 State = (i == NewSel) ? Mask : 0;        // Select or Deselect
01386         ListView_SetItemState(hLV, i, State, Mask);
01387     }
01388 
01389     // Scroll the view to show the selected item
01390     ListView_EnsureVisible(hLV, NewSel, FALSE);
01391 }
01392 
01393 
01394 
01395 INT32 CCListGadget::GetItemCount()
01396 {
01397     HWND hLV = GetDlgItem((HWND) formID, listID);
01398     return ListView_GetItemCount(hLV);
01399 }
01400 
01401 
01402 
01403 /******************************************************************************************
01404 
01405 >   BOOL CCListGadget::OnGadgetClicked()
01406 
01407     Author:     Adrian_Stoicar (Xara Group Ltd) <camelotdev@xara.com>, upgraded to auto-select by Jason
01408     Created:    6/8/96? (24/8/96)
01409 
01410     Returns:    TRUE for success
01411 
01412     Purpose:    Handles clicks on the ListView control.
01413                 The behaviour is as follows:
01414                     1) Any click anywhere on an item's row selects that item
01415                     2) A click on a switch at the left end of the row will toggle
01416                        that switches state.
01417 
01418 ******************************************************************************************/
01419 
01420 BOOL CCListGadget::OnGadgetClicked()
01421 {
01422     //So the user has clicked inside the control, let's see if they have actually clicked a checkbox
01423     HWND hwndLV = GetDlgItem((HWND) formID, listID);
01424     // On Win32s we get sometimes a spurious horizontal scroll bar, so we'll turn off WS_HSCROLL  just in case
01425     /*if (IsWindows31()) 
01426     {
01427         DWORD dwStyle = GetWindowLong(hwndLV, GWL_STYLE);
01428         if (dwStyle & WS_HSCROLL)
01429             SetWindowLong(hwndLV, GWL_STYLE, (dwStyle & ~WS_HSCROLL));
01430     }*/
01431     UINT32        state;
01432     LV_HITTESTINFO lvhti; // "hit test" structure
01433     DWORD dwpos = GetMessagePos(); //get the position clicked  
01434     lvhti.pt.x = LOWORD(dwpos);
01435     lvhti.pt.y = HIWORD(dwpos);
01436     MapWindowPoints(HWND_DESKTOP, hwndLV, &lvhti.pt, 1);
01437     INT32 index = ListView_HitTest(hwndLV, &lvhti); // do a hit test to see if the point lies within the control
01438 
01439     // Added by Jason - Always make the last item clicked-on selected - this means the user
01440     // can click anywhere and it still selects
01441     if (index < 0)
01442     {
01443         // We didn't click on the important bits of the item (ticks or name text). Helpfully
01444         // the control doesn't think that clicks to the right are important. So we will
01445         // do a second hit test, using xpos == 5, to determine which line to select
01446         lvhti.pt.x = 5;
01447         index = ListView_HitTest(hwndLV, &lvhti);
01448 
01449         if (index >= 0)
01450             SetSelectedItemIndex(index);
01451     
01452         return(FALSE);      // But don't bother checking the switches
01453     }
01454 
01455     SetSelectedItemIndex(index);
01456 
01457     //Loop through the switches to find the one that has been clicked
01458     for (UINT32 i = 0; i < switches; i++)
01459     {
01460         if ((lvhti.flags & LVHT_ONITEM) && ((lvhti.pt.x >= SwitchLeftCoord[i] ) && (lvhti.pt.x <= (SwitchLeftCoord[i] + SWITCH_WIDTH))))
01461         {
01462             // Yes, a switch has been clicked so get the state from the item and toggle it
01463             // The state retrieved with the LVIS_STATEIMAGEMASK is a 1-based index into the state image list shifted 12 bits to the left,
01464             // so we shift it back and substract 1 to turn it into a two-bit value showing the state of the switches
01465             state = ListView_GetItemState(hwndLV, index, LVIS_STATEIMAGEMASK);
01466             state >>= 12;
01467             state --;
01468             state ^= (1 << (switches - 1 - i));
01469             state++;
01470             state <<= 12;
01471             ListView_SetItemState(hwndLV, index, state, LVIS_STATEIMAGEMASK);
01472             return TRUE;        
01473          }
01474     }
01475     return FALSE;
01476 }
01477 
01478 //Unimplemented as yet
01479 
01480 BOOL InsertItem(UINT32 index, StringBase& itemString, UINT32 bitmapID)
01481 {
01482     ERROR3("This function is unimplemented, use AddItem()");
01483     return FALSE;
01484 }
01485     
01486 
01487 BOOL CCListGadget::InsertItem(UINT32 index, StringBase& itemString, KernelBitmap* pItemImage)
01488 {
01489     ERROR3("This function is unimplemented, use AddItem()");
01490     return FALSE;
01491 }
01492 

Generated on Sat Nov 10 03:48:13 2007 for Camelot by  doxygen 1.4.4