--- /dev/null
+/////////////////////////////////////////////////////////////////////////////
+// Name: src/os2/listctrl.cpp
+// Purpose: wxListCtrl
+// Author: David Webster
+// Modified by:
+// Created: 01/21/03
+// RCS-ID: $Id$
+// Copyright: (c) David Webster
+// Licence: wxWindows license
+/////////////////////////////////////////////////////////////////////////////
+
+// ============================================================================
+// declarations
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
+
+#ifdef __GNUG__
+ #pragma implementation "listctrl.h"
+ #pragma implementation "listctrlbase.h"
+#endif
+
+// For compilers that support precompilation, includes "wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+ #pragma hdrstop
+#endif
+
+#if wxUSE_LISTCTRL
+
+#ifndef WX_PRECOMP
+ #include "wx/app.h"
+ #include "wx/intl.h"
+ #include "wx/log.h"
+ #include "wx/settings.h"
+#endif
+
+#include "wx/textctrl.h"
+#include "wx/imaglist.h"
+#include "wx/listctrl.h"
+#include "wx/dcclient.h"
+
+#include "wx/os2/private.h"
+
+//
+// FIELDOFFSET in DETAIL view as defined in the OS2TK45 simply doesn't work
+// We use this, which does!
+//
+#undef FIELDOFFSET
+#define FIELDOFFSET(type, field) ((ULONG)&(((type *)0)->field))
+
+// ----------------------------------------------------------------------------
+// private helper classes
+// ----------------------------------------------------------------------------
+
+/////////////////////////////////////////////////////////////////////////////
+// STRUCT SMYRECORD
+// Under OS/2 we have to use our own RECORDCORE based struct if we have
+// user data to store in a PM Container Control (and CListCtrl is a PM
+// Container in ICON, NAME, TEXT or DETAILview). m_ulUserData is a four
+// byte value containing a pointer to our CListIntemInternalData class
+// instance.
+/////////////////////////////////////////////////////////////////////////////
+typedef struct _MYRECORD
+{
+ RECORDCORE m_vRecord;
+ unsigned long m_ulItemId;
+ unsigned long m_ulUserData;
+} MYRECORD, *PMYRECORD;
+
+/////////////////////////////////////////////////////////////////////////////
+// CLASS CListItemInternalData
+//
+// Problem:
+// The MSW version had problems with SetTextColour() et al as the
+// CListItemAttr's were stored keyed on the item index. If a item was
+// inserted anywhere but the end of the list the the text attributes
+// (colour etc) for the following items were out of sync.
+//
+// Solution:
+// Under MSW the only way to associate data with a
+// List item independant of its position in the list is to store a pointer
+// to it in its lParam attribute. However user programs are already using
+// this (via the SetItemData() GetItemData() calls).
+//
+// However what we can do is store a pointer to a structure which contains
+// the attributes we want *and* a lParam for the users data, e.g.
+//
+// class CListItemInternalData
+// {
+// public:
+// GuiAdvCtrl_CListItemAttr* pAttr;
+// long lParam; // user data
+// };
+//
+// To conserve memory, a CListItemInternalData is only allocated for a
+// LV_ITEM if text attributes or user data(lparam) are being set.
+//
+// For OS/2, the lParam value points to whatever actual data we have
+/////////////////////////////////////////////////////////////////////////////
+class CListItemInternalData
+{
+public:
+
+ CListItemInternalData(): m_pAttr(NULL)
+ ,m_lParam(0)
+ {}
+
+ ~CListItemInternalData()
+ {
+ delete m_pAttr;
+ m_pAttr = NULL;
+ }
+
+ wxListItemAttr* m_pAttr;
+ WXLPARAM m_lParam; // user data
+ PMYRECORD m_pMyRecord; // so we can set the m_ulUserData to 0 when this is deleted
+}; // end of CLASS CListItemInternalData
+
+/////////////////////////////////////////////////////////////////////////////
+// STRUCT SInternalDataSort
+//
+// Sort items.
+//
+// fn is a function which takes 3 long arguments: item1, item2, data.
+// item1 is the long data associated with a first item (NOT the index).
+// item2 is the long data associated with a second item (NOT the index).
+// data is the same value as passed to SortItems.
+//
+// The return value is a negative number if the first item should precede the
+// second item, a positive number of the second item should precede the first,
+// or zero if the two items are equivalent.
+//
+// data is arbitrary data to be passed to the sort function.
+//
+// Internal structures for proxying the user compare function
+// so that we can pass it the *real* user data
+/////////////////////////////////////////////////////////////////////////////
+typedef struct internalDataSort
+{
+ wxListCtrlCompare m_fnUser;
+ long m_lData;
+} SInternalDataSort; // end of STRUCT SInternalDataSort
+
+// ----------------------------------------------------------------------------
+// private helper functions
+// ----------------------------------------------------------------------------
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// FindOS2ListFieldByColNum
+//
+// There is no way, under OS/2 to get a field in a container by index,
+// directly, so you must get the first one, then cycle through the list
+// until you get to where you want to be.
+//
+// PARAMETERS
+// hWnd -- window handle of container to search
+// lIndex -- index to set
+//
+// RETURN VALUE
+// pointer to the FIELDINFO struct at the index in the container record
+//
+/////////////////////////////////////////////////////////////////////////////
+PFIELDINFO FindOS2ListFieldByColNum (
+ HWND hWnd
+, long lIndex
+)
+{
+ PFIELDINFO pFieldInfo = NULL;
+ CNRINFO vCnrInfo;
+ ULONG i;
+
+ if (!::WinSendMsg( hWnd
+ ,CM_QUERYCNRINFO
+ ,MPFROMP(&vCnrInfo)
+ ,(MPARAM)(USHORT)sizeof(CNRINFO)
+ ))
+ return NULL;
+ for (i = 0; i < vCnrInfo.cFields; i++)
+ {
+ if (i == 0)
+ pFieldInfo = (PFIELDINFO)PVOIDFROMMR(::WinSendMsg( hWnd
+ ,CM_QUERYDETAILFIELDINFO
+ ,MPFROMP(pFieldInfo)
+ ,(MPARAM)CMA_FIRST
+ ));
+ else
+ pFieldInfo = (PFIELDINFO)PVOIDFROMMR(::WinSendMsg( hWnd
+ ,CM_QUERYDETAILFIELDINFO
+ ,MPFROMP(pFieldInfo)
+ ,(MPARAM)CMA_NEXT
+ ));
+ if (!pFieldInfo)
+ return NULL;
+ if (i == (ULONG)lIndex)
+ break;
+ }
+ if (!pFieldInfo)
+ return NULL;
+ return pFieldInfo;
+} // end of FindOS2ListFieldByColNum
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// FindOS2ListRecordByID
+//
+// There is no way, under OS/2 to get a record in a container by index,
+// directly, so you must get the first one, then cycle through the list
+// until you get to where you want to be.
+//
+// PARAMETERS
+// hWnd -- window handle of container to search
+// lItemId -- index to set
+//
+// RETURN VALUE
+// pointer to the internal RECORDCORE struct at the index in the container
+//
+/////////////////////////////////////////////////////////////////////////////
+PMYRECORD FindOS2ListRecordByID (
+ HWND hWnd
+, long lItemId
+)
+{
+ PMYRECORD pRecord = NULL;
+ CNRINFO vCnrInfo;
+ unsigned long i;
+
+ if (!::WinSendMsg( hWnd
+ ,CM_QUERYCNRINFO
+ ,MPFROMP(&vCnrInfo)
+ ,(MPARAM)(USHORT)sizeof(CNRINFO)
+ ))
+ return NULL;
+ for (i = 0; i < vCnrInfo.cRecords; i++)
+ {
+ if (i == 0)
+ pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( hWnd
+ ,CM_QUERYRECORD
+ ,MPFROMP(pRecord)
+ ,MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER)
+ ));
+ else
+ pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( hWnd
+ ,CM_QUERYRECORD
+ ,MPFROMP(pRecord)
+ ,MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER)
+ ));
+ if (!pRecord)
+ return NULL;
+ if (pRecord->m_ulItemId == (ULONG)lItemId)
+ break;
+ }
+ return pRecord;
+} // end of FindOS2ListRecordByID
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// BumpRecordIds
+//
+// Since OS/2 does not keep native record id's but wx insists on inserting
+// and selecting via ID's, when we insert a record in the middle we need
+// to bump the id's of each record after the one we just inserted.
+//
+// PARAMETERS
+// hWnd -- window handle of container to search
+// pRecord -- record after which we starting bumping id's
+//
+// RETURN VALUE
+// none
+//
+/////////////////////////////////////////////////////////////////////////////
+void BumpRecordIds (
+ HWND hWnd
+, PMYRECORD pRecord
+)
+{
+ while(pRecord)
+ {
+ pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( hWnd
+ ,CM_QUERYRECORD
+ ,MPFROMP(pRecord)
+ ,MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER)
+ ));
+ if (pRecord)
+ pRecord->m_ulItemId++;
+ }
+} // end of BumpRecordIds
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// GetInternalData
+//
+// Get the internal data given a handle and an id
+//
+// PARAMETERS
+// hWnd -- window handle to the control in which item is located
+// lItemId -- ID to get
+//
+// RETURN VALUE
+// pointer to the internal data
+//
+// Note:
+// Under OS/2 PM a container item cannot be obtained via a simple index or
+// id retrieval. We have to walk the record list if we are looking for
+// a record at a specific index location
+/////////////////////////////////////////////////////////////////////////////
+CListItemInternalData* GetInternalData (
+ HWND hWnd
+, long lItemId
+)
+{
+ PMYRECORD pRecord = FindOS2ListRecordByID( hWnd
+ ,lItemId
+ );
+ //
+ // Internal user data is stored AFTER the last field of the RECORDCORE
+ //
+ if (!pRecord)
+ return NULL;
+ return((CListItemInternalData *)(pRecord->m_ulUserData));
+} // end of GetInternalData
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// GetInternalData
+//
+// Get the internal data given a pointer to a list control and an id
+//
+// PARAMETERS
+// pCtl -- pointer to control inwhich item is located
+// lItemId -- ID to get
+//
+// RETURN VALUE
+// pointer to the internal data
+//
+/////////////////////////////////////////////////////////////////////////////
+CListItemInternalData* GetInternalData (
+ wxListCtrl* pCtl
+, long lItemId
+)
+{
+ return(GetInternalData( (HWND)pCtl->GetHWND()
+ ,lItemId
+ ));
+} // end of GetInternalData
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DeleteInternalData
+//
+// Delete the internal data for a record
+//
+// PARAMETERS
+// pCtl -- pointer to the list control containing the record
+// lItemId -- the record index to delete the internal data from
+//
+// RETURN VALUE
+// pointer to the internal data attribute
+//
+/////////////////////////////////////////////////////////////////////////////
+void DeleteInternalData (
+ wxListCtrl* pCtl
+, long lItemId
+)
+{
+ CListItemInternalData* pData = GetInternalData( pCtl
+ ,lItemId
+ );
+ if (pData)
+ {
+ if (pData->m_pMyRecord)
+ pData->m_pMyRecord->m_ulUserData = 0;
+ delete pData;
+ }
+} // end of DeleteInternalData
+
+// #pragma page "GetInternalDataAttr"
+/////////////////////////////////////////////////////////////////////////////
+//
+// GetInternalDataAttr
+//
+// Get the internal data item attribute given a pointer to a list control
+// and an id
+//
+// PARAMETERS
+// pCtl -- pointer to control to set
+// lItemId -- ID to set
+//
+// RETURN VALUE
+// pointer to the internal data attribute
+//
+/////////////////////////////////////////////////////////////////////////////
+wxListItemAttr* GetInternalDataAttr (
+ wxListCtrl* pCtl
+, long lItemId
+)
+{
+ CListItemInternalData* pData = GetInternalData( pCtl
+ ,lItemId
+ );
+
+ if (pData)
+ return(pData->m_pAttr);
+ else
+ return NULL;
+} // end of GetInternalDataAttr
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// InternalDataCompareFunc
+//
+// This is compare function we pass to PM. It wraps the real compare
+// function in SInternalDataSort
+//
+// PARAMETERS
+// p1 -- is the first record structure to compare
+// p2 -- is the second record structure to compare
+// lStorage -- is the same value as passed to SortItems.
+//
+// RETURN VALUE
+// pointer to the internal data attribute
+//
+/////////////////////////////////////////////////////////////////////////////
+SHORT EXPENTRY InternalDataCompareFunc (
+ PMYRECORD p1
+, PMYRECORD p2
+, PVOID pStorage
+)
+{
+ SInternalDataSort* pInternalData = (SInternalDataSort *)pStorage;
+ CListItemInternalData* pData1 = (CListItemInternalData *)p1->m_ulUserData;
+ CListItemInternalData* pData2 = (CListItemInternalData *)p2->m_ulUserData;
+ long lD1 = (pData1 == NULL ? 0 : (long)pData1->m_lParam);
+ long lD2 = (pData2 == NULL ? 0 : (long)pData2->m_lParam);
+
+ return(pInternalData->m_fnUser( lD1
+ ,lD2
+ ,pInternalData->m_lData
+ ));
+} // end of InternalDataCompareFunc
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// ConvertFromOS2ListItem
+//
+// Convert from an internal PM List item to a Toolkit List item
+//
+// PARAMETERS
+// hWndListCtrl -- the control's windows handle
+// rInfo -- the library list control to convert to
+// pRecord -- the OS list control to convert from
+//
+// RETURN VALUE
+// none
+//
+/////////////////////////////////////////////////////////////////////////////
+void ConvertFromOS2ListItem (
+ HWND hWndListCtrl
+, wxListItem& rInfo
+, PMYRECORD pRecord
+)
+{
+ CListItemInternalData* pInternaldata = (CListItemInternalData *)pRecord->m_ulUserData;
+ bool bNeedText = FALSE;
+
+ if (pInternaldata)
+ rInfo.SetData(pInternaldata->m_lParam);
+
+ rInfo.SetMask(0);
+ rInfo.SetState(0);
+ rInfo.SetStateMask(0);
+ rInfo.SetId((long)pRecord->m_ulItemId);
+ if (hWndListCtrl != 0)
+ {
+ pRecord = FindOS2ListRecordByID( hWndListCtrl
+ ,rInfo.GetId()
+ );
+ }
+
+ //
+ // The wxListItem class is really set up to handle the WIN32 list item
+ // and OS/2 are not as complicated. Just set both state members to the
+ // same thing under OS/2
+ //
+ if (pRecord->m_vRecord.flRecordAttr & CRA_DROPONABLE)
+ {
+ rInfo.SetStateMask(rInfo.m_stateMask | wxLIST_STATE_DROPHILITED);
+ rInfo.SetState(rInfo.m_state | wxLIST_STATE_DROPHILITED);
+ }
+ if (pRecord->m_vRecord.flRecordAttr & CRA_SELECTED)
+ {
+ rInfo.SetStateMask(rInfo.m_stateMask | wxLIST_STATE_SELECTED);
+ rInfo.SetState(rInfo.m_state | wxLIST_STATE_SELECTED);
+ }
+ if (pRecord->m_vRecord.flRecordAttr & CRA_DISABLED)
+ {
+ rInfo.SetStateMask(rInfo.m_stateMask | wxLIST_STATE_DISABLED);
+ rInfo.SetState(rInfo.m_state | wxLIST_STATE_DISABLED);
+ }
+ if (pRecord->m_vRecord.flRecordAttr & CRA_FILTERED)
+ {
+ rInfo.SetStateMask(rInfo.m_stateMask | wxLIST_STATE_FILTERED);
+ rInfo.SetState(rInfo.m_state | wxLIST_STATE_FILTERED);
+ }
+ if (pRecord->m_vRecord.flRecordAttr & CRA_INUSE)
+ {
+ rInfo.SetStateMask(rInfo.m_stateMask | wxLIST_STATE_INUSE);
+ rInfo.SetState(rInfo.m_state | wxLIST_STATE_INUSE);
+ }
+ if (pRecord->m_vRecord.flRecordAttr & CRA_PICKED)
+ {
+ rInfo.SetStateMask(rInfo.m_stateMask | wxLIST_STATE_PICKED);
+ rInfo.SetState(rInfo.m_state | wxLIST_STATE_PICKED);
+ }
+ if (pRecord->m_vRecord.flRecordAttr & CRA_SOURCE)
+ {
+ rInfo.SetStateMask(rInfo.m_stateMask | wxLIST_STATE_SOURCE);
+ rInfo.SetState(rInfo.m_state | wxLIST_STATE_SOURCE);
+ }
+
+ if (pRecord->m_vRecord.pszText != (PSZ)NULL)
+ {
+ rInfo.SetMask(rInfo.GetMask() | wxLIST_MASK_TEXT);
+ rInfo.SetText(pRecord->m_vRecord.pszText);
+ }
+ if (pRecord->m_vRecord.pszIcon != (PSZ)NULL ||
+ pRecord->m_vRecord.pszName != (PSZ)NULL)
+ {
+ rInfo.SetMask(rInfo.GetMask() | wxLIST_MASK_IMAGE);
+ rInfo.SetImage(pRecord->m_vRecord.hptrIcon);
+ }
+ if (pRecord->m_ulUserData)
+ rInfo.SetMask(rInfo.GetMask() | wxLIST_MASK_DATA);
+} // end of ConvertFromOS2ListItem
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// ConvertToOS2Flags
+//
+// Convert from an library states to OS states
+//
+// PARAMETERS
+// lState -- the state
+// pRecord -- the OS list control to use
+//
+// RETURN VALUE
+// none
+//
+/////////////////////////////////////////////////////////////////////////////
+void ConvertToOS2Flags (
+ long lState
+, PMYRECORD pRecord
+)
+{
+ if (lState & wxLIST_STATE_DROPHILITED)
+ pRecord->m_vRecord.flRecordAttr |= CRA_DROPONABLE;
+ if (lState & wxLIST_STATE_SELECTED)
+ pRecord->m_vRecord.flRecordAttr |= CRA_SELECTED;
+ if (lState & wxLIST_STATE_DISABLED)
+ pRecord->m_vRecord.flRecordAttr |= CRA_DISABLED;
+ if (lState & wxLIST_STATE_FILTERED)
+ pRecord->m_vRecord.flRecordAttr |= CRA_FILTERED;
+ if (lState & wxLIST_STATE_INUSE)
+ pRecord->m_vRecord.flRecordAttr |= CRA_INUSE;
+ if (lState & wxLIST_STATE_PICKED)
+ pRecord->m_vRecord.flRecordAttr |= CRA_PICKED;
+ if (lState & wxLIST_STATE_SOURCE)
+ pRecord->m_vRecord.flRecordAttr |= CRA_SOURCE;
+} // end of ConvertToOS2Flags
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// ConvertToOS2ListItem
+//
+// Convert from a library List item to an internal OS2 List item. We set
+// only the fields we need to set. Some of them are set by the API when
+// they are added to the container.
+//
+// PARAMETERS
+// pCtrl -- the control to use
+// rInfo -- the item to convert
+// pRecord -- the OS list control to use, should be zeroed out
+//
+// RETURN VALUE
+// none
+//
+/////////////////////////////////////////////////////////////////////////////
+void ConvertToOS2ListItem (
+ const wxListCtrl* pCtrl
+, const wxListItem& rInfo
+, PMYRECORD pRecord
+)
+{
+ pRecord->m_ulItemId = (ULONG)rInfo.GetId();
+ if (rInfo.GetMask() & wxLIST_MASK_STATE)
+ {
+ ConvertToOS2Flags( rInfo.m_state
+ ,pRecord
+ );
+ }
+ if (pCtrl->GetWindowStyleFlag() & wxLC_ICON ||
+ pCtrl->GetWindowStyleFlag() & wxLC_SMALL_ICON)
+ {
+ pRecord->m_vRecord.pszIcon = (char*)rInfo.GetText().c_str();
+ }
+ if (pCtrl->GetWindowStyleFlag() & wxLC_LIST) // PM TEXT view
+ {
+ pRecord->m_vRecord.pszText = (char*)rInfo.GetText().c_str();
+ }
+ if (rInfo.GetMask() & wxLIST_MASK_IMAGE)
+ {
+ pRecord->m_vRecord.hptrIcon = (HPOINTER)rInfo.GetImage();
+ pRecord->m_vRecord.hptrMiniIcon = (HPOINTER)rInfo.m_miniImage;
+ }
+} // end of ConvertToOS2ListItem
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// ConvertToOS2ListCol
+//
+// Convert from a library List column to an internal PM List column
+//
+// PARAMETERS
+// lCol -- the columnd to convert
+// rItem -- the item to convert
+// pField -- the OS list column to use
+//
+// RETURN VALUE
+// none
+//
+/////////////////////////////////////////////////////////////////////////////
+void ConvertToOS2ListCol (
+ long lCol
+, const wxListItem& rItem
+, PFIELDINFO pField
+)
+{
+ memset(pField, '\0', sizeof(FIELDINFO));
+ pField->cb = sizeof(FIELDINFO);
+ if (rItem.GetMask() & wxLIST_MASK_TEXT)
+ {
+ pField->flData |= CFA_STRING;
+ pField->pUserData = (void *)rItem.GetText().c_str();
+ }
+ if (rItem.GetMask() & wxLIST_MASK_FORMAT)
+ {
+ if (rItem.m_format == wxLIST_FORMAT_LEFT)
+ pField->flData |= CFA_LEFT;
+ else if (rItem.m_format == wxLIST_FORMAT_RIGHT)
+ pField->flData |= CFA_RIGHT;
+ else if (rItem.m_format == wxLIST_FORMAT_CENTRE)
+ pField->flData |= CFA_CENTER;
+ }
+ if (rItem.GetMask() & wxLIST_MASK_WIDTH)
+ {
+ if (!(rItem.GetWidth() == wxLIST_AUTOSIZE ||
+ rItem.GetWidth() == wxLIST_AUTOSIZE_USEHEADER))
+ pField->cxWidth = rItem.GetWidth();
+ // else: OS/2 automatically sets the width if created with the approppriate style
+ }
+} // end of ConvertToOS2ListCol
+
+// ----------------------------------------------------------------------------
+// events
+// ----------------------------------------------------------------------------
+
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_DRAG)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_RDRAG)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_END_LABEL_EDIT)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ITEM)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_GET_INFO)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_SET_INFO)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_SELECTED)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_DESELECTED)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_KEY_DOWN)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_INSERT_ITEM)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_CLICK)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_RIGHT_CLICK)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_BEGIN_DRAG)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_DRAGGING)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_END_DRAG)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_ACTIVATED)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_FOCUSED)
+DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_CACHE_HINT)
+
+IMPLEMENT_DYNAMIC_CLASS(wxListCtrl, wxControl)
+IMPLEMENT_DYNAMIC_CLASS(wxListView, wxListCtrl)
+IMPLEMENT_DYNAMIC_CLASS(wxListItem, wxObject)
+
+IMPLEMENT_DYNAMIC_CLASS(wxListEvent, wxNotifyEvent)
+
+BEGIN_EVENT_TABLE(wxListCtrl, wxControl)
+ EVT_PAINT(wxListCtrl::OnPaint)
+END_EVENT_TABLE()
+
+// ============================================================================
+// implementation
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// wxListCtrl construction
+// ----------------------------------------------------------------------------
+
+void wxListCtrl::Init ()
+{
+ m_pImageListNormal = NULL;
+ m_pImageListSmall = NULL;
+ m_pImageListState = NULL;
+ m_bOwnsImageListNormal = FALSE;
+ m_bOwnsImageListSmall = FALSE;
+ m_bOwnsImageListState = FALSE;
+ m_lBaseStyle = 0L;
+ m_nColCount = 0;
+ m_pTextCtrl = NULL;
+ m_bAnyInternalData = FALSE;
+ m_bHasAnyAttr = FALSE;
+} // end of wxListCtrl::Init
+
+bool wxListCtrl::Create (
+ wxWindow* pParent
+, wxWindowID vId
+, const wxPoint& rPos
+, const wxSize& rSize
+, long lStyle
+, const wxValidator& rValidator
+, const wxString& rsName
+)
+{
+ int nX = rPos.x;
+ int nY = rPos.y;
+ int nWidth = rSize.x;
+ int nHeight = rSize.y;
+
+#if wxUSE_VALIDATORS
+ SetValidator(rValidator);
+#endif // wxUSE_VALIDATORS
+
+ SetName(rsName);
+ SetWindowStyleFlag(lStyle);
+ SetParent(pParent);
+ if (nWidth <= 0)
+ nWidth = 100;
+ if (nHeight <= 0)
+ nHeight = 30;
+ if (nX < 0)
+ nX = 0;
+ if (nY < 0)
+ nY = 0;
+
+ m_windowId = (vId == -1) ? NewControlId() : vId;
+
+ long lSstyle = WS_VISIBLE | WS_TABSTOP;
+
+ if (GetWindowStyleFlag() & wxCLIP_SIBLINGS)
+ lSstyle |= WS_CLIPSIBLINGS;
+ m_lBaseStyle = lSstyle;
+ if (!DoCreateControl( nX
+ ,nY
+ ,nWidth
+ ,nHeight
+ ))
+ return FALSE;
+ if (pParent)
+ pParent->AddChild(this);
+ return TRUE;
+} // end of wxListCtrl::Create
+
+bool wxListCtrl::DoCreateControl (
+ int nX
+, int nY
+, int nWidth
+, int nHeight
+)
+{
+ DWORD lWstyle = m_lBaseStyle;
+ long lOldStyle = 0; // Dummy
+
+ CNRINFO vCnrInfo;
+
+ lWstyle |= ConvertToOS2Style( lOldStyle
+ ,GetWindowStyleFlag()
+ );
+
+ m_hWnd = (WXHWND)::WinCreateWindow( GetParent()->GetHWND()
+ ,WC_CONTAINER
+ ,NULL
+ ,m_lBaseStyle
+ ,0, 0, 0, 0
+ ,GetParent()->GetHWND()
+ ,HWND_BOTTOM
+ ,(ULONG)m_windowId
+ ,NULL
+ ,NULL
+ );
+ if (!m_hWnd)
+ {
+ return FALSE;
+ }
+
+ //
+ // Now set the display attributes of the container
+ //
+ if (!::WinSendMsg( GetHWND()
+ ,CM_QUERYCNRINFO
+ ,MPFROMP(&vCnrInfo)
+ ,(MPARAM)(USHORT)sizeof(CNRINFO)
+ ))
+ lWstyle = ConvertViewToOS2Style(GetWindowStyleFlag());
+ vCnrInfo.flWindowAttr != lWstyle;
+ ::WinSendMsg( GetHWND()
+ ,CM_SETCNRINFO
+ ,MPFROMP(&vCnrInfo)
+ ,(MPARAM)CMA_FLWINDOWATTR
+ );
+
+ //
+ // And now set needed arrangement flags
+ //
+ lWstyle = ConvertArrangeToOS2Style(GetWindowStyleFlag());
+ ::WinSendMsg( GetHWND()
+ ,CM_ARRANGE
+ ,(MPARAM)CMA_ARRANGEGRID
+ ,(MPARAM)lWstyle
+ );
+ SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
+ SetForegroundColour(GetParent()->GetForegroundColour());
+ SubclassWin(m_hWnd);
+ SetFont(*wxSMALL_FONT);
+ SetXComp(0);
+ SetYComp(0);
+ SetSize( nX
+ ,nY
+ ,nWidth
+ ,nHeight
+ );
+ return TRUE;
+} // end of wxListCtrl::DoCreateControl
+
+void wxListCtrl::UpdateStyle ()
+{
+ if (GetHWND())
+ {
+ long lDummy;
+ DWORD dwStyleNew = ConvertToOS2Style( lDummy
+ ,GetWindowStyleFlag()
+ );
+
+ dwStyleNew |= m_lBaseStyle;
+
+ //
+ // Get the current window style.
+ //
+ ULONG dwStyleOld = ::WinQueryWindowULong(GetHWND(), QWL_STYLE);
+
+ //
+ // Only set the window style if the view bits have changed.
+ //
+ if (dwStyleOld != dwStyleNew)
+ {
+ ::WinSetWindowULong(GetHWND(), QWL_STYLE, dwStyleNew);
+ }
+ }
+} // end of wxListCtrl::UpdateStyle
+
+void wxListCtrl::FreeAllInternalData ()
+{
+ if (m_bAnyInternalData)
+ {
+ int n = GetItemCount();
+ int i = 0;
+
+ for (i = 0; i < n; i++)
+ DeleteInternalData(this, (long)i);
+ m_bAnyInternalData = FALSE;
+ }
+} // end of wxListCtrl::FreeAllInternalData
+
+wxListCtrl::~wxListCtrl ()
+{
+ FreeAllInternalData();
+ if (m_pTextCtrl )
+ {
+ m_pTextCtrl->SetHWND(0);
+ m_pTextCtrl->UnsubclassWin();
+ delete m_pTextCtrl;
+ m_pTextCtrl = NULL;
+ }
+
+ if (m_bOwnsImageListNormal)
+ delete m_pImageListNormal;
+ if (m_bOwnsImageListSmall)
+ delete m_pImageListSmall;
+ if (m_bOwnsImageListState)
+ delete m_pImageListState;
+} // end of wxListCtrl::~wxListCtrl
+
+// ----------------------------------------------------------------------------
+// set/get/change style
+// ----------------------------------------------------------------------------
+
+// Add or remove a single window style
+void wxListCtrl::SetSingleStyle (
+ long lStyle
+, bool bAdd
+)
+{
+ long lFlag = GetWindowStyleFlag();
+
+ //
+ // Get rid of conflicting styles
+ //
+ if (bAdd)
+ {
+ if (lStyle & wxLC_MASK_TYPE)
+ lFlag = lFlag & ~wxLC_MASK_TYPE;
+ if (lStyle & wxLC_MASK_ALIGN )
+ lFlag = lFlag & ~wxLC_MASK_ALIGN;
+ if (lStyle & wxLC_MASK_SORT )
+ lFlag = lFlag & ~wxLC_MASK_SORT;
+ }
+ if (lFlag & lStyle)
+ {
+ if (!bAdd)
+ lFlag -= lStyle;
+ }
+ else
+ {
+ if (bAdd)
+ {
+ lFlag |= lStyle;
+ }
+ }
+ m_windowStyle = lFlag;
+ UpdateStyle();
+} // end of wxListCtrl::SetSingleStyle
+
+// Set the whole window style
+void wxListCtrl::SetWindowStyleFlag (
+ long lFlag
+)
+{
+ m_windowStyle = lFlag;
+ UpdateStyle();
+} // end of wxListCtrl::SetWindowStyleFlag
+
+long wxListCtrl::ConvertToOS2Style (
+ long& rOldStyle
+, long lStyle
+) const
+{
+ long lWstyle = 0L;
+
+ //
+ // The only styles OS2 uses on creation are auto arrange, read only, and
+ // and selection styles. This lib does not support OS/2 MINIRECORDCORE
+ // or VERIFYPOINTER styles
+ //
+ if (lStyle & wxLC_AUTOARRANGE)
+ lWstyle |= CCS_AUTOPOSITION;
+ if (lStyle & wxLC_SINGLE_SEL)
+ lWstyle |= CCS_SINGLESEL;
+ else
+ lWstyle |= CCS_EXTENDSEL;
+ if (!(lStyle & wxLC_EDIT_LABELS))
+ lWstyle |= CCS_READONLY;
+ return lWstyle;
+} // end of wxListCtrl::ConvertToOS2Style
+
+long wxListCtrl::ConvertArrangeToOS2Style (
+ long lStyle
+)
+{
+ long lWstyle = 0;
+
+ if (lStyle & wxLC_ALIGN_LEFT)
+ {
+ lWstyle |= CMA_LEFT;
+ }
+
+ if (lStyle & wxLC_ALIGN_TOP)
+ {
+ lWstyle |= CMA_TOP;
+ }
+ return lWstyle;
+} // end of wxListCtrl::ConvertArrangeToOS2Style
+
+long wxListCtrl::ConvertViewToOS2Style (
+ long lStyle
+)
+{
+ long lWstyle = CA_DRAWICON; // we will only use icons
+
+ if (lStyle & wxLC_ICON)
+ {
+ lWstyle |= CV_ICON;
+ }
+ if (lStyle & wxLC_SMALL_ICON)
+ {
+ lWstyle |= (CV_ICON | CV_MINI);
+ }
+ if (lStyle & wxLC_LIST)
+ {
+ lWstyle |= CV_TEXT;
+ }
+ if (lStyle & wxLC_REPORT)
+ {
+ lWstyle |= CV_DETAIL;
+ }
+ if (lStyle & wxLC_VIRTUAL)
+ {
+ lWstyle |= CA_OWNERDRAW;
+ }
+ if (lStyle & wxLC_AUTOARRANGE)
+ {
+ lWstyle |= CV_FLOW;
+ }
+ if (!(lStyle & wxLC_NO_HEADER))
+ {
+ lWstyle |= CA_DETAILSVIEWTITLES;
+ }
+ return lWstyle;
+} // end of wxListCtrl::ConvertViewToOS2Style
+
+// ----------------------------------------------------------------------------
+// accessors
+// ----------------------------------------------------------------------------
+
+// Sets the foreground, i.e. text, colour
+bool wxListCtrl::SetForegroundColour (
+ const wxColour& rCol)
+{
+ ULONG ulColor = wxColourToRGB(rCol);
+
+ if (!wxWindow::SetForegroundColour(rCol))
+ return FALSE;
+
+
+ ::WinSetPresParam( GetHWND()
+ ,PP_FOREGROUNDCOLOR
+ ,sizeof(ULONG)
+ ,&ulColor
+ );
+ return TRUE;
+} // end of wxListCtrl::SetForegroundColour
+
+// Sets the background colour
+bool wxListCtrl::SetBackgroundColour (
+ const wxColour& rCol
+)
+{
+ if (!wxWindow::SetBackgroundColour(rCol))
+ return FALSE;
+
+ //
+ // We set the same colour for both the "empty" background and the items
+ // background
+ //
+ ULONG ulColor = wxColourToRGB(rCol);
+
+ ::WinSetPresParam( GetHWND()
+ ,PP_BACKGROUNDCOLOR
+ ,sizeof(ULONG)
+ ,&ulColor
+ );
+ return TRUE;
+} // end of wxListCtrl::SetBackgroundColour
+
+// Gets information about this column
+bool wxListCtrl::GetColumn (
+ int nCol
+, wxListItem& rItem
+) const
+{
+ PFIELDINFO pFieldInfo = FindOS2ListFieldByColNum ( GetHWND()
+ ,nCol
+ );
+
+ if (!pFieldInfo)
+ return FALSE;
+ rItem.SetWidth(pFieldInfo->cxWidth);
+ if ((rItem.GetMask() & wxLIST_MASK_TEXT) &&
+ (pFieldInfo->flData & CFA_STRING) &&
+ (pFieldInfo->pUserData != NULL))
+ {
+ rItem.SetText((char*)pFieldInfo->pUserData);
+ }
+ if (rItem.GetMask() & wxLIST_MASK_FORMAT )
+ {
+ if (pFieldInfo->flData & CFA_LEFT)
+ rItem.m_format = wxLIST_FORMAT_LEFT;
+ else if (pFieldInfo->flData & CFA_RIGHT)
+ rItem.m_format = wxLIST_FORMAT_RIGHT;
+ else if (pFieldInfo->flData & CFA_CENTER)
+ rItem.m_format = wxLIST_FORMAT_CENTRE;
+ }
+ return TRUE;
+} // end of wxListCtrl::GetColumn
+
+// Sets information about this column
+bool wxListCtrl::SetColumn (
+ int nCol
+, wxListItem& rItem
+)
+{
+ PFIELDINFO pFieldInfo = FindOS2ListFieldByColNum( GetHWND()
+ ,nCol
+ );
+ ConvertToOS2ListCol( nCol
+ ,rItem
+ ,pFieldInfo
+ );
+ //
+ // Since we changed the field pointed to, we invalidate to see the result
+ //
+ ::WinSendMsg(GetHWND(), CM_INVALIDATEDETAILFIELDINFO, NULL, NULL);
+ return TRUE;
+} // end of wxListCtrl::SetColumn
+
+// Gets the column width
+int wxListCtrl::GetColumnWidth (
+ int nCol
+) const
+{
+ PFIELDINFO pFieldInfo = FindOS2ListFieldByColNum ( GetHWND()
+ ,nCol
+ );
+
+ if (!pFieldInfo)
+ return 0;
+ return((int)pFieldInfo->cxWidth);
+} // end of wxListCtrl::GetColumnWidth
+
+// Sets the column width
+bool wxListCtrl::SetColumnWidth (
+ int nCol
+, int nWidth
+)
+{
+ int nCol2 = nCol;
+ int nWidth2 = nWidth;
+
+ if (GetWindowStyleFlag() & wxLC_LIST)
+ nCol2 = -1;
+
+ PFIELDINFO pFieldInfo = FindOS2ListFieldByColNum( GetHWND()
+ ,nCol
+ );
+ pFieldInfo->cxWidth = nWidth;
+ ::WinSendMsg(GetHWND(), CM_INVALIDATEDETAILFIELDINFO, NULL, NULL);
+ return TRUE;
+} // end of wxListCtrl::SetColumnWidth
+
+// Gets the number of items that can fit vertically in the
+// visible area of the list control (list or report view)
+// or the total number of items in the list control (icon
+// or small icon view)
+int wxListCtrl::GetCountPerPage () const
+{
+ QUERYRECORDRECT vQueryRect;
+ CNRINFO vCnrInfo;
+ RECTL vRectRecord;
+ RECTL vRectControl;
+ int nCount;
+
+ if (!::WinSendMsg( GetHWND()
+ ,CM_QUERYCNRINFO
+ ,MPFROMP(&vCnrInfo)
+ ,(MPARAM)(USHORT)sizeof(CNRINFO)
+ ))
+ return 0;
+ memset(&vQueryRect, '\0', sizeof(QUERYRECORDRECT));
+ vQueryRect.cb = sizeof(QUERYRECORDRECT);
+ if (vCnrInfo.flWindowAttr & CV_ICON)
+ vQueryRect.fsExtent = CMA_ICON | CMA_TEXT;
+ else if (vCnrInfo.flWindowAttr & CV_NAME)
+ vQueryRect.fsExtent = CMA_ICON | CMA_TEXT;
+ else if (vCnrInfo.flWindowAttr & CV_TEXT)
+ vQueryRect.fsExtent = CMA_TEXT;
+ else if (vCnrInfo.flWindowAttr & CV_DETAIL)
+ vQueryRect.fsExtent = CMA_TEXT;
+ if (!::WinSendMsg( GetHWND()
+ ,CM_QUERYRECORDRECT
+ ,MPFROMP(&vRectRecord)
+ ,MPFROMP(&vQueryRect)
+ ))
+ return 0;
+ if (!::WinSendMsg( GetHWND()
+ ,CM_QUERYVIEWPORTRECT
+ ,MPFROMP(&vRectControl)
+ ,MPFROM2SHORT(CMA_WINDOW, (USHORT)FALSE)
+ ))
+ return 0;
+ nCount = (int)((int)((vRectControl.xRight - vRectControl.xLeft) / (vRectRecord.xRight - vRectRecord.xLeft)) *
+ (int)((vRectControl.yTop - vRectControl.yBottom) / (vRectRecord.yTop - vRectRecord.yBottom))
+ );
+ if (nCount > (int)vCnrInfo.cFields)
+ nCount = (int)vCnrInfo.cFields;
+ return nCount;
+} // end of wxListCtrl::GetCountPerPage
+
+// Gets the edit control for editing labels.
+wxTextCtrl* wxListCtrl::GetEditControl() const
+{
+ return m_pTextCtrl;
+}
+
+// Gets information about the item
+bool wxListCtrl::GetItem (
+ wxListItem& rInfo
+) const
+{
+ PMYRECORD pRecord = FindOS2ListRecordByID( GetHWND()
+ ,rInfo.GetId()
+ );
+
+ //
+ // Give NULL as hwnd as we already have everything we need
+ //
+ ConvertFromOS2ListItem( NULL
+ ,rInfo
+ ,pRecord
+ );
+ return TRUE;
+} // end of wxListCtrl::GetItem
+
+// Sets information about the item
+bool wxListCtrl::SetItem (
+ wxListItem& rInfo
+)
+{
+ PMYRECORD pRecord = FindOS2ListRecordByID( GetHWND()
+ ,rInfo.GetId()
+ );
+
+ ConvertToOS2ListItem( this
+ ,rInfo
+ ,pRecord
+ );
+
+ //
+ // Check if setting attributes or lParam
+ //
+ if (rInfo.HasAttributes() || (rInfo.GetMask() & wxLIST_MASK_DATA))
+ {
+ //
+ // Get internal item data
+ // perhaps a cache here ?
+ //
+ CListItemInternalData* pData = GetInternalData( this
+ ,rInfo.GetId()
+ );
+
+ if (!pData)
+ {
+ //
+ // Need to set it
+ //
+ m_bAnyInternalData = TRUE;
+ pData = new CListItemInternalData();
+ pRecord->m_ulUserData = (unsigned long)pData;
+ };
+
+ //
+ // User data
+ //
+ if (rInfo.GetMask() & wxLIST_MASK_DATA)
+ pData->m_lParam = (WXLPARAM)rInfo.GetData();
+
+ // attributes
+ if (rInfo.HasAttributes())
+ {
+ if (pData->m_pAttr)
+ *pData->m_pAttr = *rInfo.GetAttributes();
+ else
+ pData->m_pAttr = new wxListItemAttr(*rInfo.GetAttributes());
+ }
+ }
+
+ //
+ // We need to update the item immediately to show the new image
+ //
+ bool bUpdateNow = (rInfo.GetMask() & wxLIST_MASK_IMAGE) != 0;
+
+ //
+ // Check whether it has any custom attributes
+ //
+ if (rInfo.HasAttributes())
+ {
+ m_bHasAnyAttr = TRUE;
+
+ //
+ // If the colour has changed, we must redraw the item
+ //
+ bUpdateNow = TRUE;
+ }
+ ::WinSendMsg( GetHWND()
+ ,CM_INVALIDATERECORD
+ ,MPFROMP(pRecord)
+ ,MPFROM2SHORT(1, CMA_ERASE | CMA_REPOSITION | CMA_TEXTCHANGED)
+ );
+ RefreshItem(pRecord->m_ulItemId);
+ return TRUE;
+} // end of wxListCtrl::SetItem
+
+long wxListCtrl::SetItem (
+ long lIndex
+, int nCol
+, const wxString& rsLabel
+, int nImageId
+)
+{
+ wxListItem vInfo;
+
+ vInfo.m_text = rsLabel;
+ vInfo.m_mask = wxLIST_MASK_TEXT;
+ vInfo.m_itemId = lIndex;
+ vInfo.m_col = nCol;
+ if (nImageId > -1)
+ {
+ vInfo.m_image = nImageId;
+ vInfo.m_mask |= wxLIST_MASK_IMAGE;
+ }
+ return SetItem(vInfo);
+} // end of wxListCtrl::SetItem
+
+// Gets the item state
+int wxListCtrl::GetItemState (
+ long lItem
+, long lStateMask
+) const
+{
+ wxListItem vInfo;
+
+ vInfo.m_mask = wxLIST_MASK_STATE;
+ vInfo.m_stateMask = lStateMask;
+ vInfo.m_itemId = lItem;
+
+ if (!GetItem(vInfo))
+ return 0;
+ return vInfo.m_state;
+} // end of wxListCtrl::GetItemState
+
+// Sets the item state
+bool wxListCtrl::SetItemState (
+ long lItem
+, long lState
+, long lStateMask
+)
+{
+ PMYRECORD pRecord = FindOS2ListRecordByID( GetHWND()
+ ,lItem
+ );
+
+ //
+ // Don't use SetItem() here as it doesn't work with the virtual list
+ // controls
+ //
+ ConvertToOS2Flags( lState
+ ,pRecord
+ );
+
+ //
+ // for the virtual list controls we need to refresh the previously focused
+ // item manually when changing focus without changing selection
+ // programmatically because otherwise it keeps its focus rectangle until
+ // next repaint (yet another comctl32 bug)
+ //
+ long lFocusOld;
+
+ if (IsVirtual() &&
+ (lStateMask & wxLIST_STATE_FOCUSED) &&
+ (lState & wxLIST_STATE_FOCUSED) )
+ {
+ lFocusOld = GetNextItem( -1
+ ,wxLIST_NEXT_ALL
+ ,wxLIST_STATE_FOCUSED
+ );
+ }
+ else
+ {
+ lFocusOld = -1;
+ }
+ ::WinSendMsg( GetHWND()
+ ,CM_INVALIDATERECORD
+ ,MPFROMP(pRecord)
+ ,MPFROM2SHORT(1, CMA_ERASE | CMA_REPOSITION | CMA_TEXTCHANGED)
+ );
+
+ if (lFocusOld != -1)
+ {
+ //
+ // No need to refresh the item if it was previously selected, it would
+ // only result in annoying flicker
+ //
+ if (!(GetItemState( lFocusOld
+ ,wxLIST_STATE_SELECTED
+ ) & wxLIST_STATE_SELECTED))
+ {
+ RefreshItem(lFocusOld);
+ }
+ }
+ return TRUE;
+} // end of wxListCtrl::SetItemState
+
+// Sets the item image
+bool wxListCtrl::SetItemImage (
+ long lItem
+, int nImage
+, int WXUNUSED(nSelImage))
+{
+ wxListItem vInfo;
+
+ vInfo.m_mask = wxLIST_MASK_IMAGE;
+ vInfo.m_image = nImage;
+ vInfo.m_itemId = lItem;
+ return SetItem(vInfo);
+} // end of wxListCtrl::SetItemImage
+
+// Gets the item text
+wxString wxListCtrl::GetItemText (
+ long lItem
+) const
+{
+ wxListItem vInfo;
+
+ vInfo.m_mask = wxLIST_MASK_TEXT;
+ vInfo.m_itemId = lItem;
+
+ if (!GetItem(vInfo))
+ return wxEmptyString;
+ return vInfo.m_text;
+} // end of wxListCtrl::GetItemText
+
+// Sets the item text
+void wxListCtrl::SetItemText (
+ long lItem
+, const wxString& rsStr
+)
+{
+ wxListItem vInfo;
+
+ vInfo.m_mask = wxLIST_MASK_TEXT;
+ vInfo.m_itemId = lItem;
+ vInfo.m_text = rsStr;
+ SetItem(vInfo);
+} // end of wxListCtrl::SetItemText
+
+// Gets the item data
+long wxListCtrl::GetItemData (
+ long lItem
+) const
+{
+ wxListItem vInfo;
+
+ vInfo.m_mask = wxLIST_MASK_DATA;
+ vInfo.m_itemId = lItem;
+ if (!GetItem(vInfo))
+ return 0;
+ return vInfo.m_data;
+} // end of wxListCtrl::GetItemData
+
+// Sets the item data
+bool wxListCtrl::SetItemData (
+ long lItem
+, long lData
+)
+{
+ wxListItem vInfo;
+
+ vInfo.m_mask = wxLIST_MASK_DATA;
+ vInfo.m_itemId = lItem;
+ vInfo.m_data = lData;
+ return SetItem(vInfo);
+} // end of wxListCtrl::SetItemData
+
+// Gets the item rectangle
+bool wxListCtrl::GetItemRect (
+ long lItem
+, wxRect& rRect
+, int nCode
+) const
+{
+ bool bSuccess;
+ PMYRECORD pRecord = FindOS2ListRecordByID( GetHWND()
+ ,lItem
+ );
+ QUERYRECORDRECT vQueryRect;
+ RECTL vRect;
+ int nHeight;
+
+ if (!pRecord)
+ return FALSE;
+ vQueryRect.cb = sizeof(QUERYRECORDRECT);
+ vQueryRect.pRecord = &pRecord->m_vRecord;
+ vQueryRect.fRightSplitWindow = TRUE;
+ vQueryRect.fsExtent = CMA_ICON | CMA_TEXT;
+ ::WinSendMsg( GetHWND()
+ ,CM_QUERYRECORDRECT
+ ,MPFROMP(&vRect)
+ ,MPFROMP(&vQueryRect)
+ );
+ //
+ // remember OS/2 is backwards
+ //
+ GetClientSize( NULL
+ ,&nHeight
+ );
+ rRect.x = vRect.xLeft;
+ rRect.y = nHeight - vRect.yTop;
+ rRect.width = vRect.xRight;
+ rRect.height = nHeight - vRect.yBottom;
+ bSuccess = TRUE;
+ return bSuccess;
+} // end of wxListCtrl::GetItemRect
+
+// Gets the item position
+bool wxListCtrl::GetItemPosition (
+ long lItem
+, wxPoint& rPos
+) const
+{
+ bool bSuccess;
+ PMYRECORD pRecord = FindOS2ListRecordByID( GetHWND()
+ ,lItem
+ );
+ QUERYRECORDRECT vQueryRect;
+ RECTL vRect;
+ int nHeight;
+
+ if (!pRecord)
+ return FALSE;
+ vQueryRect.cb = sizeof(QUERYRECORDRECT);
+ vQueryRect.pRecord = &pRecord->m_vRecord;
+ vQueryRect.fRightSplitWindow = TRUE;
+ vQueryRect.fsExtent = CMA_ICON | CMA_TEXT;
+ ::WinSendMsg( GetHWND()
+ ,CM_QUERYRECORDRECT
+ ,MPFROMP(&vRect)
+ ,MPFROMP(&vQueryRect)
+ );
+ //
+ // remember OS/2 is backwards
+ //
+ GetClientSize( NULL
+ ,&nHeight
+ );
+ rPos.x = vRect.xLeft;
+ rPos.y = nHeight - vRect.yTop;
+ bSuccess = TRUE;
+ return bSuccess;
+} // end of wxListCtrl::GetItemPosition
+
+// Sets the item position.
+bool wxListCtrl::SetItemPosition (
+ long lItem
+, const wxPoint& rPos
+)
+{
+ //
+ // Items cannot be positioned in X/Y coord in OS/2
+ //
+ return FALSE;
+} // end of wxListCtrl::SetItemPosition
+
+// Gets the number of items in the list control
+int wxListCtrl::GetItemCount () const
+{
+ CNRINFO vCnrInfo;
+
+ if (!::WinSendMsg( GetHWND()
+ ,CM_QUERYCNRINFO
+ ,MPFROMP(&vCnrInfo)
+ ,(MPARAM)(USHORT)sizeof(CNRINFO)
+ ))
+ return -1;
+ return vCnrInfo.cRecords;
+} // end of wxListCtrl::GetItemCount
+
+// Retrieves the spacing between icons in pixels.
+// If small is TRUE, gets the spacing for the small icon
+// view, otherwise the large icon view.
+int wxListCtrl::GetItemSpacing (
+ bool bIsSmall
+) const
+{
+ CNRINFO vCnrInfo;
+
+ if (!::WinSendMsg( GetHWND()
+ ,CM_QUERYCNRINFO
+ ,MPFROMP(&vCnrInfo)
+ ,(MPARAM)(USHORT)sizeof(CNRINFO)
+ ))
+ return -1;
+ return vCnrInfo.cyLineSpacing;
+} // end of wxListCtrl::GetItemSpacing
+
+void wxListCtrl::SetItemTextColour (
+ long lItem
+, const wxColour& rCol
+)
+{
+ wxListItem vInfo;
+
+ vInfo.m_itemId = lItem;
+ vInfo.SetTextColour(rCol);
+ SetItem(vInfo);
+} // end of wxListCtrl::SetItemTextColour
+
+wxColour wxListCtrl::GetItemTextColour (
+ long lItem
+) const
+{
+ wxListItem vInfo;
+
+ vInfo.m_itemId = lItem;
+ GetItem(vInfo);
+ return vInfo.GetTextColour();
+} // end of wxListCtrl::GetItemTextColour
+
+void wxListCtrl::SetItemBackgroundColour (
+ long lItem
+, const wxColour& rCol
+)
+{
+ wxListItem vInfo;
+
+ vInfo.m_itemId = lItem;
+ vInfo.SetBackgroundColour(rCol);
+ SetItem(vInfo);
+} // end of wxListCtrl::SetItemBackgroundColour
+
+wxColour wxListCtrl::GetItemBackgroundColour (
+ long lItem
+) const
+{
+ wxListItem vInfo;
+
+ vInfo.m_itemId = lItem;
+ GetItem(vInfo);
+ return vInfo.GetBackgroundColour();
+} // end of wxListCtrl::GetItemBackgroundColour
+
+// Gets the number of selected items in the list control
+int wxListCtrl::GetSelectedItemCount () const
+{
+ PMYRECORD pRecord = NULL;
+ int nCount = 0;
+ pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( GetHWND()
+ ,CM_QUERYRECORDEMPHASIS
+ ,(MPARAM)CMA_FIRST
+ ,(MPARAM)CRA_SELECTED
+ ));
+ if (pRecord)
+ nCount++;
+ else
+ return 0;
+ while (pRecord)
+ {
+ pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( GetHWND()
+ ,CM_QUERYRECORDEMPHASIS
+ ,MPFROMP(pRecord)
+ ,(MPARAM)CRA_SELECTED
+ ));
+ if (pRecord)
+ nCount++;
+ }
+ return nCount;
+} // end of wxListCtrl::GetSelectedItemCount
+
+// Gets the text colour of the listview
+wxColour wxListCtrl::GetTextColour () const
+{
+ wxColour vCol;
+ ULONG ulColor;
+
+ ::WinQueryPresParam( GetHWND()
+ ,PP_FOREGROUNDCOLOR
+ ,0
+ ,NULL
+ ,sizeof(ULONG)
+ ,&ulColor
+ ,QPF_PURERGBCOLOR
+ );
+ vCol.Set(ulColor);
+ return vCol;
+} // end of wxListCtrl::GetTextColour
+
+// Sets the text colour of the listview
+void wxListCtrl::SetTextColour (
+ const wxColour& rCol
+)
+{
+ ULONG ulColor = wxColourToRGB(rCol);
+
+ ::WinSetPresParam( GetHWND()
+ ,PP_FOREGROUNDCOLOR
+ ,sizeof(ULONG)
+ ,&ulColor
+ );
+} // end of wxListCtrl::SetTextColour
+
+// Gets the index of the topmost visible item when in
+// list or report view
+long wxListCtrl::GetTopItem () const
+{
+ PMYRECORD pRecord = NULL;
+ QUERYRECFROMRECT vQueryRect;
+ RECTL vRect;
+
+ ::WinSendMsg( GetHWND()
+ ,CM_QUERYVIEWPORTRECT
+ ,MPFROMP(&vRect)
+ ,MPFROM2SHORT(CMA_WINDOW, TRUE)
+ );
+ vQueryRect.cb = sizeof(QUERYRECFROMRECT);
+ vQueryRect.rect = vRect;
+ vQueryRect.fsSearch = CMA_PARTIAL;
+
+ pRecord = (PMYRECORD)::WinSendMsg( GetHWND()
+ ,CM_QUERYRECORDFROMRECT
+ ,(MPARAM)CMA_FIRST
+ ,MPFROMP(&vQueryRect)
+ );
+
+ if (!pRecord)
+ return -1L;
+ return (long)pRecord->m_ulItemId;
+} // end of wxListCtrl::GetTopItem
+
+// Searches for an item, starting from 'item'.
+// 'geometry' is one of
+// wxLIST_NEXT_ABOVE/ALL/BELOW/LEFT/RIGHT.
+// 'state' is a state bit flag, one or more of
+// wxLIST_STATE_DROPHILITED/FOCUSED/SELECTED/CUT.
+// item can be -1 to find the first item that matches the
+// specified flags.
+// Returns the item or -1 if unsuccessful.
+long wxListCtrl::GetNextItem (
+ long lItem
+, int WXUNUSED(nGeom)
+, int WXUNUSED(nState)
+) const
+{
+ PMYRECORD pRecord = FindOS2ListRecordByID( GetHWND()
+ ,lItem
+ );
+
+ pRecord = (PMYRECORD)pRecord->m_vRecord.preccNextRecord;
+ if (pRecord)
+ return((long)pRecord->m_ulItemId);
+ return -1L;
+} // end of wxListCtrl::GetNextItem
+
+wxImageList* wxListCtrl::GetImageList (
+ int nWhich
+) const
+{
+ if (nWhich == wxIMAGE_LIST_NORMAL )
+ {
+ return m_pImageListNormal;
+ }
+ else if (nWhich == wxIMAGE_LIST_SMALL )
+ {
+ return m_pImageListSmall;
+ }
+ else if (nWhich == wxIMAGE_LIST_STATE )
+ {
+ return m_pImageListState;
+ }
+ return NULL;
+} // end of wxListCtrl::GetImageList
+
+void wxListCtrl::SetImageList (
+ wxImageList* pImageList
+, int nWhich
+)
+{
+ if (nWhich == wxIMAGE_LIST_NORMAL)
+ {
+ if (m_bOwnsImageListNormal)
+ delete m_pImageListNormal;
+ m_pImageListNormal = pImageList;
+ m_bOwnsImageListNormal = FALSE;
+ }
+ else if (nWhich == wxIMAGE_LIST_SMALL)
+ {
+ if (m_bOwnsImageListSmall)
+ delete m_pImageListSmall;
+ m_pImageListSmall = pImageList;
+ m_bOwnsImageListSmall = FALSE;
+ }
+ else if (nWhich == wxIMAGE_LIST_STATE)
+ {
+ if (m_bOwnsImageListState)
+ delete m_pImageListState;
+ m_pImageListState = pImageList;
+ m_bOwnsImageListState = FALSE;
+ }
+} // end of wxListCtrl::SetImageList
+
+void wxListCtrl::AssignImageList (
+ wxImageList* pImageList
+, int nWhich
+)
+{
+ SetImageList( pImageList
+ ,nWhich
+ );
+ if (nWhich == wxIMAGE_LIST_NORMAL )
+ m_bOwnsImageListNormal = TRUE;
+ else if (nWhich == wxIMAGE_LIST_SMALL )
+ m_bOwnsImageListSmall = TRUE;
+ else if (nWhich == wxIMAGE_LIST_STATE )
+ m_bOwnsImageListState = TRUE;
+} // end of wxListCtrl::AssignImageList
+
+// ----------------------------------------------------------------------------
+// Operations
+// ----------------------------------------------------------------------------
+
+// Arranges the items
+bool wxListCtrl::Arrange (
+ int nFlag
+)
+{
+ ULONG ulType = 0L;
+ ULONG ulFlags = 0L;
+
+ if (nFlag == wxLIST_ALIGN_SNAP_TO_GRID)
+ {
+ ulType = CMA_ARRANGEGRID;
+ if (nFlag == wxLIST_ALIGN_LEFT)
+ ulFlags |= CMA_LEFT;
+ else if (nFlag == wxLIST_ALIGN_TOP)
+ ulFlags |= CMA_TOP;
+ else if (nFlag == wxLIST_ALIGN_DEFAULT)
+ ulFlags |= CMA_LEFT;
+ }
+ else
+ ulType = CMA_ARRANGESTANDARD;
+ ::WinSendMsg( GetHWND()
+ ,CM_ARRANGE
+ ,(MPARAM)ulType
+ ,(MPARAM)ulFlags
+ );
+ //
+ // We do not support CMA_ARRANGESELECTED
+ //
+ return TRUE;
+} // end of wxListCtrl::Arrange
+
+// Deletes an item
+bool wxListCtrl::DeleteItem (
+ long lItem
+)
+{
+ PMYRECORD pRecord = FindOS2ListRecordByID( GetHWND()
+ ,lItem
+ );
+ if (LONGFROMMR(::WinSendMsg( GetHWND()
+ ,CM_REMOVERECORD
+ ,(MPARAM)pRecord
+ ,MPFROM2SHORT(1, CMA_FREE)
+ )) == -1L)
+ {
+ return FALSE;
+ }
+
+ //
+ // The virtual list control doesn't refresh itself correctly, help it
+ //
+ if (IsVirtual())
+ {
+ //
+ // We need to refresh all the lines below the one which was deleted
+ //
+ wxRect vRectItem;
+
+ if (lItem > 0 && GetItemCount())
+ {
+ GetItemRect( lItem - 1
+ ,vRectItem
+ );
+ }
+ else
+ {
+ vRectItem.y = vRectItem.height = 0;
+ }
+ wxRect vRectWin = GetRect();
+
+ vRectWin.height = vRectWin.GetBottom() - vRectItem.GetBottom();
+ vRectWin.y = vRectItem.GetBottom();
+ RefreshRect(vRectWin);
+ }
+ return TRUE;
+} // end of wxListCtrl::DeleteItem
+
+// Deletes all items
+bool wxListCtrl::DeleteAllItems ()
+{
+ return((LONG)::WinSendMsg( GetHWND()
+ ,CM_REMOVERECORD
+ ,NULL
+ ,MPFROM2SHORT(0, CMA_FREE)
+ ) != -1L);
+} // end of wxListCtrl::DeleteAllItems
+
+// Deletes all items
+bool wxListCtrl::DeleteAllColumns ()
+{
+ while (m_nColCount > 0)
+ {
+ DeleteColumn(m_nColCount - 1);
+ m_nColCount--;
+ }
+
+ wxASSERT_MSG(m_nColCount == 0, wxT("no columns should be left"));
+ return TRUE;
+} // end of wxListCtrl::DeleteAllColumns
+
+// Deletes a column
+bool wxListCtrl::DeleteColumn (
+ int nCol
+)
+{
+ bool bSuccess = FALSE;
+ PFIELDINFO pField = FindOS2ListFieldByColNum( GetHWND()
+ ,nCol
+ );
+ bSuccess = ((LONG)::WinSendMsg( GetHWND()
+ ,CM_REMOVEDETAILFIELDINFO
+ ,MPFROMP(pField)
+ ,MPFROM2SHORT((SHORT)1, CMA_FREE)
+ ) == -1L);
+ if (bSuccess && (m_nColCount > 0))
+ m_nColCount--;
+ return bSuccess;
+} // end of wxListCtrl::DeleteColumn
+
+// Clears items, and columns if there are any.
+void wxListCtrl::ClearAll ()
+{
+ DeleteAllItems();
+ if (m_nColCount > 0)
+ DeleteAllColumns();
+} // end of wxListCtrl::ClearAll
+
+//
+// OS/2 does not use a text control for its container labels. You merely
+// "open" a record for editting.
+//
+wxTextCtrl* wxListCtrl::EditLabel (
+ long lItem
+, wxClassInfo* WXUNUSED(pTextControlClass)
+)
+{
+ CNREDITDATA vEdit;
+ PMYRECORD pRecord = FindOS2ListRecordByID( GetHWND()
+ ,lItem
+ );
+
+ vEdit.cb = sizeof(CNREDITDATA);
+ vEdit.hwndCnr = GetHWND();
+ vEdit.pRecord = &pRecord->m_vRecord;
+ vEdit.pFieldInfo = NULL;
+ vEdit.ppszText = NULL;
+ vEdit.cbText = 0;
+ vEdit.id = 0;
+
+ ::WinSendMsg( GetHWND()
+ ,CM_OPENEDIT
+ ,MPFROMP(&vEdit)
+ ,(MPARAM)0
+ );
+ return m_pTextCtrl;
+} // end of wxListCtrl::EditLabel
+
+// End label editing, optionally cancelling the edit. Under OS/2 you close
+// the record for editting
+bool wxListCtrl::EndEditLabel (
+ bool WXUNUSED(bCancel)
+)
+{
+ ::WinSendMsg( GetHWND()
+ ,CM_CLOSEEDIT
+ ,(MPARAM)0
+ ,(MPARAM)0
+ );
+ return TRUE;
+} // end of wxListCtrl::EndEditLabel
+
+// Ensures this item is visible
+bool wxListCtrl::EnsureVisible (
+ long lItem
+)
+{
+ PMYRECORD pRecord = FindOS2ListRecordByID( GetHWND()
+ ,lItem
+ );
+ ::WinSendMsg( GetHWND()
+ ,CM_INVALIDATERECORD
+ ,MPFROMP(pRecord)
+ ,MPFROM2SHORT((SHORT)1, CMA_NOREPOSITION)
+ );
+ return TRUE;
+} // end of wxListCtrl::EnsureVisible
+
+// Find an item whose label matches this string, starting from the item after 'start'
+// or the beginning if 'start' is -1.
+long wxListCtrl::FindItem (
+ long lStart
+, const wxString& rsStr
+, bool bPartial
+)
+{
+ CNRINFO vCnrInfo;
+ SEARCHSTRING vSearch;
+ PMYRECORD pRecord = FindOS2ListRecordByID( GetHWND()
+ ,lStart
+ );
+ ULONG ulFlag;
+
+
+ if (!::WinSendMsg( GetHWND()
+ ,CM_QUERYCNRINFO
+ ,MPFROMP(&vCnrInfo)
+ ,(MPARAM)(USHORT)sizeof(CNRINFO)
+ ))
+ return -1L;
+
+ if (vCnrInfo.flWindowAttr & CV_ICON)
+ ulFlag = CV_ICON;
+ if (vCnrInfo.flWindowAttr & CV_NAME)
+ ulFlag = CV_NAME;
+ if (vCnrInfo.flWindowAttr & CV_TEXT)
+ ulFlag = CV_TEXT;
+ if (vCnrInfo.flWindowAttr & CV_DETAIL)
+ ulFlag = CV_DETAIL;
+ if (!bPartial)
+ ulFlag |= CV_EXACTLENGTH;
+
+ vSearch.cb = sizeof(SEARCHSTRING);
+ vSearch.pszSearch = (char*)rsStr.c_str();
+ vSearch.fsPrefix = TRUE;
+ vSearch.fsCaseSensitive = TRUE;
+ vSearch.usView = ulFlag;
+
+ if (lStart == -1)
+ {
+ pRecord = (PMYRECORD)::WinSendMsg( GetHWND()
+ ,CM_SEARCHSTRING
+ ,MPFROMP(&vSearch)
+ ,(MPARAM)CMA_FIRST
+ );
+ }
+ else
+ {
+ pRecord = (PMYRECORD)::WinSendMsg( GetHWND()
+ ,CM_SEARCHSTRING
+ ,MPFROMP(&vSearch)
+ ,MPFROMP(pRecord)
+ );
+ }
+ if (!pRecord)
+ return -1L;
+ return pRecord->m_ulItemId;
+} // end of wxListCtrl::FindItem
+
+// Find an item whose data matches this data, starting from the item after 'start'
+// or the beginning if 'start' is -1.
+long wxListCtrl::FindItem (
+ long lStart
+, long lData
+)
+{
+ long lIdx = lStart + 1;
+ long lCount = GetItemCount();
+
+ while (lIdx < lCount)
+ {
+ if (GetItemData(lIdx) == lData)
+ return lIdx;
+ lIdx++;
+ };
+ return -1;
+} // end of wxListCtrl::FindItem
+
+// Find an item nearest this position in the specified direction, starting from
+// the item after 'start' or the beginning if 'start' is -1.
+long wxListCtrl::FindItem (
+ long lStart
+, const wxPoint& rPoint
+, int nDirection
+)
+{
+ RECTL vRect;
+ QUERYRECORDRECT vQueryRect;
+ PMYRECORD pRecord = FindOS2ListRecordByID( GetHWND()
+ ,lStart
+ );
+ CNRINFO vCnrInfo;
+ ULONG i;
+ wxRect vLibRect;
+
+ if (!::WinSendMsg( GetHWND()
+ ,CM_QUERYCNRINFO
+ ,MPFROMP(&vCnrInfo)
+ ,(MPARAM)(USHORT)sizeof(CNRINFO)
+ ))
+ return -1L;
+
+ vQueryRect.cb = sizeof(QUERYRECORDRECT);
+ vQueryRect.pRecord = &pRecord->m_vRecord;
+ vQueryRect.fRightSplitWindow = TRUE;
+ vQueryRect.fsExtent = CMA_ICON | CMA_TEXT;
+
+ ::WinSendMsg( GetHWND()
+ ,CM_QUERYRECORDRECT
+ ,MPFROMP(&vRect)
+ ,MPFROMP(&vQueryRect)
+ );
+ vLibRect.SetLeft(vRect.xLeft);
+ vLibRect.SetTop(vRect.yTop);
+ vLibRect.SetRight(vRect.xRight);
+ vLibRect.SetBottom(vRect.yBottom);
+ if (vLibRect.Inside(rPoint))
+ return pRecord->m_ulItemId;
+
+ for (i = lStart + 1; i < vCnrInfo.cRecords; i++)
+ {
+ pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( GetHWND()
+ ,CM_QUERYRECORD
+ ,MPFROMP(pRecord)
+ ,MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER)
+ ));
+ vQueryRect.pRecord = (PRECORDCORE)pRecord;
+ ::WinSendMsg( GetHWND()
+ ,CM_QUERYRECORDRECT
+ ,MPFROMP(&vRect)
+ ,MPFROMP(&vQueryRect)
+ );
+ vLibRect.SetLeft(vRect.xLeft);
+ vLibRect.SetTop(vRect.yTop);
+ vLibRect.SetRight(vRect.xRight);
+ vLibRect.SetBottom(vRect.yBottom);
+ if (vLibRect.Inside(rPoint))
+ return pRecord->m_ulItemId;
+ }
+ return -1L;
+} // end of wxListCtrl::FindItem
+
+// Determines which item (if any) is at the specified point,
+// giving details in 'flags' (see wxLIST_HITTEST_... flags above)
+long wxListCtrl::HitTest (
+ const wxPoint& rPoint
+, int& WXUNUSED(rFlags)
+)
+{
+ PMYRECORD pRecord = NULL;
+ QUERYRECFROMRECT vQueryRect;
+ RECTL vRect;
+ long lHeight;
+
+ //
+ // Get height for OS/2 point conversion
+ //
+ ::WinSendMsg( GetHWND()
+ ,CM_QUERYVIEWPORTRECT
+ ,MPFROMP(&vRect)
+ ,MPFROM2SHORT(CMA_WINDOW, TRUE)
+ );
+ lHeight = vRect.yTop - vRect.yBottom;
+
+ //
+ // For now just try and get a record in the general vicinity and forget
+ // the flag
+ //
+ vRect.xLeft = rPoint.x - 2;
+ vRect.xRight = rPoint.x + 2;
+ vRect.yTop = (lHeight - rPoint.y) + 2;
+ vRect.yBottom = (lHeight - rPoint.y) - 2;
+
+ vQueryRect.cb = sizeof(QUERYRECFROMRECT);
+ vQueryRect.rect = vRect;
+ vQueryRect.fsSearch = CMA_PARTIAL;
+
+ pRecord = (PMYRECORD)::WinSendMsg( GetHWND()
+ ,CM_QUERYRECORDFROMRECT
+ ,(MPARAM)CMA_FIRST
+ ,MPFROMP(&vQueryRect)
+ );
+
+ if (!pRecord)
+ return -1L;
+ return pRecord->m_ulItemId;
+} // end of wxListCtrl::HitTest
+
+// Inserts an item, returning the index of the new item if successful,
+// -1 otherwise.
+long wxListCtrl::InsertItem (
+ wxListItem& rInfo
+)
+{
+ wxASSERT_MSG( !IsVirtual(), _T("can't be used with virtual controls") );
+
+ PMYRECORD pRecordAfter = FindOS2ListRecordByID ( GetHWND()
+ ,rInfo.GetId() - 1
+ );
+ PMYRECORD pRecord = (PMYRECORD)::WinSendMsg( GetHWND()
+ ,CM_ALLOCRECORD
+ ,MPFROMLONG(sizeof(MYRECORD) - sizeof(RECORDCORE))
+ ,MPFROMLONG(1)
+ );
+ RECORDINSERT vInsert;
+
+ vInsert.cb = sizeof(RECORDINSERT);
+ vInsert.pRecordOrder = (PRECORDCORE)pRecordAfter;
+ vInsert.pRecordParent = NULL;
+ vInsert.fInvalidateRecord = TRUE;
+ vInsert.zOrder = CMA_TOP;
+ vInsert.cRecordsInsert = 1;
+
+ ConvertToOS2ListItem( this
+ ,rInfo
+ ,pRecord
+ );
+
+ //
+ // Check wether we need to allocate our internal data
+ //
+ bool bNeedInternalData = ((rInfo.GetMask() & wxLIST_MASK_DATA) ||
+ rInfo.HasAttributes()
+ );
+ if (bNeedInternalData)
+ {
+ m_bAnyInternalData = TRUE;
+
+ //
+ // Internal stucture that manages data
+ //
+ CListItemInternalData* pData = new CListItemInternalData();
+
+ pRecord->m_ulUserData = (unsigned long)pData;
+ if (rInfo.GetMask() & wxLIST_MASK_DATA)
+ pData->m_lParam = (WXLPARAM)rInfo.GetData();
+
+ //
+ // Check whether it has any custom attributes
+ //
+ if (rInfo.HasAttributes())
+ {
+ //
+ // Take copy of attributes
+ //
+ pData->m_pAttr = new wxListItemAttr(*rInfo.GetAttributes());
+ }
+ }
+ ::WinSendMsg( GetHWND()
+ ,CM_INSERTRECORD
+ ,MPFROMP(pRecord)
+ ,MPFROMP(pRecordAfter)
+ );
+ //
+ // OS/2 must mannually bump the index's of following records
+ //
+ BumpRecordIds( GetHWND()
+ ,pRecord
+ );
+ return pRecord->m_ulItemId;
+} // end of wxListCtrl::InsertItem
+
+long wxListCtrl::InsertItem (
+ long lIndex
+, const wxString& rsLabel
+)
+{
+ wxListItem vInfo;
+
+ vInfo.m_text = rsLabel;
+ vInfo.m_mask = wxLIST_MASK_TEXT;
+ vInfo.m_itemId = lIndex;
+ return InsertItem(vInfo);
+} // end of wxListCtrl::InsertItem
+
+// Inserts an image item
+long wxListCtrl::InsertItem (
+ long lIndex
+, int nImageIndex
+)
+{
+ wxListItem vInfo;
+
+ vInfo.m_image = nImageIndex;
+ vInfo.m_mask = wxLIST_MASK_IMAGE;
+ vInfo.m_itemId = lIndex;
+ return InsertItem(vInfo);
+} // end of wxListCtrl::InsertItem
+
+// Inserts an image/string item
+long wxListCtrl::InsertItem (
+ long lIndex
+, const wxString& rsLabel
+, int nImageIndex
+)
+{
+ wxListItem vInfo;
+
+ vInfo.m_image = nImageIndex;
+ vInfo.m_text = rsLabel;
+ vInfo.m_mask = wxLIST_MASK_IMAGE | wxLIST_MASK_TEXT;
+ vInfo.m_itemId = lIndex;
+ return InsertItem(vInfo);
+} // end of wxListCtrl::InsertItem
+
+// For details view mode (only), inserts a column.
+long wxListCtrl::InsertColumn (
+ long lCol
+, wxListItem& rItem
+)
+{
+ bool bSuccess;
+ PFIELDINFO pField = (PFIELDINFO)::WinSendMsg( GetHWND()
+ ,CM_ALLOCDETAILFIELDINFO
+ ,MPFROMLONG(1)
+ ,NULL
+ );
+ PFIELDINFO pFieldAfter = FindOS2ListFieldByColNum ( GetHWND()
+ ,lCol - 1
+ );
+ FIELDINFOINSERT vInsert;
+
+ vInsert.cb = sizeof(FIELDINFOINSERT);
+ vInsert.pFieldInfoOrder = pFieldAfter;
+ vInsert.fInvalidateFieldInfo = TRUE;
+ vInsert.cFieldInfoInsert = 1;
+
+ ConvertToOS2ListCol ( lCol
+ ,rItem
+ ,pField
+ );
+ bSuccess = ::WinSendMsg( GetHWND()
+ ,CM_INSERTDETAILFIELDINFO
+ ,MPFROMP(pField)
+ ,MPFROMP(&vInsert)
+ ) != (MRESULT)0;
+ return bSuccess;
+} // end of wxListCtrl::InsertColumn
+
+long wxListCtrl::InsertColumn (
+ long lCol
+, const wxString& rsHeading
+, int nFormat
+, int nWidth
+)
+{
+ wxListItem vItem;
+
+ vItem.m_mask = wxLIST_MASK_TEXT | wxLIST_MASK_FORMAT;
+ vItem.m_text = rsHeading;
+ if (nWidth > -1)
+ {
+ vItem.m_mask |= wxLIST_MASK_WIDTH;
+ vItem.m_width = nWidth;
+ }
+ vItem.m_format = nFormat;
+
+ return InsertColumn( lCol
+ ,vItem
+ );
+} // end of wxListCtrl::InsertColumn
+
+// scroll the control by the given number of pixels (exception: in list view,
+// dx is interpreted as number of columns)
+bool wxListCtrl::ScrollList (
+ int nDx
+, int nDy
+)
+{
+ if (nDx > 0)
+ ::WinSendMsg( GetHWND()
+ ,CM_SCROLLWINDOW
+ ,(MPARAM)CMA_HORIZONTAL
+ ,(MPARAM)nDx
+ );
+ if (nDy > 0)
+ ::WinSendMsg( GetHWND()
+ ,CM_SCROLLWINDOW
+ ,(MPARAM)CMA_VERTICAL
+ ,(MPARAM)nDy
+ );
+ return TRUE;
+} // end of wxListCtrl::ScrollList
+
+bool wxListCtrl::SortItems (
+ wxListCtrlCompare fn
+, long lData
+)
+{
+ SInternalDataSort vInternalData;
+
+ vInternalData.m_fnUser = fn;
+ vInternalData.m_lData = lData;
+
+ // WPARAM cast is needed for mingw/cygwin
+ if (!::WinSendMsg( GetHWND()
+ ,CM_SORTRECORD
+ ,(PFN)InternalDataCompareFunc
+ ,(PVOID)&vInternalData
+ ))
+ {
+ wxLogDebug(_T("CM_SORTRECORD failed"));
+ return FALSE;
+ }
+ return TRUE;
+} // end of wxListCtrl::SortItems
+
+// ----------------------------------------------------------------------------
+// message processing
+// ----------------------------------------------------------------------------
+
+bool wxListCtrl::OS2Command (
+ WXUINT uCmd
+, WXWORD wId
+)
+{
+ if (uCmd == CN_ENDEDIT)
+ {
+ wxCommandEvent vEvent( wxEVT_COMMAND_TEXT_UPDATED
+ ,wId
+ );
+
+ vEvent.SetEventObject( this );
+ ProcessCommand(vEvent);
+ return TRUE;
+ }
+ else if (uCmd == CN_KILLFOCUS)
+ {
+ wxCommandEvent vEvent( wxEVT_KILL_FOCUS
+ ,wId
+ );
+ vEvent.SetEventObject( this );
+ ProcessCommand(vEvent);
+ return TRUE;
+ }
+ else
+ return FALSE;
+} // end of wxListCtrl::OS2Command
+
+// Necessary for drawing hrules and vrules, if specified
+void wxListCtrl::OnPaint (
+ wxPaintEvent& rEvent
+)
+{
+ wxPaintDC vDc(this);
+ wxPen vPen(wxSystemSettings::GetColour( wxSYS_COLOUR_3DLIGHT)
+ ,1
+ ,wxSOLID
+ );
+ wxSize vClientSize = GetClientSize();
+ wxRect vItemRect;
+ int nItemCount = GetItemCount();
+ int nCy = 0;
+ int i;
+ bool bDrawHRules = ((GetWindowStyle() & wxLC_HRULES) != 0);
+ bool bDrawVRules = ((GetWindowStyle() & wxLC_VRULES) != 0);
+
+ wxControl::OnPaint(rEvent);
+
+ //
+ // Reset the device origin since it may have been set
+ //
+ vDc.SetDeviceOrigin(0, 0);
+ if (!bDrawHRules && !bDrawVRules)
+ return;
+ if ((GetWindowStyle() & wxLC_REPORT) == 0)
+ return;
+ vDc.SetPen(vPen);
+ vDc.SetBrush(*wxTRANSPARENT_BRUSH);
+
+ if (bDrawHRules)
+ {
+ long lTop = GetTopItem();
+
+ for (i = lTop; i < lTop + GetCountPerPage() + 1; i++)
+ {
+ if (GetItemRect( i
+ ,vItemRect
+ ))
+ {
+ nCy = vItemRect.GetTop();
+ if (i != 0) // Don't draw the first one
+ {
+ vDc.DrawLine( 0
+ ,nCy
+ ,vClientSize.x
+ ,nCy
+ );
+ }
+ // Draw last line
+ if (i == nItemCount - 1)
+ {
+ nCy = vItemRect.GetBottom();
+ vDc.DrawLine( 0
+ ,nCy
+ ,vClientSize.x
+ ,nCy
+ );
+ }
+ }
+ }
+ }
+ i = nItemCount - 1;
+ if (bDrawVRules && (i > -1))
+ {
+ wxRect vFirstItemRect;
+
+ GetItemRect( 0
+ ,vFirstItemRect
+ );
+ if (GetItemRect( i
+ ,vItemRect
+ ))
+ {
+ int nCol;
+ int nX = vItemRect.GetX();
+
+ for (nCol = 0; nCol < GetColumnCount(); nCol++)
+ {
+ int nColWidth = GetColumnWidth(nCol);
+
+ nX += nColWidth ;
+ vDc.DrawLine( nX - 1
+ ,vFirstItemRect.GetY() - 2
+ ,nX - 1
+ ,vItemRect.GetBottom()
+ );
+ }
+ }
+ }
+} // end of wxListCtrl::OnPaint
+
+// ----------------------------------------------------------------------------
+// virtual list controls
+// ----------------------------------------------------------------------------
+
+wxString wxListCtrl::OnGetItemText (
+ long WXUNUSED(lItem)
+, long WXUNUSED(lCol)
+) const
+{
+ // this is a pure virtual function, in fact - which is not really pure
+ // because the controls which are not virtual don't need to implement it
+ wxFAIL_MSG( _T("not supposed to be called") );
+ return wxEmptyString;
+} // end of wxListCtrl::OnGetItemText
+
+int wxListCtrl::OnGetItemImage (
+ long WXUNUSED(lItem)
+) const
+{
+ // same as above
+ wxFAIL_MSG( _T("not supposed to be called") );
+ return -1;
+} // end of wxListCtrl::OnGetItemImage
+
+wxListItemAttr* wxListCtrl::OnGetItemAttr (
+ long WXUNUSED_UNLESS_DEBUG(lItem)
+) const
+{
+ wxASSERT_MSG( lItem >= 0 && lItem < GetItemCount(),
+ _T("invalid item index in OnGetItemAttr()") );
+
+ //
+ // No attributes by default
+ //
+ return NULL;
+} // end of wxListCtrl::OnGetItemAttr
+
+void wxListCtrl::SetItemCount (
+ long lCount
+)
+{
+ wxASSERT_MSG( IsVirtual(), _T("this is for virtual controls only") );
+
+ //
+ // Cannot explicitly set the record count in OS/2
+ //
+} // end of wxListCtrl::SetItemCount
+
+void wxListCtrl::RefreshItem (
+ long lItem
+)
+{
+ wxRect vRect;
+
+ GetItemRect( lItem
+ ,vRect
+ );
+ RefreshRect(vRect);
+} // end of wxListCtrl::RefreshItem
+
+void wxListCtrl::RefreshItems (
+ long lItemFrom
+, long lItemTo
+)
+{
+ wxRect vRect1;
+ wxRect vRect2;
+
+ GetItemRect( lItemFrom
+ ,vRect1
+ );
+ GetItemRect( lItemTo
+ ,vRect2
+ );
+
+ wxRect vRect = vRect1;
+
+ vRect.height = vRect2.GetBottom() - vRect1.GetTop();
+ RefreshRect(vRect);
+} // end of wxListCtrl::RefreshItems
+
+MRESULT wxListCtrl::OS2WindowProc(
+ WXUINT uMsg
+, WXWPARAM wParam
+, WXLPARAM lParam
+)
+{
+ bool bProcessed = FALSE;
+ MRESULT lRc;
+ wxListEvent vEvent( wxEVT_NULL
+ ,m_windowId
+ );
+ wxEventType vEventType = wxEVT_NULL;
+ PCNRDRAGINIT pDragInit = NULL;
+ PCNREDITDATA pEditData = NULL;
+ PNOTIFYRECORDENTER pNotifyEnter = NULL;
+
+ vEvent.SetEventObject(this);
+ switch (uMsg)
+ {
+ case WM_CONTROL:
+ //
+ // First off let's set some internal data
+ //
+ switch(SHORT2FROMMP(wParam))
+ {
+ case CN_INITDRAG:
+ case CN_DRAGOVER:
+ case CN_DRAGAFTER:
+ {
+ CListItemInternalData* pInternaldata = (CListItemInternalData *)lParam;
+
+ if (pInternaldata)
+ {
+ wxListItem* pItem = (wxListItem*)&vEvent.GetItem();
+
+ pItem->SetData((long)pInternaldata->m_lParam);
+ }
+ }
+ break;
+ }
+ //
+ // Now let's go through the codes we're interested in
+ //
+ switch(SHORT2FROMMP(wParam))
+ {
+ case CN_INITDRAG:
+ pDragInit = (PCNRDRAGINIT)lParam;
+ if (pDragInit)
+ {
+ PMYRECORD pRecord = (PMYRECORD)pDragInit->pRecord;
+
+ vEventType = wxEVT_COMMAND_LIST_BEGIN_RDRAG;
+ vEvent.m_itemIndex = pRecord->m_ulItemId;
+ vEvent.m_pointDrag.x = pDragInit->x;
+ vEvent.m_pointDrag.y = pDragInit->y;
+ }
+ break;
+
+ case CN_BEGINEDIT:
+ pEditData = (PCNREDITDATA)lParam;
+ if (pEditData)
+ {
+ vEventType = wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT;
+ ConvertFromOS2ListItem( GetHWND()
+ ,(wxListItem &)vEvent.GetItem()
+ ,(PMYRECORD)pEditData->pRecord
+ );
+ vEvent.m_itemIndex = vEvent.GetItem().GetId();
+ }
+ break;
+
+ case CN_ENDEDIT:
+ pEditData = (PCNREDITDATA)lParam;
+ if (pEditData)
+ {
+ vEventType = wxEVT_COMMAND_LIST_END_LABEL_EDIT;
+ ConvertFromOS2ListItem( GetHWND()
+ ,(wxListItem &)vEvent.GetItem()
+ ,(PMYRECORD)pEditData->pRecord
+ );
+ if (pEditData->cbText == 0)
+ return (MRESULT)FALSE;
+ vEvent.m_itemIndex = vEvent.GetItem().GetId();
+ }
+ break;
+
+ case CN_ENTER:
+ pNotifyEnter = (PNOTIFYRECORDENTER)lParam;
+ if (pNotifyEnter)
+ {
+ wxListItem* pItem = (wxListItem*)&vEvent.GetItem();
+ PMYRECORD pMyRecord = (PMYRECORD)pNotifyEnter->pRecord;
+
+ vEventType = wxEVT_COMMAND_LIST_ITEM_ACTIVATED;
+ vEvent.m_itemIndex = pMyRecord->m_ulItemId;
+ pItem->SetText(GetItemText(pMyRecord->m_ulItemId));
+ pItem->SetData(GetItemData(pMyRecord->m_ulItemId));
+ }
+ break;
+
+ //
+ // Add the CN_DROP messages for Direct Manipulation
+ //
+ }
+ vEvent.SetEventType(vEventType);
+ bProcessed = GetEventHandler()->ProcessEvent(vEvent);
+ break;
+ }
+ if (!bProcessed)
+ lRc = wxControl::OS2WindowProc( uMsg
+ ,wParam
+ ,lParam
+ );
+ return lRc;
+} // end of wxListCtrl::WindowProc
+
+#endif // wxUSE_LISTCTRL