Files
wxWidgets/src/os2/listctrl.cpp
2005-04-08 14:34:30 +00:00

2900 lines
93 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
// ----------------------------------------------------------------------------
#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 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 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()
{
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
// 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( _T("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
// ----------------------------------------------------------------------------
// 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)
))
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();
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
)
{
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))
{
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") );
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 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());
}
}
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(_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