[Date Prev][Date Next][Thread Prev][Thread Next][Thread Index]

[XaraXtreme-commits] Commit Complete



Commit by  : phil
Repository : xara
Revision   : 1063
Date       : Mon May 15 22:40:10 BST 2006

Changed paths:
   A /Trunk/XaraLX/wxOil/CustomList.cpp
   A /Trunk/XaraLX/wxOil/CustomList.h

CustomList control class from Xtreme


Diff:
Index: Trunk/XaraLX/wxOil/CustomList.cpp
===================================================================
--- Trunk/XaraLX/wxOil/CustomList.cpp	(revision 0)
+++ Trunk/XaraLX/wxOil/CustomList.cpp	(revision 1063)
@@ -0,0 +1,1125 @@
+// $Id: wxOil/CustomList.cpp, 1, 01-Jan-2006, Anonymous $
+// CustomList.cpp : implementation file
+//
+// Contains the classes that make up the custom list control. These are :
+//
+// CCustomList					-	represents a custom list control to the 
+//									outside world. A calling class interacts with
+//									this class, not the helpers. (Hence perhaps
+//									the helper classes should be private nested?)
+// CCustomListScrollableArea	-	helper class containing the whole scrollable
+//									area, some of which may not be visible (ie.
+//									the verticle area is less than the area of
+//									the containing CCustomList
+// CCustomListRowWnd			-	helper class representing a list row
+//
+// Author:						MarcP
+// Date:						18/11/04
+/* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
+================================XARAHEADERSTART===========================
+ 
+               Xara LX, a vector drawing and manipulation program.
+                    Copyright (C) 1993-2006 Xara Group Ltd.
+       Copyright on certain contributions may be held in joint with their
+              respective authors. See AUTHORS file for details.
+
+LICENSE TO USE AND MODIFY SOFTWARE
+----------------------------------
+
+This file is part of Xara LX.
+
+Xara LX is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License version 2 as published
+by the Free Software Foundation.
+
+Xara LX and its component source files are 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 Xara LX (see the file GPL in the root directory of the
+distribution); if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+
+
+ADDITIONAL RIGHTS
+-----------------
+
+Conditional upon your continuing compliance with the GNU General Public
+License described above, Xara Group Ltd grants to you certain additional
+rights. 
+
+The additional rights are to use, modify, and distribute the software
+together with the wxWidgets library, the wxXtra library, and the "CDraw"
+library and any other such library that any version of Xara LX relased
+by Xara Group Ltd requires in order to compile and execute, including
+the static linking of that library to XaraLX. In the case of the
+"CDraw" library, you may satisfy obligation under the GNU General Public
+License to provide source code by providing a binary copy of the library
+concerned and a copy of the license accompanying it.
+
+Nothing in this section restricts any of the rights you have under
+the GNU General Public License.
+
+
+SCOPE OF LICENSE
+----------------
+
+This license applies to this program (XaraLX) and its constituent source
+files only, and does not necessarily apply to other Xara products which may
+in part share the same code base, and are subject to their own licensing
+terms.
+
+This license does not apply to files in the wxXtra directory, which
+are built into a separate library, and are subject to the wxWindows
+license contained within that directory in the file "WXXTRA-LICENSE".
+
+This license does not apply to the binary libraries (if any) within
+the "libs" directory, which are subject to a separate license contained
+within that directory in the file "LIBS-LICENSE".
+
+
+ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
+----------------------------------------------
+
+Subject to the terms of the GNU Public License (see above), you are
+free to do whatever you like with your modifications. However, you may
+(at your option) wish contribute them to Xara's source tree. You can
+find details of how to do this at:
+  http://www.xaraxtreme.org/developers/
+
+Prior to contributing your modifications, you will need to complete our
+contributor agreement. This can be found at:
+  http://www.xaraxtreme.org/developers/contribute/
+
+Please note that Xara will not accept modifications which modify any of
+the text between the start and end of this header (marked
+XARAHEADERSTART and XARAHEADEREND).
+
+
+MARKS
+-----
+
+Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
+designs are registered or unregistered trademarks, design-marks, and/or
+service marks of Xara Group Ltd. All rights in these marks are reserved.
+
+
+      Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
+                        http://www.xara.com/
+
+=================================XARAHEADEREND============================
+ */
+
+#include "camtypes.h" 
+#include "customlist.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+//                                                                         //
+//								CCustomList                                //
+//                                                                         //
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+
+const INT32		CCustomList::MAXCOLUMNS = 8;
+const INT32		CCustomList::MAXROWS = 100;
+const INT32		CCustomList::FONTHEIGHT = 14;
+const INT32		CCustomList::ROWHEIGHT = 17 ;
+const INT32		CCustomList::COLOUR_PATCH_WIDTH  =	12 ;
+const INT32		CCustomList::COLOUR_PATCH_HEIGHT = 12 ;
+const CString	CCustomList::WNDCLASSNAME = "cc_CustomList";
+
+BEGIN_MESSAGE_MAP(CCustomList, CWnd)
+	//{{AFX_MSG_MAP(CCustomList)
+	ON_WM_CREATE()
+	ON_WM_VSCROLL()
+	ON_WM_SETFOCUS()
+	ON_WM_MOUSEWHEEL()
+	//}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+// CCustomList constructor
+CCustomList::CCustomList() :
+	m_VScrollBar(NULL),
+	m_ScrollableArea(NULL)
+{
+	// create column positioning data
+	m_ColumnOffsetsArray = new INT32[MAXCOLUMNS];
+	m_ColumnOffsetsArray[0] = 10; // indent for first offset
+	for( INT32 i=1; i < MAXCOLUMNS ; i++)
+		m_ColumnOffsetsArray[i] = -1;
+}
+
+// Intial window procedure for the custom control, specified in the WNDCLASS structure - see RegisterWindowClass.
+// Once registered Dialogs creating a cc_CustomList window will start through here. It is only called once per 
+// instance so once we hahave created the object we can then hand over to MFC to do manage the rest.
+extern "C" LRESULT CALLBACK EXPORT CCustomList::CustomWindowProc(HWND hWnd, UINT32 nMsg, WPARAM wParam, LPARAM lParam)
+{
+	// Create CCustomList object and attach it to window
+	CCustomList* pWnd = new CCustomList;
+	pWnd->Attach(hWnd);
+	// Switch over to MFC WndProc
+	::SetWindowLong(hWnd, GWL_WNDPROC, (DWORD)AfxWndProc);
+	// and call it
+	return ::CallWindowProc(AfxWndProc, hWnd, nMsg, wParam, lParam);
+}
+
+// register the the window class for this custom control. this must be executed before
+// invoking any dialogs that use the control, because it specifies the WndProc that 
+// they must use to create it
+BOOL CCustomList::RegisterWindowClass()
+{
+    HINSTANCE hInst = AfxGetInstanceHandle();
+	WNDCLASS wc;
+	if (!(::GetClassInfo(hInst, WNDCLASSNAME, &wc)))
+	{
+		// Fill in the values for the class
+		wc.style         = CS_HREDRAW | CS_VREDRAW | CS_GLOBALCLASS ;
+		wc.lpfnWndProc   = (WNDPROC) CCustomList::CustomWindowProc;
+		wc.cbClsExtra       = wc.cbWndExtra = 0;
+		wc.hInstance     = hInst;
+		wc.hIcon         = NULL;
+		wc.hCursor       = LoadCursor (NULL, _R(IDC_ARROW));
+		wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
+		wc.lpszMenuName  = (LPSTR) NULL;
+		wc.lpszClassName = (LPCTSTR) WNDCLASSNAME;
+
+		// try and register the class
+		if (!RegisterClass (&wc))
+		{
+			ASSERT(FALSE);
+			return FALSE;
+		}
+	}
+    return TRUE;
+}
+
+CCustomList::~CCustomList()
+{
+	// delete column offsets array
+	delete m_ColumnOffsetsArray;
+	// delete CScrollbar
+	delete m_VScrollBar ;
+}
+
+// Called by the default OnNcDestroy member function after the window has been destroyed.
+void CCustomList::PostNcDestroy() 
+{
+	delete this;
+	CWnd::PostNcDestroy();
+}
+
+
+// Static function to retrieve a pointer to a custom list gadget knowing its resource ID and the parent's handle
+CCustomList* CCustomList::GetGadget(CWindowID hDlg, CGadgetID nIDDlgItem)
+{
+	HWND listwnd = ::GetDlgItem(hDlg, nIDDlgItem);
+	CCustomList* pListGadget = (CCustomList*)CWnd::FromHandlePermanent(listwnd);
+	return pListGadget ;
+}
+
+
+// Adds an item to the list (pItemImage points to an optional bitmap associated with the item and displayed to its right
+BOOL CCustomList::AddItem(StringBase& itemString, KernelBitmap* pItemImage)
+{
+	CCustomListRowWnd* pNewRow = GetScrollableArea()->AddRow();
+	pNewRow ->AddCheck(0);
+	pNewRow ->AddText(1,(TCHAR *)itemString);
+	return TRUE;
+}
+
+// Adds a "references" item to the list
+BOOL CCustomList::AddRefsItem(UINT32 idStatusBitmap, StringBase& strItemName, StringBase& strDetails)
+{
+	CCustomListRowWnd* pNewRow = GetScrollableArea()->AddRow();
+	if (pNewRow)
+	{
+		if (idStatusBitmap!=0)
+		{
+			HBITMAP hBitmap = LoadBitmap(AfxGetResourceHandle(), MAKEINTRESOURCE(idStatusBitmap));
+			pNewRow->AddBitmap(0, hBitmap, NULL, 0xFFFFFF);	// We know background colour is white for these bitmaps!
+		}
+		pNewRow->AddText(1, (TCHAR*)strItemName);
+		pNewRow->AddText(2, (TCHAR*)strDetails);
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+// Retrieve the text of an item or one of its components
+BOOL CCustomList::GetItemString(StringBase& itemString, UINT32 itemIndex, UINT32 columnIndex) const
+{
+	CString s = GetScrollableArea()->GetRow(itemIndex)->GetText(columnIndex);
+	itemString.Empty(); // ensure buffer is empty
+	itemString+= s;
+	return TRUE;
+}
+
+// Retrieves the current state of a switch (ON/OFF)
+BOOL CCustomList::GetSwitchState(UINT32 itemIndex, UINT32 switchIndex) const
+{
+	return GetScrollableArea()->GetRow(itemIndex)->IsChecked(switchIndex);
+}
+
+// Returns the number of items contained in the list
+INT32 CCustomList::GetItemCount() const
+{
+	return GetScrollableArea()->m_RowCount;
+}
+
+// Returns the index of the item currently selected, -1 if none 
+INT32 CCustomList::GetSelectedItemIndex() const
+{
+	return GetScrollableArea()->m_CurrentSelectedRow;
+}
+
+// Sets the state of a switch (determines whether the bitmapOn or bitmapOf is shown)
+BOOL CCustomList::SetSwitchState(BOOL state, UINT32 itemIndex, UINT32 switchIndex)
+{
+	GetScrollableArea()->GetRow(itemIndex)->SetChecked(switchIndex,state);
+	return TRUE;
+}
+
+// Adds an item to the list, creating the associated image from a bitmap resource ID
+BOOL CCustomList::AddItem(StringBase& itemString, UINT32 bitmapEnabledID, UINT32 bitmapDisabledID)
+{
+	HBITMAP hItemBitmapEnabled = LoadBitmap (AfxGetResourceHandle(),MAKEINTRESOURCE(bitmapEnabledID));
+	// the greyed bitmap feature is unimplemented for now
+	//HBITMAP hItemBitmapDisabled = LoadBitmap (AfxGetResourceHandle(),MAKEINTRESOURCE(bitmapDisabledID));
+
+	// note: RowWnd objects destroy any bitmaps on deletion 
+	CCustomListRowWnd* pNewRow = GetScrollableArea()->AddRow();
+	pNewRow ->AddCheck(0);
+	pNewRow ->AddBitmap(1,hItemBitmapEnabled,NULL);
+	pNewRow ->AddText(2,(TCHAR *)itemString);
+
+	return TRUE;
+}
+
+// Sets the given item to be selected (and deselects all other items)
+void CCustomList::SetSelectedItemIndex(INT32 NewSel)
+{
+	GetScrollableArea()->SelectRow(NewSel);
+}
+
+// deletes the list by deleting the scrollable area and replacing it with a new one
+BOOL CCustomList::DeleteAllItems()
+{
+	if(m_ScrollableArea)
+	{
+		m_ScrollableArea->DestroyWindow();
+		//delete m_ScrollableArea;
+	}
+	NewScrollableArea();
+	return TRUE;
+}
+
+// creates a new scrollable area
+void CCustomList::NewScrollableArea()
+{
+	m_ScrollableArea = new CCustomListScrollableArea(this);
+	BOOL b = m_ScrollableArea->Create(_T("STATIC"), NULL, WS_CHILD | WS_VISIBLE,CRect(0,0,0,0),this,0,NULL);
+}
+
+// called on creation. creates the v scroller and a new scrollable area
+INT32 CCustomList::OnCreate(LPCREATESTRUCT lpCreateStruct) 
+{
+	if (CWnd::OnCreate(lpCreateStruct) == -1)
+		return -1;
+
+	m_VScrollBar = new CScrollBar();
+	CRect parentRect;
+	CRect rect;
+	GetClientRect(&parentRect);
+	rect.left = parentRect.right - ::GetSystemMetrics(SM_CXVSCROLL) ;
+	rect.top = 0;
+	rect.right = parentRect.right ;
+	rect.bottom = parentRect.bottom ;
+	m_VScrollBar->Create(SBS_VERT, rect, this, NULL);
+	m_VScrollBar->ShowWindow(SW_SHOW);
+
+	NewScrollableArea();
+
+	return 0;
+}
+
+// handle a scroll message
+void CCustomList::OnVScroll(UINT32 nSBCode, UINT32 nPos, CScrollBar* pScrollBar) 
+{
+	m_ScrollableArea->HandleScrollMessage(nSBCode, nPos) ;
+	CWnd::OnVScroll(nSBCode, nPos, pScrollBar);
+}
+
+// helper function - creates a bitmap of the specified width and height
+HBITMAP CreateScreenCompatibleBitmap( INT32 width, INT32 height)
+{
+	HDC hProbeDC = ::CreateCompatibleDC(NULL); // device context used to probe the current screen mode
+	ERROR3IF(hProbeDC == NULL, "Couldn't create probe DC");
+	const BITMAP bitmapData = 
+	{ 
+		0,
+		width,
+		height,
+		width * GetDeviceCaps(hProbeDC, BITSPIXEL) * GetDeviceCaps(hProbeDC, PLANES) / 8 ,
+		GetDeviceCaps(hProbeDC, PLANES),
+		GetDeviceCaps(hProbeDC, BITSPIXEL),
+		0L
+	};
+	DeleteDC(hProbeDC);
+	return CreateBitmapIndirect(&bitmapData);
+}
+
+// Used if the the listitem is a actually a colour - it displays a square colour patch next to the color name
+BOOL CCustomList::AddColourListItem(StringBase& colourName, INT32 red, INT32 green, INT32 blue, BOOL IsSpotColour)
+{
+	//First create and insert the colour patch associated with the item
+	//Create a memory DC and 2 bitmaps (enbled/disabled) compatible with the screen 
+	HDC hDC = ::CreateCompatibleDC(NULL);
+	ERROR3IF(hDC == NULL, "Couldn't create rendering DC");
+
+	// do not create grey bitmaps for now (to add back in extend array to 2 and comment
+	// below back in)
+	HBITMAP bitmaps[1];
+	bitmaps[0] = CreateScreenCompatibleBitmap(COLOUR_PATCH_WIDTH,	COLOUR_PATCH_HEIGHT);
+	//bitmaps[1] = CreateScreenCompatibleBitmap(COLOUR_PATCH_WIDTH,	COLOUR_PATCH_HEIGHT);
+	//ERROR2IF(!(bitmaps[0] && bitmaps[1]), FALSE, "GDI Error");
+
+	// And draw the colour patch into the bitmap
+	for (INT32 i = 0; i <= 1; i++)
+	{
+		if (hDC != NULL)
+		{
+			HBITMAP OldBitmap = (HBITMAP) ::SelectObject(hDC, bitmaps[i]);
+
+			COLORREF Colour = RGB(red, green, blue);
+			if (i != 0)
+			{
+				// Convert the colour to a greyscale
+				BYTE Grey = BYTE((red * 0.305) + (green * 0.586) + (blue * 0.109));
+				Colour = RGB(Grey, Grey, Grey);
+			}
+
+			HBRUSH Brush = ::CreateSolidBrush(Colour);
+
+			ERROR3IF(Brush == NULL, "Couldn't create brush");
+
+			HPEN BlackPen = (HPEN) ::GetStockObject(BLACK_PEN);
+
+			HBRUSH WhiteBrush	= (HBRUSH) ::GetStockObject(WHITE_BRUSH);
+			HPEN NullPen		= (HPEN) ::GetStockObject(NULL_PEN);
+			HPEN OldPen			= (HPEN) ::SelectObject(hDC, NullPen);
+			HBRUSH OldBrush		= (HBRUSH) ::SelectObject(hDC, WhiteBrush);
+			if (IsSpotColour)
+			{
+				// Spot colours are drawn as circles - but first, fill the bitmap with white,
+				// so that the un-covered corners of the square are a sensible colour.
+
+				::Rectangle(hDC, 0, 0, COLOUR_PATCH_WIDTH+1, COLOUR_PATCH_HEIGHT+1);
+				::SelectObject(hDC, BlackPen);
+				::SelectObject(hDC, Brush);
+				::Ellipse(hDC, 0, 0, COLOUR_PATCH_WIDTH, COLOUR_PATCH_HEIGHT);
+
+			}
+			else
+			{
+				// Process colours are shown as rectangles
+
+				::Rectangle(hDC, 0, 0, COLOUR_PATCH_WIDTH+1, COLOUR_PATCH_HEIGHT+1);
+				::SelectObject(hDC, BlackPen);
+				::SelectObject(hDC, Brush);
+				::Rectangle(hDC, 0, 0, COLOUR_PATCH_WIDTH-1, COLOUR_PATCH_HEIGHT-1);
+			
+			}
+
+			::SelectObject(hDC, OldPen);
+			::SelectObject(hDC, OldBrush);
+			::SelectObject(hDC, OldBitmap);
+
+			::DeleteObject(Brush);
+		}
+	}
+
+	DeleteDC(hDC);
+//	this->AddItem(colourName,bitmaps[0],bitmaps[1]);
+	CCustomListRowWnd* pNewRow = GetScrollableArea()->AddRow();
+	pNewRow ->AddCheck(0);
+	pNewRow ->AddCheck(1);
+	pNewRow ->AddBitmap(2,bitmaps[0],NULL);
+	pNewRow ->AddText(3,(TCHAR*)colourName);
+
+	return TRUE;
+}
+
+// Sets the text for an item or one of its components
+BOOL CCustomList::SetItemString(StringBase& itemString, UINT32 itemIndex, UINT32 columnIndex)
+{
+	GetScrollableArea()->GetRow(itemIndex)->SetText(columnIndex,(TCHAR*)  itemString);
+    return TRUE;
+}
+
+// helper function to loop through and enable / disable all child windows
+void EnableDescendants(HWND hWnd, BOOL enable)
+{
+	// walk through HWNDs to avoid creating temporary CWnd objects
+	// unless we need to call this function recursively
+	for (HWND hWndChild = ::GetTopWindow(hWnd); hWndChild != NULL;
+		hWndChild = ::GetNextWindow(hWndChild, GW_HWNDNEXT))
+	{
+		CWnd* pWnd = CWnd::FromHandlePermanent(hWndChild);
+		if (pWnd != NULL)
+		{
+			pWnd->EnableWindow(enable);
+			pWnd->RedrawWindow();
+		}
+		if (::GetTopWindow(hWndChild) != NULL)
+		{
+			// send to child windows after parent
+			EnableDescendants(hWndChild,enable);
+		}
+	}
+}
+
+// We are using our own enabler function as the Windows one looks awful (called by the DialogManager)
+// DO NOT call DialogManager::EnableGadget on a control before you have created it!
+BOOL CCustomList::SetEnabled(BOOL enabled)
+{
+	GetScrollableArea()->SelectRow(-1); // deselect any selected row 
+	EnableWindow(enabled);
+	EnableDescendants(m_hWnd,enabled);
+	return TRUE;
+}
+
+// sets the offset of the numbered column by adding the specified width to preceding offsets
+void	CCustomList::SetColumnWidth(INT32 colnum,INT32 colwidth)
+{
+	ASSERT(colnum + 1 < MAXCOLUMNS);
+
+	// set at colnum+1
+	///
+	ERROR3IF(m_ColumnOffsetsArray[colnum]==-1,"SetColumnWidth - illegal column offset. ensure preceding column widths are set");
+	m_ColumnOffsetsArray[colnum+1] = m_ColumnOffsetsArray[colnum] + colwidth;
+}
+
+// helper function to change the background colour of the bitmap to the one used by dialog backgrounds
+BOOL SetBitmapBkgToSystem(HBITMAP hBitmap)
+{
+	BITMAP bitmap;
+	HDC hBitmapDC = CreateCompatibleDC(NULL);
+	if (!GetObject(hBitmap, sizeof(bitmap), &bitmap) || !hBitmapDC)
+	{
+		ERROR2RAW("Non-fatal GDI error");
+		return(FALSE);
+	}
+	SelectObject(hBitmapDC, hBitmap);
+	// We make the assumption that the pixel in the lower right corner has the background colour 
+	DWORD currentBkColour = (DWORD) GetPixel(hBitmapDC, bitmap.bmWidth - 1, bitmap.bmHeight -1); 
+	DWORD sysBkColour = GetSysColor(COLOR_3DFACE);
+	for (INT32 i = 0; i < bitmap.bmWidth; i++)
+	{
+		for (INT32 j = 0; j < bitmap.bmHeight; j++)
+		{
+			if ((DWORD) GetPixel(hBitmapDC, i, j) == currentBkColour)
+				SetPixelV(hBitmapDC, i, j, (COLORREF) sysBkColour);
+		}
+	}
+	DeleteDC(hBitmapDC);
+	return TRUE;
+}
+
+// Function to create a custom header from a bitmap resource
+BOOL CCustomList::CreateCustomHeader(UINT32 bitmapID)
+{
+	//The listview control has a built-in header, but we will create our own as we want it to display bitmaps
+	//First get control's coordinates, so that we know where to place the header
+
+	CRect listviewRect;
+	GetWindowRect(&listviewRect);
+	POINT listviewOrigin = { listviewRect.left, listviewRect.top };
+	::ScreenToClient((HWND) GetOwner()->m_hWnd, &listviewOrigin);
+
+	if(!m_hHeaderBitmap.LoadBitmap(MAKEINTRESOURCE(bitmapID)))
+		ERROR2RAW("Failed to load header bitmap");
+
+	//Get the height of the bitmap so we can figure out the height of the header
+	BITMAP bitmap ;
+	if (!m_hHeaderBitmap.GetBitmap(&bitmap))
+	{
+		ERROR2RAW("Failed to get header bitmap data");
+		return(FALSE);
+	}
+	//Change the background colour of the bitmap to the one used by dialog backgrounds, in case the colour scheme used is not the default 
+	SetBitmapBkgToSystem(m_hHeaderBitmap);
+	
+	CRect srect;
+	srect.left = listviewOrigin.x + m_ColumnOffsetsArray[0] + 1;
+	srect.right = listviewRect.right  ;
+	srect.top	= listviewOrigin.y - bitmap.bmHeight;
+	srect.bottom = listviewOrigin.y;
+
+	m_hHeader.Create(NULL, WS_VISIBLE | SS_BITMAP, srect, this->GetOwner());
+	m_hHeader.SetBitmap(m_hHeaderBitmap);
+	return TRUE;
+}
+
+
+// called when the custom control receives the focus. ensure we are sensibly
+// initialised before actually doing anything
+void CCustomList::OnSetFocus(CWnd* pOldWnd) 
+{
+	CWnd::OnSetFocus(pOldWnd);
+	
+	if(GetScrollableArea()->GetSafeHwnd()!=NULL)
+	{
+		if(GetScrollableArea()->m_RowCount > 0 && GetScrollableArea()->m_ListRowsArray)
+		{
+			INT32 Sel = GetScrollableArea()->m_CurrentSelectedRow;
+			if(Sel==-1 || GetScrollableArea()->m_CurrentSelectedRow > GetScrollableArea()->m_RowCount)
+				Sel=0;
+			GetScrollableArea()->SelectRow(Sel);
+		}
+	}
+	
+}
+
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+//                                                                         //
+//					CCustomListScrollableArea                              //
+//                                                                         //
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+
+BEGIN_MESSAGE_MAP(CCustomListScrollableArea, CWnd)
+	//{{AFX_MSG_MAP(CCustomListScrollableArea)
+	ON_WM_SIZE()
+	//}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+// CCustomListScrollableArea constructor
+CCustomListScrollableArea::CCustomListScrollableArea(CCustomList* parent) :
+	m_CurrentSelectedRow(-1),
+	m_RowCount(0),
+	m_Parent(parent),
+	m_ListRowsArray(NULL),
+	m_ScrollPos(0)
+{
+	// create font for text items
+	LOGFONT lf;                        // Used to create the CFont.
+	memset(&lf, 0, sizeof(LOGFONT));   // Clear out structure.
+	lf.lfHeight = CCustomList::FONTHEIGHT;
+	strcpy(lf.lfFaceName, "Microsoft Sans Serif");    //    with face name "Arial".
+	m_Font.CreateFontIndirect(&lf);    // Create the font.
+
+	// create the row objects
+	m_ListRowsArray = new CCustomListRowWnd*[CCustomList::MAXROWS];
+	for(INT32 i=0; i<CCustomList::MAXROWS; i++)
+	{
+		m_ListRowsArray[i] = NULL;
+	}
+
+	//	set up window class for the rows
+	WNDCLASS NewWindowClass;
+	memset(&NewWindowClass, 0, sizeof(WNDCLASS));
+	NewWindowClass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS ;
+	NewWindowClass.lpfnWndProc = ::DefWindowProc;
+	NewWindowClass.hInstance = AfxGetInstanceHandle();
+	NewWindowClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); ;//(HBRUSH) ((COLOR_BTNFACE));
+	NewWindowClass.lpszMenuName = NULL;
+	NewWindowClass.lpszClassName = _T("RowClass");
+	AfxRegisterClass(&NewWindowClass);
+}
+
+// CCustomListScrollableArea destructor
+CCustomListScrollableArea::~CCustomListScrollableArea()
+{
+	delete m_ListRowsArray;
+	m_ListRowsArray = NULL;
+}
+
+// Called after the window has been destroyed.
+void CCustomListScrollableArea::PostNcDestroy() 
+{
+	delete this;
+	CWnd::PostNcDestroy();
+}
+
+
+// respond to a scrollbar event by scrolling this window up or down
+void CCustomListScrollableArea::HandleScrollMessage(UINT32 nSBCode, UINT32 nPos )
+{
+	SCROLLINFO si;
+	si.cbSize = sizeof(SCROLLINFO);
+	si.fMask = SIF_TRACKPOS|SIF_PAGE|SIF_RANGE;
+	m_Parent->GetVScrollBar()->GetScrollInfo(&si);
+
+	INT32 NewPos = m_ScrollPos ;
+	switch(nSBCode)
+	{
+	case SB_PAGEDOWN:
+		NewPos = m_ScrollPos + si.nPage;
+		break ;
+	case SB_PAGEUP:
+		NewPos = m_ScrollPos - si.nPage;
+		break ;
+	case SB_LINEDOWN:
+		NewPos = m_ScrollPos + CCustomList::ROWHEIGHT;
+		break ;
+	case SB_LINEUP:
+		NewPos = m_ScrollPos - CCustomList::ROWHEIGHT;
+		break ;
+	case SB_THUMBTRACK:
+	case SB_THUMBPOSITION:
+		NewPos = nPos;
+		break;
+	}
+	INT32 LastPos = si.nMax-si.nPage + 1 ; 
+
+	if( NewPos < 0 )
+		NewPos = 0;
+	if( NewPos > LastPos )
+		NewPos = LastPos ;
+
+	INT32 offset = m_ScrollPos - NewPos;
+	this->ScrollWindow(0,offset);
+	m_ScrollPos = NewPos;
+	m_Parent->GetVScrollBar()->SetScrollPos(m_ScrollPos , true);
+}
+
+// return a pointer to the specified row object
+CCustomListRowWnd* CCustomListScrollableArea::GetRow(INT32 row)
+{
+	ASSERT(row < m_RowCount);
+	return m_ListRowsArray[row] ;
+}
+
+
+// select the specified row, scrolling if necessary so that 
+// the selection is in view. a value of -1 deselects any 
+// selection
+
+void CCustomListScrollableArea::SelectRow(INT32 RowNum)
+{
+	if( m_CurrentSelectedRow > -1 )
+	{
+		m_ListRowsArray[m_CurrentSelectedRow]->m_Selected = false ;
+		m_ListRowsArray[m_CurrentSelectedRow]->RedrawWindow();
+	}
+	m_CurrentSelectedRow = RowNum;
+
+	if( m_CurrentSelectedRow > -1 && this->IsWindowEnabled())
+	{
+		// scroll if necessary so that the selection is in view
+		CRect parentRect;
+		m_Parent->GetClientRect(&parentRect);
+		INT32 Page = parentRect.Height();
+		if((m_CurrentSelectedRow) * CCustomList::ROWHEIGHT < m_ScrollPos)
+		{
+			HandleScrollMessage(SB_THUMBPOSITION,m_CurrentSelectedRow * CCustomList::ROWHEIGHT);
+		}
+		else if((m_CurrentSelectedRow+1) * CCustomList::ROWHEIGHT > (m_ScrollPos + Page))
+		{
+			HandleScrollMessage(SB_THUMBPOSITION,(m_CurrentSelectedRow+1) * CCustomList::ROWHEIGHT - Page);
+		}
+
+		ASSERT(m_ListRowsArray!=NULL);
+		m_ListRowsArray[m_CurrentSelectedRow]->m_Selected = true ;
+		m_ListRowsArray[m_CurrentSelectedRow]->RedrawWindow();
+		m_ListRowsArray[m_CurrentSelectedRow]->SetFocus();
+	}
+}
+
+// the size has changed so adjust the scrollbar to reflect the new scrollable area size
+void CCustomListScrollableArea::OnSize(UINT32 nType, INT32 cx, INT32 cy) 
+{
+	ASSERT( GetHeight() == cy );
+	CWnd::OnSize(nType, cx, cy);
+	
+	CRect parentRect;
+	m_Parent->GetClientRect(parentRect);
+
+	// scrollbar window may not actually be visible
+	SCROLLINFO si;
+	si.cbSize = sizeof(SCROLLINFO);
+	si.fMask = SIF_PAGE|SIF_RANGE;
+	si.nPage = (INT32)parentRect.Height();
+	si.nMin = 0;     
+	si.nMax = GetHeight(); 
+	m_Parent->m_VScrollBar->SetScrollInfo(&si, true);
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+//                                                                         //
+//							CCustomListRowWnd                              //
+//                                                                         //
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+
+BEGIN_MESSAGE_MAP(CCustomListRowWnd, CWnd)
+	//{{AFX_MSG_MAP(CCustomListRowWnd)
+	ON_WM_LBUTTONUP()
+	ON_WM_ERASEBKGND()
+	ON_WM_CTLCOLOR()
+	ON_WM_LBUTTONDBLCLK()
+	ON_WM_KEYDOWN()
+	ON_WM_GETDLGCODE()
+	ON_WM_DESTROY()
+	//}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+CCustomListRowWnd::CCustomListRowWnd(INT32 RowNo, CCustomListScrollableArea* parent) :
+	m_BackBrush(RGB(255,255,255)) ,
+	m_BackBrushSel(::GetSysColor (COLOR_HIGHLIGHT)),
+	m_Selected(false),
+	m_RowNum(RowNo),
+	m_Parent(parent)
+{
+
+	// column object storage
+	m_ColumnObjects = new CObject* [CCustomList::MAXCOLUMNS];
+	for( INT32 i=0; i < CCustomList::MAXCOLUMNS; i++)
+		m_ColumnObjects[i] = NULL;
+}
+
+CCustomListRowWnd::~CCustomListRowWnd()
+{
+	// clear down column object storage
+	for( INT32 i=0; i < CCustomList::MAXCOLUMNS; i++)
+	{
+		if ( m_ColumnObjects[i] !=NULL )
+		{
+			delete m_ColumnObjects[i];
+			m_ColumnObjects[i] = NULL;
+		}
+	}
+	delete m_ColumnObjects ;
+}
+
+//Called after the window has been destroyed.
+void CCustomListRowWnd::PostNcDestroy() 
+{
+	delete this;
+	CWnd::PostNcDestroy();
+}
+
+// Ensure that any bitmap handles are deleted. We do it here because we need
+// the controls that store them to still be "alive"
+void CCustomListRowWnd::OnDestroy() 
+{
+	CWnd::OnDestroy();
+	for( INT32 i=0; i < CCustomList::MAXCOLUMNS; i++)
+	{
+		if ( m_ColumnObjects[i] !=NULL )
+		{
+			if( m_ColumnObjects[i]->IsKindOf(RUNTIME_CLASS(CStatic)) )
+			{
+				if( ((CStatic*)m_ColumnObjects[i])->GetSafeHwnd() )
+				{
+					HBITMAP hBitmap = ((CStatic*)m_ColumnObjects[i])->GetBitmap();
+					if(hBitmap)
+					{
+						::DeleteObject(hBitmap);
+					}
+				}
+			}
+		}
+	}
+}
+
+// add a check box at the specified column
+void CCustomListRowWnd::AddCheck(INT32 col)
+{
+	CButton* pBut = new CButton();
+	m_ColumnObjects[col] = pBut ;
+
+	CRect cr;
+	GetClientRect(&cr);
+	ASSERT(cr.Height() == CCustomList::ROWHEIGHT);
+
+	CRect rect;
+	rect.left	=	m_Parent->m_Parent->m_ColumnOffsetsArray[col] ;
+	rect.right	=	rect.left + GetSystemMetrics(SM_CXMENUCHECK);
+	rect.top	= (CCustomList::ROWHEIGHT - GetSystemMetrics(SM_CYMENUCHECK))/2;
+	rect.bottom = rect.top + GetSystemMetrics(SM_CYMENUCHECK)  ;
+	pBut->Create(NULL, WS_CHILD|WS_VISIBLE|BS_AUTOCHECKBOX, rect, this, 4);
+}
+
+// set the checkbox at the specified  column
+void CCustomListRowWnd::SetChecked(INT32 col, BOOL checked)
+{
+	ASSERT(m_ColumnObjects[col] != NULL );
+	ASSERT(m_ColumnObjects[col]->IsKindOf(RUNTIME_CLASS( CButton)));
+
+	CButton* pBut = (CButton*)m_ColumnObjects[col];
+	pBut->SetCheck(checked ? BST_CHECKED : BST_UNCHECKED );
+	pBut->UpdateWindow();
+}
+
+// test the switch value at the specified  column
+bool CCustomListRowWnd::IsChecked(INT32 col) const
+{
+	CButton* pBut = (CButton*)m_ColumnObjects[col];
+	return pBut->GetCheck() == BST_CHECKED;
+}
+
+
+// we have been clicked - but let the parent class manage it
+void CCustomListRowWnd::OnLButtonUp(UINT32 nFlags, CPoint point) 
+{
+	CWnd::OnLButtonUp(nFlags, point);
+	m_Parent->SelectRow(m_RowNum);
+	CWnd::OnLButtonUp(nFlags, point);
+}
+
+// called when object background needs erasing (for example, when resized). 
+BOOL CCustomListRowWnd::OnEraseBkgnd(CDC* pDC) 
+{
+	CBrush* pOldBrush = pDC->SelectObject(m_Selected ? &m_BackBrushSel : &m_BackBrush);
+
+	CRect rect;
+	pDC->GetClipBox(&rect);     // Erase the area needed
+
+	pDC->PatBlt(rect.left,rect.top,rect.Width(),rect.Height(),PATCOPY);
+	pDC->SelectObject(pOldBrush);
+
+	return true;
+}
+
+// add text to the specified column of this row
+void CCustomListRowWnd::AddText(INT32 col, CString text)
+{
+	ASSERT(m_ColumnObjects[col] == NULL);
+
+	CStatic* pStat = new CStatic();
+	m_ColumnObjects[col] = pStat ;
+	
+	CRect cr;
+	GetClientRect(&cr);
+
+	CRect srect;
+	srect.left= m_Parent->m_Parent->m_ColumnOffsetsArray[col] ;
+	if( col < CCustomList::MAXCOLUMNS && m_Parent->m_Parent->m_ColumnOffsetsArray[col + 1] > 0)
+		srect.right= m_Parent->m_Parent->m_ColumnOffsetsArray[col + 1] ;
+	else
+		srect.right= cr.right;
+	srect.top	= (CCustomList::ROWHEIGHT - CCustomList::FONTHEIGHT)/2;
+	srect.bottom = srect.top + CCustomList::FONTHEIGHT;
+	pStat->Create(text, WS_CHILD|WS_VISIBLE|WS_EX_LEFT, srect, this);
+	pStat->SetFont(&m_Parent->m_Font);
+}
+
+// set the text at the specified column of this row
+void CCustomListRowWnd::SetText(INT32 col, CString text)
+{
+	CStatic* pStat = (CStatic*)m_ColumnObjects[col];
+	if( pStat == NULL )
+		AddText(col,text);
+	else
+	{
+		pStat->SetWindowText(text);
+		pStat->UpdateWindow();
+	}
+}
+
+// add bitmap at the specified  column
+void CCustomListRowWnd::AddBitmap(INT32 col, HBITMAP hBitmap,HBITMAP, DWORD dwBackColour)
+{
+	CStatic* pStat = new CStatic();
+	ASSERT(m_ColumnObjects[col] == NULL);
+	m_ColumnObjects[col] = pStat ;
+
+	CRect cr;
+	GetClientRect(&cr);
+
+	BITMAP bitmap;
+	CBitmap::FromHandle(hBitmap)->GetBitmap(&bitmap);
+	CRect srect;
+	srect.left = m_Parent->m_Parent->m_ColumnOffsetsArray[col] ;
+	srect.right = srect.left + bitmap.bmWidth;
+	srect.top	= cr.Height()/2 - bitmap.bmHeight/2;
+	srect.bottom = cr.Height()/2 + bitmap.bmHeight/2;
+
+	////
+	HDC hBitmapDC = CreateCompatibleDC(NULL);
+	if (!hBitmapDC)
+	{
+		ERROR2RAW("Non-fatal GDI error");
+	}
+	SelectObject(hBitmapDC, hBitmap);
+	// Iff we haven't been told what the background colour is...
+	// We make the assumption that the pixel in the lower right corner has the background colour
+	if (dwBackColour == 0xFFFFFFFF)
+		dwBackColour = (DWORD) GetPixel(hBitmapDC, bitmap.bmWidth - 1, bitmap.bmHeight -1); 
+	DWORD sysBkColour = GetSysColor(COLOR_3DFACE);
+	for (INT32 i = 0; i < bitmap.bmWidth; i++)
+	{
+		for (INT32 j = 0; j < bitmap.bmHeight; j++)
+		{
+			if ((DWORD) GetPixel(hBitmapDC, i, j) == dwBackColour)
+				SetPixelV(hBitmapDC, i, j, (COLORREF) sysBkColour);
+		}
+	}
+	DeleteDC(hBitmapDC);
+
+	////
+	pStat->Create(NULL, WS_VISIBLE | SS_BITMAP, srect, this);
+	pStat->SetBitmap(hBitmap);
+}
+
+// invoked when child control is about to be drawn. prepare the pDC for drawing the 
+// control using the correct system colors.
+HBRUSH CCustomListRowWnd::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT32 nCtlColor) 
+{
+	HBRUSH hbr = CWnd::OnCtlColor(pDC, pWnd, nCtlColor);
+	COLORREF text = m_Selected ? GetSysColor(COLOR_HIGHLIGHTTEXT) : GetSysColor(COLOR_WINDOWTEXT);
+	pDC->SetTextColor(text);
+	pDC->SetBkMode(TRANSPARENT);
+
+	return GetBackgroundBrush();
+}
+
+// The row has been double-clicked. Notify the control calling window
+// (usually a dialog) 
+void CCustomListRowWnd::OnLButtonDblClk(UINT32 nFlags, CPoint point) 
+{
+	m_Parent->SelectRow(m_RowNum); // make sure we are selected
+	CWnd* caller = m_Parent->m_Parent->GetOwner();
+	INT32 ControlID = m_Parent->m_Parent->GetDlgCtrlID();
+	if(caller && ControlID )
+	{
+		NMHDR nm;
+		nm.hwndFrom = m_Parent->m_Parent->m_hWnd;
+		nm.idFrom = ControlID;
+		nm.code = NM_DBLCLK;
+
+		::SendMessage(caller->m_hWnd ,WM_NOTIFY,ControlID , (LPARAM)&nm	);
+	}
+}
+
+// return the text at the specified column
+CString CCustomListRowWnd::GetText(INT32 col) const
+{
+	CStatic* pStat = (CStatic*)m_ColumnObjects[col];
+	CString ret ;
+	pStat->GetWindowText(ret);
+	return ret;
+}
+
+// if up or down has been clicked, pass it on to the scrolling code
+void CCustomListRowWnd::OnKeyDown(UINT32 nChar, UINT32 nRepCnt, UINT32 nFlags) 
+{
+	if(nChar == CAMKEY(DOWN) && m_RowNum + 1 < m_Parent->m_RowCount)
+		m_Parent->SelectRow(m_RowNum+1);
+	else if(nChar == CAMKEY(UP) && m_RowNum - 1 >= 0)
+		m_Parent->SelectRow(m_RowNum-1);
+
+	CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
+}
+
+//	Make sure we receive UP/DOWN arrow key message (otherwise dialogs swallow them)
+UINT32 CCustomListRowWnd::OnGetDlgCode() 
+{
+    UINT32 uRet = CWnd::OnGetDlgCode();
+    uRet |= DLGC_WANTARROWS;
+    return uRet;
+}
+
+// The framework calls this member function when a child control sends a notification message, 
+// or when an accelerator keystroke is translated. 
+BOOL CCustomListRowWnd::OnCommand(WPARAM wParam, LPARAM lParam) 
+{
+	UINT32 nID = LOWORD(wParam);
+	HWND hWndCtrl = (HWND)lParam;
+	INT32 nCode = HIWORD(wParam);
+	///
+	m_Parent->SelectRow(m_RowNum); // make sure we are selected
+	CWnd* caller = m_Parent->m_Parent->GetOwner();
+	INT32 ControlID = m_Parent->m_Parent->GetDlgCtrlID();
+	if(caller && ControlID )
+	{
+		NMHDR nm;
+		nm.hwndFrom = m_hWnd;
+		nm.idFrom = ControlID;
+		nm.code = NULL;
+
+		::SendMessage(caller->m_hWnd ,WM_NOTIFY, ControlID , (LPARAM)&nm);
+	}
+	return CWnd::OnCommand(wParam, lParam);
+}
+
+// adds a row window object to the scrollable area. Note the resultant
+// height change triggers a WM_SIZE message (handled by OnSize()).
+// Returns a pointer to the row window
+CCustomListRowWnd* CCustomListScrollableArea::AddRow()
+{
+	CCustomListRowWnd* pRow = new CCustomListRowWnd(m_RowCount,this);
+	ASSERT(pRow);
+	m_ListRowsArray[m_RowCount] = pRow;
+	m_RowCount++;
+
+	CRect parentRect;
+	m_Parent->GetClientRect(&parentRect);
+
+	CRect rect ;
+	rect.top = (m_RowCount-1) * CCustomList::ROWHEIGHT ;
+	rect.left = 0 ;
+	rect.bottom = 0 + (m_RowCount) * CCustomList::ROWHEIGHT ;
+	rect.right = parentRect.right - 1;
+
+	pRow->Create("RowClass","",WS_CHILD,rect,this,0);
+	pRow->ShowWindow(SW_SHOW);
+
+	// recalculate height and scrollbar position
+	BOOL needScroll = GetHeight() > parentRect.Height();
+	INT32 width = parentRect.right;
+	if(needScroll)
+		width=width - ::GetSystemMetrics(SM_CXVSCROLL); //+2
+	m_Parent->m_VScrollBar->ShowWindow(needScroll ? SW_SHOW : SW_HIDE);
+	SetWindowPos(NULL,0,0,width,GetHeight(),0);
+
+	return pRow;
+}
+
+
+
+// respond to mousewheel events by paging or scrolling accordingly
+BOOL CCustomList::OnMouseWheel(UINT32 nFlags, short zDelta, CPoint pt) 
+{
+	SCROLLINFO si;
+	si.cbSize = sizeof(SCROLLINFO);
+	si.fMask = SIF_TRACKPOS|SIF_PAGE|SIF_RANGE;
+	GetVScrollBar()->GetScrollInfo(&si);
+
+	INT32 nStep = GetKeyState(CAMKEY(CONTROL))<0 ? si.nPage : ROWHEIGHT ;
+
+	INT32 newPos = GetVScrollBar()->GetScrollPos() - nStep*zDelta/WHEEL_DELTA;
+
+	// force to zero if the first line would appear partially off screen
+	if(newPos < ROWHEIGHT)
+		newPos = 0;
+	// keep the upper limit within bounds
+	if(newPos > si.nMax)
+		newPos = si.nMax;
+
+	if (m_ScrollableArea)
+	{
+		m_ScrollableArea->HandleScrollMessage(SB_THUMBPOSITION, newPos);
+	}
+	return CWnd::OnMouseWheel(nFlags, zDelta, pt);
+}
Index: Trunk/XaraLX/wxOil/CustomList.h
===================================================================
--- Trunk/XaraLX/wxOil/CustomList.h	(revision 0)
+++ Trunk/XaraLX/wxOil/CustomList.h	(revision 1063)
@@ -0,0 +1,285 @@
+// $Id: wxOil/CustomList.h, 1, 01-Jan-2006, Anonymous $
+/* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
+================================XARAHEADERSTART===========================
+ 
+               Xara LX, a vector drawing and manipulation program.
+                    Copyright (C) 1993-2006 Xara Group Ltd.
+       Copyright on certain contributions may be held in joint with their
+              respective authors. See AUTHORS file for details.
+
+LICENSE TO USE AND MODIFY SOFTWARE
+----------------------------------
+
+This file is part of Xara LX.
+
+Xara LX is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License version 2 as published
+by the Free Software Foundation.
+
+Xara LX and its component source files are 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 Xara LX (see the file GPL in the root directory of the
+distribution); if not, write to the Free Software Foundation, Inc., 51
+Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+
+
+ADDITIONAL RIGHTS
+-----------------
+
+Conditional upon your continuing compliance with the GNU General Public
+License described above, Xara Group Ltd grants to you certain additional
+rights. 
+
+The additional rights are to use, modify, and distribute the software
+together with the wxWidgets library, the wxXtra library, and the "CDraw"
+library and any other such library that any version of Xara LX relased
+by Xara Group Ltd requires in order to compile and execute, including
+the static linking of that library to XaraLX. In the case of the
+"CDraw" library, you may satisfy obligation under the GNU General Public
+License to provide source code by providing a binary copy of the library
+concerned and a copy of the license accompanying it.
+
+Nothing in this section restricts any of the rights you have under
+the GNU General Public License.
+
+
+SCOPE OF LICENSE
+----------------
+
+This license applies to this program (XaraLX) and its constituent source
+files only, and does not necessarily apply to other Xara products which may
+in part share the same code base, and are subject to their own licensing
+terms.
+
+This license does not apply to files in the wxXtra directory, which
+are built into a separate library, and are subject to the wxWindows
+license contained within that directory in the file "WXXTRA-LICENSE".
+
+This license does not apply to the binary libraries (if any) within
+the "libs" directory, which are subject to a separate license contained
+within that directory in the file "LIBS-LICENSE".
+
+
+ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
+----------------------------------------------
+
+Subject to the terms of the GNU Public License (see above), you are
+free to do whatever you like with your modifications. However, you may
+(at your option) wish contribute them to Xara's source tree. You can
+find details of how to do this at:
+  http://www.xaraxtreme.org/developers/
+
+Prior to contributing your modifications, you will need to complete our
+contributor agreement. This can be found at:
+  http://www.xaraxtreme.org/developers/contribute/
+
+Please note that Xara will not accept modifications which modify any of
+the text between the start and end of this header (marked
+XARAHEADERSTART and XARAHEADEREND).
+
+
+MARKS
+-----
+
+Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
+designs are registered or unregistered trademarks, design-marks, and/or
+service marks of Xara Group Ltd. All rights in these marks are reserved.
+
+
+      Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
+                        http://www.xara.com/
+
+=================================XARAHEADEREND============================
+ */
+#if !defined(AFX_CUSTOMLIST_H__32AE552D_C07B_4C09_9030_AB20E842FFD6__INCLUDED_)
+#define AFX_CUSTOMLIST_H__32AE552D_C07B_4C09_9030_AB20E842FFD6__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+// CustomList.h : header file
+//
+
+class CCustomListScrollableArea;
+class CCustomListRowWnd;
+
+/////////////////////////////////////////////////////////////////////////////
+// CCustomList - Custom List Control class. Hosts a vertical scrollbar and
+// a CCustomListScrollableArea
+
+class CCustomList : public CWnd
+{
+	friend class CCustomListScrollableArea;
+	friend class CCustomListRowWnd;
+public:
+//	constants
+	static const INT32 MAXCOLUMNS ;
+	static const INT32 MAXROWS ;
+	static const INT32 FONTHEIGHT;
+	static const INT32 ROWHEIGHT ;
+	static const INT32 COLOUR_PATCH_WIDTH ;
+	static const INT32 COLOUR_PATCH_HEIGHT;
+	static const CString WNDCLASSNAME;
+
+
+public:
+// constructor & destructor
+	CCustomList();
+	virtual ~CCustomList();
+	static BOOL RegisterWindowClass();
+	static LRESULT CALLBACK EXPORT CustomWindowProc(HWND hWnd, UINT32 nMsg, WPARAM wParam,LPARAM lParam);
+	void SetColumnWidth(INT32 colnum,INT32 offset);
+
+	// The following block of public methods is the API actually used by Camelot. It is
+	// almost identical to the original CCListGadget interface which it replaces
+
+	static CCustomList*	GetGadget(CWindowID parentID, CGadgetID gadgetID);
+	BOOL CreateCustomHeader (UINT32 bitmapID);
+
+	BOOL GetSwitchState(UINT32 itemIndex, UINT32 switchIndex) const;
+	INT32	 GetItemCount() const;
+	BOOL GetItemString(StringBase& itemString, UINT32 itemIndex, UINT32 columnIndex) const;
+	INT32	 GetSelectedItemIndex() const;
+
+	BOOL AddItem(StringBase& itemString, KernelBitmap* pItemImage = 0);
+	BOOL AddItem(StringBase& itemString, UINT32 bitmapEnabledID, UINT32 bitmapDisabledID);
+	BOOL AddRefsItem(UINT32 idStatusBitmap, StringBase& strItemName, StringBase& strDetails);
+	BOOL AddColourListItem(StringBase& colourName, INT32 red, INT32 green, INT32 blue, BOOL IsSpotColour = FALSE);
+	BOOL SetSwitchState(BOOL state, UINT32 itemIndex, UINT32 switchIndex);
+	void SetSelectedItemIndex(INT32 NewSel);
+	BOOL SetItemString(StringBase& itemString, UINT32 itemIndex, UINT32 columnIndex);
+	BOOL SetEnabled(BOOL enabled);
+	BOOL DeleteAllItems();
+
+protected:
+	//{{AFX_VIRTUAL(CCustomList)
+	protected:
+	virtual void PostNcDestroy();
+	//}}AFX_VIRTUAL
+
+	//{{AFX_MSG(CCustomList)
+	afx_msg INT32 OnCreate(LPCREATESTRUCT lpCreateStruct);
+	afx_msg void OnVScroll(UINT32 nSBCode, UINT32 nPos, CScrollBar* pScrollBar);
+	afx_msg void OnSetFocus(CWnd* pOldWnd);
+	afx_msg BOOL OnMouseWheel(UINT32 nFlags, short zDelta, CPoint pt);
+	//}}AFX_MSG
+	DECLARE_MESSAGE_MAP()
+private:
+	
+	void NewScrollableArea();	// creates a new scrollable area wnd
+	CScrollBar*					GetVScrollBar()		const {return m_VScrollBar;}     // get vertical scrollbar
+	CCustomListScrollableArea*	GetScrollableArea() const {return m_ScrollableArea;} // get the scrollable area 
+
+	CCustomListScrollableArea*	m_ScrollableArea;			// the scrollable area wnd
+	CScrollBar*					m_VScrollBar;				// the scrollbar
+	INT32*						m_ColumnOffsetsArray;		// array of column offsets
+	CBitmap						m_hHeaderBitmap;			// header bitmap 
+	CStatic						m_hHeader;					// header window 
+};
+
+/////////////////////////////////////////////////////////////////////////////
+// CCustomListScrollableArea window .  Represents the scrollable area and
+// hosts the list row wnds.
+
+class CCustomListScrollableArea : public CWnd
+{
+	friend class CCustomListRowWnd;
+	friend class CCustomList;
+	;
+protected:
+	// constructor, destructor
+	CCustomListScrollableArea(CCustomList* parent);
+	virtual ~CCustomListScrollableArea();
+
+	CCustomListRowWnd*	AddRow();
+	void				SelectRow(INT32 RowNum);
+	void				HandleScrollMessage(UINT32 nSBCode, UINT32 nPos);
+	CCustomListRowWnd*	GetRow(INT32 row);
+	INT32					GetHeight() const {return m_RowCount * CCustomList::ROWHEIGHT ;}
+
+
+
+protected:
+	// Generated message map functions
+	//{{AFX_VIRTUAL(CCustomListScrollableArea)
+	protected:
+	virtual void PostNcDestroy();
+	//}}AFX_VIRTUAL
+	//{{AFX_MSG(CCustomListScrollableArea)
+	afx_msg void OnSize(UINT32 nType, INT32 cx, INT32 cy);
+	//}}AFX_MSG
+	DECLARE_MESSAGE_MAP()
+
+private:
+	CCustomListRowWnd** m_ListRowsArray;		// the array of row wnd objects
+	INT32					m_ScrollPos ;			// the current scroll pos
+	INT32					m_CurrentSelectedRow;	// the currently selected row
+	CFont				m_Font;					// the font
+	INT32					m_RowCount;				// current row count 
+	CCustomList* m_Parent;						// the parent CCustomList
+};
+
+/////////////////////////////////////////////////////////////////////////////
+// CCustomListRowWnd window. A single row object within a scrollable area
+// object. Contains text, controls and bitmaps in column positions.
+
+class CCustomListRowWnd : public CWnd
+{
+	friend CCustomListScrollableArea; // grant full access to my parent
+public:
+	// construct with the parent Scrollable Area
+	CCustomListRowWnd	(INT32 i, CCustomListScrollableArea* parent);
+	virtual ~CCustomListRowWnd();
+
+	void AddText(INT32 col, CString text);
+	void SetText(INT32 col, CString text);
+	void AddCheck(INT32 col);
+	void AddBitmap(INT32 col, HBITMAP bmp1, HBITMAP bmp2, DWORD dwBackColour=0xFFFFFFFF);
+	void SetChecked(INT32 col,BOOL checked);
+	bool IsChecked(INT32 col) const;
+	CString GetText(INT32 col) const;
+
+private:
+	HBRUSH GetBackgroundBrush(){return (m_Selected ? m_BackBrushSel:m_BackBrush ); }
+
+	const INT32 m_RowNum;						// index of this row in the list
+	CCustomListScrollableArea* m_Parent;	// pointer to our parent
+	CBrush m_BackBrush;						// background brush
+	CBrush m_BackBrushSel;					// background brush to use when selected
+	CObject** m_ColumnObjects;				// array of our column aligned objects
+	bool m_Selected;						// true if this row is selected
+
+
+protected:
+
+// Overrides
+	// ClassWizard generated virtual function overrides
+	//{{AFX_VIRTUAL(CCustomListRowWnd)
+	protected:
+	virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam);
+	virtual void PostNcDestroy();
+	//}}AFX_VIRTUAL
+
+// Generated message map functions
+
+	//{{AFX_MSG(CCustomListRowWnd)
+	afx_msg void OnLButtonUp(UINT32 nFlags, CPoint point);
+	afx_msg BOOL OnEraseBkgnd(CDC* pDC);
+	afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT32 nCtlColor);
+	afx_msg void OnLButtonDblClk(UINT32 nFlags, CPoint point);
+	afx_msg void OnKeyDown(UINT32 nChar, UINT32 nRepCnt, UINT32 nFlags);
+	afx_msg UINT32 OnGetDlgCode();
+	afx_msg void OnDestroy();
+	//}}AFX_MSG
+	DECLARE_MESSAGE_MAP()
+};
+
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_CUSTOMLIST_H__32AE552D_C07B_4C09_9030_AB20E842FFD6__INCLUDED_)


Xara