]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/os2/listctrl.cpp
Fix explicitly setting focus to generic wxSpinCtrl.
[wxWidgets.git] / src / os2 / listctrl.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/os2/listctrl.cpp
3// Purpose: wxListCtrl
4// Author: David Webster
5// Modified by:
6// Created: 01/21/03
7// RCS-ID: $Id$
8// Copyright: (c) David Webster
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
24 #pragma hdrstop
25#endif
26
27#if wxUSE_LISTCTRL
28
29#ifndef WX_PRECOMP
30 #include "wx/app.h"
31 #include "wx/intl.h"
32 #include "wx/log.h"
33 #include "wx/settings.h"
34 #include "wx/dcclient.h"
35 #include "wx/textctrl.h"
36#endif
37
38#include "wx/imaglist.h"
39#include "wx/listctrl.h"
40
41#include "wx/os2/private.h"
42
43//
44// FIELDOFFSET in DETAIL view as defined in the OS2TK45 simply doesn't work
45// We use this, which does!
46//
47#undef FIELDOFFSET
48#define FIELDOFFSET(type, field) ((ULONG)&(((type *)0)->field))
49
50// ----------------------------------------------------------------------------
51// private helper classes
52// ----------------------------------------------------------------------------
53
54/////////////////////////////////////////////////////////////////////////////
55// STRUCT SMYRECORD
56// Under OS/2 we have to use our own RECORDCORE based struct if we have
57// user data to store in a PM Container Control (and wxListCtrl is a PM
58// Container in ICON, NAME, TEXT or DETAIL view). m_ulUserData is a four
59// byte value containing a pointer to our CListIntemInternalData class
60// instance.
61//
62// And now for the big time OS/2 Kludge. In traditional OS/2 PM
63// applications using containers, programmers determine BEFORE creation
64// how many records the view will have, initially, and how many columns
65// the detail view of the container will have, as the container represents
66// a known data block. Thus the OS/2 PM CV_DETAIL view, i.e.
67// the wxWidgets wxLC_REPORT view, relies on STATIC structure for its
68// columnar data. It gets the data to display by telling it the specific
69// offset of the field in the struct containing the displayable data. That
70// data has be of OS/2 Types, PSZ (char string), CDATE or CTIME format.
71// wxWidgets is dynamic in nature, however. We insert columns, one at a
72// time and do not know how many until the app is done inserting them. So
73// for OS/2 I have to set a max allowable since they are fixed. We return
74// an error to the app if they include more than we can handle.
75//
76// For example to display the data "Col 4 of Item 6" in a report view, I'd
77// have to do:
78// pRecord->m_pzColumn4 = "Col 4 of Item 6";
79// pField->offStruct = FIELDOFFSET(MYRECORD, m_pzColumn4);
80// and then call the PM API to set it.
81//
82// This really stinks but I can't use a pointer to another struct as the
83// FIELDOFFSET call could only tell OS/2 the four byte value offset of
84// pointer field and it would display giberish in the column.
85/////////////////////////////////////////////////////////////////////////////
86typedef struct _MYRECORD
87{
88 RECORDCORE m_vRecord;
89 unsigned long m_ulItemId;
90 unsigned long m_ulUserData; //actually a pointer value to real data (a CListItemInternalData class instance)
91 PSZ m_pzColumn1;
92 PSZ m_pzColumn2;
93 PSZ m_pzColumn3;
94 PSZ m_pzColumn4;
95 PSZ m_pzColumn5;
96 PSZ m_pzColumn6;
97 PSZ m_pzColumn7;
98 PSZ m_pzColumn8;
99 PSZ m_pzColumn9;
100 PSZ m_pzColumn10;
101} MYRECORD, *PMYRECORD;
102
103/////////////////////////////////////////////////////////////////////////////
104// CLASS CListItemInternalData
105//
106// Problem:
107// The MSW version had problems with SetTextColour() et al as the
108// CListItemAttr's were stored keyed on the item index. If a item was
109// inserted anywhere but the end of the list the the text attributes
110// (colour etc) for the following items were out of sync.
111//
112// Solution:
113// Under MSW the only way to associate data with a
114// List item independent of its position in the list is to store a pointer
115// to it in its lParam attribute. However user programs are already using
116// this (via the SetItemData() GetItemData() calls).
117//
118// However what we can do is store a pointer to a structure which contains
119// the attributes we want *and* a lParam for the users data, e.g.
120//
121// class CListItemInternalData
122// {
123// public:
124// GuiAdvCtrl_CListItemAttr* pAttr;
125// long lParam; // user data
126// };
127//
128// To conserve memory, a CListItemInternalData is only allocated for a
129// LV_ITEM if text attributes or user data(lparam) are being set.
130//
131// For OS/2, the lParam value points to whatever actual data we have
132/////////////////////////////////////////////////////////////////////////////
133class CListItemInternalData
134{
135public:
136
137 CListItemInternalData(): m_pAttr(NULL)
138 ,m_lParam(0)
139 {}
140
141 ~CListItemInternalData()
142 {
143 wxDELETE(m_pAttr);
144 }
145
146 wxListItemAttr* m_pAttr;
147 WXLPARAM m_lParam; // user data
148 PMYRECORD m_pMyRecord; // so we can set the m_ulUserData to 0 when this is deleted
149}; // end of CLASS CListItemInternalData
150
151/////////////////////////////////////////////////////////////////////////////
152// STRUCT SInternalDataSort
153//
154// Sort items.
155//
156// fn is a function which takes 3 long arguments: item1, item2, data.
157// item1 is the long data associated with a first item (NOT the index).
158// item2 is the long data associated with a second item (NOT the index).
159// data is the same value as passed to SortItems.
160//
161// The return value is a negative number if the first item should precede the
162// second item, a positive number of the second item should precede the first,
163// or zero if the two items are equivalent.
164//
165// data is arbitrary data to be passed to the sort function.
166//
167// Internal structures for proxying the user compare function
168// so that we can pass it the *real* user data
169/////////////////////////////////////////////////////////////////////////////
170typedef struct internalDataSort
171{
172 wxListCtrlCompare m_fnUser;
173 long m_lData;
174} SInternalDataSort; // end of STRUCT SInternalDataSort
175
176// ----------------------------------------------------------------------------
177// private helper functions
178// ----------------------------------------------------------------------------
179
180/////////////////////////////////////////////////////////////////////////////
181//
182// FindOS2ListFieldByColNum
183//
184// There is no way, under OS/2 to get a field in a container by index,
185// directly, so you must get the first one, then cycle through the list
186// until you get to where you want to be.
187//
188// PARAMETERS
189// hWnd -- window handle of container to search
190// lIndex -- index to set
191//
192// RETURN VALUE
193// pointer to the FIELDINFO struct at the index in the container record
194//
195/////////////////////////////////////////////////////////////////////////////
196PFIELDINFO FindOS2ListFieldByColNum (
197 HWND hWnd
198, long lIndex
199)
200{
201 PFIELDINFO pFieldInfo = NULL;
202 CNRINFO vCnrInfo;
203 ULONG i;
204
205 if (!::WinSendMsg( hWnd
206 ,CM_QUERYCNRINFO
207 ,MPFROMP(&vCnrInfo)
208 ,(MPARAM)(USHORT)sizeof(CNRINFO)
209 ))
210 return NULL;
211 for (i = 0; i < vCnrInfo.cFields; i++)
212 {
213 if (i == 0)
214 pFieldInfo = (PFIELDINFO)PVOIDFROMMR(::WinSendMsg( hWnd
215 ,CM_QUERYDETAILFIELDINFO
216 ,MPFROMP(pFieldInfo)
217 ,(MPARAM)CMA_FIRST
218 ));
219 else
220 pFieldInfo = (PFIELDINFO)PVOIDFROMMR(::WinSendMsg( hWnd
221 ,CM_QUERYDETAILFIELDINFO
222 ,MPFROMP(pFieldInfo)
223 ,(MPARAM)CMA_NEXT
224 ));
225 if (!pFieldInfo)
226 return NULL;
227 if (i == (ULONG)lIndex)
228 break;
229 }
230 if (!pFieldInfo)
231 return NULL;
232 return pFieldInfo;
233} // end of FindOS2ListFieldByColNum
234
235/////////////////////////////////////////////////////////////////////////////
236//
237// FindOS2ListRecordByID
238//
239// There is no way, under OS/2 to get a record in a container by index,
240// directly, so you must get the first one, then cycle through the list
241// until you get to where you want to be.
242//
243// PARAMETERS
244// hWnd -- window handle of container to search
245// lItemId -- index to set
246//
247// RETURN VALUE
248// pointer to the internal RECORDCORE struct at the index in the container
249//
250/////////////////////////////////////////////////////////////////////////////
251PMYRECORD FindOS2ListRecordByID (
252 HWND hWnd
253, long lItemId
254)
255{
256 PMYRECORD pRecord = NULL;
257 CNRINFO vCnrInfo;
258 unsigned long i;
259
260 if (!::WinSendMsg( hWnd
261 ,CM_QUERYCNRINFO
262 ,MPFROMP(&vCnrInfo)
263 ,(MPARAM)(USHORT)sizeof(CNRINFO)
264 ))
265 return NULL;
266 for (i = 0; i < vCnrInfo.cRecords; i++)
267 {
268 if (i == 0)
269 pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( hWnd
270 ,CM_QUERYRECORD
271 ,MPFROMP(pRecord)
272 ,MPFROM2SHORT(CMA_FIRST, CMA_ITEMORDER)
273 ));
274 else
275 pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( hWnd
276 ,CM_QUERYRECORD
277 ,MPFROMP(pRecord)
278 ,MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER)
279 ));
280 if (!pRecord)
281 return NULL;
282 if (pRecord->m_ulItemId == (ULONG)lItemId)
283 break;
284 }
285 return pRecord;
286} // end of FindOS2ListRecordByID
287
288/////////////////////////////////////////////////////////////////////////////
289//
290// BumpRecordIds
291//
292// Since OS/2 does not keep native record id's but wx insists on inserting
293// and selecting via ID's, when we insert a record in the middle we need
294// to bump the id's of each record after the one we just inserted.
295//
296// PARAMETERS
297// hWnd -- window handle of container to search
298// pRecord -- record after which we starting bumping id's
299//
300// RETURN VALUE
301// none
302//
303/////////////////////////////////////////////////////////////////////////////
304void BumpRecordIds (
305 HWND hWnd
306, PMYRECORD pRecord
307)
308{
309 while(pRecord)
310 {
311 pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( hWnd
312 ,CM_QUERYRECORD
313 ,MPFROMP(pRecord)
314 ,MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER)
315 ));
316 if (pRecord)
317 pRecord->m_ulItemId++;
318 }
319} // end of BumpRecordIds
320
321/////////////////////////////////////////////////////////////////////////////
322//
323// GetInternalData
324//
325// Get the internal data given a handle and an id
326//
327// PARAMETERS
328// hWnd -- window handle to the control in which item is located
329// lItemId -- ID to get
330//
331// RETURN VALUE
332// pointer to the internal data
333//
334// Note:
335// Under OS/2 PM a container item cannot be obtained via a simple index or
336// id retrieval. We have to walk the record list if we are looking for
337// a record at a specific index location
338/////////////////////////////////////////////////////////////////////////////
339CListItemInternalData* GetInternalData (
340 HWND hWnd
341, long lItemId
342)
343{
344 PMYRECORD pRecord = FindOS2ListRecordByID( hWnd
345 ,lItemId
346 );
347 //
348 // Internal user data is stored AFTER the last field of the RECORDCORE
349 //
350 if (!pRecord)
351 return NULL;
352 return((CListItemInternalData *)(pRecord->m_ulUserData));
353} // end of GetInternalData
354
355/////////////////////////////////////////////////////////////////////////////
356//
357// GetInternalData
358//
359// Get the internal data given a pointer to a list control and an id
360//
361// PARAMETERS
362// pCtl -- pointer to control inwhich item is located
363// lItemId -- ID to get
364//
365// RETURN VALUE
366// pointer to the internal data
367//
368/////////////////////////////////////////////////////////////////////////////
369CListItemInternalData* GetInternalData (
370 wxListCtrl* pCtl
371, long lItemId
372)
373{
374 return(GetInternalData( (HWND)pCtl->GetHWND()
375 ,lItemId
376 ));
377} // end of GetInternalData
378
379/////////////////////////////////////////////////////////////////////////////
380//
381// DeleteInternalData
382//
383// Delete the internal data for a record
384//
385// PARAMETERS
386// pCtl -- pointer to the list control containing the record
387// lItemId -- the record index to delete the internal data from
388//
389// RETURN VALUE
390// pointer to the internal data attribute
391//
392/////////////////////////////////////////////////////////////////////////////
393void DeleteInternalData (
394 wxListCtrl* pCtl
395, long lItemId
396)
397{
398 CListItemInternalData* pData = GetInternalData( pCtl
399 ,lItemId
400 );
401 if (pData)
402 {
403 if (pData->m_pMyRecord)
404 pData->m_pMyRecord->m_ulUserData = 0;
405 delete pData;
406 }
407} // end of DeleteInternalData
408
409// #pragma page "GetInternalDataAttr"
410/////////////////////////////////////////////////////////////////////////////
411//
412// GetInternalDataAttr
413//
414// Get the internal data item attribute given a pointer to a list control
415// and an id
416//
417// PARAMETERS
418// pCtl -- pointer to control to set
419// lItemId -- ID to set
420//
421// RETURN VALUE
422// pointer to the internal data attribute
423//
424/////////////////////////////////////////////////////////////////////////////
425wxListItemAttr* GetInternalDataAttr (
426 wxListCtrl* pCtl
427, long lItemId
428)
429{
430 CListItemInternalData* pData = GetInternalData( pCtl
431 ,lItemId
432 );
433
434 if (pData)
435 return(pData->m_pAttr);
436 else
437 return NULL;
438} // end of GetInternalDataAttr
439
440/////////////////////////////////////////////////////////////////////////////
441//
442// InternalDataCompareFunc
443//
444// This is compare function we pass to PM. It wraps the real compare
445// function in SInternalDataSort
446//
447// PARAMETERS
448// p1 -- is the first record structure to compare
449// p2 -- is the second record structure to compare
450// lStorage -- is the same value as passed to SortItems.
451//
452// RETURN VALUE
453// pointer to the internal data attribute
454//
455/////////////////////////////////////////////////////////////////////////////
456SHORT EXPENTRY InternalDataCompareFunc (
457 PMYRECORD p1
458, PMYRECORD p2
459, PVOID pStorage
460)
461{
462 SInternalDataSort* pInternalData = (SInternalDataSort *)pStorage;
463 CListItemInternalData* pData1 = (CListItemInternalData *)p1->m_ulUserData;
464 CListItemInternalData* pData2 = (CListItemInternalData *)p2->m_ulUserData;
465 long lD1 = (pData1 == NULL ? 0 : (long)pData1->m_lParam);
466 long lD2 = (pData2 == NULL ? 0 : (long)pData2->m_lParam);
467
468 return(pInternalData->m_fnUser( lD1
469 ,lD2
470 ,pInternalData->m_lData
471 ));
472} // end of InternalDataCompareFunc
473
474/////////////////////////////////////////////////////////////////////////////
475//
476// ConvertFromOS2ListItem
477//
478// Convert from an internal PM List item to a Toolkit List item
479//
480// PARAMETERS
481// hWndListCtrl -- the control's windows handle
482// rInfo -- the library list control to convert to
483// pRecord -- the OS list control to convert from
484//
485// RETURN VALUE
486// none
487//
488/////////////////////////////////////////////////////////////////////////////
489void ConvertFromOS2ListItem ( HWND hWndListCtrl,
490 wxListItem& rInfo,
491 PMYRECORD pRecord )
492{
493 CListItemInternalData* pInternaldata = (CListItemInternalData *)pRecord->m_ulUserData;
494 bool bNeedText = false;
495
496 if (pInternaldata)
497 rInfo.SetData(pInternaldata->m_lParam);
498
499 rInfo.SetMask(0);
500 rInfo.SetState(0);
501 rInfo.SetStateMask(0);
502 rInfo.SetId((long)pRecord->m_ulItemId);
503 if (hWndListCtrl != 0)
504 {
505 pRecord = FindOS2ListRecordByID( hWndListCtrl
506 ,rInfo.GetId()
507 );
508 }
509
510 //
511 // The wxListItem class is really set up to handle the WIN32 list item
512 // and OS/2 are not as complicated. Just set both state members to the
513 // same thing under OS/2
514 //
515 if (pRecord->m_vRecord.flRecordAttr & CRA_DROPONABLE)
516 {
517 rInfo.SetStateMask(rInfo.m_stateMask | wxLIST_STATE_DROPHILITED);
518 rInfo.SetState(rInfo.m_state | wxLIST_STATE_DROPHILITED);
519 }
520 if (pRecord->m_vRecord.flRecordAttr & CRA_SELECTED)
521 {
522 rInfo.SetStateMask(rInfo.m_stateMask | wxLIST_STATE_SELECTED);
523 rInfo.SetState(rInfo.m_state | wxLIST_STATE_SELECTED);
524 }
525 if (pRecord->m_vRecord.flRecordAttr & CRA_DISABLED)
526 {
527 rInfo.SetStateMask(rInfo.m_stateMask | wxLIST_STATE_DISABLED);
528 rInfo.SetState(rInfo.m_state | wxLIST_STATE_DISABLED);
529 }
530 if (pRecord->m_vRecord.flRecordAttr & CRA_FILTERED)
531 {
532 rInfo.SetStateMask(rInfo.m_stateMask | wxLIST_STATE_FILTERED);
533 rInfo.SetState(rInfo.m_state | wxLIST_STATE_FILTERED);
534 }
535 if (pRecord->m_vRecord.flRecordAttr & CRA_INUSE)
536 {
537 rInfo.SetStateMask(rInfo.m_stateMask | wxLIST_STATE_INUSE);
538 rInfo.SetState(rInfo.m_state | wxLIST_STATE_INUSE);
539 }
540 if (pRecord->m_vRecord.flRecordAttr & CRA_PICKED)
541 {
542 rInfo.SetStateMask(rInfo.m_stateMask | wxLIST_STATE_PICKED);
543 rInfo.SetState(rInfo.m_state | wxLIST_STATE_PICKED);
544 }
545 if (pRecord->m_vRecord.flRecordAttr & CRA_SOURCE)
546 {
547 rInfo.SetStateMask(rInfo.m_stateMask | wxLIST_STATE_SOURCE);
548 rInfo.SetState(rInfo.m_state | wxLIST_STATE_SOURCE);
549 }
550
551 if (pRecord->m_vRecord.pszText != (PSZ)NULL)
552 {
553 rInfo.SetMask(rInfo.GetMask() | wxLIST_MASK_TEXT);
554 rInfo.SetText(pRecord->m_vRecord.pszText);
555 }
556 if (pRecord->m_vRecord.pszIcon != (PSZ)NULL ||
557 pRecord->m_vRecord.pszName != (PSZ)NULL)
558 {
559 rInfo.SetMask(rInfo.GetMask() | wxLIST_MASK_IMAGE);
560 rInfo.SetImage(pRecord->m_vRecord.hptrIcon);
561 }
562 if (pRecord->m_ulUserData)
563 rInfo.SetMask(rInfo.GetMask() | wxLIST_MASK_DATA);
564} // end of ConvertFromOS2ListItem
565
566/////////////////////////////////////////////////////////////////////////////
567//
568// ConvertToOS2Flags
569//
570// Convert from an library states to OS states
571//
572// PARAMETERS
573// lState -- the state
574// pRecord -- the OS list control to use
575//
576// RETURN VALUE
577// none
578//
579/////////////////////////////////////////////////////////////////////////////
580void ConvertToOS2Flags (
581 long lState
582, PMYRECORD pRecord
583)
584{
585 if (lState & wxLIST_STATE_DROPHILITED)
586 pRecord->m_vRecord.flRecordAttr |= CRA_DROPONABLE;
587 if (lState & wxLIST_STATE_SELECTED)
588 pRecord->m_vRecord.flRecordAttr |= CRA_SELECTED;
589 if (lState & wxLIST_STATE_DISABLED)
590 pRecord->m_vRecord.flRecordAttr |= CRA_DISABLED;
591 if (lState & wxLIST_STATE_FILTERED)
592 pRecord->m_vRecord.flRecordAttr |= CRA_FILTERED;
593 if (lState & wxLIST_STATE_INUSE)
594 pRecord->m_vRecord.flRecordAttr |= CRA_INUSE;
595 if (lState & wxLIST_STATE_PICKED)
596 pRecord->m_vRecord.flRecordAttr |= CRA_PICKED;
597 if (lState & wxLIST_STATE_SOURCE)
598 pRecord->m_vRecord.flRecordAttr |= CRA_SOURCE;
599} // end of ConvertToOS2Flags
600
601/////////////////////////////////////////////////////////////////////////////
602//
603// ConvertToOS2ListItem
604//
605// Convert from a library List item to an internal OS2 List item. We set
606// only the fields we need to set. Some of them are set by the API when
607// they are added to the container.
608//
609// PARAMETERS
610// pCtrl -- the control to use
611// rInfo -- the item to convert
612// pRecord -- the OS list control to use, should be zeroed out
613// pFieldinfo -- a field struct that may contain columnar data for detail view
614//
615// RETURN VALUE
616// none
617//
618/////////////////////////////////////////////////////////////////////////////
619void ConvertToOS2ListItem (
620 const wxListCtrl* pCtrl
621, const wxListItem& rInfo
622, PMYRECORD pRecord
623, PFIELDINFO pFieldInfo
624)
625{
626 pRecord->m_ulItemId = (ULONG)rInfo.GetId();
627 pRecord->m_vRecord.cb = sizeof(RECORDCORE);
628 if (rInfo.GetMask() & wxLIST_MASK_STATE)
629 {
630 ConvertToOS2Flags( rInfo.m_state
631 ,pRecord
632 );
633 }
634 if (pCtrl->GetWindowStyleFlag() & wxLC_ICON ||
635 pCtrl->GetWindowStyleFlag() & wxLC_SMALL_ICON)
636 {
637 pRecord->m_vRecord.pszIcon = (char*)rInfo.GetText().c_str();
638 }
639 if (pCtrl->GetWindowStyleFlag() & wxLC_LIST) // PM TEXT view
640 {
641 pRecord->m_vRecord.pszText = (char*)rInfo.GetText().c_str();
642 }
643 //
644 // In the case of a report view the text will be the data in the lead column
645 // ???? Don't know why, but that is how it works in other ports.
646 //
647 if (pCtrl->GetWindowStyleFlag() & wxLC_REPORT)
648 {
649 if (pFieldInfo)
650 {
651 switch(rInfo.GetColumn())
652 {
653 case 0:
654 pRecord->m_pzColumn1 = (char*)rInfo.GetText().c_str();
655 pFieldInfo->offStruct = FIELDOFFSET(MYRECORD, m_pzColumn1);
656 break;
657
658 case 1:
659 pRecord->m_pzColumn2 = (char*)rInfo.GetText().c_str();
660 pFieldInfo->offStruct = FIELDOFFSET(MYRECORD, m_pzColumn2);
661 break;
662
663 case 2:
664 pRecord->m_pzColumn3 = (char*)rInfo.GetText().c_str();
665 pFieldInfo->offStruct = FIELDOFFSET(MYRECORD, m_pzColumn3);
666 break;
667
668 case 3:
669 pRecord->m_pzColumn4 = (char*)rInfo.GetText().c_str();
670 pFieldInfo->offStruct = FIELDOFFSET(MYRECORD, m_pzColumn4);
671 break;
672
673 case 4:
674 pRecord->m_pzColumn5 = (char*)rInfo.GetText().c_str();
675 pFieldInfo->offStruct = FIELDOFFSET(MYRECORD, m_pzColumn5);
676 break;
677
678 case 5:
679 pRecord->m_pzColumn6 = (char*)rInfo.GetText().c_str();
680 pFieldInfo->offStruct = FIELDOFFSET(MYRECORD, m_pzColumn6);
681 break;
682
683 case 6:
684 pRecord->m_pzColumn7 = (char*)rInfo.GetText().c_str();
685 pFieldInfo->offStruct = FIELDOFFSET(MYRECORD, m_pzColumn7);
686 break;
687
688 case 7:
689 pRecord->m_pzColumn8 = (char*)rInfo.GetText().c_str();
690 pFieldInfo->offStruct = FIELDOFFSET(MYRECORD, m_pzColumn8);
691 break;
692
693 case 8:
694 pRecord->m_pzColumn9 = (char*)rInfo.GetText().c_str();
695 pFieldInfo->offStruct = FIELDOFFSET(MYRECORD, m_pzColumn9);
696 break;
697
698 case 9:
699 pRecord->m_pzColumn10 = (char*)rInfo.GetText().c_str();
700 pFieldInfo->offStruct = FIELDOFFSET(MYRECORD, m_pzColumn10);
701 break;
702
703 default:
704 wxFAIL_MSG( wxT("wxOS2 does not support more than 10 columns in REPORT view") );
705 break;
706 }
707 }
708 }
709 if (rInfo.GetMask() & wxLIST_MASK_IMAGE)
710 {
711 pRecord->m_vRecord.hptrIcon = (HPOINTER)rInfo.GetImage();
712 pRecord->m_vRecord.hptrMiniIcon = (HPOINTER)rInfo.m_miniImage;
713 }
714} // end of ConvertToOS2ListItem
715
716/////////////////////////////////////////////////////////////////////////////
717//
718// ConvertToOS2ListCol
719//
720// Convert from a library List column to an internal PM List column
721//
722// PARAMETERS
723// lCol -- the columnd to convert
724// rItem -- the item to convert
725// pField -- the OS list column to use
726//
727// RETURN VALUE
728// none
729//
730/////////////////////////////////////////////////////////////////////////////
731void ConvertToOS2ListCol (
732 long lCol
733, const wxListItem& rItem
734, PFIELDINFO pField
735)
736{
737 memset(pField, '\0', sizeof(FIELDINFO));
738 pField->cb = sizeof(FIELDINFO);
739
740 //
741 // Default some settings
742 //
743 pField->flData = CFA_HORZSEPARATOR | CFA_SEPARATOR;
744 pField->flTitle = CFA_CENTER;
745
746 if (rItem.GetMask() & wxLIST_MASK_TEXT)
747 {
748 pField->flData |= CFA_STRING;
749 pField->pTitleData = (PVOID)rItem.GetText().c_str(); // text is column title not data
750 }
751 if (rItem.GetMask() & wxLIST_MASK_FORMAT)
752 {
753 if (rItem.m_format == wxLIST_FORMAT_LEFT)
754 pField->flData |= CFA_LEFT;
755 else if (rItem.m_format == wxLIST_FORMAT_RIGHT)
756 pField->flData |= CFA_RIGHT;
757 else if (rItem.m_format == wxLIST_FORMAT_CENTRE)
758 pField->flData |= CFA_CENTER;
759 }
760 else
761 pField->flData |= CFA_CENTER; // Just ensure the default is centered
762 if (rItem.GetMask() & wxLIST_MASK_WIDTH)
763 {
764 if (!(rItem.GetWidth() == wxLIST_AUTOSIZE ||
765 rItem.GetWidth() == wxLIST_AUTOSIZE_USEHEADER))
766 pField->cxWidth = rItem.GetWidth();
767 // else: OS/2 automatically sets the width if created with the approppriate style
768 }
769
770 //
771 // Still need to set the actual data
772 //
773 pField->offStruct = 0;
774} // end of ConvertToOS2ListCol
775
776
777IMPLEMENT_DYNAMIC_CLASS(wxListCtrl, wxControl)
778IMPLEMENT_DYNAMIC_CLASS(wxListView, wxListCtrl)
779IMPLEMENT_DYNAMIC_CLASS(wxListItem, wxObject)
780
781IMPLEMENT_DYNAMIC_CLASS(wxListEvent, wxNotifyEvent)
782
783BEGIN_EVENT_TABLE(wxListCtrl, wxControl)
784 EVT_PAINT(wxListCtrl::OnPaint)
785END_EVENT_TABLE()
786
787// ============================================================================
788// implementation
789// ============================================================================
790
791// ----------------------------------------------------------------------------
792// wxListCtrl construction
793// ----------------------------------------------------------------------------
794
795void wxListCtrl::Init ()
796{
797 m_pImageListNormal = NULL;
798 m_pImageListSmall = NULL;
799 m_pImageListState = NULL;
800 m_bOwnsImageListNormal = false;
801 m_bOwnsImageListSmall = false;
802 m_bOwnsImageListState = false;
803 m_lBaseStyle = 0L;
804 m_nColCount = 0;
805 m_pTextCtrl = NULL;
806 m_bAnyInternalData = false;
807 m_bHasAnyAttr = false;
808} // end of wxListCtrl::Init
809
810bool wxListCtrl::Create ( wxWindow* pParent,
811 wxWindowID vId,
812 const wxPoint& rPos,
813 const wxSize& rSize,
814 long lStyle,
815 const wxValidator& rValidator,
816 const wxString& rsName )
817{
818 int nX = rPos.x;
819 int nY = rPos.y;
820 int nWidth = rSize.x;
821 int nHeight = rSize.y;
822
823#if wxUSE_VALIDATORS
824 SetValidator(rValidator);
825#endif // wxUSE_VALIDATORS
826
827 SetName(rsName);
828 SetWindowStyleFlag(lStyle);
829 SetParent(pParent);
830 if (nWidth <= 0)
831 nWidth = 100;
832 if (nHeight <= 0)
833 nHeight = 30;
834 if (nX < 0)
835 nX = 0;
836 if (nY < 0)
837 nY = 0;
838
839 m_windowId = (vId == -1) ? NewControlId() : vId;
840
841 long lSstyle = WS_VISIBLE | WS_TABSTOP;
842
843 if (GetWindowStyleFlag() & wxCLIP_SIBLINGS)
844 lSstyle |= WS_CLIPSIBLINGS;
845 m_lBaseStyle = lSstyle;
846 if (!DoCreateControl( nX
847 ,nY
848 ,nWidth
849 ,nHeight
850 ))
851 return false;
852 if (pParent)
853 pParent->AddChild(this);
854 return true;
855} // end of wxListCtrl::Create
856
857bool wxListCtrl::DoCreateControl ( int nX, int nY,
858 int nWidth, int nHeight )
859{
860 DWORD lWstyle = m_lBaseStyle;
861 long lOldStyle = 0; // Dummy
862
863 CNRINFO vCnrInfo;
864
865 lWstyle |= ConvertToOS2Style( lOldStyle
866 ,GetWindowStyleFlag()
867 );
868
869 m_hWnd = (WXHWND)::WinCreateWindow( GetParent()->GetHWND()
870 ,WC_CONTAINER
871 ,NULL
872 ,m_lBaseStyle
873 ,0, 0, 0, 0
874 ,GetParent()->GetHWND()
875 ,HWND_BOTTOM
876 ,(ULONG)m_windowId
877 ,NULL
878 ,NULL
879 );
880 if (!m_hWnd)
881 {
882 return false;
883 }
884
885 //
886 // Now set the display attributes of the container
887 //
888 if (!::WinSendMsg( GetHWND()
889 ,CM_QUERYCNRINFO
890 ,MPFROMP(&vCnrInfo)
891 ,(MPARAM)(USHORT)sizeof(CNRINFO)
892 ))
893 return false;
894 lWstyle = ConvertViewToOS2Style(GetWindowStyleFlag());
895 vCnrInfo.flWindowAttr |= lWstyle;
896 if (!::WinSendMsg( GetHWND()
897 ,CM_SETCNRINFO
898 ,MPFROMP(&vCnrInfo)
899 ,(MPARAM)CMA_FLWINDOWATTR
900 ))
901 return false;
902
903 //
904 // And now set needed arrangement flags
905 //
906 lWstyle = ConvertArrangeToOS2Style(GetWindowStyleFlag());
907 if (!::WinSendMsg( GetHWND()
908 ,CM_ARRANGE
909 ,(MPARAM)CMA_ARRANGEGRID
910 ,(MPARAM)lWstyle
911 ))
912 return false;
913 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
914 SetForegroundColour(GetParent()->GetForegroundColour());
915 SubclassWin(m_hWnd);
916 SetFont(*wxSMALL_FONT);
917 SetXComp(0);
918 SetYComp(0);
919 SetSize( nX, nY, nWidth, nHeight );
920 return true;
921} // end of wxListCtrl::DoCreateControl
922
923void wxListCtrl::UpdateStyle ()
924{
925 if (GetHWND())
926 {
927 long lDummy;
928 DWORD dwStyleNew = ConvertToOS2Style( lDummy, GetWindowStyleFlag() );
929
930 dwStyleNew |= m_lBaseStyle;
931
932 //
933 // Get the current window style.
934 //
935 ULONG dwStyleOld = ::WinQueryWindowULong(GetHWND(), QWL_STYLE);
936
937 //
938 // Only set the window style if the view bits have changed.
939 //
940 if (dwStyleOld != dwStyleNew)
941 {
942 ::WinSetWindowULong(GetHWND(), QWL_STYLE, dwStyleNew);
943 }
944 }
945} // end of wxListCtrl::UpdateStyle
946
947void wxListCtrl::FreeAllInternalData ()
948{
949 if (m_bAnyInternalData)
950 {
951 int n = GetItemCount();
952 int i = 0;
953
954 for (i = 0; i < n; i++)
955 DeleteInternalData(this, (long)i);
956 m_bAnyInternalData = false;
957 }
958} // end of wxListCtrl::FreeAllInternalData
959
960wxListCtrl::~wxListCtrl ()
961{
962 FreeAllInternalData();
963 if (m_pTextCtrl )
964 {
965 m_pTextCtrl->SetHWND(0);
966 m_pTextCtrl->UnsubclassWin();
967 wxDELETE(m_pTextCtrl);
968 }
969
970 if (m_bOwnsImageListNormal)
971 delete m_pImageListNormal;
972 if (m_bOwnsImageListSmall)
973 delete m_pImageListSmall;
974 if (m_bOwnsImageListState)
975 delete m_pImageListState;
976} // end of wxListCtrl::~wxListCtrl
977
978// ----------------------------------------------------------------------------
979// set/get/change style
980// ----------------------------------------------------------------------------
981
982// Add or remove a single window style
983void wxListCtrl::SetSingleStyle (
984 long lStyle
985, bool bAdd
986)
987{
988 long lFlag = GetWindowStyleFlag();
989
990 //
991 // Get rid of conflicting styles
992 //
993 if (bAdd)
994 {
995 if (lStyle & wxLC_MASK_TYPE)
996 lFlag = lFlag & ~wxLC_MASK_TYPE;
997 if (lStyle & wxLC_MASK_ALIGN )
998 lFlag = lFlag & ~wxLC_MASK_ALIGN;
999 if (lStyle & wxLC_MASK_SORT )
1000 lFlag = lFlag & ~wxLC_MASK_SORT;
1001 }
1002 if (lFlag & lStyle)
1003 {
1004 if (!bAdd)
1005 lFlag -= lStyle;
1006 }
1007 else
1008 {
1009 if (bAdd)
1010 {
1011 lFlag |= lStyle;
1012 }
1013 }
1014 m_windowStyle = lFlag;
1015 UpdateStyle();
1016} // end of wxListCtrl::SetSingleStyle
1017
1018// Set the whole window style
1019void wxListCtrl::SetWindowStyleFlag (
1020 long lFlag
1021)
1022{
1023 m_windowStyle = lFlag;
1024 UpdateStyle();
1025} // end of wxListCtrl::SetWindowStyleFlag
1026
1027long wxListCtrl::ConvertToOS2Style (
1028 long& rOldStyle
1029, long lStyle
1030) const
1031{
1032 long lWstyle = 0L;
1033
1034 //
1035 // The only styles OS2 uses on creation are auto arrange, read only, and
1036 // and selection styles. This lib does not support OS/2 MINIRECORDCORE
1037 // or VERIFYPOINTER styles
1038 //
1039 if (lStyle & wxLC_AUTOARRANGE)
1040 lWstyle |= CCS_AUTOPOSITION;
1041 if (lStyle & wxLC_SINGLE_SEL)
1042 lWstyle |= CCS_SINGLESEL;
1043 else
1044 lWstyle |= CCS_EXTENDSEL;
1045 if (!(lStyle & wxLC_EDIT_LABELS))
1046 lWstyle |= CCS_READONLY;
1047 return lWstyle;
1048} // end of wxListCtrl::ConvertToOS2Style
1049
1050long wxListCtrl::ConvertArrangeToOS2Style (
1051 long lStyle
1052)
1053{
1054 long lWstyle = 0;
1055
1056 if (lStyle & wxLC_ALIGN_LEFT)
1057 {
1058 lWstyle |= CMA_LEFT;
1059 }
1060
1061 if (lStyle & wxLC_ALIGN_TOP)
1062 {
1063 lWstyle |= CMA_TOP;
1064 }
1065 return lWstyle;
1066} // end of wxListCtrl::ConvertArrangeToOS2Style
1067
1068long wxListCtrl::ConvertViewToOS2Style (
1069 long lStyle
1070)
1071{
1072 long lWstyle = CA_DRAWICON; // we will only use icons
1073
1074 if (lStyle & wxLC_ICON)
1075 {
1076 lWstyle |= CV_ICON;
1077 }
1078 if (lStyle & wxLC_SMALL_ICON)
1079 {
1080 lWstyle |= (CV_ICON | CV_MINI);
1081 }
1082 if (lStyle & wxLC_LIST)
1083 {
1084 lWstyle |= CV_TEXT;
1085 }
1086 if (lStyle & wxLC_REPORT)
1087 {
1088 lWstyle |= CV_DETAIL;
1089 }
1090 if (lStyle & wxLC_VIRTUAL)
1091 {
1092 lWstyle |= CA_OWNERDRAW;
1093 }
1094 if (lStyle & wxLC_AUTOARRANGE)
1095 {
1096 lWstyle |= CV_FLOW;
1097 }
1098 if (!(lStyle & wxLC_NO_HEADER))
1099 {
1100 lWstyle |= CA_DETAILSVIEWTITLES;
1101 }
1102 return lWstyle;
1103} // end of wxListCtrl::ConvertViewToOS2Style
1104
1105// ----------------------------------------------------------------------------
1106// accessors
1107// ----------------------------------------------------------------------------
1108
1109// Sets the foreground, i.e. text, colour
1110bool wxListCtrl::SetForegroundColour (const wxColour& rCol)
1111{
1112 ULONG ulColor = wxColourToRGB(rCol);
1113
1114 if (!wxWindow::SetForegroundColour(rCol))
1115 return false;
1116
1117 ::WinSetPresParam( GetHWND()
1118 ,PP_FOREGROUNDCOLOR
1119 ,sizeof(ULONG)
1120 ,&ulColor
1121 );
1122 return true;
1123} // end of wxListCtrl::SetForegroundColour
1124
1125// Sets the background colour
1126bool wxListCtrl::SetBackgroundColour ( const wxColour& rCol )
1127{
1128 if (!wxWindow::SetBackgroundColour(rCol))
1129 return false;
1130
1131 //
1132 // We set the same colour for both the "empty" background and the items
1133 // background
1134 //
1135 ULONG ulColor = wxColourToRGB(rCol);
1136
1137 ::WinSetPresParam( GetHWND()
1138 ,PP_BACKGROUNDCOLOR
1139 ,sizeof(ULONG)
1140 ,&ulColor
1141 );
1142 return true;
1143} // end of wxListCtrl::SetBackgroundColour
1144
1145// Gets information about this column
1146bool wxListCtrl::GetColumn ( int nCol, wxListItem& rItem ) const
1147{
1148 PFIELDINFO pFieldInfo = FindOS2ListFieldByColNum ( GetHWND(), nCol );
1149
1150 if (!pFieldInfo)
1151 return false;
1152 rItem.SetWidth(pFieldInfo->cxWidth);
1153 if ((rItem.GetMask() & wxLIST_MASK_TEXT) &&
1154 (pFieldInfo->flData & CFA_STRING) &&
1155 (pFieldInfo->pUserData != NULL))
1156 {
1157 rItem.SetText((char*)pFieldInfo->pUserData);
1158 }
1159 if (rItem.GetMask() & wxLIST_MASK_FORMAT )
1160 {
1161 if (pFieldInfo->flData & CFA_LEFT)
1162 rItem.m_format = wxLIST_FORMAT_LEFT;
1163 else if (pFieldInfo->flData & CFA_RIGHT)
1164 rItem.m_format = wxLIST_FORMAT_RIGHT;
1165 else if (pFieldInfo->flData & CFA_CENTER)
1166 rItem.m_format = wxLIST_FORMAT_CENTRE;
1167 }
1168 return true;
1169} // end of wxListCtrl::GetColumn
1170
1171// Sets information about this column
1172bool wxListCtrl::SetColumn ( int nCol, wxListItem& rItem )
1173{
1174 PFIELDINFO pFieldInfo = FindOS2ListFieldByColNum( GetHWND(), nCol );
1175 ConvertToOS2ListCol( nCol, rItem, pFieldInfo );
1176 //
1177 // Since we changed the field pointed to, we invalidate to see the result
1178 //
1179 ::WinSendMsg(GetHWND(), CM_INVALIDATEDETAILFIELDINFO, NULL, NULL);
1180 return true;
1181} // end of wxListCtrl::SetColumn
1182
1183// Gets the column width
1184int wxListCtrl::GetColumnWidth ( int nCol ) const
1185{
1186 PFIELDINFO pFieldInfo = FindOS2ListFieldByColNum ( GetHWND(), nCol );
1187
1188 if (!pFieldInfo)
1189 return 0;
1190 return((int)pFieldInfo->cxWidth);
1191} // end of wxListCtrl::GetColumnWidth
1192
1193// Sets the column width
1194bool wxListCtrl::SetColumnWidth ( int nCol, int nWidth )
1195{
1196 int nCol2 = nCol;
1197 int nWidth2 = nWidth;
1198
1199 if (GetWindowStyleFlag() & wxLC_LIST)
1200 nCol2 = -1;
1201
1202 PFIELDINFO pFieldInfo = FindOS2ListFieldByColNum( GetHWND(), nCol );
1203 pFieldInfo->cxWidth = nWidth;
1204 ::WinSendMsg(GetHWND(), CM_INVALIDATEDETAILFIELDINFO, NULL, NULL);
1205 return true;
1206} // end of wxListCtrl::SetColumnWidth
1207
1208// Gets the number of items that can fit vertically in the
1209// visible area of the list control (list or report view)
1210// or the total number of items in the list control (icon
1211// or small icon view)
1212int wxListCtrl::GetCountPerPage () const
1213{
1214 QUERYRECORDRECT vQueryRect;
1215 CNRINFO vCnrInfo;
1216 RECTL vRectRecord;
1217 RECTL vRectControl;
1218 int nCount;
1219
1220 if (!::WinSendMsg( GetHWND()
1221 ,CM_QUERYCNRINFO
1222 ,MPFROMP(&vCnrInfo)
1223 ,(MPARAM)(USHORT)sizeof(CNRINFO)
1224 ))
1225 return 0;
1226 memset(&vQueryRect, '\0', sizeof(QUERYRECORDRECT));
1227 vQueryRect.cb = sizeof(QUERYRECORDRECT);
1228 if (vCnrInfo.flWindowAttr & CV_ICON)
1229 vQueryRect.fsExtent = CMA_ICON | CMA_TEXT;
1230 else if (vCnrInfo.flWindowAttr & CV_NAME)
1231 vQueryRect.fsExtent = CMA_ICON | CMA_TEXT;
1232 else if (vCnrInfo.flWindowAttr & CV_TEXT)
1233 vQueryRect.fsExtent = CMA_TEXT;
1234 else if (vCnrInfo.flWindowAttr & CV_DETAIL)
1235 vQueryRect.fsExtent = CMA_TEXT;
1236 if (!::WinSendMsg( GetHWND()
1237 ,CM_QUERYRECORDRECT
1238 ,MPFROMP(&vRectRecord)
1239 ,MPFROMP(&vQueryRect)
1240 ))
1241 return 0;
1242 if (!::WinSendMsg( GetHWND()
1243 ,CM_QUERYVIEWPORTRECT
1244 ,MPFROMP(&vRectControl)
1245 ,MPFROM2SHORT(CMA_WINDOW, (USHORT)FALSE)
1246 ))
1247 return 0;
1248 nCount = (int)((int)((vRectControl.xRight - vRectControl.xLeft) / (vRectRecord.xRight - vRectRecord.xLeft)) *
1249 (int)((vRectControl.yTop - vRectControl.yBottom) / (vRectRecord.yTop - vRectRecord.yBottom))
1250 );
1251 if (nCount > (int)vCnrInfo.cFields)
1252 nCount = (int)vCnrInfo.cFields;
1253 return nCount;
1254} // end of wxListCtrl::GetCountPerPage
1255
1256// Gets the edit control for editing labels.
1257wxTextCtrl* wxListCtrl::GetEditControl() const
1258{
1259 return m_pTextCtrl;
1260}
1261
1262// Gets information about the item
1263bool wxListCtrl::GetItem ( wxListItem& rInfo ) const
1264{
1265 PMYRECORD pRecord = FindOS2ListRecordByID( GetHWND(), rInfo.GetId() );
1266
1267 //
1268 // Give NULL as hwnd as we already have everything we need
1269 //
1270 ConvertFromOS2ListItem( NULL, rInfo, pRecord );
1271 return true;
1272} // end of wxListCtrl::GetItem
1273
1274// Sets information about the item
1275bool wxListCtrl::SetItem ( wxListItem& rInfo )
1276{
1277 PFIELDINFO pFieldInfo = FindOS2ListFieldByColNum ( GetHWND(), rInfo.GetColumn() );
1278 PMYRECORD pRecord = FindOS2ListRecordByID( GetHWND(), rInfo.GetId() );
1279
1280 ConvertToOS2ListItem( this
1281 ,rInfo
1282 ,pRecord
1283 ,pFieldInfo
1284 );
1285
1286 //
1287 // Check if setting attributes or lParam
1288 //
1289 if (rInfo.HasAttributes() || (rInfo.GetMask() & wxLIST_MASK_DATA))
1290 {
1291 //
1292 // Get internal item data
1293 // perhaps a cache here ?
1294 //
1295 CListItemInternalData* pData = GetInternalData( this
1296 ,rInfo.GetId()
1297 );
1298
1299 if (!pData)
1300 {
1301 //
1302 // Need to set it
1303 //
1304 m_bAnyInternalData = true;
1305 pData = new CListItemInternalData();
1306 pRecord->m_ulUserData = (unsigned long)pData;
1307 };
1308
1309 //
1310 // User data
1311 //
1312 if (rInfo.GetMask() & wxLIST_MASK_DATA)
1313 pData->m_lParam = (WXLPARAM)rInfo.GetData();
1314
1315 // attributes
1316 if (rInfo.HasAttributes())
1317 {
1318 if (pData->m_pAttr)
1319 *pData->m_pAttr = *rInfo.GetAttributes();
1320 else
1321 pData->m_pAttr = new wxListItemAttr(*rInfo.GetAttributes());
1322 }
1323 pData->m_pMyRecord = pRecord; // they point to each other
1324 }
1325
1326 //
1327 // We need to update the item immediately to show the new image
1328 //
1329 bool bUpdateNow = (rInfo.GetMask() & wxLIST_MASK_IMAGE) != 0;
1330
1331 //
1332 // Check whether it has any custom attributes
1333 //
1334 if (rInfo.HasAttributes())
1335 {
1336 m_bHasAnyAttr = true;
1337
1338 //
1339 // If the colour has changed, we must redraw the item
1340 //
1341 bUpdateNow = true;
1342 }
1343 if (::WinIsWindowVisible(GetHWND()))
1344 {
1345 ::WinSendMsg( GetHWND()
1346 ,CM_INVALIDATERECORD
1347 ,MPFROMP(pRecord)
1348 ,MPFROM2SHORT(1, CMA_ERASE | CMA_REPOSITION | CMA_TEXTCHANGED)
1349 );
1350 RefreshItem(pRecord->m_ulItemId);
1351 }
1352 ::WinSendMsg( GetHWND()
1353 ,CM_INVALIDATEDETAILFIELDINFO
1354 ,NULL
1355 ,NULL
1356 );
1357 return true;
1358} // end of wxListCtrl::SetItem
1359
1360long wxListCtrl::SetItem (
1361 long lIndex
1362, int nCol
1363, const wxString& rsLabel
1364, int nImageId
1365)
1366{
1367 wxListItem vInfo;
1368
1369 vInfo.m_text = rsLabel;
1370 vInfo.m_mask = wxLIST_MASK_TEXT;
1371 vInfo.m_itemId = lIndex;
1372 vInfo.m_col = nCol;
1373 if (nImageId > -1)
1374 {
1375 vInfo.m_image = nImageId;
1376 vInfo.m_mask |= wxLIST_MASK_IMAGE;
1377 }
1378 return SetItem(vInfo);
1379} // end of wxListCtrl::SetItem
1380
1381// Gets the item state
1382int wxListCtrl::GetItemState (
1383 long lItem
1384, long lStateMask
1385) const
1386{
1387 wxListItem vInfo;
1388
1389 vInfo.m_mask = wxLIST_MASK_STATE;
1390 vInfo.m_stateMask = lStateMask;
1391 vInfo.m_itemId = lItem;
1392
1393 if (!GetItem(vInfo))
1394 return 0;
1395 return vInfo.m_state;
1396} // end of wxListCtrl::GetItemState
1397
1398// Sets the item state
1399bool wxListCtrl::SetItemState ( long lItem, long lState, long lStateMask )
1400{
1401 PMYRECORD pRecord = FindOS2ListRecordByID( GetHWND(), lItem );
1402
1403 //
1404 // Don't use SetItem() here as it doesn't work with the virtual list
1405 // controls
1406 //
1407 ConvertToOS2Flags( lState, pRecord );
1408
1409 //
1410 // for the virtual list controls we need to refresh the previously focused
1411 // item manually when changing focus without changing selection
1412 // programmatically because otherwise it keeps its focus rectangle until
1413 // next repaint (yet another comctl32 bug)
1414 //
1415 long lFocusOld;
1416
1417 if (IsVirtual() &&
1418 (lStateMask & wxLIST_STATE_FOCUSED) &&
1419 (lState & wxLIST_STATE_FOCUSED) )
1420 {
1421 lFocusOld = GetNextItem( -1
1422 ,wxLIST_NEXT_ALL
1423 ,wxLIST_STATE_FOCUSED
1424 );
1425 }
1426 else
1427 {
1428 lFocusOld = -1;
1429 }
1430 ::WinSendMsg( GetHWND()
1431 ,CM_INVALIDATERECORD
1432 ,MPFROMP(pRecord)
1433 ,MPFROM2SHORT(1, CMA_ERASE | CMA_REPOSITION | CMA_TEXTCHANGED)
1434 );
1435
1436 if (lFocusOld != -1)
1437 {
1438 //
1439 // No need to refresh the item if it was previously selected, it would
1440 // only result in annoying flicker
1441 //
1442 if (!(GetItemState( lFocusOld
1443 ,wxLIST_STATE_SELECTED
1444 ) & wxLIST_STATE_SELECTED))
1445 {
1446 RefreshItem(lFocusOld);
1447 }
1448 }
1449 return true;
1450} // end of wxListCtrl::SetItemState
1451
1452// Sets the item image
1453bool wxListCtrl::SetItemImage (
1454 long lItem
1455, int nImage
1456, int WXUNUSED(nSelImage))
1457{
1458 return SetItemColumnInfo(lItem, 0, nImage);
1459} // end of wxListCtrl::SetItemImage
1460
1461// Sets the item image
1462bool wxListCtrl::SetItemColumnImage (
1463 long lItem
1464, long lColumn
1465, int nImage)
1466{
1467 wxListItem vInfo;
1468
1469 vInfo.m_mask = wxLIST_MASK_IMAGE;
1470 vInfo.m_image = nImage;
1471 vInfo.m_itemId = lItem;
1472 vInfo.m_col = lColumn;
1473 return SetItem(vInfo);
1474} // end of wxListCtrl::SetItemColumnImage
1475
1476// Gets the item text
1477wxString wxListCtrl::GetItemText (
1478 long lItem
1479) const
1480{
1481 wxListItem vInfo;
1482
1483 vInfo.m_mask = wxLIST_MASK_TEXT;
1484 vInfo.m_itemId = lItem;
1485
1486 if (!GetItem(vInfo))
1487 return wxEmptyString;
1488 return vInfo.m_text;
1489} // end of wxListCtrl::GetItemText
1490
1491// Sets the item text
1492void wxListCtrl::SetItemText (
1493 long lItem
1494, const wxString& rsStr
1495)
1496{
1497 wxListItem vInfo;
1498
1499 vInfo.m_mask = wxLIST_MASK_TEXT;
1500 vInfo.m_itemId = lItem;
1501 vInfo.m_text = rsStr;
1502 SetItem(vInfo);
1503} // end of wxListCtrl::SetItemText
1504
1505// Gets the item data
1506long wxListCtrl::GetItemData (
1507 long lItem
1508) const
1509{
1510 wxListItem vInfo;
1511
1512 vInfo.m_mask = wxLIST_MASK_DATA;
1513 vInfo.m_itemId = lItem;
1514 if (!GetItem(vInfo))
1515 return 0;
1516 return vInfo.m_data;
1517} // end of wxListCtrl::GetItemData
1518
1519// Sets the item data
1520bool wxListCtrl::SetItemPtrData (
1521 long lItem
1522, wxUIntPtr lData
1523)
1524{
1525 wxListItem vInfo;
1526
1527 vInfo.m_mask = wxLIST_MASK_DATA;
1528 vInfo.m_itemId = lItem;
1529 vInfo.m_data = lData;
1530 return SetItem(vInfo);
1531} // end of wxListCtrl::SetItemPtrData
1532
1533// Gets the item rectangle
1534bool wxListCtrl::GetItemRect ( long lItem,
1535 wxRect& rRect,
1536 int nCode ) const
1537{
1538 bool bSuccess;
1539 PMYRECORD pRecord = FindOS2ListRecordByID( GetHWND(), lItem );
1540 QUERYRECORDRECT vQueryRect;
1541 RECTL vRect;
1542 int nHeight;
1543
1544 if (!pRecord)
1545 return false;
1546 vQueryRect.cb = sizeof(QUERYRECORDRECT);
1547 vQueryRect.pRecord = &pRecord->m_vRecord;
1548 vQueryRect.fRightSplitWindow = TRUE;
1549 vQueryRect.fsExtent = CMA_ICON | CMA_TEXT;
1550 ::WinSendMsg( GetHWND()
1551 ,CM_QUERYRECORDRECT
1552 ,MPFROMP(&vRect)
1553 ,MPFROMP(&vQueryRect)
1554 );
1555 //
1556 // remember OS/2 is backwards
1557 //
1558 GetClientSize( NULL, &nHeight );
1559 rRect.x = vRect.xLeft;
1560 rRect.y = nHeight - vRect.yTop;
1561 rRect.width = vRect.xRight;
1562 rRect.height = nHeight - vRect.yBottom;
1563 bSuccess = true;
1564 return bSuccess;
1565} // end of wxListCtrl::GetItemRect
1566
1567// Gets the item position
1568bool wxListCtrl::GetItemPosition ( long lItem, wxPoint& rPos ) const
1569{
1570 bool bSuccess;
1571 PMYRECORD pRecord = FindOS2ListRecordByID( GetHWND() , lItem );
1572 QUERYRECORDRECT vQueryRect;
1573 RECTL vRect;
1574 int nHeight;
1575
1576 if (!pRecord)
1577 return false;
1578 vQueryRect.cb = sizeof(QUERYRECORDRECT);
1579 vQueryRect.pRecord = &pRecord->m_vRecord;
1580 vQueryRect.fRightSplitWindow = TRUE;
1581 vQueryRect.fsExtent = CMA_ICON | CMA_TEXT;
1582 ::WinSendMsg( GetHWND()
1583 ,CM_QUERYRECORDRECT
1584 ,MPFROMP(&vRect)
1585 ,MPFROMP(&vQueryRect)
1586 );
1587 //
1588 // remember OS/2 is backwards
1589 //
1590 GetClientSize( NULL, &nHeight );
1591 rPos.x = vRect.xLeft;
1592 rPos.y = nHeight - vRect.yTop;
1593 bSuccess = true;
1594 return bSuccess;
1595} // end of wxListCtrl::GetItemPosition
1596
1597// Sets the item position.
1598bool wxListCtrl::SetItemPosition ( long lItem, const wxPoint& rPos )
1599{
1600 //
1601 // Items cannot be positioned in X/Y coord in OS/2
1602 //
1603 return false;
1604} // end of wxListCtrl::SetItemPosition
1605
1606// Gets the number of items in the list control
1607int wxListCtrl::GetItemCount () const
1608{
1609 CNRINFO vCnrInfo;
1610
1611 if (!::WinSendMsg( GetHWND()
1612 ,CM_QUERYCNRINFO
1613 ,MPFROMP(&vCnrInfo)
1614 ,(MPARAM)(USHORT)sizeof(CNRINFO)
1615 ))
1616 return -1;
1617 return vCnrInfo.cRecords;
1618} // end of wxListCtrl::GetItemCount
1619
1620// Retrieves the spacing between icons in pixels.
1621// If bIsSmall is true, gets the spacing for the small icon
1622// view, otherwise the large icon view.
1623int wxListCtrl::GetItemSpacing ( bool bIsSmall ) const
1624{
1625 CNRINFO vCnrInfo;
1626
1627 if (!::WinSendMsg( GetHWND()
1628 ,CM_QUERYCNRINFO
1629 ,MPFROMP(&vCnrInfo)
1630 ,(MPARAM)(USHORT)sizeof(CNRINFO)
1631 ))
1632 return -1;
1633 return vCnrInfo.cyLineSpacing;
1634} // end of wxListCtrl::GetItemSpacing
1635
1636void wxListCtrl::SetItemTextColour (
1637 long lItem
1638, const wxColour& rCol
1639)
1640{
1641 wxListItem vInfo;
1642
1643 vInfo.m_itemId = lItem;
1644 vInfo.SetTextColour(rCol);
1645 SetItem(vInfo);
1646} // end of wxListCtrl::SetItemTextColour
1647
1648wxColour wxListCtrl::GetItemTextColour (
1649 long lItem
1650) const
1651{
1652 wxListItem vInfo;
1653
1654 vInfo.m_itemId = lItem;
1655 GetItem(vInfo);
1656 return vInfo.GetTextColour();
1657} // end of wxListCtrl::GetItemTextColour
1658
1659void wxListCtrl::SetItemBackgroundColour (
1660 long lItem
1661, const wxColour& rCol
1662)
1663{
1664 wxListItem vInfo;
1665
1666 vInfo.m_itemId = lItem;
1667 vInfo.SetBackgroundColour(rCol);
1668 SetItem(vInfo);
1669} // end of wxListCtrl::SetItemBackgroundColour
1670
1671wxColour wxListCtrl::GetItemBackgroundColour (
1672 long lItem
1673) const
1674{
1675 wxListItem vInfo;
1676
1677 vInfo.m_itemId = lItem;
1678 GetItem(vInfo);
1679 return vInfo.GetBackgroundColour();
1680} // end of wxListCtrl::GetItemBackgroundColour
1681
1682// Gets the number of selected items in the list control
1683int wxListCtrl::GetSelectedItemCount () const
1684{
1685 PMYRECORD pRecord = NULL;
1686 int nCount = 0;
1687 pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( GetHWND()
1688 ,CM_QUERYRECORDEMPHASIS
1689 ,(MPARAM)CMA_FIRST
1690 ,(MPARAM)CRA_SELECTED
1691 ));
1692 if (pRecord)
1693 nCount++;
1694 else
1695 return 0;
1696 while (pRecord)
1697 {
1698 pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( GetHWND()
1699 ,CM_QUERYRECORDEMPHASIS
1700 ,MPFROMP(pRecord)
1701 ,(MPARAM)CRA_SELECTED
1702 ));
1703 if (pRecord)
1704 nCount++;
1705 }
1706 return nCount;
1707} // end of wxListCtrl::GetSelectedItemCount
1708
1709// Gets the text colour of the listview
1710wxColour wxListCtrl::GetTextColour () const
1711{
1712 wxColour vCol;
1713 ULONG ulColor;
1714
1715 ::WinQueryPresParam( GetHWND()
1716 ,PP_FOREGROUNDCOLOR
1717 ,0
1718 ,NULL
1719 ,sizeof(ULONG)
1720 ,&ulColor
1721 ,QPF_PURERGBCOLOR
1722 );
1723 vCol.Set(ulColor);
1724 return vCol;
1725} // end of wxListCtrl::GetTextColour
1726
1727// Sets the text colour of the listview
1728void wxListCtrl::SetTextColour (
1729 const wxColour& rCol
1730)
1731{
1732 ULONG ulColor = wxColourToRGB(rCol);
1733
1734 ::WinSetPresParam( GetHWND()
1735 ,PP_FOREGROUNDCOLOR
1736 ,sizeof(ULONG)
1737 ,&ulColor
1738 );
1739} // end of wxListCtrl::SetTextColour
1740
1741// Gets the index of the topmost visible item when in
1742// list or report view
1743long wxListCtrl::GetTopItem () const
1744{
1745 PMYRECORD pRecord = NULL;
1746 QUERYRECFROMRECT vQueryRect;
1747 RECTL vRect;
1748
1749 ::WinSendMsg( GetHWND()
1750 ,CM_QUERYVIEWPORTRECT
1751 ,MPFROMP(&vRect)
1752 ,MPFROM2SHORT(CMA_WINDOW, TRUE)
1753 );
1754 vQueryRect.cb = sizeof(QUERYRECFROMRECT);
1755 vQueryRect.rect = vRect;
1756 vQueryRect.fsSearch = CMA_PARTIAL;
1757
1758 pRecord = (PMYRECORD)::WinSendMsg( GetHWND()
1759 ,CM_QUERYRECORDFROMRECT
1760 ,(MPARAM)CMA_FIRST
1761 ,MPFROMP(&vQueryRect)
1762 );
1763
1764 if (!pRecord)
1765 return -1L;
1766 return (long)pRecord->m_ulItemId;
1767} // end of wxListCtrl::GetTopItem
1768
1769// Searches for an item, starting from 'item'.
1770// 'geometry' is one of
1771// wxLIST_NEXT_ABOVE/ALL/BELOW/LEFT/RIGHT.
1772// 'state' is a state bit flag, one or more of
1773// wxLIST_STATE_DROPHILITED/FOCUSED/SELECTED/CUT.
1774// item can be -1 to find the first item that matches the
1775// specified flags.
1776// Returns the item or -1 if unsuccessful.
1777long wxListCtrl::GetNextItem (
1778 long lItem
1779, int WXUNUSED(nGeom)
1780, int WXUNUSED(nState)
1781) const
1782{
1783 PMYRECORD pRecord = FindOS2ListRecordByID( GetHWND()
1784 ,lItem
1785 );
1786
1787 pRecord = (PMYRECORD)pRecord->m_vRecord.preccNextRecord;
1788 if (pRecord)
1789 return((long)pRecord->m_ulItemId);
1790 return -1L;
1791} // end of wxListCtrl::GetNextItem
1792
1793wxImageList* wxListCtrl::GetImageList (
1794 int nWhich
1795) const
1796{
1797 if (nWhich == wxIMAGE_LIST_NORMAL )
1798 {
1799 return m_pImageListNormal;
1800 }
1801 else if (nWhich == wxIMAGE_LIST_SMALL )
1802 {
1803 return m_pImageListSmall;
1804 }
1805 else if (nWhich == wxIMAGE_LIST_STATE )
1806 {
1807 return m_pImageListState;
1808 }
1809 return NULL;
1810} // end of wxListCtrl::GetImageList
1811
1812void wxListCtrl::SetImageList ( wxImageList* pImageList,
1813 int nWhich )
1814{
1815 if (nWhich == wxIMAGE_LIST_NORMAL)
1816 {
1817 if (m_bOwnsImageListNormal)
1818 delete m_pImageListNormal;
1819 m_pImageListNormal = pImageList;
1820 m_bOwnsImageListNormal = false;
1821 }
1822 else if (nWhich == wxIMAGE_LIST_SMALL)
1823 {
1824 if (m_bOwnsImageListSmall)
1825 delete m_pImageListSmall;
1826 m_pImageListSmall = pImageList;
1827 m_bOwnsImageListSmall = false;
1828 }
1829 else if (nWhich == wxIMAGE_LIST_STATE)
1830 {
1831 if (m_bOwnsImageListState)
1832 delete m_pImageListState;
1833 m_pImageListState = pImageList;
1834 m_bOwnsImageListState = false;
1835 }
1836} // end of wxListCtrl::SetImageList
1837
1838void wxListCtrl::AssignImageList ( wxImageList* pImageList, int nWhich )
1839{
1840 SetImageList( pImageList, nWhich );
1841
1842 if (nWhich == wxIMAGE_LIST_NORMAL )
1843 m_bOwnsImageListNormal = true;
1844 else if (nWhich == wxIMAGE_LIST_SMALL )
1845 m_bOwnsImageListSmall = true;
1846 else if (nWhich == wxIMAGE_LIST_STATE )
1847 m_bOwnsImageListState = true;
1848} // end of wxListCtrl::AssignImageList
1849
1850// ----------------------------------------------------------------------------
1851// Operations
1852// ----------------------------------------------------------------------------
1853
1854// Arranges the items
1855bool wxListCtrl::Arrange ( int nFlag )
1856{
1857 ULONG ulType = 0L;
1858 ULONG ulFlags = 0L;
1859
1860 if (nFlag == wxLIST_ALIGN_SNAP_TO_GRID)
1861 {
1862 ulType = CMA_ARRANGEGRID;
1863 if (nFlag == wxLIST_ALIGN_LEFT)
1864 ulFlags |= CMA_LEFT;
1865 else if (nFlag == wxLIST_ALIGN_TOP)
1866 ulFlags |= CMA_TOP;
1867 else if (nFlag == wxLIST_ALIGN_DEFAULT)
1868 ulFlags |= CMA_LEFT;
1869 }
1870 else
1871 ulType = CMA_ARRANGESTANDARD;
1872 ::WinSendMsg( GetHWND()
1873 ,CM_ARRANGE
1874 ,(MPARAM)ulType
1875 ,(MPARAM)ulFlags
1876 );
1877 //
1878 // We do not support CMA_ARRANGESELECTED
1879 //
1880 return true;
1881} // end of wxListCtrl::Arrange
1882
1883// Deletes an item
1884bool wxListCtrl::DeleteItem ( long lItem )
1885{
1886 PMYRECORD pRecord = FindOS2ListRecordByID( GetHWND(), lItem );
1887 if (LONGFROMMR(::WinSendMsg( GetHWND()
1888 ,CM_REMOVERECORD
1889 ,(MPARAM)pRecord
1890 ,MPFROM2SHORT(1, CMA_FREE)
1891 )) == -1L)
1892 {
1893 return false;
1894 }
1895
1896 //
1897 // The virtual list control doesn't refresh itself correctly, help it
1898 //
1899 if (IsVirtual())
1900 {
1901 //
1902 // We need to refresh all the lines below the one which was deleted
1903 //
1904 wxRect vRectItem;
1905
1906 if (lItem > 0 && GetItemCount())
1907 {
1908 GetItemRect( lItem - 1
1909 ,vRectItem
1910 );
1911 }
1912 else
1913 {
1914 vRectItem.y = vRectItem.height = 0;
1915 }
1916 wxRect vRectWin = GetRect();
1917
1918 vRectWin.height = vRectWin.GetBottom() - vRectItem.GetBottom();
1919 vRectWin.y = vRectItem.GetBottom();
1920 RefreshRect(vRectWin);
1921 }
1922 return true;
1923} // end of wxListCtrl::DeleteItem
1924
1925// Deletes all items
1926bool wxListCtrl::DeleteAllItems ()
1927{
1928 return((LONG)::WinSendMsg( GetHWND()
1929 ,CM_REMOVERECORD
1930 ,NULL
1931 ,MPFROM2SHORT(0, CMA_FREE)
1932 ) != -1L);
1933} // end of wxListCtrl::DeleteAllItems
1934
1935// Deletes all items
1936bool wxListCtrl::DeleteAllColumns ()
1937{
1938 while (m_nColCount > 0)
1939 {
1940 DeleteColumn(m_nColCount - 1);
1941 m_nColCount--;
1942 }
1943
1944 wxASSERT_MSG(m_nColCount == 0, wxT("no columns should be left"));
1945 return true;
1946} // end of wxListCtrl::DeleteAllColumns
1947
1948// Deletes a column
1949bool wxListCtrl::DeleteColumn ( int nCol )
1950{
1951 bool bSuccess = false;
1952 PFIELDINFO pField = FindOS2ListFieldByColNum( GetHWND(), nCol );
1953 bSuccess = ((LONG)::WinSendMsg( GetHWND()
1954 ,CM_REMOVEDETAILFIELDINFO
1955 ,MPFROMP(pField)
1956 ,MPFROM2SHORT((SHORT)1, CMA_FREE)
1957 ) == -1L);
1958 if (bSuccess && (m_nColCount > 0))
1959 m_nColCount--;
1960 return bSuccess;
1961} // end of wxListCtrl::DeleteColumn
1962
1963// Clears items, and columns if there are any.
1964void wxListCtrl::ClearAll ()
1965{
1966 DeleteAllItems();
1967 if (m_nColCount > 0)
1968 DeleteAllColumns();
1969} // end of wxListCtrl::ClearAll
1970
1971//
1972// OS/2 does not use a text control for its container labels. You merely
1973// "open" a record for editting.
1974//
1975wxTextCtrl* wxListCtrl::EditLabel (
1976 long lItem
1977, wxClassInfo* WXUNUSED(pTextControlClass)
1978)
1979{
1980 CNREDITDATA vEdit;
1981 PMYRECORD pRecord = FindOS2ListRecordByID( GetHWND()
1982 ,lItem
1983 );
1984
1985 vEdit.cb = sizeof(CNREDITDATA);
1986 vEdit.hwndCnr = GetHWND();
1987 vEdit.pRecord = &pRecord->m_vRecord;
1988 vEdit.pFieldInfo = NULL;
1989 vEdit.ppszText = NULL;
1990 vEdit.cbText = 0;
1991 vEdit.id = 0;
1992
1993 ::WinSendMsg( GetHWND()
1994 ,CM_OPENEDIT
1995 ,MPFROMP(&vEdit)
1996 ,(MPARAM)0
1997 );
1998 return m_pTextCtrl;
1999} // end of wxListCtrl::EditLabel
2000
2001// End label editing, optionally cancelling the edit. Under OS/2 you close
2002// the record for editting
2003bool wxListCtrl::EndEditLabel ( bool WXUNUSED(bCancel) )
2004{
2005 ::WinSendMsg( GetHWND()
2006 ,CM_CLOSEEDIT
2007 ,(MPARAM)0
2008 ,(MPARAM)0
2009 );
2010 return true;
2011} // end of wxListCtrl::EndEditLabel
2012
2013// Ensures this item is visible
2014bool wxListCtrl::EnsureVisible ( long lItem )
2015{
2016 PMYRECORD pRecord = FindOS2ListRecordByID( GetHWND(), lItem );
2017 ::WinSendMsg( GetHWND()
2018 ,CM_INVALIDATERECORD
2019 ,MPFROMP(pRecord)
2020 ,MPFROM2SHORT((SHORT)1, CMA_NOREPOSITION)
2021 );
2022 return true;
2023} // end of wxListCtrl::EnsureVisible
2024
2025// Find an item whose label matches this string, starting from the item after 'start'
2026// or the beginning if 'start' is -1.
2027long wxListCtrl::FindItem (
2028 long lStart
2029, const wxString& rsStr
2030, bool bPartial
2031)
2032{
2033 CNRINFO vCnrInfo;
2034 SEARCHSTRING vSearch;
2035 PMYRECORD pRecord = FindOS2ListRecordByID( GetHWND()
2036 ,lStart
2037 );
2038 ULONG ulFlag;
2039
2040
2041 if (!::WinSendMsg( GetHWND()
2042 ,CM_QUERYCNRINFO
2043 ,MPFROMP(&vCnrInfo)
2044 ,(MPARAM)(USHORT)sizeof(CNRINFO)
2045 ))
2046 return -1L;
2047
2048 if (vCnrInfo.flWindowAttr & CV_ICON)
2049 ulFlag = CV_ICON;
2050 if (vCnrInfo.flWindowAttr & CV_NAME)
2051 ulFlag = CV_NAME;
2052 if (vCnrInfo.flWindowAttr & CV_TEXT)
2053 ulFlag = CV_TEXT;
2054 if (vCnrInfo.flWindowAttr & CV_DETAIL)
2055 ulFlag = CV_DETAIL;
2056 if (!bPartial)
2057 ulFlag |= CV_EXACTLENGTH;
2058
2059 vSearch.cb = sizeof(SEARCHSTRING);
2060 vSearch.pszSearch = (char*)rsStr.c_str();
2061 vSearch.fsPrefix = TRUE;
2062 vSearch.fsCaseSensitive = TRUE;
2063 vSearch.usView = ulFlag;
2064
2065 if (lStart == -1)
2066 {
2067 pRecord = (PMYRECORD)::WinSendMsg( GetHWND()
2068 ,CM_SEARCHSTRING
2069 ,MPFROMP(&vSearch)
2070 ,(MPARAM)CMA_FIRST
2071 );
2072 }
2073 else
2074 {
2075 pRecord = (PMYRECORD)::WinSendMsg( GetHWND()
2076 ,CM_SEARCHSTRING
2077 ,MPFROMP(&vSearch)
2078 ,MPFROMP(pRecord)
2079 );
2080 }
2081 if (!pRecord)
2082 return -1L;
2083 return pRecord->m_ulItemId;
2084} // end of wxListCtrl::FindItem
2085
2086// Find an item whose data matches this data, starting from the item after 'start'
2087// or the beginning if 'start' is -1.
2088long wxListCtrl::FindItem (
2089 long lStart
2090, long lData
2091)
2092{
2093 long lIdx = lStart + 1;
2094 long lCount = GetItemCount();
2095
2096 while (lIdx < lCount)
2097 {
2098 if (GetItemData(lIdx) == lData)
2099 return lIdx;
2100 lIdx++;
2101 };
2102 return -1;
2103} // end of wxListCtrl::FindItem
2104
2105// Find an item nearest this position in the specified direction, starting from
2106// the item after 'start' or the beginning if 'start' is -1.
2107long wxListCtrl::FindItem (
2108 long lStart
2109, const wxPoint& rPoint
2110, int nDirection
2111)
2112{
2113 RECTL vRect;
2114 QUERYRECORDRECT vQueryRect;
2115 PMYRECORD pRecord = FindOS2ListRecordByID( GetHWND()
2116 ,lStart
2117 );
2118 CNRINFO vCnrInfo;
2119 ULONG i;
2120 wxRect vLibRect;
2121
2122 if (!::WinSendMsg( GetHWND()
2123 ,CM_QUERYCNRINFO
2124 ,MPFROMP(&vCnrInfo)
2125 ,(MPARAM)(USHORT)sizeof(CNRINFO)
2126 ))
2127 return -1L;
2128
2129 vQueryRect.cb = sizeof(QUERYRECORDRECT);
2130 vQueryRect.pRecord = &pRecord->m_vRecord;
2131 vQueryRect.fRightSplitWindow = TRUE;
2132 vQueryRect.fsExtent = CMA_ICON | CMA_TEXT;
2133
2134 ::WinSendMsg( GetHWND()
2135 ,CM_QUERYRECORDRECT
2136 ,MPFROMP(&vRect)
2137 ,MPFROMP(&vQueryRect)
2138 );
2139 vLibRect.SetLeft(vRect.xLeft);
2140 vLibRect.SetTop(vRect.yTop);
2141 vLibRect.SetRight(vRect.xRight);
2142 vLibRect.SetBottom(vRect.yBottom);
2143 if (vLibRect.Contains(rPoint))
2144 return pRecord->m_ulItemId;
2145
2146 for (i = lStart + 1; i < vCnrInfo.cRecords; i++)
2147 {
2148 pRecord = (PMYRECORD)PVOIDFROMMR(::WinSendMsg( GetHWND()
2149 ,CM_QUERYRECORD
2150 ,MPFROMP(pRecord)
2151 ,MPFROM2SHORT(CMA_NEXT, CMA_ITEMORDER)
2152 ));
2153 vQueryRect.pRecord = (PRECORDCORE)pRecord;
2154 ::WinSendMsg( GetHWND()
2155 ,CM_QUERYRECORDRECT
2156 ,MPFROMP(&vRect)
2157 ,MPFROMP(&vQueryRect)
2158 );
2159 vLibRect.SetLeft(vRect.xLeft);
2160 vLibRect.SetTop(vRect.yTop);
2161 vLibRect.SetRight(vRect.xRight);
2162 vLibRect.SetBottom(vRect.yBottom);
2163 if (vLibRect.Contains(rPoint))
2164 return pRecord->m_ulItemId;
2165 }
2166 return -1L;
2167} // end of wxListCtrl::FindItem
2168
2169// Determines which item (if any) is at the specified point,
2170// giving details in 'flags' (see wxLIST_HITTEST_... flags above)
2171long wxListCtrl::HitTest (
2172 const wxPoint& rPoint
2173, int& WXUNUSED(rFlags)
2174)
2175{
2176 PMYRECORD pRecord = NULL;
2177 QUERYRECFROMRECT vQueryRect;
2178 RECTL vRect;
2179 long lHeight;
2180
2181 //
2182 // Get height for OS/2 point conversion
2183 //
2184 ::WinSendMsg( GetHWND()
2185 ,CM_QUERYVIEWPORTRECT
2186 ,MPFROMP(&vRect)
2187 ,MPFROM2SHORT(CMA_WINDOW, TRUE)
2188 );
2189 lHeight = vRect.yTop - vRect.yBottom;
2190
2191 //
2192 // For now just try and get a record in the general vicinity and forget
2193 // the flag
2194 //
2195 vRect.xLeft = rPoint.x - 2;
2196 vRect.xRight = rPoint.x + 2;
2197 vRect.yTop = (lHeight - rPoint.y) + 2;
2198 vRect.yBottom = (lHeight - rPoint.y) - 2;
2199
2200 vQueryRect.cb = sizeof(QUERYRECFROMRECT);
2201 vQueryRect.rect = vRect;
2202 vQueryRect.fsSearch = CMA_PARTIAL;
2203
2204 pRecord = (PMYRECORD)::WinSendMsg( GetHWND()
2205 ,CM_QUERYRECORDFROMRECT
2206 ,(MPARAM)CMA_FIRST
2207 ,MPFROMP(&vQueryRect)
2208 );
2209
2210 if (!pRecord)
2211 return -1L;
2212 return pRecord->m_ulItemId;
2213} // end of wxListCtrl::HitTest
2214
2215// Inserts an item, returning the index of the new item if successful,
2216// -1 otherwise.
2217long wxListCtrl::InsertItem (
2218 wxListItem& rInfo
2219)
2220{
2221 wxASSERT_MSG( !IsVirtual(), wxT("can't be used with virtual controls") );
2222
2223 PFIELDINFO pFieldInfo = FindOS2ListFieldByColNum ( GetHWND()
2224 ,rInfo.GetColumn()
2225 );
2226 PMYRECORD pRecordAfter = NULL;
2227 PMYRECORD pRecord = (PMYRECORD)::WinSendMsg( GetHWND()
2228 ,CM_ALLOCRECORD
2229 ,MPFROMLONG(sizeof(MYRECORD) - sizeof(RECORDCORE))
2230 ,MPFROMSHORT(1)
2231 );
2232
2233 ConvertToOS2ListItem( this
2234 ,rInfo
2235 ,pRecord
2236 ,pFieldInfo
2237 );
2238
2239 if (rInfo.GetId() > 0)
2240 pRecordAfter = FindOS2ListRecordByID( GetHWND()
2241 ,rInfo.GetId() - 1
2242 );
2243
2244 RECORDINSERT vInsert;
2245
2246 vInsert.cb = sizeof(RECORDINSERT);
2247 vInsert.pRecordParent = NULL;
2248 if (!pRecordAfter)
2249 vInsert.pRecordOrder = (PRECORDCORE)CMA_FIRST;
2250 else
2251 vInsert.pRecordOrder = (PRECORDCORE)pRecordAfter;
2252 vInsert.zOrder = CMA_TOP;
2253 vInsert.cRecordsInsert = 1;
2254 vInsert.fInvalidateRecord = TRUE;
2255
2256 //
2257 // Check wether we need to allocate our internal data
2258 //
2259 bool bNeedInternalData = ((rInfo.GetMask() & wxLIST_MASK_DATA) ||
2260 rInfo.HasAttributes()
2261 );
2262 if (bNeedInternalData)
2263 {
2264 m_bAnyInternalData = true;
2265
2266 //
2267 // Internal stucture that manages data
2268 //
2269 CListItemInternalData* pData = new CListItemInternalData();
2270
2271 pRecord->m_ulUserData = (unsigned long)pData;
2272 if (rInfo.GetMask() & wxLIST_MASK_DATA)
2273 pData->m_lParam = (WXLPARAM)rInfo.GetData();
2274
2275 //
2276 // Check whether it has any custom attributes
2277 //
2278 if (rInfo.HasAttributes())
2279 {
2280 //
2281 // Take copy of attributes
2282 //
2283 pData->m_pAttr = new wxListItemAttr(*rInfo.GetAttributes());
2284 }
2285 }
2286 if (!::WinSendMsg( GetHWND()
2287 ,CM_INSERTRECORD
2288 ,MPFROMP(pRecord)
2289 ,MPFROMP(&vInsert)
2290 ))
2291 return -1;
2292 //
2293 // OS/2 must mannually bump the index's of following records
2294 //
2295 BumpRecordIds( GetHWND()
2296 ,pRecord
2297 );
2298 ::WinSendMsg( GetHWND()
2299 ,CM_INVALIDATEDETAILFIELDINFO
2300 ,NULL
2301 ,NULL
2302 );
2303 return pRecord->m_ulItemId;
2304} // end of wxListCtrl::InsertItem
2305
2306long wxListCtrl::InsertItem (
2307 long lIndex
2308, const wxString& rsLabel
2309)
2310{
2311 wxListItem vInfo;
2312
2313 memset(&vInfo, '\0', sizeof(wxListItem));
2314 vInfo.m_text = rsLabel;
2315 vInfo.m_mask = wxLIST_MASK_TEXT;
2316 vInfo.m_itemId = lIndex;
2317 return InsertItem(vInfo);
2318} // end of wxListCtrl::InsertItem
2319
2320// Inserts an image item
2321long wxListCtrl::InsertItem (
2322 long lIndex
2323, int nImageIndex
2324)
2325{
2326 wxListItem vInfo;
2327
2328 vInfo.m_image = nImageIndex;
2329 vInfo.m_mask = wxLIST_MASK_IMAGE;
2330 vInfo.m_itemId = lIndex;
2331 return InsertItem(vInfo);
2332} // end of wxListCtrl::InsertItem
2333
2334// Inserts an image/string item
2335long wxListCtrl::InsertItem (
2336 long lIndex
2337, const wxString& rsLabel
2338, int nImageIndex
2339)
2340{
2341 wxListItem vInfo;
2342
2343 vInfo.m_image = nImageIndex;
2344 vInfo.m_text = rsLabel;
2345 vInfo.m_mask = wxLIST_MASK_IMAGE | wxLIST_MASK_TEXT;
2346 vInfo.m_itemId = lIndex;
2347 return InsertItem(vInfo);
2348} // end of wxListCtrl::InsertItem
2349
2350// For details view mode (only), inserts a column.
2351long wxListCtrl::InsertColumn (
2352 long lCol
2353, wxListItem& rItem
2354)
2355{
2356 bool bSuccess;
2357 PFIELDINFO pField = (PFIELDINFO)::WinSendMsg( GetHWND()
2358 ,CM_ALLOCDETAILFIELDINFO
2359 ,MPFROMLONG(1)
2360 ,NULL
2361 );
2362 PFIELDINFO pFieldAfter = FindOS2ListFieldByColNum ( GetHWND()
2363 ,lCol - 1
2364 );
2365 FIELDINFOINSERT vInsert;
2366
2367 ConvertToOS2ListCol ( lCol
2368 ,rItem
2369 ,pField
2370 );
2371
2372 vInsert.cb = sizeof(FIELDINFOINSERT);
2373 vInsert.pFieldInfoOrder = pFieldAfter;
2374 vInsert.fInvalidateFieldInfo = TRUE;
2375 vInsert.cFieldInfoInsert = 1;
2376
2377 bSuccess = ::WinSendMsg( GetHWND()
2378 ,CM_INSERTDETAILFIELDINFO
2379 ,MPFROMP(pField)
2380 ,MPFROMP(&vInsert)
2381 ) != (MRESULT)0;
2382 return bSuccess;
2383} // end of wxListCtrl::InsertColumn
2384
2385long wxListCtrl::InsertColumn (
2386 long lCol
2387, const wxString& rsHeading
2388, int nFormat
2389, int nWidth
2390)
2391{
2392 wxListItem vItem;
2393
2394 vItem.m_mask = wxLIST_MASK_TEXT | wxLIST_MASK_FORMAT;
2395 vItem.m_text = rsHeading;
2396 if (nWidth > -1)
2397 {
2398 vItem.m_mask |= wxLIST_MASK_WIDTH;
2399 vItem.m_width = nWidth;
2400 }
2401 vItem.m_format = nFormat;
2402
2403 return InsertColumn( lCol
2404 ,vItem
2405 );
2406} // end of wxListCtrl::InsertColumn
2407
2408// scroll the control by the given number of pixels (exception: in list view,
2409// dx is interpreted as number of columns)
2410bool wxListCtrl::ScrollList ( int nDx, int nDy )
2411{
2412 if (nDx > 0)
2413 ::WinSendMsg( GetHWND()
2414 ,CM_SCROLLWINDOW
2415 ,(MPARAM)CMA_HORIZONTAL
2416 ,(MPARAM)nDx
2417 );
2418 if (nDy > 0)
2419 ::WinSendMsg( GetHWND()
2420 ,CM_SCROLLWINDOW
2421 ,(MPARAM)CMA_VERTICAL
2422 ,(MPARAM)nDy
2423 );
2424 return true;
2425} // end of wxListCtrl::ScrollList
2426
2427bool wxListCtrl::SortItems ( wxListCtrlCompare fn, long lData )
2428{
2429 SInternalDataSort vInternalData;
2430
2431 vInternalData.m_fnUser = fn;
2432 vInternalData.m_lData = lData;
2433
2434 // WPARAM cast is needed for mingw/cygwin
2435 if (!::WinSendMsg( GetHWND()
2436 ,CM_SORTRECORD
2437 ,(PFN)InternalDataCompareFunc
2438 ,(PVOID)&vInternalData
2439 ))
2440 {
2441 wxLogDebug(wxT("CM_SORTRECORD failed"));
2442 return false;
2443 }
2444 return true;
2445} // end of wxListCtrl::SortItems
2446
2447// ----------------------------------------------------------------------------
2448// message processing
2449// ----------------------------------------------------------------------------
2450
2451bool wxListCtrl::OS2Command ( WXUINT uCmd, WXWORD wId )
2452{
2453 if (uCmd == CN_ENDEDIT)
2454 {
2455 wxCommandEvent vEvent( wxEVT_COMMAND_TEXT_UPDATED, wId );
2456
2457 vEvent.SetEventObject( this );
2458 ProcessCommand(vEvent);
2459 return true;
2460 }
2461 else if (uCmd == CN_KILLFOCUS)
2462 {
2463 wxCommandEvent vEvent( wxEVT_KILL_FOCUS, wId );
2464 vEvent.SetEventObject( this );
2465 ProcessCommand(vEvent);
2466 return true;
2467 }
2468 else
2469 return false;
2470} // end of wxListCtrl::OS2Command
2471
2472// Necessary for drawing hrules and vrules, if specified
2473void wxListCtrl::OnPaint ( wxPaintEvent& rEvent )
2474{
2475 wxPaintDC vDc(this);
2476 wxPen vPen(wxSystemSettings::GetColour( wxSYS_COLOUR_3DLIGHT)
2477 ,1
2478 ,wxSOLID
2479 );
2480 wxSize vClientSize = GetClientSize();
2481 wxRect vItemRect;
2482 int nItemCount = GetItemCount();
2483 int nCy = 0;
2484 int i;
2485 bool bDrawHRules = ((GetWindowStyle() & wxLC_HRULES) != 0);
2486 bool bDrawVRules = ((GetWindowStyle() & wxLC_VRULES) != 0);
2487
2488 wxControl::OnPaint(rEvent);
2489
2490 //
2491 // Reset the device origin since it may have been set
2492 //
2493 vDc.SetDeviceOrigin(0, 0);
2494 if (!bDrawHRules && !bDrawVRules)
2495 return;
2496 if ((GetWindowStyle() & wxLC_REPORT) == 0)
2497 return;
2498 vDc.SetPen(vPen);
2499 vDc.SetBrush(*wxTRANSPARENT_BRUSH);
2500
2501 if (bDrawHRules)
2502 {
2503 long lTop = GetTopItem();
2504
2505 for (i = lTop; i < lTop + GetCountPerPage() + 1; i++)
2506 {
2507 if (GetItemRect( i
2508 ,vItemRect
2509 ))
2510 {
2511 nCy = vItemRect.GetTop();
2512 if (i != 0) // Don't draw the first one
2513 {
2514 vDc.DrawLine( 0
2515 ,nCy
2516 ,vClientSize.x
2517 ,nCy
2518 );
2519 }
2520 // Draw last line
2521 if (i == nItemCount - 1)
2522 {
2523 nCy = vItemRect.GetBottom();
2524 vDc.DrawLine( 0
2525 ,nCy
2526 ,vClientSize.x
2527 ,nCy
2528 );
2529 }
2530 }
2531 }
2532 }
2533 i = nItemCount - 1;
2534 if (bDrawVRules && (i > -1))
2535 {
2536 wxRect vFirstItemRect;
2537
2538 GetItemRect( 0
2539 ,vFirstItemRect
2540 );
2541 if (GetItemRect( i
2542 ,vItemRect
2543 ))
2544 {
2545 int nCol;
2546 int nX = vItemRect.GetX();
2547
2548 for (nCol = 0; nCol < GetColumnCount(); nCol++)
2549 {
2550 int nColWidth = GetColumnWidth(nCol);
2551
2552 nX += nColWidth ;
2553 vDc.DrawLine( nX - 1
2554 ,vFirstItemRect.GetY() - 2
2555 ,nX - 1
2556 ,vItemRect.GetBottom()
2557 );
2558 }
2559 }
2560 }
2561} // end of wxListCtrl::OnPaint
2562
2563// ----------------------------------------------------------------------------
2564// virtual list controls
2565// ----------------------------------------------------------------------------
2566
2567wxString wxListCtrl::OnGetItemText (
2568 long WXUNUSED(lItem)
2569, long WXUNUSED(lCol)
2570) const
2571{
2572 // this is a pure virtual function, in fact - which is not really pure
2573 // because the controls which are not virtual don't need to implement it
2574 wxFAIL_MSG( wxT("not supposed to be called") );
2575 return wxEmptyString;
2576} // end of wxListCtrl::OnGetItemText
2577
2578int wxListCtrl::OnGetItemImage (
2579 long WXUNUSED(lItem)
2580) const
2581{
2582 // same as above
2583 wxFAIL_MSG( wxT("not supposed to be called") );
2584 return -1;
2585} // end of wxListCtrl::OnGetItemImage
2586
2587int wxListCtrl::OnGetItemColumnImage (
2588 long lItem,
2589 long lColumn
2590) const
2591{
2592 if (!lColumn)
2593 return OnGetItemImage(lItem);
2594
2595 return -1;
2596} // end of wxListCtrl::OnGetItemColumnImage
2597
2598wxListItemAttr* wxListCtrl::OnGetItemAttr (
2599 long WXUNUSED_UNLESS_DEBUG(lItem)
2600) const
2601{
2602 wxASSERT_MSG( lItem >= 0 && lItem < GetItemCount(),
2603 wxT("invalid item index in OnGetItemAttr()") );
2604
2605 //
2606 // No attributes by default
2607 //
2608 return NULL;
2609} // end of wxListCtrl::OnGetItemAttr
2610
2611void wxListCtrl::SetItemCount (
2612 long lCount
2613)
2614{
2615 wxASSERT_MSG( IsVirtual(), wxT("this is for virtual controls only") );
2616
2617 //
2618 // Cannot explicitly set the record count in OS/2
2619 //
2620} // end of wxListCtrl::SetItemCount
2621
2622void wxListCtrl::RefreshItem (
2623 long lItem
2624)
2625{
2626 wxRect vRect;
2627
2628 GetItemRect( lItem
2629 ,vRect
2630 );
2631 RefreshRect(vRect);
2632} // end of wxListCtrl::RefreshItem
2633
2634void wxListCtrl::RefreshItems ( long lItemFrom, long lItemTo )
2635{
2636 wxRect vRect1;
2637 wxRect vRect2;
2638
2639 GetItemRect( lItemFrom , vRect1 );
2640 GetItemRect( lItemTo , vRect2 );
2641
2642 wxRect vRect = vRect1;
2643
2644 vRect.height = vRect2.GetBottom() - vRect1.GetTop();
2645 RefreshRect(vRect);
2646} // end of wxListCtrl::RefreshItems
2647
2648MRESULT wxListCtrl::OS2WindowProc( WXUINT uMsg,
2649 WXWPARAM wParam,
2650 WXLPARAM lParam )
2651{
2652 bool bProcessed = false;
2653 MRESULT lRc;
2654 wxListEvent vEvent( wxEVT_NULL
2655 ,m_windowId
2656 );
2657 wxEventType vEventType = wxEVT_NULL;
2658 PCNRDRAGINIT pDragInit = NULL;
2659 PCNREDITDATA pEditData = NULL;
2660 PNOTIFYRECORDENTER pNotifyEnter = NULL;
2661
2662 vEvent.SetEventObject(this);
2663 switch (uMsg)
2664 {
2665 case WM_CONTROL:
2666 //
2667 // First off let's set some internal data
2668 //
2669 switch(SHORT2FROMMP(wParam))
2670 {
2671 case CN_INITDRAG:
2672 case CN_DRAGOVER:
2673 case CN_DRAGAFTER:
2674 {
2675 CListItemInternalData* pInternaldata = (CListItemInternalData *)lParam;
2676
2677 if (pInternaldata)
2678 {
2679 wxListItem* pItem = (wxListItem*)&vEvent.GetItem();
2680
2681 pItem->SetData((long)pInternaldata->m_lParam);
2682 }
2683 }
2684 break;
2685 }
2686 //
2687 // Now let's go through the codes we're interested in
2688 //
2689 switch(SHORT2FROMMP(wParam))
2690 {
2691 case CN_INITDRAG:
2692 pDragInit = (PCNRDRAGINIT)lParam;
2693 if (pDragInit)
2694 {
2695 PMYRECORD pRecord = (PMYRECORD)pDragInit->pRecord;
2696
2697 vEventType = wxEVT_COMMAND_LIST_BEGIN_RDRAG;
2698 vEvent.m_itemIndex = pRecord->m_ulItemId;
2699 vEvent.m_pointDrag.x = pDragInit->x;
2700 vEvent.m_pointDrag.y = pDragInit->y;
2701 }
2702 break;
2703
2704 case CN_BEGINEDIT:
2705 pEditData = (PCNREDITDATA)lParam;
2706 if (pEditData)
2707 {
2708 vEventType = wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT;
2709 ConvertFromOS2ListItem( GetHWND()
2710 ,(wxListItem &)vEvent.GetItem()
2711 ,(PMYRECORD)pEditData->pRecord
2712 );
2713 vEvent.m_itemIndex = vEvent.GetItem().GetId();
2714 }
2715 break;
2716
2717 case CN_ENDEDIT:
2718 pEditData = (PCNREDITDATA)lParam;
2719 if (pEditData)
2720 {
2721 vEventType = wxEVT_COMMAND_LIST_END_LABEL_EDIT;
2722 ConvertFromOS2ListItem( GetHWND()
2723 ,(wxListItem &)vEvent.GetItem()
2724 ,(PMYRECORD)pEditData->pRecord
2725 );
2726 if (pEditData->cbText == 0)
2727 return (MRESULT)FALSE;
2728 vEvent.m_itemIndex = vEvent.GetItem().GetId();
2729 }
2730 break;
2731
2732 case CN_ENTER:
2733 pNotifyEnter = (PNOTIFYRECORDENTER)lParam;
2734 if (pNotifyEnter)
2735 {
2736 wxListItem* pItem = (wxListItem*)&vEvent.GetItem();
2737 PMYRECORD pMyRecord = (PMYRECORD)pNotifyEnter->pRecord;
2738
2739 vEventType = wxEVT_COMMAND_LIST_ITEM_ACTIVATED;
2740 vEvent.m_itemIndex = pMyRecord->m_ulItemId;
2741 pItem->SetText(GetItemText(pMyRecord->m_ulItemId));
2742 pItem->SetData(GetItemData(pMyRecord->m_ulItemId));
2743 }
2744 break;
2745
2746 //
2747 // Add the CN_DROP messages for Direct Manipulation
2748 //
2749 }
2750 vEvent.SetEventType(vEventType);
2751 bProcessed = HandleWindowEvent(vEvent);
2752 break;
2753 }
2754 if (!bProcessed)
2755 lRc = wxControl::OS2WindowProc( uMsg
2756 ,wParam
2757 ,lParam
2758 );
2759 return lRc;
2760} // end of wxListCtrl::WindowProc
2761
2762#endif // wxUSE_LISTCTRL