Use the same short names as are used by the event table macros for the event type constants themselves. This makes them much more comfortable to use, e.g. Bind(wxEVT_BUTTON) compared to Bind(wxEVT_COMMAND_BUTTON_CLICKED). The old long names are still kept for backwards compatibility and shouldn't be removed as it doesn't really cost anything to continue providing them, but all new event types should only use the short versions. Closes #10661. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@73850 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2743 lines
87 KiB
C++
2743 lines
87 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// 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 licence
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// ============================================================================
|
|
// declarations
|
|
// ============================================================================
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// headers
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// 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"
|
|
#include "wx/dcclient.h"
|
|
#include "wx/textctrl.h"
|
|
#endif
|
|
|
|
#include "wx/imaglist.h"
|
|
#include "wx/listctrl.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 wxListCtrl is a PM
|
|
// Container in ICON, NAME, TEXT or DETAIL view). m_ulUserData is a four
|
|
// byte value containing a pointer to our CListIntemInternalData class
|
|
// instance.
|
|
//
|
|
// And now for the big time OS/2 Kludge. In traditional OS/2 PM
|
|
// applications using containers, programmers determine BEFORE creation
|
|
// how many records the view will have, initially, and how many columns
|
|
// the detail view of the container will have, as the container represents
|
|
// a known data block. Thus the OS/2 PM CV_DETAIL view, i.e.
|
|
// the wxWidgets wxLC_REPORT view, relies on STATIC structure for its
|
|
// columnar data. It gets the data to display by telling it the specific
|
|
// offset of the field in the struct containing the displayable data. That
|
|
// data has be of OS/2 Types, PSZ (char string), CDATE or CTIME format.
|
|
// wxWidgets is dynamic in nature, however. We insert columns, one at a
|
|
// time and do not know how many until the app is done inserting them. So
|
|
// for OS/2 I have to set a max allowable since they are fixed. We return
|
|
// an error to the app if they include more than we can handle.
|
|
//
|
|
// For example to display the data "Col 4 of Item 6" in a report view, I'd
|
|
// have to do:
|
|
// pRecord->m_pzColumn4 = "Col 4 of Item 6";
|
|
// pField->offStruct = FIELDOFFSET(MYRECORD, m_pzColumn4);
|
|
// and then call the PM API to set it.
|
|
//
|
|
// This really stinks but I can't use a pointer to another struct as the
|
|
// FIELDOFFSET call could only tell OS/2 the four byte value offset of
|
|
// pointer field and it would display giberish in the column.
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
typedef struct _MYRECORD
|
|
{
|
|
RECORDCORE m_vRecord;
|
|
unsigned long m_ulItemId;
|
|
unsigned long m_ulUserData; //actually a pointer value to real data (a CListItemInternalData class instance)
|
|
PSZ m_pzColumn1;
|
|
PSZ m_pzColumn2;
|
|
PSZ m_pzColumn3;
|
|
PSZ m_pzColumn4;
|
|
PSZ m_pzColumn5;
|
|
PSZ m_pzColumn6;
|
|
PSZ m_pzColumn7;
|
|
PSZ m_pzColumn8;
|
|
PSZ m_pzColumn9;
|
|
PSZ m_pzColumn10;
|
|
} 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 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 independent 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()
|
|
{
|
|
wxDELETE(m_pAttr);
|
|
}
|
|
|
|
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
|
|
// pFieldinfo -- a field struct that may contain columnar data for detail view
|
|
//
|
|
// RETURN VALUE
|
|
// none
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
void ConvertToOS2ListItem (
|
|
const wxListCtrl* pCtrl
|
|
, const wxListItem& rInfo
|
|
, PMYRECORD pRecord
|
|
, PFIELDINFO pFieldInfo
|
|
)
|
|
{
|
|
pRecord->m_ulItemId = (ULONG)rInfo.GetId();
|
|
pRecord->m_vRecord.cb = sizeof(RECORDCORE);
|
|
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();
|
|
}
|
|
//
|
|
// In the case of a report view the text will be the data in the lead column
|
|
// ???? Don't know why, but that is how it works in other ports.
|
|
//
|
|
if (pCtrl->GetWindowStyleFlag() & wxLC_REPORT)
|
|
{
|
|
if (pFieldInfo)
|
|
{
|
|
switch(rInfo.GetColumn())
|
|
{
|
|
case 0:
|
|
pRecord->m_pzColumn1 = (char*)rInfo.GetText().c_str();
|
|
pFieldInfo->offStruct = FIELDOFFSET(MYRECORD, m_pzColumn1);
|
|
break;
|
|
|
|
case 1:
|
|
pRecord->m_pzColumn2 = (char*)rInfo.GetText().c_str();
|
|
pFieldInfo->offStruct = FIELDOFFSET(MYRECORD, m_pzColumn2);
|
|
break;
|
|
|
|
case 2:
|
|
pRecord->m_pzColumn3 = (char*)rInfo.GetText().c_str();
|
|
pFieldInfo->offStruct = FIELDOFFSET(MYRECORD, m_pzColumn3);
|
|
break;
|
|
|
|
case 3:
|
|
pRecord->m_pzColumn4 = (char*)rInfo.GetText().c_str();
|
|
pFieldInfo->offStruct = FIELDOFFSET(MYRECORD, m_pzColumn4);
|
|
break;
|
|
|
|
case 4:
|
|
pRecord->m_pzColumn5 = (char*)rInfo.GetText().c_str();
|
|
pFieldInfo->offStruct = FIELDOFFSET(MYRECORD, m_pzColumn5);
|
|
break;
|
|
|
|
case 5:
|
|
pRecord->m_pzColumn6 = (char*)rInfo.GetText().c_str();
|
|
pFieldInfo->offStruct = FIELDOFFSET(MYRECORD, m_pzColumn6);
|
|
break;
|
|
|
|
case 6:
|
|
pRecord->m_pzColumn7 = (char*)rInfo.GetText().c_str();
|
|
pFieldInfo->offStruct = FIELDOFFSET(MYRECORD, m_pzColumn7);
|
|
break;
|
|
|
|
case 7:
|
|
pRecord->m_pzColumn8 = (char*)rInfo.GetText().c_str();
|
|
pFieldInfo->offStruct = FIELDOFFSET(MYRECORD, m_pzColumn8);
|
|
break;
|
|
|
|
case 8:
|
|
pRecord->m_pzColumn9 = (char*)rInfo.GetText().c_str();
|
|
pFieldInfo->offStruct = FIELDOFFSET(MYRECORD, m_pzColumn9);
|
|
break;
|
|
|
|
case 9:
|
|
pRecord->m_pzColumn10 = (char*)rInfo.GetText().c_str();
|
|
pFieldInfo->offStruct = FIELDOFFSET(MYRECORD, m_pzColumn10);
|
|
break;
|
|
|
|
default:
|
|
wxFAIL_MSG( wxT("wxOS2 does not support more than 10 columns in REPORT view") );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
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);
|
|
|
|
//
|
|
// Default some settings
|
|
//
|
|
pField->flData = CFA_HORZSEPARATOR | CFA_SEPARATOR;
|
|
pField->flTitle = CFA_CENTER;
|
|
|
|
if (rItem.GetMask() & wxLIST_MASK_TEXT)
|
|
{
|
|
pField->flData |= CFA_STRING;
|
|
pField->pTitleData = (PVOID)rItem.GetText().c_str(); // text is column title not data
|
|
}
|
|
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;
|
|
}
|
|
else
|
|
pField->flData |= CFA_CENTER; // Just ensure the default is centered
|
|
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
|
|
}
|
|
|
|
//
|
|
// Still need to set the actual data
|
|
//
|
|
pField->offStruct = 0;
|
|
} // end of ConvertToOS2ListCol
|
|
|
|
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)
|
|
))
|
|
return false;
|
|
lWstyle = ConvertViewToOS2Style(GetWindowStyleFlag());
|
|
vCnrInfo.flWindowAttr |= lWstyle;
|
|
if (!::WinSendMsg( GetHWND()
|
|
,CM_SETCNRINFO
|
|
,MPFROMP(&vCnrInfo)
|
|
,(MPARAM)CMA_FLWINDOWATTR
|
|
))
|
|
return false;
|
|
|
|
//
|
|
// And now set needed arrangement flags
|
|
//
|
|
lWstyle = ConvertArrangeToOS2Style(GetWindowStyleFlag());
|
|
if (!::WinSendMsg( GetHWND()
|
|
,CM_ARRANGE
|
|
,(MPARAM)CMA_ARRANGEGRID
|
|
,(MPARAM)lWstyle
|
|
))
|
|
return false;
|
|
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();
|
|
wxDELETE(m_pTextCtrl);
|
|
}
|
|
|
|
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 )
|
|
{
|
|
PFIELDINFO pFieldInfo = FindOS2ListFieldByColNum ( GetHWND(), rInfo.GetColumn() );
|
|
PMYRECORD pRecord = FindOS2ListRecordByID( GetHWND(), rInfo.GetId() );
|
|
|
|
ConvertToOS2ListItem( this
|
|
,rInfo
|
|
,pRecord
|
|
,pFieldInfo
|
|
);
|
|
|
|
//
|
|
// 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());
|
|
}
|
|
pData->m_pMyRecord = pRecord; // they point to each other
|
|
}
|
|
|
|
//
|
|
// 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;
|
|
}
|
|
if (::WinIsWindowVisible(GetHWND()))
|
|
{
|
|
::WinSendMsg( GetHWND()
|
|
,CM_INVALIDATERECORD
|
|
,MPFROMP(pRecord)
|
|
,MPFROM2SHORT(1, CMA_ERASE | CMA_REPOSITION | CMA_TEXTCHANGED)
|
|
);
|
|
RefreshItem(pRecord->m_ulItemId);
|
|
}
|
|
::WinSendMsg( GetHWND()
|
|
,CM_INVALIDATEDETAILFIELDINFO
|
|
,NULL
|
|
,NULL
|
|
);
|
|
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))
|
|
{
|
|
return SetItemColumnInfo(lItem, 0, nImage);
|
|
} // end of wxListCtrl::SetItemImage
|
|
|
|
// Sets the item image
|
|
bool wxListCtrl::SetItemColumnImage (
|
|
long lItem
|
|
, long lColumn
|
|
, int nImage)
|
|
{
|
|
wxListItem vInfo;
|
|
|
|
vInfo.m_mask = wxLIST_MASK_IMAGE;
|
|
vInfo.m_image = nImage;
|
|
vInfo.m_itemId = lItem;
|
|
vInfo.m_col = lColumn;
|
|
return SetItem(vInfo);
|
|
} // end of wxListCtrl::SetItemColumnImage
|
|
|
|
// 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::SetItemPtrData (
|
|
long lItem
|
|
, wxUIntPtr lData
|
|
)
|
|
{
|
|
wxListItem vInfo;
|
|
|
|
vInfo.m_mask = wxLIST_MASK_DATA;
|
|
vInfo.m_itemId = lItem;
|
|
vInfo.m_data = lData;
|
|
return SetItem(vInfo);
|
|
} // end of wxListCtrl::SetItemPtrData
|
|
|
|
// 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 bIsSmall 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.Contains(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.Contains(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(), wxT("can't be used with virtual controls") );
|
|
|
|
PFIELDINFO pFieldInfo = FindOS2ListFieldByColNum ( GetHWND()
|
|
,rInfo.GetColumn()
|
|
);
|
|
PMYRECORD pRecordAfter = NULL;
|
|
PMYRECORD pRecord = (PMYRECORD)::WinSendMsg( GetHWND()
|
|
,CM_ALLOCRECORD
|
|
,MPFROMLONG(sizeof(MYRECORD) - sizeof(RECORDCORE))
|
|
,MPFROMSHORT(1)
|
|
);
|
|
|
|
ConvertToOS2ListItem( this
|
|
,rInfo
|
|
,pRecord
|
|
,pFieldInfo
|
|
);
|
|
|
|
if (rInfo.GetId() > 0)
|
|
pRecordAfter = FindOS2ListRecordByID( GetHWND()
|
|
,rInfo.GetId() - 1
|
|
);
|
|
|
|
RECORDINSERT vInsert;
|
|
|
|
vInsert.cb = sizeof(RECORDINSERT);
|
|
vInsert.pRecordParent = NULL;
|
|
if (!pRecordAfter)
|
|
vInsert.pRecordOrder = (PRECORDCORE)CMA_FIRST;
|
|
else
|
|
vInsert.pRecordOrder = (PRECORDCORE)pRecordAfter;
|
|
vInsert.zOrder = CMA_TOP;
|
|
vInsert.cRecordsInsert = 1;
|
|
vInsert.fInvalidateRecord = TRUE;
|
|
|
|
//
|
|
// Check whether 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());
|
|
}
|
|
}
|
|
if (!::WinSendMsg( GetHWND()
|
|
,CM_INSERTRECORD
|
|
,MPFROMP(pRecord)
|
|
,MPFROMP(&vInsert)
|
|
))
|
|
return -1;
|
|
//
|
|
// OS/2 must mannually bump the index's of following records
|
|
//
|
|
BumpRecordIds( GetHWND()
|
|
,pRecord
|
|
);
|
|
::WinSendMsg( GetHWND()
|
|
,CM_INVALIDATEDETAILFIELDINFO
|
|
,NULL
|
|
,NULL
|
|
);
|
|
return pRecord->m_ulItemId;
|
|
} // end of wxListCtrl::InsertItem
|
|
|
|
long wxListCtrl::InsertItem (
|
|
long lIndex
|
|
, const wxString& rsLabel
|
|
)
|
|
{
|
|
wxListItem vInfo;
|
|
|
|
memset(&vInfo, '\0', sizeof(wxListItem));
|
|
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;
|
|
|
|
ConvertToOS2ListCol ( lCol
|
|
,rItem
|
|
,pField
|
|
);
|
|
|
|
vInsert.cb = sizeof(FIELDINFOINSERT);
|
|
vInsert.pFieldInfoOrder = pFieldAfter;
|
|
vInsert.fInvalidateFieldInfo = TRUE;
|
|
vInsert.cFieldInfoInsert = 1;
|
|
|
|
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(wxT("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_TEXT, 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( wxT("not supposed to be called") );
|
|
return wxEmptyString;
|
|
} // end of wxListCtrl::OnGetItemText
|
|
|
|
int wxListCtrl::OnGetItemImage (
|
|
long WXUNUSED(lItem)
|
|
) const
|
|
{
|
|
// same as above
|
|
wxFAIL_MSG( wxT("not supposed to be called") );
|
|
return -1;
|
|
} // end of wxListCtrl::OnGetItemImage
|
|
|
|
int wxListCtrl::OnGetItemColumnImage (
|
|
long lItem,
|
|
long lColumn
|
|
) const
|
|
{
|
|
if (!lColumn)
|
|
return OnGetItemImage(lItem);
|
|
|
|
return -1;
|
|
} // end of wxListCtrl::OnGetItemColumnImage
|
|
|
|
void wxListCtrl::SetItemCount (
|
|
long lCount
|
|
)
|
|
{
|
|
wxASSERT_MSG( IsVirtual(), wxT("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_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_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_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_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 = HandleWindowEvent(vEvent);
|
|
break;
|
|
}
|
|
if (!bProcessed)
|
|
lRc = wxControl::OS2WindowProc( uMsg
|
|
,wParam
|
|
,lParam
|
|
);
|
|
return lRc;
|
|
} // end of wxListCtrl::WindowProc
|
|
|
|
#endif // wxUSE_LISTCTRL
|