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