]> git.saurik.com Git - wxWidgets.git/blame - src/generic/listctrl.cpp
more scrolling tests
[wxWidgets.git] / src / generic / listctrl.cpp
CommitLineData
c801d85f 1/////////////////////////////////////////////////////////////////////////////
54442116
VZ
2// Name: generic/listctrl.cpp
3// Purpose: generic implementation of wxListCtrl
c801d85f 4// Author: Robert Roebling
cf1dfa6b 5// Vadim Zeitlin (virtual list control support)
0208334d
RR
6// Id: $Id$
7// Copyright: (c) 1998 Robert Roebling
bd8289c1 8// Licence: wxWindows licence
c801d85f
KB
9/////////////////////////////////////////////////////////////////////////////
10
b54e41c5
VZ
11/*
12 FIXME for virtual list controls
13
14 +1. clicking on the item with a mouse is awfully slow, what is going on?
15 note that selecting with keyboard seems to be much faster
16 => fixed HighlightAll() - iterating over 1000000 items *is* slow
17
18 2. background colour is wrong?
19 */
20
21/*
22 TODO for better virtual list control support:
23
24 1. less dumb line caching, we should cache at least all those visible
25 in the control itself and probably twice as many (we might also need to
26 cache the first one always for geometry calculations?)
27
28 +2. storing selections: we can't use an array to store the selected indices
29 like right now as selecting all in a control with 1000000 items is not
30 doable like this - instead, store selections as collection of individual
31 items and ranges
32
33 => wxSelectionStore
34
35 3. we need to implement searching/sorting somehow
36
37 4. the idea of storing the line index in the line itself is really stupid,
38 we shouldn't need it - but for this we have to get rid of all calles to
39 wxListLineData::GetFoo() and replace them with something like
40 if ( IsVirtual()
41 ... we have it ourselves ...
42 else
43 line->GetFoo();
44 */
45
1370703e
VZ
46// ============================================================================
47// declarations
48// ============================================================================
49
50// ----------------------------------------------------------------------------
51// headers
52// ----------------------------------------------------------------------------
53
c801d85f 54#ifdef __GNUG__
510fc784
RR
55 #pragma implementation "listctrl.h"
56 #pragma implementation "listctrlbase.h"
c801d85f
KB
57#endif
58
5cd89174
VZ
59#if 0
60#include "listctrl.old.cpp"
61#else
62
1e6d9499
JS
63// For compilers that support precompilation, includes "wx.h".
64#include "wx/wxprec.h"
65
66#ifdef __BORLANDC__
67#pragma hdrstop
68#endif
69
1e6feb95
VZ
70#if wxUSE_LISTCTRL
71
0208334d
RR
72#include "wx/dcscreen.h"
73#include "wx/app.h"
02527779 74#include "wx/listctrl.h"
b54e41c5 75#include "wx/imaglist.h"
f6bcfd97 76#include "wx/dynarray.h"
c801d85f 77
3fb435df
RR
78#ifdef __WXGTK__
79#include <gtk/gtk.h>
80#include "wx/gtk/win_gtk.h"
81#endif
82
2e4df4bf
VZ
83// ----------------------------------------------------------------------------
84// events
85// ----------------------------------------------------------------------------
86
87DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_DRAG)
88DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_RDRAG)
89DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT)
90DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_END_LABEL_EDIT)
91DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ITEM)
92DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS)
93DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_GET_INFO)
94DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_SET_INFO)
95DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_SELECTED)
96DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_DESELECTED)
97DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_KEY_DOWN)
98DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_INSERT_ITEM)
99DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_CLICK)
100DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK)
101DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK)
102DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_ACTIVATED)
103
cf1dfa6b
VZ
104// ----------------------------------------------------------------------------
105// constants
106// ----------------------------------------------------------------------------
107
108// the height of the header window (FIXME: should depend on its font!)
109static const int HEADER_HEIGHT = 23;
110
111// the scrollbar units
112static const int SCROLL_UNIT_X = 15;
113static const int SCROLL_UNIT_Y = 15;
114
115// the spacing between the lines (in report mode)
b54e41c5 116static const int LINE_SPACING = 0;
cf1dfa6b
VZ
117
118// extra margins around the text label
119static const int EXTRA_WIDTH = 3;
120static const int EXTRA_HEIGHT = 4;
121
122// offset for the header window
123static const int HEADER_OFFSET_X = 1;
124static const int HEADER_OFFSET_Y = 1;
125
126// when autosizing the columns, add some slack
127static const int AUTOSIZE_COL_MARGIN = 10;
128
129// default and minimal widths for the header columns
130static const int WIDTH_COL_DEFAULT = 80;
131static const int WIDTH_COL_MIN = 10;
132
efbb7287
VZ
133// ============================================================================
134// private classes
135// ============================================================================
136
b54e41c5
VZ
137// ----------------------------------------------------------------------------
138// wxSelectionStore
139// ----------------------------------------------------------------------------
140
141int CMPFUNC_CONV wxSizeTCmpFn(size_t n1, size_t n2) { return n1 - n2; }
142
143WX_DEFINE_SORTED_EXPORTED_ARRAY(size_t, wxIndexArray);
144
145// this class is used to store the selected items in the virtual list control
146// (but it is not tied to list control and so can be used with other controls
147// such as wxListBox in wxUniv)
148//
149// the idea is to make it really smart later (i.e. store the selections as an
150// array of ranes + individual items) but, as I don't have time to do it now
151// (this would require writing code to merge/break ranges and much more) keep
152// it simple but define a clean interface to it which allows it to be made
153// smarter later
154class WXDLLEXPORT wxSelectionStore
155{
156public:
157 wxSelectionStore() : m_itemsSel(wxSizeTCmpFn) { Init(); }
158
159 // set the total number of items we handle
160 void SetItemCount(size_t count) { m_count = count; }
161
162 // special case of SetItemCount(0)
163 void Clear() { m_itemsSel.Clear(); m_count = 0; }
164
165 // must be called when a new item is inserted/added
166 void OnItemAdd(size_t item) { wxFAIL_MSG( _T("TODO") ); }
167
168 // must be called when an item is deleted
169 void OnItemDelete(size_t item);
170
171 // select one item, use SelectRange() insted if possible!
172 //
173 // returns true if the items selection really changed
174 bool SelectItem(size_t item, bool select = TRUE);
175
176 // select the range of items
177 void SelectRange(size_t itemFrom, size_t itemTo, bool select = TRUE);
178
179 // return true if the given item is selected
180 bool IsSelected(size_t item) const;
181
182 // return the total number of selected items
183 size_t GetSelectedCount() const
184 {
185 return m_defaultState ? m_count - m_itemsSel.GetCount()
186 : m_itemsSel.GetCount();
187 }
188
189private:
190 // (re)init
191 void Init() { m_defaultState = FALSE; }
192
193 // the total number of items we handle
194 size_t m_count;
195
196 // the default state: normally, FALSE (i.e. off) but maybe set to TRUE if
197 // there are more selected items than non selected ones - this allows to
198 // handle selection of all items efficiently
199 bool m_defaultState;
200
201 // the array of items whose selection state is different from default
202 wxIndexArray m_itemsSel;
203
204 DECLARE_NO_COPY_CLASS(wxSelectionStore)
205};
206
efbb7287
VZ
207//-----------------------------------------------------------------------------
208// wxListItemData (internal)
209//-----------------------------------------------------------------------------
210
cf1dfa6b 211class WXDLLEXPORT wxListItemData
efbb7287 212{
efbb7287 213public:
cf1dfa6b
VZ
214 wxListItemData(wxListMainWindow *owner);
215 ~wxListItemData() { delete m_attr; delete m_rect; }
efbb7287 216
efbb7287 217 void SetItem( const wxListItem &info );
cf1dfa6b
VZ
218 void SetImage( int image ) { m_image = image; }
219 void SetData( long data ) { m_data = data; }
efbb7287
VZ
220 void SetPosition( int x, int y );
221 void SetSize( int width, int height );
54442116
VZ
222
223 bool HasText() const { return !m_text.empty(); }
224 const wxString& GetText() const { return m_text; }
225 void SetText(const wxString& text) { m_text = text; }
226
cf1dfa6b
VZ
227 // we can't use empty string for measuring the string width/height, so
228 // always return something
229 wxString GetTextForMeasuring() const
230 {
231 wxString s = GetText();
232 if ( s.empty() )
233 s = _T('H');
234
235 return s;
236 }
237
efbb7287 238 bool IsHit( int x, int y ) const;
54442116 239
cf1dfa6b
VZ
240 int GetX() const;
241 int GetY() const;
efbb7287
VZ
242 int GetWidth() const;
243 int GetHeight() const;
cf1dfa6b
VZ
244
245 int GetImage() const { return m_image; }
246 bool HasImage() const { return GetImage() != -1; }
247
efbb7287
VZ
248 void GetItem( wxListItem &info ) const;
249
250 wxListItemAttr *GetAttributes() const { return m_attr; }
251
54442116 252public:
cf1dfa6b
VZ
253 // the item image or -1
254 int m_image;
255
256 // user data associated with the item
257 long m_data;
54442116 258
cf1dfa6b
VZ
259 // the item coordinates are not used in report mode, instead this pointer
260 // is NULL and the owner window is used to retrieve the item position and
261 // size
262 wxRect *m_rect;
263
264 // the list ctrl we are in
265 wxListMainWindow *m_owner;
266
267 // custom attributes or NULL
54442116
VZ
268 wxListItemAttr *m_attr;
269
270protected:
cf1dfa6b
VZ
271 // common part of all ctors
272 void Init();
54442116 273
cf1dfa6b 274 wxString m_text;
efbb7287
VZ
275};
276
277//-----------------------------------------------------------------------------
278// wxListHeaderData (internal)
279//-----------------------------------------------------------------------------
280
281class WXDLLEXPORT wxListHeaderData : public wxObject
282{
283protected:
284 long m_mask;
285 int m_image;
286 wxString m_text;
287 int m_format;
288 int m_width;
2c1f73ee
VZ
289 int m_xpos,
290 m_ypos;
efbb7287
VZ
291 int m_height;
292
293public:
294 wxListHeaderData();
295 wxListHeaderData( const wxListItem &info );
296 void SetItem( const wxListItem &item );
297 void SetPosition( int x, int y );
298 void SetWidth( int w );
299 void SetFormat( int format );
300 void SetHeight( int h );
301 bool HasImage() const;
54442116
VZ
302
303 bool HasText() const { return !m_text.empty(); }
304 const wxString& GetText() const { return m_text; }
305 void SetText(const wxString& text) { m_text = text; }
306
efbb7287 307 void GetItem( wxListItem &item );
54442116
VZ
308
309 bool IsHit( int x, int y ) const;
efbb7287
VZ
310 int GetImage() const;
311 int GetWidth() const;
312 int GetFormat() const;
f6bcfd97 313
efbb7287
VZ
314private:
315 DECLARE_DYNAMIC_CLASS(wxListHeaderData);
316};
317
318//-----------------------------------------------------------------------------
319// wxListLineData (internal)
320//-----------------------------------------------------------------------------
321
2c1f73ee
VZ
322WX_DECLARE_LIST(wxListItemData, wxListItemDataList);
323#include "wx/listimpl.cpp"
324WX_DEFINE_LIST(wxListItemDataList);
325
cf1dfa6b 326class WXDLLEXPORT wxListLineData
efbb7287
VZ
327{
328public:
cf1dfa6b
VZ
329 // the list of subitems: only may have more than one item in report mode
330 wxListItemDataList m_items;
331
332 // this is not used in report view
333 struct GeometryInfo
334 {
335 // total item rect
336 wxRect m_rectAll;
337
338 // label only
339 wxRect m_rectLabel;
340
341 // icon only
342 wxRect m_rectIcon;
343
344 // the part to be highlighted
b54e41c5 345 wxRect m_rectHighlight;
cf1dfa6b 346 } *m_gi;
efbb7287 347
cf1dfa6b 348 // is this item selected? [NB: not used in virtual mode]
b54e41c5 349 bool m_highlighted;
cf1dfa6b
VZ
350
351 // back pointer to the list ctrl
352 wxListMainWindow *m_owner;
efbb7287
VZ
353
354public:
5cd89174 355 wxListLineData(wxListMainWindow *owner);
cf1dfa6b
VZ
356
357 ~wxListLineData() { delete m_gi; }
358
359 // are we in report mode?
360 inline bool InReportView() const;
361
362 // are we in virtual report mode?
b54e41c5 363 inline bool IsVirtual() const;
cf1dfa6b
VZ
364
365 // these 2 methods shouldn't be called for report view controls, in that
366 // case we determine our position/size ourselves
367
368 // calculate the size of the line
efbb7287 369 void CalculateSize( wxDC *dc, int spacing );
cf1dfa6b
VZ
370
371 // remember the position this line appears at
372 void SetPosition( int x, int y, int window_width, int spacing );
373
5cd89174
VZ
374 // wxListCtrl API
375
376 void SetImage( int image ) { SetImage(0, image); }
377 int GetImage() const { return GetImage(0); }
378 bool HasImage() const { return GetImage() != -1; }
379 bool HasText() const { return !GetText(0).empty(); }
cf1dfa6b 380
efbb7287
VZ
381 void SetItem( int index, const wxListItem &info );
382 void GetItem( int index, wxListItem &info );
cf1dfa6b 383
54442116 384 wxString GetText(int index) const;
efbb7287 385 void SetText( int index, const wxString s );
cf1dfa6b 386
cf1dfa6b 387 // return true if the highlighting really changed
b54e41c5 388 bool Highlight( bool on );
cf1dfa6b 389
b54e41c5 390 void ReverseHighlight();
cf1dfa6b 391
b54e41c5 392 bool IsHighlighted() const
cf1dfa6b 393 {
b54e41c5 394 wxASSERT_MSG( !IsVirtual(), _T("unexpected call to IsHighlighted") );
cf1dfa6b 395
b54e41c5 396 return m_highlighted;
cf1dfa6b
VZ
397 }
398
5cd89174
VZ
399 // draw the line on the given DC in icon/list mode
400 void Draw( wxDC *dc );
401
402 // the same in report mode
403 void DrawInReportMode( wxDC *dc,
404 const wxRect& rect,
405 const wxRect& rectHL,
406 bool highlighted );
f6bcfd97 407
efbb7287 408private:
cf1dfa6b
VZ
409 // set the line to contain num items (only can be > 1 in report mode)
410 void InitItems( int num );
411
412 // get the mode (i.e. style) of the list control
413 inline int GetMode() const;
414
efbb7287
VZ
415 void SetAttributes(wxDC *dc,
416 const wxListItemAttr *attr,
cf1dfa6b
VZ
417 const wxColour& colText,
418 const wxFont& font,
b54e41c5 419 bool highlight);
efbb7287 420
5cd89174
VZ
421 // these are only used by GetImage/SetImage above, we don't support images
422 // with subitems at the public API level yet
423 void SetImage( int index, int image );
424 int GetImage( int index ) const;
efbb7287
VZ
425};
426
f6bcfd97
BP
427WX_DECLARE_EXPORTED_OBJARRAY(wxListLineData, wxListLineDataArray);
428#include "wx/arrimpl.cpp"
429WX_DEFINE_OBJARRAY(wxListLineDataArray);
430
efbb7287
VZ
431//-----------------------------------------------------------------------------
432// wxListHeaderWindow (internal)
433//-----------------------------------------------------------------------------
434
435class WXDLLEXPORT wxListHeaderWindow : public wxWindow
436{
437protected:
438 wxListMainWindow *m_owner;
439 wxCursor *m_currentCursor;
440 wxCursor *m_resizeCursor;
441 bool m_isDragging;
f6bcfd97
BP
442
443 // column being resized
444 int m_column;
445
446 // divider line position in logical (unscrolled) coords
447 int m_currentX;
448
449 // minimal position beyond which the divider line can't be dragged in
450 // logical coords
451 int m_minX;
efbb7287
VZ
452
453public:
454 wxListHeaderWindow();
f6bcfd97
BP
455 virtual ~wxListHeaderWindow();
456
457 wxListHeaderWindow( wxWindow *win,
458 wxWindowID id,
459 wxListMainWindow *owner,
460 const wxPoint &pos = wxDefaultPosition,
461 const wxSize &size = wxDefaultSize,
462 long style = 0,
463 const wxString &name = "wxlistctrlcolumntitles" );
464
efbb7287 465 void DoDrawRect( wxDC *dc, int x, int y, int w, int h );
efbb7287 466 void DrawCurrent();
f6bcfd97
BP
467 void AdjustDC(wxDC& dc);
468
469 void OnPaint( wxPaintEvent &event );
efbb7287
VZ
470 void OnMouse( wxMouseEvent &event );
471 void OnSetFocus( wxFocusEvent &event );
472
f6bcfd97
BP
473 // needs refresh
474 bool m_dirty;
475
efbb7287
VZ
476private:
477 DECLARE_DYNAMIC_CLASS(wxListHeaderWindow)
478 DECLARE_EVENT_TABLE()
479};
480
481//-----------------------------------------------------------------------------
482// wxListRenameTimer (internal)
483//-----------------------------------------------------------------------------
484
485class WXDLLEXPORT wxListRenameTimer: public wxTimer
486{
487private:
1370703e 488 wxListMainWindow *m_owner;
efbb7287
VZ
489
490public:
491 wxListRenameTimer( wxListMainWindow *owner );
492 void Notify();
493};
494
495//-----------------------------------------------------------------------------
496// wxListTextCtrl (internal)
497//-----------------------------------------------------------------------------
498
499class WXDLLEXPORT wxListTextCtrl: public wxTextCtrl
500{
501private:
502 bool *m_accept;
503 wxString *m_res;
504 wxListMainWindow *m_owner;
505 wxString m_startValue;
506
507public:
508 wxListTextCtrl() {}
509 wxListTextCtrl( wxWindow *parent, const wxWindowID id,
510 bool *accept, wxString *res, wxListMainWindow *owner,
511 const wxString &value = "",
512 const wxPoint &pos = wxDefaultPosition, const wxSize &size = wxDefaultSize,
513 int style = 0,
514 const wxValidator& validator = wxDefaultValidator,
809934d2 515 const wxString &name = "listctrltextctrl" );
efbb7287 516 void OnChar( wxKeyEvent &event );
c13cace1 517 void OnKeyUp( wxKeyEvent &event );
efbb7287
VZ
518 void OnKillFocus( wxFocusEvent &event );
519
520private:
521 DECLARE_DYNAMIC_CLASS(wxListTextCtrl);
522 DECLARE_EVENT_TABLE()
523};
524
525//-----------------------------------------------------------------------------
526// wxListMainWindow (internal)
527//-----------------------------------------------------------------------------
528
24b9f055
VZ
529WX_DECLARE_LIST(wxListHeaderData, wxListHeaderDataList);
530#include "wx/listimpl.cpp"
531WX_DEFINE_LIST(wxListHeaderDataList);
532
cf1dfa6b 533class WXDLLEXPORT wxListMainWindow : public wxScrolledWindow
efbb7287 534{
efbb7287
VZ
535public:
536 wxListMainWindow();
1370703e
VZ
537 wxListMainWindow( wxWindow *parent,
538 wxWindowID id,
539 const wxPoint& pos = wxDefaultPosition,
540 const wxSize& size = wxDefaultSize,
541 long style = 0,
542 const wxString &name = _T("listctrlmainwindow") );
543
544 virtual ~wxListMainWindow();
545
cf1dfa6b
VZ
546 bool HasFlag(int flag) const { return m_parent->HasFlag(flag); }
547
1370703e 548 // return true if this is a virtual list control
cf1dfa6b
VZ
549 bool IsVirtual() const { return HasFlag(wxLC_VIRTUAL); }
550
5cd89174
VZ
551 // return true if the control is in report mode
552 bool InReportView() const { return HasFlag(wxLC_REPORT); }
553
b54e41c5
VZ
554 // return true if we are in single selection mode, false if multi sel
555 bool IsSingleSel() const { return HasFlag(wxLC_SINGLE_SEL); }
556
cf1dfa6b
VZ
557 // do we have a header window?
558 bool HasHeader() const
559 { return HasFlag(wxLC_REPORT) && !HasFlag(wxLC_NO_HEADER); }
1370703e 560
b54e41c5 561 void HighlightAll( bool on );
cf1dfa6b
VZ
562
563 // all these functions only do something if the line is currently visible
564
565 // change the line "selected" state, return TRUE if it really changed
b54e41c5
VZ
566 bool HighlightLine( size_t line, bool highlight = TRUE);
567
568 // as HighlightLine() but do it for the range of lines: this is incredibly
569 // more efficient for virtual list controls!
570 //
571 // NB: unlike HighlightLine() this one does refresh the lines on screen
572 void HighlightLines( size_t lineFrom, size_t lineTo, bool on = TRUE );
cf1dfa6b
VZ
573
574 // toggle the line state and refresh it
b54e41c5
VZ
575 void ReverseHighlight( size_t line )
576 { HighlightLine(line, !IsHighlighted(line)); RefreshLine(line); }
cf1dfa6b
VZ
577
578 // refresh one or several lines at once
579 void RefreshLine( size_t line );
580 void RefreshLines( size_t lineFrom, size_t lineTo );
581
582 // return true if the line is highlighted
b54e41c5 583 bool IsHighlighted(size_t line) const;
efbb7287 584
5cd89174
VZ
585 // the methods which are forwarded to wxListLineData itself in list/icon
586 // modes but are here because the lines don't store their positions in the
587 // report mode
588
589 // get the bound rect for the entire line
590 wxRect GetLineRect(size_t line) const;
591
592 // get the bound rect of the label
593 wxRect GetLineLabelRect(size_t line) const;
594
595 // get the bound rect of the items icon (only may be called if we do have
596 // an icon!)
597 wxRect GetLineIconRect(size_t line) const;
598
599 // get the rect to be highlighted when the item has focus
600 wxRect GetLineHighlightRect(size_t line) const;
601
602 // get the size of the total line rect
603 wxSize GetLineSize(size_t line) const
604 { return GetLineRect(line).GetSize(); }
605
606 // return the hit code for the corresponding position (in this line)
607 long HitTestLine(size_t line, int x, int y) const;
608
efbb7287 609 void EditLabel( long item );
efbb7287
VZ
610 void OnRenameTimer();
611 void OnRenameAccept();
612
613 void OnMouse( wxMouseEvent &event );
614 void MoveToFocus();
cf1dfa6b
VZ
615
616 // called to switch the selection from the current item to newCurrent,
617 void OnArrowChar( size_t newCurrent, const wxKeyEvent& event );
618
efbb7287
VZ
619 void OnChar( wxKeyEvent &event );
620 void OnKeyDown( wxKeyEvent &event );
621 void OnSetFocus( wxFocusEvent &event );
622 void OnKillFocus( wxFocusEvent &event );
efbb7287 623 void OnScroll(wxScrollWinEvent& event) ;
f6bcfd97 624
cf1dfa6b
VZ
625 void OnPaint( wxPaintEvent &event );
626
efbb7287 627 void DrawImage( int index, wxDC *dc, int x, int y );
5cd89174
VZ
628 void GetImageSize( int index, int &width, int &height ) const;
629 int GetTextLength( const wxString &s ) const;
efbb7287
VZ
630
631 void SetImageList( wxImageList *imageList, int which );
632 void SetItemSpacing( int spacing, bool isSmall = FALSE );
633 int GetItemSpacing( bool isSmall = FALSE );
cf1dfa6b 634
efbb7287
VZ
635 void SetColumn( int col, wxListItem &item );
636 void SetColumnWidth( int col, int width );
cf1dfa6b
VZ
637 void GetColumn( int col, wxListItem &item ) const;
638 int GetColumnWidth( int col ) const;
639 int GetColumnCount() const { return m_columns.GetCount(); }
640
641 // returns the sum of the heights of all columns
642 int GetHeaderWidth() const;
643
5cd89174 644 int GetCountPerPage() const;
cf1dfa6b 645
efbb7287
VZ
646 void SetItem( wxListItem &item );
647 void GetItem( wxListItem &item );
648 void SetItemState( long item, long state, long stateMask );
649 int GetItemState( long item, long stateMask );
efbb7287
VZ
650 void GetItemRect( long index, wxRect &rect );
651 bool GetItemPosition( long item, wxPoint& pos );
652 int GetSelectedItemCount();
cf1dfa6b
VZ
653
654 // set the scrollbars and update the positions of the items
b54e41c5
VZ
655 void RecalculatePositions();
656
657 // refresh the window and the header
658 void RefreshAll();
cf1dfa6b 659
efbb7287
VZ
660 long GetNextItem( long item, int geometry, int state );
661 void DeleteItem( long index );
662 void DeleteAllItems();
663 void DeleteColumn( int col );
664 void DeleteEverything();
665 void EnsureVisible( long index );
666 long FindItem( long start, const wxString& str, bool partial = FALSE );
667 long FindItem( long start, long data);
668 long HitTest( int x, int y, int &flags );
669 void InsertItem( wxListItem &item );
efbb7287 670 void InsertColumn( long col, wxListItem &item );
efbb7287
VZ
671 void SortItems( wxListCtrlCompare fn, long data );
672
cf1dfa6b 673 size_t GetItemCount() const;
1370703e 674 bool IsEmpty() const { return GetItemCount() == 0; }
2c1f73ee
VZ
675 void SetItemCount(long count);
676
b54e41c5 677 void ResetCurrent() { m_current = (size_t)-1; }
cf1dfa6b
VZ
678 bool HasCurrent() const { return m_current != (size_t)-1; }
679
680 // send out a wxListEvent
681 void SendNotify( size_t line,
682 wxEventType command,
683 wxPoint point = wxDefaultPosition );
684
b54e41c5
VZ
685 // override base class virtual to reset m_lineHeight when the font changes
686 virtual bool SetFont(const wxFont& font)
687 {
688 if ( !wxScrolledWindow::SetFont(font) )
689 return FALSE;
690
691 m_lineHeight = 0;
692
693 return TRUE;
694 }
cf1dfa6b
VZ
695
696 // these are for wxListLineData usage only
697
698 // get the backpointer to the list ctrl
699 wxListCtrl *GetListCtrl() const
700 {
701 return wxStaticCast(GetParent(), wxListCtrl);
702 }
703
704 // get the height of all lines (assuming they all do have the same height)
705 wxCoord GetLineHeight() const;
706
707 // get the y position of the given line (only for report view)
708 wxCoord GetLineY(size_t line) const;
709
710//protected:
711 // the array of all line objects for a non virtual list control
712 wxListLineDataArray m_lines;
713
714 // the list of column objects
715 wxListHeaderDataList m_columns;
716
717 // currently focused item or -1
718 size_t m_current;
719
720 // the item currently being edited or -1
721 size_t m_currentEdit;
722
723 // the number of lines per page
724 int m_linesPerPage;
725
726 // this flag is set when something which should result in the window
727 // redrawing happens (i.e. an item was added or deleted, or its appearance
728 // changed) and OnPaint() doesn't redraw the window while it is set which
729 // allows to minimize the number of repaintings when a lot of items are
730 // being added. The real repainting occurs only after the next OnIdle()
731 // call
732 bool m_dirty;
733
b54e41c5
VZ
734 wxBrush *m_highlightBrush;
735 wxColour *m_highlightColour;
cf1dfa6b
VZ
736 int m_xScroll,
737 m_yScroll;
738 wxImageList *m_small_image_list;
739 wxImageList *m_normal_image_list;
740 int m_small_spacing;
741 int m_normal_spacing;
742 bool m_hasFocus;
743
744 bool m_lastOnSame;
745 wxTimer *m_renameTimer;
746 bool m_renameAccept;
747 wxString m_renameRes;
748 bool m_isCreated;
749 int m_dragCount;
750 wxPoint m_dragStart;
751
752 // for double click logic
753 size_t m_lineLastClicked,
754 m_lineBeforeLastClicked;
755
1370703e 756protected:
cf1dfa6b 757 // the total count of items in a virtual list control
b54e41c5 758 size_t m_countVirt;
cf1dfa6b 759
b54e41c5
VZ
760 // the object maintaining the items selection state, only used in virtual
761 // controls
762 wxSelectionStore m_selStore;
cf1dfa6b 763
1370703e
VZ
764 // common part of all ctors
765 void Init();
766
cf1dfa6b
VZ
767 // intiialize m_[xy]Scroll
768 void InitScrolling();
769
1370703e
VZ
770 // get the line data for the given index
771 wxListLineData *GetLine(size_t n) const
772 {
773 wxASSERT_MSG( n != (size_t)-1, _T("invalid line index") );
774
cf1dfa6b
VZ
775 if ( IsVirtual() )
776 {
777 wxConstCast(this, wxListMainWindow)->CacheLineData(n);
778
779 n = 0;
780 }
781
1370703e
VZ
782 return &m_lines[n];
783 }
784
b54e41c5
VZ
785 // get a dummy line which can be used for geometry calculations and such:
786 // you must use GetLine() if you want to really draw the line
787 wxListLineData *GetDummyLine() const;
cf1dfa6b
VZ
788
789 // cache the line data of the n-th line in m_lines[0]
790 void CacheLineData(size_t line);
791
b54e41c5
VZ
792 // get the range of visible lines
793 void GetVisibleLinesRange(size_t *from, size_t *to);
794
795 // force us to recalculate the range of visible lines
796 void ResetVisibleLinesRange() { m_lineFrom = (size_t)-1; }
797
798 // get the colour to be used for drawing the rules
799 wxColour GetRuleColour() const
800 {
801#ifdef __WXMAC__
802 return *wxWHITE;
803#else
804 return wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DLIGHT);
805#endif
806 }
cf1dfa6b 807
efbb7287 808private:
cf1dfa6b
VZ
809 // initialize the current item if needed
810 void UpdateCurrent();
811
812 // called when an item is [un]focuded, i.e. becomes [not] current
813 //
814 // currently unused
815 void OnFocusLine( size_t line );
816 void OnUnfocusLine( size_t line );
817
818 // the height of one line using the current font
819 wxCoord m_lineHeight;
820
821 // the total header width or 0 if not calculated yet
822 wxCoord m_headerWidth;
823
b54e41c5
VZ
824 // the first and last lines being shown on screen right now (inclusive),
825 // both may be -1 if they must be calculated so never access them directly:
826 // use GetVisibleLinesRange() above instead
827 size_t m_lineFrom,
828 m_lineTo;
829
efbb7287
VZ
830 DECLARE_DYNAMIC_CLASS(wxListMainWindow);
831 DECLARE_EVENT_TABLE()
832};
833
834// ============================================================================
835// implementation
836// ============================================================================
837
b54e41c5
VZ
838// ----------------------------------------------------------------------------
839// wxSelectionStore
840// ----------------------------------------------------------------------------
841
842bool wxSelectionStore::IsSelected(size_t item) const
843{
844 bool isSel = m_itemsSel.Index(item) != wxNOT_FOUND;
845
846 // if the default state is to be selected, being in m_itemsSel means that
847 // the item is not selected, so we have to inverse the logic
848 return m_defaultState ? !isSel : isSel;
849}
850
851bool wxSelectionStore::SelectItem(size_t item, bool select)
852{
853 // search for the item ourselves as like this we get the index where to
854 // insert it later if needed, so we do only one search in the array instead
855 // of two (adding item to a sorted array requires a search)
856 size_t index = m_itemsSel.IndexForInsert(item);
857 bool isSel = index < m_itemsSel.GetCount() && m_itemsSel[index] == item;
858
859 if ( select != m_defaultState )
860 {
861 if ( !isSel )
862 {
863 m_itemsSel.AddAt(item, index);
864
865 return TRUE;
866 }
867 }
868 else // reset to default state
869 {
870 if ( isSel )
871 {
872 m_itemsSel.RemoveAt(index);
873 return TRUE;
874 }
875 }
876
877 return FALSE;
878}
879
880void wxSelectionStore::SelectRange(size_t itemFrom, size_t itemTo, bool select)
881{
882 wxASSERT_MSG( itemFrom <= itemTo, _T("should be in order") );
883
884 // are we going to have more [un]selected items than the other ones?
885 if ( itemTo - itemFrom > m_count / 2 )
886 {
887 if ( select != m_defaultState )
888 {
889 // the default state now becomes the same as 'select'
890 m_defaultState = select;
891
892 // so all the old selections (which had state select) shouldn't be
893 // selected any more, but all the other ones should
894 wxIndexArray selOld = m_itemsSel;
895 m_itemsSel.Empty();
896
897 // TODO: it should be possible to optimize the searches a bit
898 // knowing the possible range
899
900 size_t item;
901 for ( item = 0; item < itemFrom; item++ )
902 {
903 if ( selOld.Index(item) == wxNOT_FOUND )
904 m_itemsSel.Add(item);
905 }
906
907 for ( item = itemTo + 1; item < m_count; item++ )
908 {
909 if ( selOld.Index(item) == wxNOT_FOUND )
910 m_itemsSel.Add(item);
911 }
912 }
913 else // select == m_defaultState
914 {
915 // get the inclusive range of items between itemFrom and itemTo
916 size_t count = m_itemsSel.GetCount(),
917 start = m_itemsSel.IndexForInsert(itemFrom),
918 end = m_itemsSel.IndexForInsert(itemTo);
919
920 if ( start == count || m_itemsSel[start] < itemFrom )
921 {
922 start++;
923 }
924
925 if ( end == count || m_itemsSel[end] > itemTo )
926 {
927 end--;
928 }
929
930 if ( start <= end )
931 {
932 // delete all of them (from end to avoid changing indices)
933 for ( int i = end; i >= (int)start; i-- )
934 {
935 m_itemsSel.RemoveAt(i);
936 }
937 }
938 }
939 }
940 else // "few" items change state
941 {
942 // just add the items to the selection
943 for ( size_t item = itemFrom; item <= itemTo; item++ )
944 {
945 SelectItem(item, select);
946 }
947 }
948}
949
950void wxSelectionStore::OnItemDelete(size_t item)
951{
952 size_t count = m_itemsSel.GetCount(),
953 i = m_itemsSel.IndexForInsert(item);
954
955 if ( i < count && m_itemsSel[i] == item )
956 {
957 // this item itself was in m_itemsSel, remove it from there
958 m_itemsSel.RemoveAt(i);
959 }
960
961 // and adjust the index of all which follow it
962 while ( i < count )
963 {
964 // all following elements must be greater than the one we deleted
965 wxASSERT_MSG( m_itemsSel[i] > item, _T("logic error") );
966
967 m_itemsSel[i++]--;
968 }
969}
970
c801d85f
KB
971//-----------------------------------------------------------------------------
972// wxListItemData
973//-----------------------------------------------------------------------------
974
cf1dfa6b 975void wxListItemData::Init()
c801d85f 976{
92976ab6
RR
977 m_image = -1;
978 m_data = 0;
cf1dfa6b 979
0530737d 980 m_attr = NULL;
e1e955e1 981}
c801d85f 982
cf1dfa6b 983wxListItemData::wxListItemData(wxListMainWindow *owner)
c801d85f 984{
cf1dfa6b 985 Init();
0530737d 986
cf1dfa6b
VZ
987 m_owner = owner;
988
989 if ( owner->HasFlag(wxLC_REPORT) )
990 {
991 m_rect = NULL;
992 }
993 else
994 {
995 m_rect = new wxRect;
996 }
e1e955e1 997}
c801d85f
KB
998
999void wxListItemData::SetItem( const wxListItem &info )
1000{
cf1dfa6b 1001 if ( info.m_mask & wxLIST_MASK_TEXT )
54442116 1002 SetText(info.m_text);
cf1dfa6b 1003 if ( info.m_mask & wxLIST_MASK_IMAGE )
54442116 1004 m_image = info.m_image;
cf1dfa6b 1005 if ( info.m_mask & wxLIST_MASK_DATA )
54442116 1006 m_data = info.m_data;
0530737d
VZ
1007
1008 if ( info.HasAttributes() )
1009 {
1010 if ( m_attr )
1011 *m_attr = *info.GetAttributes();
1012 else
1013 m_attr = new wxListItemAttr(*info.GetAttributes());
1014 }
1015
cf1dfa6b
VZ
1016 if ( m_rect )
1017 {
1018 m_rect->x =
1019 m_rect->y =
1020 m_rect->height = 0;
1021 m_rect->width = info.m_width;
1022 }
e1e955e1 1023}
c801d85f 1024
debe6624 1025void wxListItemData::SetPosition( int x, int y )
c801d85f 1026{
cf1dfa6b
VZ
1027 wxCHECK_RET( m_rect, _T("unexpected SetPosition() call") );
1028
1029 m_rect->x = x;
1030 m_rect->y = y;
e1e955e1 1031}
c801d85f 1032
1e6d9499 1033void wxListItemData::SetSize( int width, int height )
c801d85f 1034{
cf1dfa6b 1035 wxCHECK_RET( m_rect, _T("unexpected SetSize() call") );
c801d85f 1036
cf1dfa6b
VZ
1037 if ( width != -1 )
1038 m_rect->width = width;
1039 if ( height != -1 )
1040 m_rect->height = height;
e1e955e1 1041}
c801d85f 1042
debe6624 1043bool wxListItemData::IsHit( int x, int y ) const
c801d85f 1044{
cf1dfa6b
VZ
1045 wxCHECK_MSG( m_rect, FALSE, _T("can't be called in this mode") );
1046
1047 return wxRect(GetX(), GetY(), GetWidth(), GetHeight()).Inside(x, y);
e1e955e1 1048}
c801d85f 1049
fd9811b1 1050int wxListItemData::GetX() const
c801d85f 1051{
cf1dfa6b
VZ
1052 wxCHECK_MSG( m_rect, 0, _T("can't be called in this mode") );
1053
1054 return m_rect->x;
e1e955e1 1055}
c801d85f 1056
fd9811b1 1057int wxListItemData::GetY() const
c801d85f 1058{
cf1dfa6b
VZ
1059 wxCHECK_MSG( m_rect, 0, _T("can't be called in this mode") );
1060
1061 return m_rect->y;
e1e955e1 1062}
c801d85f 1063
fd9811b1 1064int wxListItemData::GetWidth() const
c801d85f 1065{
cf1dfa6b
VZ
1066 wxCHECK_MSG( m_rect, 0, _T("can't be called in this mode") );
1067
1068 return m_rect->width;
e1e955e1 1069}
c801d85f 1070
fd9811b1 1071int wxListItemData::GetHeight() const
c801d85f 1072{
cf1dfa6b 1073 wxCHECK_MSG( m_rect, 0, _T("can't be called in this mode") );
c801d85f 1074
cf1dfa6b 1075 return m_rect->height;
e1e955e1 1076}
c801d85f 1077
0530737d 1078void wxListItemData::GetItem( wxListItem &info ) const
c801d85f 1079{
92976ab6
RR
1080 info.m_text = m_text;
1081 info.m_image = m_image;
1082 info.m_data = m_data;
c801d85f 1083
0530737d
VZ
1084 if ( m_attr )
1085 {
1086 if ( m_attr->HasTextColour() )
1087 info.SetTextColour(m_attr->GetTextColour());
1088 if ( m_attr->HasBackgroundColour() )
1089 info.SetBackgroundColour(m_attr->GetBackgroundColour());
1090 if ( m_attr->HasFont() )
1091 info.SetFont(m_attr->GetFont());
1092 }
e1e955e1 1093}
c801d85f
KB
1094
1095//-----------------------------------------------------------------------------
1096// wxListHeaderData
1097//-----------------------------------------------------------------------------
1098
1099IMPLEMENT_DYNAMIC_CLASS(wxListHeaderData,wxObject);
1100
fd9811b1 1101wxListHeaderData::wxListHeaderData()
c801d85f 1102{
92976ab6
RR
1103 m_mask = 0;
1104 m_image = 0;
1105 m_format = 0;
1106 m_width = 0;
1107 m_xpos = 0;
1108 m_ypos = 0;
1109 m_height = 0;
e1e955e1 1110}
c801d85f
KB
1111
1112wxListHeaderData::wxListHeaderData( const wxListItem &item )
1113{
92976ab6
RR
1114 SetItem( item );
1115 m_xpos = 0;
1116 m_ypos = 0;
1117 m_height = 0;
e1e955e1 1118}
c801d85f
KB
1119
1120void wxListHeaderData::SetItem( const wxListItem &item )
1121{
92976ab6
RR
1122 m_mask = item.m_mask;
1123 m_text = item.m_text;
1124 m_image = item.m_image;
1125 m_format = item.m_format;
cf1dfa6b
VZ
1126
1127 SetWidth(item.m_width);
e1e955e1 1128}
c801d85f 1129
debe6624 1130void wxListHeaderData::SetPosition( int x, int y )
c801d85f 1131{
92976ab6
RR
1132 m_xpos = x;
1133 m_ypos = y;
e1e955e1 1134}
c801d85f 1135
debe6624 1136void wxListHeaderData::SetHeight( int h )
c801d85f 1137{
92976ab6 1138 m_height = h;
e1e955e1 1139}
c801d85f 1140
debe6624 1141void wxListHeaderData::SetWidth( int w )
c801d85f 1142{
92976ab6 1143 m_width = w;
cf1dfa6b
VZ
1144 if (m_width < 0)
1145 m_width = WIDTH_COL_DEFAULT;
1146 if (m_width < WIDTH_COL_MIN)
1147 m_width = WIDTH_COL_MIN;
e1e955e1 1148}
c801d85f 1149
debe6624 1150void wxListHeaderData::SetFormat( int format )
c801d85f 1151{
92976ab6 1152 m_format = format;
e1e955e1 1153}
c801d85f 1154
fd9811b1 1155bool wxListHeaderData::HasImage() const
c801d85f 1156{
92976ab6 1157 return (m_image != 0);
e1e955e1 1158}
c801d85f 1159
c801d85f
KB
1160bool wxListHeaderData::IsHit( int x, int y ) const
1161{
92976ab6 1162 return ((x >= m_xpos) && (x <= m_xpos+m_width) && (y >= m_ypos) && (y <= m_ypos+m_height));
e1e955e1 1163}
c801d85f
KB
1164
1165void wxListHeaderData::GetItem( wxListItem &item )
1166{
92976ab6
RR
1167 item.m_mask = m_mask;
1168 item.m_text = m_text;
1169 item.m_image = m_image;
1170 item.m_format = m_format;
1171 item.m_width = m_width;
e1e955e1 1172}
c801d85f 1173
fd9811b1 1174int wxListHeaderData::GetImage() const
c801d85f 1175{
92976ab6 1176 return m_image;
e1e955e1 1177}
c801d85f 1178
fd9811b1 1179int wxListHeaderData::GetWidth() const
c801d85f 1180{
92976ab6 1181 return m_width;
e1e955e1 1182}
c801d85f 1183
fd9811b1 1184int wxListHeaderData::GetFormat() const
c801d85f 1185{
92976ab6 1186 return m_format;
e1e955e1 1187}
c801d85f
KB
1188
1189//-----------------------------------------------------------------------------
1190// wxListLineData
1191//-----------------------------------------------------------------------------
1192
cf1dfa6b
VZ
1193inline int wxListLineData::GetMode() const
1194{
b54e41c5 1195 return m_owner->GetListCtrl()->GetWindowStyleFlag() & wxLC_MASK_TYPE;
cf1dfa6b 1196}
c801d85f 1197
cf1dfa6b 1198inline bool wxListLineData::InReportView() const
c801d85f 1199{
cf1dfa6b 1200 return m_owner->HasFlag(wxLC_REPORT);
e1e955e1 1201}
c801d85f 1202
b54e41c5 1203inline bool wxListLineData::IsVirtual() const
c801d85f 1204{
cf1dfa6b
VZ
1205 return m_owner->IsVirtual();
1206}
2c1f73ee 1207
5cd89174 1208wxListLineData::wxListLineData( wxListMainWindow *owner )
cf1dfa6b
VZ
1209{
1210 m_owner = owner;
1211 m_items.DeleteContents( TRUE );
2c1f73ee 1212
cf1dfa6b
VZ
1213 if ( InReportView() )
1214 {
1215 m_gi = NULL;
1216 }
1217 else // !report
1218 {
1219 m_gi = new GeometryInfo;
1220 }
f6bcfd97 1221
b54e41c5 1222 m_highlighted = FALSE;
f6bcfd97 1223
cf1dfa6b
VZ
1224 InitItems( GetMode() == wxLC_REPORT ? m_owner->GetColumnCount() : 1 );
1225}
f6bcfd97 1226
cf1dfa6b
VZ
1227void wxListLineData::CalculateSize( wxDC *dc, int spacing )
1228{
1229 wxListItemDataList::Node *node = m_items.GetFirst();
1230 wxCHECK_RET( node, _T("no subitems at all??") );
1231
1232 wxListItemData *item = node->GetData();
1233
1234 switch ( GetMode() )
1235 {
1236 case wxLC_ICON:
1237 case wxLC_SMALL_ICON:
1238 {
1239 m_gi->m_rectAll.width = spacing;
1240
1241 wxString s = item->GetText();
1242
1243 wxCoord lw, lh;
1244 if ( s.empty() )
5d25c050 1245 {
cf1dfa6b
VZ
1246 lh =
1247 m_gi->m_rectLabel.width =
1248 m_gi->m_rectLabel.height = 0;
5d25c050 1249 }
cf1dfa6b
VZ
1250 else // has label
1251 {
1252 dc->GetTextExtent( s, &lw, &lh );
1253 if (lh < SCROLL_UNIT_Y)
1254 lh = SCROLL_UNIT_Y;
1255 lw += EXTRA_WIDTH;
1256 lh += EXTRA_HEIGHT;
1257
1258 m_gi->m_rectAll.height = spacing + lh;
1259 if (lw > spacing)
1260 m_gi->m_rectAll.width = lw;
1261
1262 m_gi->m_rectLabel.width = lw;
1263 m_gi->m_rectLabel.height = lh;
1264 }
1265
1266 if (item->HasImage())
1267 {
1268 int w, h;
1269 m_owner->GetImageSize( item->GetImage(), w, h );
1270 m_gi->m_rectIcon.width = w + 8;
1271 m_gi->m_rectIcon.height = h + 8;
1272
1273 if ( m_gi->m_rectIcon.width > m_gi->m_rectAll.width )
1274 m_gi->m_rectAll.width = m_gi->m_rectIcon.width;
1275 if ( m_gi->m_rectIcon.height + lh > m_gi->m_rectAll.height - 4 )
1276 m_gi->m_rectAll.height = m_gi->m_rectIcon.height + lh + 4;
1277 }
1278
1279 if ( item->HasText() )
5d25c050 1280 {
b54e41c5
VZ
1281 m_gi->m_rectHighlight.width = m_gi->m_rectLabel.width;
1282 m_gi->m_rectHighlight.height = m_gi->m_rectLabel.height;
cf1dfa6b
VZ
1283 }
1284 else // no text, highlight the icon
1285 {
b54e41c5
VZ
1286 m_gi->m_rectHighlight.width = m_gi->m_rectIcon.width;
1287 m_gi->m_rectHighlight.height = m_gi->m_rectIcon.height;
5d25c050 1288 }
92976ab6
RR
1289 }
1290 break;
cf1dfa6b 1291
92976ab6 1292 case wxLC_LIST:
92976ab6 1293 {
cf1dfa6b 1294 wxString s = item->GetTextForMeasuring();
2c1f73ee 1295
13111b2a 1296 wxCoord lw,lh;
92976ab6 1297 dc->GetTextExtent( s, &lw, &lh );
cf1dfa6b
VZ
1298 if (lh < SCROLL_UNIT_Y)
1299 lh = SCROLL_UNIT_Y;
1300 lw += EXTRA_WIDTH;
1301 lh += EXTRA_HEIGHT;
2c1f73ee 1302
cf1dfa6b
VZ
1303 m_gi->m_rectLabel.width = lw;
1304 m_gi->m_rectLabel.height = lh;
f6bcfd97 1305
cf1dfa6b
VZ
1306 m_gi->m_rectAll.width = lw;
1307 m_gi->m_rectAll.height = lh;
f6bcfd97 1308
0b855868
RR
1309 if (item->HasImage())
1310 {
cf1dfa6b 1311 int w, h;
0b855868 1312 m_owner->GetImageSize( item->GetImage(), w, h );
cf1dfa6b
VZ
1313 m_gi->m_rectIcon.width = w;
1314 m_gi->m_rectIcon.height = h;
f6bcfd97 1315
cf1dfa6b
VZ
1316 m_gi->m_rectAll.width += 4 + w;
1317 if (h > m_gi->m_rectAll.height)
1318 m_gi->m_rectAll.height = h;
bffa1c77 1319 }
f6bcfd97 1320
b54e41c5
VZ
1321 m_gi->m_rectHighlight.width = m_gi->m_rectAll.width;
1322 m_gi->m_rectHighlight.height = m_gi->m_rectAll.height;
92976ab6
RR
1323 }
1324 break;
2c1f73ee 1325
cf1dfa6b
VZ
1326 case wxLC_REPORT:
1327 wxFAIL_MSG( _T("unexpected call to SetSize") );
92976ab6 1328 break;
cf1dfa6b
VZ
1329
1330 default:
1331 wxFAIL_MSG( _T("unknown mode") );
e1e955e1 1332 }
e1e955e1 1333}
c801d85f 1334
cf1dfa6b
VZ
1335void wxListLineData::SetPosition( int x, int y,
1336 int window_width,
1337 int spacing )
c801d85f 1338{
2c1f73ee 1339 wxListItemDataList::Node *node = m_items.GetFirst();
cf1dfa6b 1340 wxCHECK_RET( node, _T("no subitems at all??") );
2c1f73ee 1341
cf1dfa6b 1342 wxListItemData *item = node->GetData();
2c1f73ee 1343
cf1dfa6b 1344 switch ( GetMode() )
0b855868
RR
1345 {
1346 case wxLC_ICON:
cf1dfa6b
VZ
1347 case wxLC_SMALL_ICON:
1348 m_gi->m_rectAll.x = x;
1349 m_gi->m_rectAll.y = y;
1350
1351 if ( item->HasImage() )
0b855868 1352 {
cf1dfa6b
VZ
1353 m_gi->m_rectIcon.x = m_gi->m_rectAll.x + 4
1354 + (spacing - m_gi->m_rectIcon.width)/2;
1355 m_gi->m_rectIcon.y = m_gi->m_rectAll.y + 4;
0b855868 1356 }
cf1dfa6b
VZ
1357
1358 if ( item->HasText() )
0b855868 1359 {
cf1dfa6b
VZ
1360 if (m_gi->m_rectAll.width > spacing)
1361 m_gi->m_rectLabel.x = m_gi->m_rectAll.x + 2;
5d25c050 1362 else
cf1dfa6b
VZ
1363 m_gi->m_rectLabel.x = m_gi->m_rectAll.x + 2 + (spacing/2) - (m_gi->m_rectLabel.width/2);
1364 m_gi->m_rectLabel.y = m_gi->m_rectAll.y + m_gi->m_rectAll.height + 2 - m_gi->m_rectLabel.height;
b54e41c5
VZ
1365 m_gi->m_rectHighlight.x = m_gi->m_rectLabel.x - 2;
1366 m_gi->m_rectHighlight.y = m_gi->m_rectLabel.y - 2;
bffa1c77 1367 }
cf1dfa6b 1368 else // no text, highlight the icon
0b855868 1369 {
b54e41c5
VZ
1370 m_gi->m_rectHighlight.x = m_gi->m_rectIcon.x - 4;
1371 m_gi->m_rectHighlight.y = m_gi->m_rectIcon.y - 4;
bffa1c77 1372 }
0b855868 1373 break;
c801d85f 1374
cf1dfa6b
VZ
1375 case wxLC_LIST:
1376 m_gi->m_rectAll.x = x;
1377 m_gi->m_rectAll.y = y;
c801d85f 1378
b54e41c5
VZ
1379 m_gi->m_rectHighlight.x = m_gi->m_rectAll.x;
1380 m_gi->m_rectHighlight.y = m_gi->m_rectAll.y;
cf1dfa6b 1381 m_gi->m_rectLabel.y = m_gi->m_rectAll.y + 2;
c801d85f 1382
cf1dfa6b
VZ
1383 if (item->HasImage())
1384 {
1385 m_gi->m_rectIcon.x = m_gi->m_rectAll.x + 2;
1386 m_gi->m_rectIcon.y = m_gi->m_rectAll.y + 2;
1387 m_gi->m_rectLabel.x = m_gi->m_rectAll.x + 6 + m_gi->m_rectIcon.width;
1388 }
1389 else
1390 {
1391 m_gi->m_rectLabel.x = m_gi->m_rectAll.x + 2;
1392 }
1393 break;
c801d85f 1394
cf1dfa6b
VZ
1395 case wxLC_REPORT:
1396 wxFAIL_MSG( _T("unexpected call to SetPosition") );
1397 break;
c801d85f 1398
cf1dfa6b
VZ
1399 default:
1400 wxFAIL_MSG( _T("unknown mode") );
1401 }
e1e955e1 1402}
c801d85f 1403
debe6624 1404void wxListLineData::InitItems( int num )
c801d85f 1405{
2c1f73ee 1406 for (int i = 0; i < num; i++)
cf1dfa6b 1407 m_items.Append( new wxListItemData(m_owner) );
e1e955e1 1408}
c801d85f 1409
debe6624 1410void wxListLineData::SetItem( int index, const wxListItem &info )
c801d85f 1411{
2c1f73ee 1412 wxListItemDataList::Node *node = m_items.Item( index );
1370703e
VZ
1413 wxCHECK_RET( node, _T("invalid column index in SetItem") );
1414
1415 wxListItemData *item = node->GetData();
1416 item->SetItem( info );
e1e955e1 1417}
c801d85f 1418
1e6d9499 1419void wxListLineData::GetItem( int index, wxListItem &info )
c801d85f 1420{
2c1f73ee 1421 wxListItemDataList::Node *node = m_items.Item( index );
139adb6a
RR
1422 if (node)
1423 {
2c1f73ee 1424 wxListItemData *item = node->GetData();
139adb6a
RR
1425 item->GetItem( info );
1426 }
e1e955e1 1427}
c801d85f 1428
54442116 1429wxString wxListLineData::GetText(int index) const
c801d85f 1430{
54442116
VZ
1431 wxString s;
1432
2c1f73ee 1433 wxListItemDataList::Node *node = m_items.Item( index );
139adb6a
RR
1434 if (node)
1435 {
2c1f73ee 1436 wxListItemData *item = node->GetData();
54442116 1437 s = item->GetText();
139adb6a 1438 }
54442116
VZ
1439
1440 return s;
e1e955e1 1441}
c801d85f 1442
debe6624 1443void wxListLineData::SetText( int index, const wxString s )
c801d85f 1444{
2c1f73ee 1445 wxListItemDataList::Node *node = m_items.Item( index );
139adb6a
RR
1446 if (node)
1447 {
2c1f73ee 1448 wxListItemData *item = node->GetData();
139adb6a
RR
1449 item->SetText( s );
1450 }
e1e955e1 1451}
c801d85f 1452
cf1dfa6b 1453void wxListLineData::SetImage( int index, int image )
c801d85f 1454{
2c1f73ee 1455 wxListItemDataList::Node *node = m_items.Item( index );
cf1dfa6b
VZ
1456 wxCHECK_RET( node, _T("invalid column index in SetImage()") );
1457
1458 wxListItemData *item = node->GetData();
1459 item->SetImage(image);
1460}
1461
1462int wxListLineData::GetImage( int index ) const
1463{
1464 wxListItemDataList::Node *node = m_items.Item( index );
1465 wxCHECK_MSG( node, -1, _T("invalid column index in GetImage()") );
1466
1467 wxListItemData *item = node->GetData();
1468 return item->GetImage();
e1e955e1 1469}
c801d85f 1470
0530737d
VZ
1471void wxListLineData::SetAttributes(wxDC *dc,
1472 const wxListItemAttr *attr,
1473 const wxColour& colText,
470caaf9 1474 const wxFont& font,
b54e41c5 1475 bool highlight)
0530737d 1476{
470caaf9
VZ
1477 // don't use foregroud colour for drawing highlighted items - this might
1478 // make them completely invisible (and there is no way to do bit
1479 // arithmetics on wxColour, unfortunately)
b54e41c5 1480 if ( !highlight && attr && attr->HasTextColour() )
0530737d
VZ
1481 {
1482 dc->SetTextForeground(attr->GetTextColour());
1483 }
1484 else
1485 {
1486 dc->SetTextForeground(colText);
1487 }
1488
1489 if ( attr && attr->HasFont() )
1490 {
1491 dc->SetFont(attr->GetFont());
1492 }
1493 else
1494 {
1495 dc->SetFont(font);
1496 }
1497}
1498
5cd89174
VZ
1499void wxListLineData::Draw( wxDC *dc )
1500{
1501 wxListItemDataList::Node *node = m_items.GetFirst();
1502 wxCHECK_RET( node, _T("no subitems at all??") );
1503
1504 wxListItemData *item = node->GetData();
1505 if (item->HasImage())
1506 {
1507 wxRect rectIcon = m_gi->m_rectIcon;
1508 m_owner->DrawImage( item->GetImage(), dc,
1509 rectIcon.x, rectIcon.y );
1510 }
1511
1512 if (item->HasText())
1513 {
1514 wxRect rectLabel = m_gi->m_rectLabel;
1515 dc->DrawText( item->GetText(), rectLabel.x, rectLabel.y );
1516 }
1517}
1518
1519void wxListLineData::DrawInReportMode( wxDC *dc,
1520 const wxRect& r,
1521 const wxRect& rectHL,
1522 bool highlighted )
c801d85f 1523{
5cd89174 1524 wxRect rect = r;
8d813b20
VZ
1525#if 0
1526 m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
004fd0c8 1527
cf1dfa6b 1528 if ( !m_owner->IsExposed( rect ) )
139adb6a 1529 return;
8d813b20 1530#endif
bd8289c1 1531
cf1dfa6b 1532 // use our own flag if we maintain it
5cd89174 1533 if ( !IsVirtual() )
b54e41c5 1534 highlighted = m_highlighted;
cf1dfa6b 1535
0530737d 1536 // default foreground colour
5cd89174 1537 wxWindow *listctrl = m_owner->GetParent();
0530737d 1538 wxColour colText;
b54e41c5 1539 if ( highlighted )
0530737d
VZ
1540 {
1541 colText = wxSystemSettings::GetSystemColour( wxSYS_COLOUR_HIGHLIGHTTEXT );
1542 }
1543 else
1544 {
1545 colText = listctrl->GetForegroundColour();
1546 }
1547
1548 // default font
1549 wxFont font = listctrl->GetFont();
1550
1551 // VZ: currently we set the colours/fonts only once, but like this (i.e.
1552 // using SetAttributes() inside the loop), it will be trivial to
1553 // customize the subitems (in report mode) too.
2c1f73ee 1554 wxListItemData *item = m_items.GetFirst()->GetData();
0530737d 1555 wxListItemAttr *attr = item->GetAttributes();
b54e41c5 1556 SetAttributes(dc, attr, colText, font, highlighted);
0530737d
VZ
1557
1558 bool hasBgCol = attr && attr->HasBackgroundColour();
b54e41c5 1559 if ( highlighted || hasBgCol )
c801d85f 1560 {
b54e41c5 1561 if ( highlighted )
63852e78 1562 {
b54e41c5 1563 dc->SetBrush( *m_owner->m_highlightBrush );
63852e78
RR
1564 }
1565 else
1566 {
0530737d
VZ
1567 if ( hasBgCol )
1568 dc->SetBrush(wxBrush(attr->GetBackgroundColour(), wxSOLID));
1569 else
1570 dc->SetBrush( * wxWHITE_BRUSH );
63852e78 1571 }
0530737d
VZ
1572
1573 dc->SetPen( * wxTRANSPARENT_PEN );
5cd89174 1574 dc->DrawRectangle( rectHL );
e1e955e1 1575 }
004fd0c8 1576
2c1f73ee 1577 wxListItemDataList::Node *node = m_items.GetFirst();
5cd89174 1578 wxCHECK_RET( node, _T("no subitems at all??") );
2c1f73ee 1579
5cd89174
VZ
1580 size_t col = 0;
1581 int x = rect.x + HEADER_OFFSET_X;
cf1dfa6b 1582
5cd89174 1583 rect.y += (LINE_SPACING + EXTRA_HEIGHT) / 2;
cf1dfa6b 1584
5cd89174
VZ
1585 while ( node )
1586 {
1587 wxListItemData *item = node->GetData();
cf1dfa6b 1588
5cd89174 1589 int xOld = x;
cf1dfa6b 1590
5cd89174
VZ
1591 if ( item->HasImage() )
1592 {
1593 int ix, iy;
1594 m_owner->DrawImage( item->GetImage(), dc, x, rect.y );
1595 m_owner->GetImageSize( item->GetImage(), ix, iy );
1596 x += ix + 5; // FIXME: what is "5"?
1597 }
cf1dfa6b 1598
5cd89174 1599 int width = m_owner->GetColumnWidth(col++);
cf1dfa6b 1600
8d813b20 1601 wxDCClipper clipper(*dc, x, rect.y, width, rect.height);
cf1dfa6b 1602
5cd89174
VZ
1603 if ( item->HasText() )
1604 {
1605 dc->DrawText( item->GetText(), x, rect.y );
1606 }
cf1dfa6b 1607
5cd89174 1608 x = xOld + width;
cf1dfa6b 1609
5cd89174 1610 node = node->GetNext();
e1e955e1 1611 }
e1e955e1 1612}
c801d85f 1613
b54e41c5 1614bool wxListLineData::Highlight( bool on )
c801d85f 1615{
b54e41c5 1616 wxCHECK_MSG( !m_owner->IsVirtual(), FALSE, _T("unexpected call to Highlight") );
c801d85f 1617
b54e41c5 1618 if ( on == m_highlighted )
cf1dfa6b 1619 return FALSE;
c801d85f 1620
b54e41c5 1621 m_highlighted = on;
c801d85f 1622
cf1dfa6b 1623 return TRUE;
e1e955e1 1624}
c801d85f 1625
b54e41c5 1626void wxListLineData::ReverseHighlight( void )
c801d85f 1627{
b54e41c5 1628 Highlight(!IsHighlighted());
e1e955e1 1629}
c801d85f
KB
1630
1631//-----------------------------------------------------------------------------
1632// wxListHeaderWindow
1633//-----------------------------------------------------------------------------
1634
1635IMPLEMENT_DYNAMIC_CLASS(wxListHeaderWindow,wxWindow);
1636
1637BEGIN_EVENT_TABLE(wxListHeaderWindow,wxWindow)
63852e78
RR
1638 EVT_PAINT (wxListHeaderWindow::OnPaint)
1639 EVT_MOUSE_EVENTS (wxListHeaderWindow::OnMouse)
1640 EVT_SET_FOCUS (wxListHeaderWindow::OnSetFocus)
c801d85f
KB
1641END_EVENT_TABLE()
1642
1643wxListHeaderWindow::wxListHeaderWindow( void )
1644{
63852e78
RR
1645 m_owner = (wxListMainWindow *) NULL;
1646 m_currentCursor = (wxCursor *) NULL;
1647 m_resizeCursor = (wxCursor *) NULL;
cfb50f14 1648 m_isDragging = FALSE;
e1e955e1 1649}
c801d85f 1650
bd8289c1 1651wxListHeaderWindow::wxListHeaderWindow( wxWindow *win, wxWindowID id, wxListMainWindow *owner,
debe6624
JS
1652 const wxPoint &pos, const wxSize &size,
1653 long style, const wxString &name ) :
c801d85f
KB
1654 wxWindow( win, id, pos, size, style, name )
1655{
63852e78 1656 m_owner = owner;
c801d85f 1657// m_currentCursor = wxSTANDARD_CURSOR;
63852e78
RR
1658 m_currentCursor = (wxCursor *) NULL;
1659 m_resizeCursor = new wxCursor( wxCURSOR_SIZEWE );
cfb50f14 1660 m_isDragging = FALSE;
f6bcfd97
BP
1661 m_dirty = FALSE;
1662
cfb50f14 1663 SetBackgroundColour( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE ) );
e1e955e1 1664}
c801d85f 1665
a367b9b3
JS
1666wxListHeaderWindow::~wxListHeaderWindow( void )
1667{
63852e78 1668 delete m_resizeCursor;
a367b9b3
JS
1669}
1670
1e6d9499 1671void wxListHeaderWindow::DoDrawRect( wxDC *dc, int x, int y, int w, int h )
c801d85f 1672{
3fb435df 1673#ifdef __WXGTK__
b54e41c5
VZ
1674 GtkStateType state = m_parent->IsEnabled() ? GTK_STATE_NORMAL
1675 : GTK_STATE_INSENSITIVE;
2c1f73ee 1676
3fb435df 1677 x = dc->XLOG2DEV( x );
2c1f73ee 1678
b54e41c5
VZ
1679 gtk_paint_box (m_wxwindow->style, GTK_PIZZA(m_wxwindow)->bin_window,
1680 state, GTK_SHADOW_OUT,
1681 (GdkRectangle*) NULL, m_wxwindow, "button",
1682 x-1, y-1, w+2, h+2);
4176fb7d
SC
1683#elif defined( __WXMAC__ )
1684 const int m_corner = 1;
1685
1686 dc->SetBrush( *wxTRANSPARENT_BRUSH );
1687
1688 dc->SetPen( wxPen( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNSHADOW ) , 1 , wxSOLID ) );
1689 dc->DrawLine( x+w-m_corner+1, y, x+w, y+h ); // right (outer)
1690 dc->DrawRectangle( x, y+h, w+1, 1 ); // bottom (outer)
1691
1692 wxPen pen( wxColour( 0x88 , 0x88 , 0x88 ), 1, wxSOLID );
1693
1694 dc->SetPen( pen );
1695 dc->DrawLine( x+w-m_corner, y, x+w-1, y+h ); // right (inner)
1696 dc->DrawRectangle( x+1, y+h-1, w-2, 1 ); // bottom (inner)
1697
1698 dc->SetPen( *wxWHITE_PEN );
1699 dc->DrawRectangle( x, y, w-m_corner+1, 1 ); // top (outer)
1700 dc->DrawRectangle( x, y, 1, h ); // left (outer)
1701 dc->DrawLine( x, y+h-1, x+1, y+h-1 );
1702 dc->DrawLine( x+w-1, y, x+w-1, y+1 );
b54e41c5 1703#else // !GTK, !Mac
63852e78 1704 const int m_corner = 1;
c801d85f 1705
63852e78 1706 dc->SetBrush( *wxTRANSPARENT_BRUSH );
c801d85f 1707
63852e78
RR
1708 dc->SetPen( *wxBLACK_PEN );
1709 dc->DrawLine( x+w-m_corner+1, y, x+w, y+h ); // right (outer)
17867d61 1710 dc->DrawRectangle( x, y+h, w+1, 1 ); // bottom (outer)
bd8289c1 1711
63852e78 1712 wxPen pen( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNSHADOW ), 1, wxSOLID );
004fd0c8 1713
63852e78
RR
1714 dc->SetPen( pen );
1715 dc->DrawLine( x+w-m_corner, y, x+w-1, y+h ); // right (inner)
1716 dc->DrawRectangle( x+1, y+h-1, w-2, 1 ); // bottom (inner)
bd8289c1 1717
63852e78
RR
1718 dc->SetPen( *wxWHITE_PEN );
1719 dc->DrawRectangle( x, y, w-m_corner+1, 1 ); // top (outer)
1720 dc->DrawRectangle( x, y, 1, h ); // left (outer)
1721 dc->DrawLine( x, y+h-1, x+1, y+h-1 );
1722 dc->DrawLine( x+w-1, y, x+w-1, y+1 );
3fb435df 1723#endif
e1e955e1 1724}
c801d85f 1725
f6bcfd97
BP
1726// shift the DC origin to match the position of the main window horz
1727// scrollbar: this allows us to always use logical coords
1728void wxListHeaderWindow::AdjustDC(wxDC& dc)
1729{
f6bcfd97
BP
1730 int xpix;
1731 m_owner->GetScrollPixelsPerUnit( &xpix, NULL );
1732
1733 int x;
1734 m_owner->GetViewStart( &x, NULL );
1735
1736 // account for the horz scrollbar offset
1737 dc.SetDeviceOrigin( -x * xpix, 0 );
f6bcfd97
BP
1738}
1739
c801d85f
KB
1740void wxListHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
1741{
10bd0724
JS
1742#ifdef __WXGTK__
1743 wxClientDC dc( this );
1744#else
63852e78 1745 wxPaintDC dc( this );
10bd0724
JS
1746#endif
1747
63852e78 1748 PrepareDC( dc );
f6bcfd97 1749 AdjustDC( dc );
bffa1c77 1750
63852e78 1751 dc.BeginDrawing();
bd8289c1 1752
63852e78 1753 dc.SetFont( GetFont() );
bd8289c1 1754
f6bcfd97
BP
1755 // width and height of the entire header window
1756 int w, h;
63852e78 1757 GetClientSize( &w, &h );
f6bcfd97 1758 m_owner->CalcUnscrolledPosition(w, 0, &w, NULL);
c801d85f 1759
f60d0f94 1760 dc.SetBackgroundMode(wxTRANSPARENT);
70846f0a
VZ
1761
1762 // do *not* use the listctrl colour for headers - one day we will have a
1763 // function to set it separately
37d403aa 1764 //dc.SetTextForeground( *wxBLACK );
cf1dfa6b
VZ
1765 dc.SetTextForeground(wxSystemSettings::
1766 GetSystemColour( wxSYS_COLOUR_WINDOWTEXT ));
1767
1768 int x = HEADER_OFFSET_X;
c801d85f 1769
63852e78
RR
1770 int numColumns = m_owner->GetColumnCount();
1771 wxListItem item;
1772 for (int i = 0; i < numColumns; i++)
1773 {
1774 m_owner->GetColumn( i, item );
f6bcfd97
BP
1775 int wCol = item.m_width;
1776 int cw = wCol - 2; // the width of the rect to draw
1777
1778 int xEnd = x + wCol;
1779
63852e78 1780 dc.SetPen( *wxWHITE_PEN );
c801d85f 1781
cf1dfa6b
VZ
1782 DoDrawRect( &dc, x, HEADER_OFFSET_Y, cw, h-2 );
1783 dc.SetClippingRegion( x, HEADER_OFFSET_Y, cw-5, h-4 );
1784 dc.DrawText( item.GetText(), x + EXTRA_WIDTH, HEADER_OFFSET_Y + EXTRA_HEIGHT );
40c70187 1785 dc.DestroyClippingRegion();
f6bcfd97
BP
1786 x += wCol;
1787
1788 if (xEnd > w+5)
1789 break;
63852e78
RR
1790 }
1791 dc.EndDrawing();
e1e955e1 1792}
c801d85f 1793
0208334d
RR
1794void wxListHeaderWindow::DrawCurrent()
1795{
63852e78
RR
1796 int x1 = m_currentX;
1797 int y1 = 0;
f6bcfd97
BP
1798 ClientToScreen( &x1, &y1 );
1799
63852e78
RR
1800 int x2 = m_currentX-1;
1801 int y2 = 0;
f6bcfd97 1802 m_owner->GetClientSize( NULL, &y2 );
63852e78 1803 m_owner->ClientToScreen( &x2, &y2 );
0208334d 1804
63852e78 1805 wxScreenDC dc;
3c679789 1806 dc.SetLogicalFunction( wxINVERT );
63852e78
RR
1807 dc.SetPen( wxPen( *wxBLACK, 2, wxSOLID ) );
1808 dc.SetBrush( *wxTRANSPARENT_BRUSH );
0208334d 1809
f6bcfd97
BP
1810 AdjustDC(dc);
1811
63852e78 1812 dc.DrawLine( x1, y1, x2, y2 );
0208334d 1813
63852e78 1814 dc.SetLogicalFunction( wxCOPY );
0208334d 1815
63852e78
RR
1816 dc.SetPen( wxNullPen );
1817 dc.SetBrush( wxNullBrush );
0208334d
RR
1818}
1819
c801d85f
KB
1820void wxListHeaderWindow::OnMouse( wxMouseEvent &event )
1821{
f6bcfd97 1822 // we want to work with logical coords
3ca6a5f0
BP
1823 int x;
1824 m_owner->CalcUnscrolledPosition(event.GetX(), 0, &x, NULL);
3ca6a5f0 1825 int y = event.GetY();
f6bcfd97 1826
cfb50f14 1827 if (m_isDragging)
0208334d 1828 {
f6bcfd97
BP
1829 // we don't draw the line beyond our window, but we allow dragging it
1830 // there
1831 int w = 0;
1832 GetClientSize( &w, NULL );
f6bcfd97 1833 m_owner->CalcUnscrolledPosition(w, 0, &w, NULL);
f6bcfd97
BP
1834 w -= 6;
1835
1836 // erase the line if it was drawn
1837 if ( m_currentX < w )
1838 DrawCurrent();
1839
63852e78
RR
1840 if (event.ButtonUp())
1841 {
1842 ReleaseMouse();
cfb50f14 1843 m_isDragging = FALSE;
f6bcfd97
BP
1844 m_dirty = TRUE;
1845 m_owner->SetColumnWidth( m_column, m_currentX - m_minX );
63852e78
RR
1846 }
1847 else
1848 {
f6bcfd97 1849 if (x > m_minX + 7)
63852e78
RR
1850 m_currentX = x;
1851 else
f6bcfd97 1852 m_currentX = m_minX + 7;
bd8289c1 1853
f6bcfd97
BP
1854 // draw in the new location
1855 if ( m_currentX < w )
1856 DrawCurrent();
bffa1c77 1857 }
0208334d 1858 }
f6bcfd97 1859 else // not dragging
c801d85f 1860 {
f6bcfd97
BP
1861 m_minX = 0;
1862 bool hit_border = FALSE;
1863
1864 // end of the current column
1865 int xpos = 0;
1866
1867 // find the column where this event occured
1868 int countCol = m_owner->GetColumnCount();
cf1dfa6b 1869 for (int col = 0; col < countCol; col++)
bffa1c77 1870 {
cf1dfa6b
VZ
1871 xpos += m_owner->GetColumnWidth( col );
1872 m_column = col;
f6bcfd97
BP
1873
1874 if ( (abs(x-xpos) < 3) && (y < 22) )
1875 {
1876 // near the column border
1877 hit_border = TRUE;
1878 break;
1879 }
1880
1881 if ( x < xpos )
1882 {
1883 // inside the column
1884 break;
1885 }
1886
1887 m_minX = xpos;
bffa1c77 1888 }
63852e78 1889
f6bcfd97 1890 if (event.LeftDown())
63852e78 1891 {
f6bcfd97
BP
1892 if (hit_border)
1893 {
1894 m_isDragging = TRUE;
1895 m_currentX = x;
1896 DrawCurrent();
1897 CaptureMouse();
1898 }
1899 else
1900 {
1901 wxWindow *parent = GetParent();
1902 wxListEvent le( wxEVT_COMMAND_LIST_COL_CLICK, parent->GetId() );
1903 le.SetEventObject( parent );
1904 le.m_col = m_column;
1905 parent->GetEventHandler()->ProcessEvent( le );
1906 }
63852e78 1907 }
f6bcfd97 1908 else if (event.Moving())
63852e78 1909 {
f6bcfd97
BP
1910 bool setCursor;
1911 if (hit_border)
1912 {
1913 setCursor = m_currentCursor == wxSTANDARD_CURSOR;
1914 m_currentCursor = m_resizeCursor;
1915 }
1916 else
1917 {
1918 setCursor = m_currentCursor != wxSTANDARD_CURSOR;
1919 m_currentCursor = wxSTANDARD_CURSOR;
1920 }
1921
1922 if ( setCursor )
1923 SetCursor(*m_currentCursor);
63852e78 1924 }
e1e955e1 1925 }
e1e955e1 1926}
c801d85f
KB
1927
1928void wxListHeaderWindow::OnSetFocus( wxFocusEvent &WXUNUSED(event) )
1929{
63852e78 1930 m_owner->SetFocus();
e1e955e1 1931}
c801d85f
KB
1932
1933//-----------------------------------------------------------------------------
1934// wxListRenameTimer (internal)
1935//-----------------------------------------------------------------------------
1936
bd8289c1
VZ
1937wxListRenameTimer::wxListRenameTimer( wxListMainWindow *owner )
1938{
63852e78 1939 m_owner = owner;
e1e955e1 1940}
c801d85f 1941
bd8289c1
VZ
1942void wxListRenameTimer::Notify()
1943{
63852e78 1944 m_owner->OnRenameTimer();
e1e955e1 1945}
c801d85f 1946
ee7ee469
RR
1947//-----------------------------------------------------------------------------
1948// wxListTextCtrl (internal)
1949//-----------------------------------------------------------------------------
1950
1951IMPLEMENT_DYNAMIC_CLASS(wxListTextCtrl,wxTextCtrl);
bd8289c1 1952
ee7ee469 1953BEGIN_EVENT_TABLE(wxListTextCtrl,wxTextCtrl)
63852e78 1954 EVT_CHAR (wxListTextCtrl::OnChar)
2c1f73ee 1955 EVT_KEY_UP (wxListTextCtrl::OnKeyUp)
63852e78 1956 EVT_KILL_FOCUS (wxListTextCtrl::OnKillFocus)
ee7ee469
RR
1957END_EVENT_TABLE()
1958
674ac8b9
VZ
1959wxListTextCtrl::wxListTextCtrl( wxWindow *parent,
1960 const wxWindowID id,
1961 bool *accept,
1962 wxString *res,
1963 wxListMainWindow *owner,
1964 const wxString &value,
1965 const wxPoint &pos,
1966 const wxSize &size,
1967 int style,
1968 const wxValidator& validator,
1969 const wxString &name )
1970 : wxTextCtrl( parent, id, value, pos, size, style, validator, name )
ee7ee469 1971{
63852e78
RR
1972 m_res = res;
1973 m_accept = accept;
1974 m_owner = owner;
5f1ea0ee
RR
1975 (*m_accept) = FALSE;
1976 (*m_res) = "";
1977 m_startValue = value;
ee7ee469
RR
1978}
1979
1980void wxListTextCtrl::OnChar( wxKeyEvent &event )
1981{
63852e78
RR
1982 if (event.m_keyCode == WXK_RETURN)
1983 {
1984 (*m_accept) = TRUE;
1985 (*m_res) = GetValue();
f6bcfd97 1986
bce1406b
RR
1987 if (!wxPendingDelete.Member(this))
1988 wxPendingDelete.Append(this);
1989
1990 if ((*m_accept) && ((*m_res) != m_startValue))
1991 m_owner->OnRenameAccept();
f6bcfd97 1992
63852e78
RR
1993 return;
1994 }
1995 if (event.m_keyCode == WXK_ESCAPE)
1996 {
1997 (*m_accept) = FALSE;
1998 (*m_res) = "";
f6bcfd97 1999
bce1406b
RR
2000 if (!wxPendingDelete.Member(this))
2001 wxPendingDelete.Append(this);
f6bcfd97 2002
63852e78
RR
2003 return;
2004 }
f6bcfd97 2005
63852e78
RR
2006 event.Skip();
2007}
2008
c13cace1
VS
2009void wxListTextCtrl::OnKeyUp( wxKeyEvent &event )
2010{
2011 // auto-grow the textctrl:
2012 wxSize parentSize = m_owner->GetSize();
2013 wxPoint myPos = GetPosition();
2014 wxSize mySize = GetSize();
2015 int sx, sy;
cf1dfa6b
VZ
2016 GetTextExtent(GetValue() + _T("MM"), &sx, &sy); // FIXME: MM??
2017 if (myPos.x + sx > parentSize.x)
2018 sx = parentSize.x - myPos.x;
2019 if (mySize.x > sx)
2020 sx = mySize.x;
c13cace1 2021 SetSize(sx, -1);
2c1f73ee 2022
c13cace1
VS
2023 event.Skip();
2024}
2025
63852e78
RR
2026void wxListTextCtrl::OnKillFocus( wxFocusEvent &WXUNUSED(event) )
2027{
bce1406b
RR
2028 if (!wxPendingDelete.Member(this))
2029 wxPendingDelete.Append(this);
004fd0c8 2030
5f1ea0ee
RR
2031 if ((*m_accept) && ((*m_res) != m_startValue))
2032 m_owner->OnRenameAccept();
ee7ee469
RR
2033}
2034
c801d85f
KB
2035//-----------------------------------------------------------------------------
2036// wxListMainWindow
2037//-----------------------------------------------------------------------------
2038
2039IMPLEMENT_DYNAMIC_CLASS(wxListMainWindow,wxScrolledWindow);
bd8289c1 2040
c801d85f
KB
2041BEGIN_EVENT_TABLE(wxListMainWindow,wxScrolledWindow)
2042 EVT_PAINT (wxListMainWindow::OnPaint)
c801d85f
KB
2043 EVT_MOUSE_EVENTS (wxListMainWindow::OnMouse)
2044 EVT_CHAR (wxListMainWindow::OnChar)
3dfb93fd 2045 EVT_KEY_DOWN (wxListMainWindow::OnKeyDown)
c801d85f
KB
2046 EVT_SET_FOCUS (wxListMainWindow::OnSetFocus)
2047 EVT_KILL_FOCUS (wxListMainWindow::OnKillFocus)
2fa7c206 2048 EVT_SCROLLWIN (wxListMainWindow::OnScroll)
c801d85f
KB
2049END_EVENT_TABLE()
2050
1370703e 2051void wxListMainWindow::Init()
c801d85f 2052{
139adb6a 2053 m_columns.DeleteContents( TRUE );
139adb6a 2054 m_dirty = TRUE;
cf1dfa6b
VZ
2055 m_countVirt = 0;
2056 m_lineFrom =
b54e41c5 2057 m_lineTo = (size_t)-1;
cf1dfa6b
VZ
2058 m_linesPerPage = 0;
2059
2060 m_headerWidth =
2061 m_lineHeight = 0;
1370703e 2062
139adb6a
RR
2063 m_small_image_list = (wxImageList *) NULL;
2064 m_normal_image_list = (wxImageList *) NULL;
1370703e 2065
139adb6a
RR
2066 m_small_spacing = 30;
2067 m_normal_spacing = 40;
1370703e 2068
139adb6a 2069 m_hasFocus = FALSE;
1370703e
VZ
2070 m_dragCount = 0;
2071 m_isCreated = FALSE;
2072
139adb6a
RR
2073 m_lastOnSame = FALSE;
2074 m_renameTimer = new wxListRenameTimer( this );
1370703e
VZ
2075 m_renameAccept = FALSE;
2076
cf1dfa6b
VZ
2077 m_current =
2078 m_currentEdit =
efbb7287 2079 m_lineLastClicked =
1370703e 2080 m_lineBeforeLastClicked = (size_t)-1;
e1e955e1 2081}
c801d85f 2082
cf1dfa6b
VZ
2083void wxListMainWindow::InitScrolling()
2084{
2085 if ( HasFlag(wxLC_REPORT) )
2086 {
2087 m_xScroll = SCROLL_UNIT_X;
2088 m_yScroll = SCROLL_UNIT_Y;
2089 }
2090 else
2091 {
2092 m_xScroll = SCROLL_UNIT_Y;
2093 m_yScroll = 0;
2094 }
2095}
2096
1370703e 2097wxListMainWindow::wxListMainWindow()
c801d85f 2098{
1370703e
VZ
2099 Init();
2100
b54e41c5 2101 m_highlightBrush = (wxBrush *) NULL;
1370703e
VZ
2102
2103 m_xScroll =
2104 m_yScroll = 0;
2105}
2106
2107wxListMainWindow::wxListMainWindow( wxWindow *parent,
2108 wxWindowID id,
2109 const wxPoint& pos,
2110 const wxSize& size,
2111 long style,
2112 const wxString &name )
2113 : wxScrolledWindow( parent, id, pos, size,
2114 style | wxHSCROLL | wxVSCROLL, name )
2115{
2116 Init();
2117
b54e41c5 2118 m_highlightBrush = new wxBrush( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHT), wxSOLID );
139adb6a
RR
2119 wxSize sz = size;
2120 sz.y = 25;
bd8289c1 2121
cf1dfa6b 2122 InitScrolling();
139adb6a 2123 SetScrollbars( m_xScroll, m_yScroll, 0, 0, 0, 0 );
bd8289c1 2124
91fc2bdc 2125 SetBackgroundColour( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_LISTBOX ) );
e1e955e1 2126}
c801d85f 2127
fd9811b1 2128wxListMainWindow::~wxListMainWindow()
c801d85f 2129{
12c1b46a
RR
2130 DeleteEverything();
2131
b54e41c5 2132 delete m_highlightBrush;
004fd0c8 2133
139adb6a 2134 delete m_renameTimer;
e1e955e1 2135}
c801d85f 2136
cf1dfa6b 2137void wxListMainWindow::CacheLineData(size_t line)
c801d85f 2138{
cf1dfa6b 2139 wxListCtrl *listctrl = GetListCtrl();
25e3a937 2140
b54e41c5 2141 wxListLineData *ld = GetDummyLine();
f6bcfd97 2142
cf1dfa6b
VZ
2143 size_t countCol = GetColumnCount();
2144 for ( size_t col = 0; col < countCol; col++ )
2145 {
2146 ld->SetText(col, listctrl->OnGetItemText(line, col));
2147 }
2148
5cd89174 2149 ld->SetImage(listctrl->OnGetItemImage(line));
e1e955e1 2150}
c801d85f 2151
b54e41c5 2152wxListLineData *wxListMainWindow::GetDummyLine() const
c801d85f 2153{
cf1dfa6b 2154 wxASSERT_MSG( !IsEmpty(), _T("invalid line index") );
2c1f73ee 2155
cf1dfa6b 2156 if ( m_lines.IsEmpty() )
2c1f73ee 2157 {
cf1dfa6b
VZ
2158 // normal controls are supposed to have something in m_lines
2159 // already if it's not empty
2160 wxASSERT_MSG( IsVirtual(), _T("logic error") );
2161
2162 wxListMainWindow *self = wxConstCast(this, wxListMainWindow);
5cd89174 2163 wxListLineData *line = new wxListLineData(self);
cf1dfa6b 2164 self->m_lines.Add(line);
2c1f73ee
VZ
2165 }
2166
cf1dfa6b
VZ
2167 return &m_lines[0];
2168}
2169
5cd89174
VZ
2170// ----------------------------------------------------------------------------
2171// line geometry (report mode only)
2172// ----------------------------------------------------------------------------
2173
cf1dfa6b
VZ
2174wxCoord wxListMainWindow::GetLineHeight() const
2175{
2176 wxASSERT_MSG( HasFlag(wxLC_REPORT), _T("only works in report mode") );
673dfcfa 2177
cf1dfa6b
VZ
2178 // we cache the line height as calling GetTextExtent() is slow
2179 if ( !m_lineHeight )
2c1f73ee 2180 {
cf1dfa6b 2181 wxListMainWindow *self = wxConstCast(this, wxListMainWindow);
bd8289c1 2182
cf1dfa6b
VZ
2183 wxClientDC dc( self );
2184 dc.SetFont( GetFont() );
c801d85f 2185
cf1dfa6b
VZ
2186 wxCoord y;
2187 dc.GetTextExtent(_T("H"), NULL, &y);
004fd0c8 2188
cf1dfa6b
VZ
2189 if ( y < SCROLL_UNIT_Y )
2190 y = SCROLL_UNIT_Y;
2191 y += EXTRA_HEIGHT;
206b0a67 2192
cf1dfa6b
VZ
2193 self->m_lineHeight = y + LINE_SPACING;
2194 }
bffa1c77 2195
cf1dfa6b
VZ
2196 return m_lineHeight;
2197}
bffa1c77 2198
cf1dfa6b
VZ
2199wxCoord wxListMainWindow::GetLineY(size_t line) const
2200{
2201 wxASSERT_MSG( HasFlag(wxLC_REPORT), _T("only works in report mode") );
1370703e 2202
cf1dfa6b
VZ
2203 return LINE_SPACING + line*GetLineHeight();
2204}
206b0a67 2205
5cd89174
VZ
2206wxRect wxListMainWindow::GetLineRect(size_t line) const
2207{
2208 if ( !InReportView() )
2209 return GetLine(line)->m_gi->m_rectAll;
2210
2211 wxRect rect;
2212 rect.x = HEADER_OFFSET_X;
2213 rect.y = GetLineY(line);
2214 rect.width = GetHeaderWidth();
2215 rect.height = GetLineHeight();
2216
2217 return rect;
2218}
2219
2220wxRect wxListMainWindow::GetLineLabelRect(size_t line) const
2221{
2222 if ( !InReportView() )
2223 return GetLine(line)->m_gi->m_rectLabel;
2224
2225 wxRect rect;
2226 rect.x = HEADER_OFFSET_X;
2227 rect.y = GetLineY(line);
2228 rect.width = GetColumnWidth(0);
2229 rect.height = GetLineHeight();
2230
2231 return rect;
2232}
2233
2234wxRect wxListMainWindow::GetLineIconRect(size_t line) const
2235{
2236 if ( !InReportView() )
2237 return GetLine(line)->m_gi->m_rectIcon;
2238
2239 wxListLineData *ld = GetLine(line);
2240 wxASSERT_MSG( ld->HasImage(), _T("should have an image") );
2241
2242 wxRect rect;
2243 rect.x = HEADER_OFFSET_X;
2244 rect.y = GetLineY(line);
2245 GetImageSize(ld->GetImage(), rect.width, rect.height);
2246
2247 return rect;
2248}
2249
2250wxRect wxListMainWindow::GetLineHighlightRect(size_t line) const
2251{
2252 return InReportView() ? GetLineRect(line)
2253 : GetLine(line)->m_gi->m_rectHighlight;
2254}
2255
2256long wxListMainWindow::HitTestLine(size_t line, int x, int y) const
2257{
2258 wxListLineData *ld = GetLine(line);
2259
2260 if ( ld->HasImage() && GetLineIconRect(line).Inside(x, y) )
2261 return wxLIST_HITTEST_ONITEMICON;
2262
2263 if ( ld->HasText() )
2264 {
2265 wxRect rect = InReportView() ? GetLineRect(line)
2266 : GetLineLabelRect(line);
2267
2268 if ( rect.Inside(x, y) )
2269 return wxLIST_HITTEST_ONITEMLABEL;
2270 }
2271
2272 return 0;
2273}
2274
2275// ----------------------------------------------------------------------------
2276// highlight (selection) handling
2277// ----------------------------------------------------------------------------
2278
b54e41c5 2279bool wxListMainWindow::IsHighlighted(size_t line) const
cf1dfa6b
VZ
2280{
2281 if ( IsVirtual() )
2282 {
b54e41c5 2283 return m_selStore.IsSelected(line);
cf1dfa6b
VZ
2284 }
2285 else // !virtual
2286 {
2287 wxListLineData *ld = GetLine(line);
b54e41c5 2288 wxCHECK_MSG( ld, FALSE, _T("invalid index in IsHighlighted") );
cf1dfa6b 2289
b54e41c5 2290 return ld->IsHighlighted();
cf1dfa6b
VZ
2291 }
2292}
2293
b54e41c5 2294void wxListMainWindow::HighlightLines( size_t lineFrom, size_t lineTo, bool highlight )
cf1dfa6b 2295{
cf1dfa6b
VZ
2296 if ( IsVirtual() )
2297 {
b54e41c5
VZ
2298 m_selStore.SelectRange(lineFrom, lineTo, highlight);
2299 RefreshLines(lineFrom, lineTo);
2300 }
2301 else
2302 {
2303 // do it the dumb way
2304 bool needsRefresh = FALSE;
2305 for ( size_t line = lineFrom; line <= lineTo; line++ )
cf1dfa6b 2306 {
b54e41c5
VZ
2307 if ( HighlightLine(line, highlight) )
2308 needsRefresh = TRUE;
cf1dfa6b 2309 }
b54e41c5
VZ
2310
2311 if ( needsRefresh )
2312 RefreshLines(lineFrom, lineTo);
2313 }
2314}
2315
2316bool wxListMainWindow::HighlightLine( size_t line, bool highlight )
2317{
2318 bool changed;
2319
2320 if ( IsVirtual() )
2321 {
2322 changed = m_selStore.SelectItem(line, highlight);
cf1dfa6b
VZ
2323 }
2324 else // !virtual
2325 {
2326 wxListLineData *ld = GetLine(line);
b54e41c5 2327 wxCHECK_MSG( ld, FALSE, _T("invalid index in IsHighlighted") );
cf1dfa6b 2328
b54e41c5 2329 changed = ld->Highlight(highlight);
cf1dfa6b
VZ
2330 }
2331
2332 if ( changed )
2333 {
b54e41c5 2334 SendNotify( line, highlight ? wxEVT_COMMAND_LIST_ITEM_SELECTED
5cd89174 2335 : wxEVT_COMMAND_LIST_ITEM_DESELECTED );
cf1dfa6b
VZ
2336 }
2337
2338 return changed;
2339}
2340
2341void wxListMainWindow::RefreshLine( size_t line )
2342{
5cd89174 2343 wxRect rect = GetLineRect(line);
cf1dfa6b
VZ
2344
2345 CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
2346 RefreshRect( rect );
2347}
2348
2349void wxListMainWindow::RefreshLines( size_t lineFrom, size_t lineTo )
2350{
2351 // we suppose that they are ordered by caller
2352 wxASSERT_MSG( lineFrom <= lineTo, _T("indices in disorder") );
2353
2354 if ( HasFlag(wxLC_REPORT) )
2355 {
b54e41c5
VZ
2356 size_t visibleFrom, visibleTo;
2357 GetVisibleLinesRange(&visibleFrom, &visibleTo);
2358
2359 if ( lineFrom < visibleFrom )
2360 lineFrom = visibleFrom;
2361 if ( lineTo > visibleTo )
2362 lineTo = visibleTo;
cf1dfa6b
VZ
2363
2364 wxRect rect;
2365 rect.x = 0;
2366 rect.y = GetLineY(lineFrom);
2367 rect.width = GetClientSize().x;
2368 rect.height = GetLineY(lineTo) - rect.y;
2369
2370 CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
2371 RefreshRect( rect );
2372 }
2373 else // !report
2374 {
2375 // TODO: this should be optimized...
2376 for ( size_t line = lineFrom; line <= lineTo; line++ )
2377 {
2378 RefreshLine(line);
2379 }
2380 }
2381}
2382
2383void wxListMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
2384{
2385 // Note: a wxPaintDC must be constructed even if no drawing is
2386 // done (a Windows requirement).
2387 wxPaintDC dc( this );
2388
cf1dfa6b
VZ
2389 if ( IsEmpty() )
2390 {
2391 // empty control. nothing to draw
2392 return;
2393 }
2394
2395 PrepareDC( dc );
2396
2397 int dev_x, dev_y;
2398 CalcScrolledPosition( 0, 0, &dev_x, &dev_y );
2399
2400 dc.BeginDrawing();
2401
2402 dc.SetFont( GetFont() );
2403
2404 if ( HasFlag(wxLC_REPORT) )
2405 {
b54e41c5 2406 int lineHeight = GetLineHeight();
cf1dfa6b 2407
b54e41c5
VZ
2408 size_t visibleFrom, visibleTo;
2409 GetVisibleLinesRange(&visibleFrom, &visibleTo);
2410 for ( size_t line = visibleFrom; line <= visibleTo; line++ )
cf1dfa6b 2411 {
5cd89174
VZ
2412 GetLine(line)->DrawInReportMode( &dc,
2413 GetLineRect(line),
2414 GetLineHighlightRect(line),
2415 IsHighlighted(line) );
cf1dfa6b
VZ
2416 }
2417
2418 if ( HasFlag(wxLC_HRULES) )
2419 {
b54e41c5 2420 wxPen pen(GetRuleColour(), 1, wxSOLID);
cf1dfa6b
VZ
2421 wxSize clientSize = GetClientSize();
2422
b54e41c5 2423 for ( size_t i = visibleFrom; i <= visibleTo; i++ )
cf1dfa6b
VZ
2424 {
2425 dc.SetPen(pen);
2426 dc.SetBrush( *wxTRANSPARENT_BRUSH );
b54e41c5
VZ
2427 dc.DrawLine(0 - dev_x, i*lineHeight,
2428 clientSize.x - dev_x, i*lineHeight);
cf1dfa6b
VZ
2429 }
2430
2431 // Draw last horizontal rule
b54e41c5 2432 if ( visibleTo > visibleFrom )
cf1dfa6b
VZ
2433 {
2434 dc.SetPen(pen);
2435 dc.SetBrush( *wxTRANSPARENT_BRUSH );
b54e41c5
VZ
2436 dc.DrawLine(0 - dev_x, m_lineTo*lineHeight,
2437 clientSize.x - dev_x , m_lineTo*lineHeight );
cf1dfa6b 2438 }
2c1f73ee 2439 }
206b0a67
JS
2440
2441 // Draw vertical rules if required
cf1dfa6b 2442 if ( HasFlag(wxLC_VRULES) && !IsEmpty() )
206b0a67 2443 {
b54e41c5 2444 wxPen pen(GetRuleColour(), 1, wxSOLID);
cf1dfa6b 2445
206b0a67
JS
2446 int col = 0;
2447 wxRect firstItemRect;
2448 wxRect lastItemRect;
2449 GetItemRect(0, firstItemRect);
2450 GetItemRect(GetItemCount() - 1, lastItemRect);
2451 int x = firstItemRect.GetX();
673dfcfa
JS
2452 dc.SetPen(pen);
2453 dc.SetBrush(* wxTRANSPARENT_BRUSH);
206b0a67
JS
2454 for (col = 0; col < GetColumnCount(); col++)
2455 {
2456 int colWidth = GetColumnWidth(col);
cf1dfa6b
VZ
2457 x += colWidth;
2458 dc.DrawLine(x - dev_x, firstItemRect.GetY() - 1 - dev_y,
2459 x - dev_x, lastItemRect.GetBottom() + 1 - dev_y);
206b0a67 2460 }
d786bf87 2461 }
139adb6a 2462 }
cf1dfa6b 2463 else // !report
139adb6a 2464 {
1370703e 2465 size_t count = GetItemCount();
cf1dfa6b
VZ
2466 for ( size_t i = 0; i < count; i++ )
2467 {
2468 GetLine(i)->Draw( &dc );
2469 }
139adb6a 2470 }
004fd0c8 2471
cf1dfa6b
VZ
2472 if ( HasCurrent() && m_hasFocus )
2473 {
4176fb7d
SC
2474#ifdef __WXMAC__
2475 // no rect outline, we already have the background color
2476#else
cf1dfa6b
VZ
2477 dc.SetPen( *wxBLACK_PEN );
2478 dc.SetBrush( *wxTRANSPARENT_BRUSH );
5cd89174 2479 dc.DrawRectangle( GetLineHighlightRect(m_current) );
4176fb7d 2480#endif
cf1dfa6b 2481 }
c801d85f 2482
139adb6a 2483 dc.EndDrawing();
e1e955e1 2484}
c801d85f 2485
b54e41c5 2486void wxListMainWindow::HighlightAll( bool on )
c801d85f 2487{
b54e41c5 2488 if ( IsSingleSel() )
c801d85f 2489 {
b54e41c5
VZ
2490 wxASSERT_MSG( !on, _T("can't do this in a single sel control") );
2491
2492 // we just have one item to turn off
2493 if ( HasCurrent() && IsHighlighted(m_current) )
139adb6a 2494 {
b54e41c5
VZ
2495 HighlightLine(m_current, FALSE);
2496 RefreshLine(m_current);
139adb6a 2497 }
e1e955e1 2498 }
b54e41c5 2499 else // multi sel
cf1dfa6b 2500 {
b54e41c5 2501 HighlightLines(0, GetItemCount() - 1, on);
cf1dfa6b 2502 }
e1e955e1 2503}
c801d85f 2504
cf1dfa6b 2505void wxListMainWindow::SendNotify( size_t line,
05a7f61d
VZ
2506 wxEventType command,
2507 wxPoint point )
c801d85f 2508{
139adb6a
RR
2509 wxListEvent le( command, GetParent()->GetId() );
2510 le.SetEventObject( GetParent() );
cf1dfa6b 2511 le.m_itemIndex = line;
05a7f61d
VZ
2512
2513 // set only for events which have position
2514 if ( point != wxDefaultPosition )
2515 le.m_pointDrag = point;
2516
cf1dfa6b 2517 GetLine(line)->GetItem( 0, le.m_item );
6e228e42 2518 GetParent()->GetEventHandler()->ProcessEvent( le );
e1e955e1 2519}
c801d85f 2520
cf1dfa6b 2521void wxListMainWindow::OnFocusLine( size_t WXUNUSED(line) )
c801d85f
KB
2522{
2523// SendNotify( line, wxEVT_COMMAND_LIST_ITEM_FOCUSSED );
e1e955e1 2524}
c801d85f 2525
cf1dfa6b 2526void wxListMainWindow::OnUnfocusLine( size_t WXUNUSED(line) )
c801d85f
KB
2527{
2528// SendNotify( line, wxEVT_COMMAND_LIST_ITEM_UNFOCUSSED );
e1e955e1 2529}
c801d85f 2530
5f1ea0ee 2531void wxListMainWindow::EditLabel( long item )
c801d85f 2532{
cf1dfa6b
VZ
2533 wxCHECK_RET( (item >= 0) && ((size_t)item < GetItemCount()),
2534 wxT("wrong index in wxListCtrl::EditLabel()") );
004fd0c8 2535
1370703e 2536 m_currentEdit = (size_t)item;
e179bd65 2537
fd9811b1 2538 wxListEvent le( wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT, GetParent()->GetId() );
139adb6a 2539 le.SetEventObject( GetParent() );
1370703e
VZ
2540 le.m_itemIndex = item;
2541 wxListLineData *data = GetLine(m_currentEdit);
2542 wxCHECK_RET( data, _T("invalid index in EditLabel()") );
2543 data->GetItem( 0, le.m_item );
139adb6a 2544 GetParent()->GetEventHandler()->ProcessEvent( le );
004fd0c8 2545
86f975a8 2546 if (!le.IsAllowed())
5f1ea0ee 2547 return;
004fd0c8 2548
cf1dfa6b
VZ
2549 // We have to call this here because the label in question might just have
2550 // been added and no screen update taken place.
2551 if (m_dirty)
2552 wxSafeYield();
004fd0c8 2553
92976ab6
RR
2554 wxClientDC dc(this);
2555 PrepareDC( dc );
bd8289c1 2556
cf1dfa6b 2557 wxString s = data->GetText(0);
5cd89174 2558 wxRect rectLabel = GetLineLabelRect(m_currentEdit);
cf1dfa6b
VZ
2559
2560 rectLabel.x = dc.LogicalToDeviceX( rectLabel.x );
2561 rectLabel.y = dc.LogicalToDeviceY( rectLabel.y );
2562
2563 wxListTextCtrl *text = new wxListTextCtrl
2564 (
2565 this, -1,
2566 &m_renameAccept,
2567 &m_renameRes,
2568 this,
2569 s,
2570 wxPoint(rectLabel.x-4,rectLabel.y-4),
2571 wxSize(rectLabel.width+11,rectLabel.height+8)
2572 );
92976ab6 2573 text->SetFocus();
e1e955e1 2574}
c801d85f 2575
e179bd65
RR
2576void wxListMainWindow::OnRenameTimer()
2577{
cf1dfa6b 2578 wxCHECK_RET( HasCurrent(), wxT("unexpected rename timer") );
004fd0c8 2579
cf1dfa6b 2580 EditLabel( m_current );
e179bd65
RR
2581}
2582
c801d85f
KB
2583void wxListMainWindow::OnRenameAccept()
2584{
e179bd65
RR
2585 wxListEvent le( wxEVT_COMMAND_LIST_END_LABEL_EDIT, GetParent()->GetId() );
2586 le.SetEventObject( GetParent() );
1370703e
VZ
2587 le.m_itemIndex = m_currentEdit;
2588
2589 wxListLineData *data = GetLine(m_currentEdit);
2590 wxCHECK_RET( data, _T("invalid index in OnRenameAccept()") );
2591
2592 data->GetItem( 0, le.m_item );
e179bd65
RR
2593 le.m_item.m_text = m_renameRes;
2594 GetParent()->GetEventHandler()->ProcessEvent( le );
004fd0c8 2595
e179bd65 2596 if (!le.IsAllowed()) return;
004fd0c8 2597
5f1ea0ee
RR
2598 wxListItem info;
2599 info.m_mask = wxLIST_MASK_TEXT;
2600 info.m_itemId = le.m_itemIndex;
2601 info.m_text = m_renameRes;
aaa37c0d 2602 info.SetTextColour(le.m_item.GetTextColour());
5f1ea0ee 2603 SetItem( info );
e1e955e1 2604}
c801d85f
KB
2605
2606void wxListMainWindow::OnMouse( wxMouseEvent &event )
2607{
3e1c4e00 2608 event.SetEventObject( GetParent() );
cf1dfa6b
VZ
2609 if ( GetParent()->GetEventHandler()->ProcessEvent( event) )
2610 return;
2611
2612 if ( !HasCurrent() || IsEmpty() )
2613 return;
2614
2615 if (m_dirty)
2616 return;
e3e65dac 2617
cf1dfa6b
VZ
2618 if ( !(event.Dragging() || event.ButtonDown() || event.LeftUp() ||
2619 event.ButtonDClick()) )
2620 return;
c801d85f 2621
aaef15bf
RR
2622 int x = event.GetX();
2623 int y = event.GetY();
2624 CalcUnscrolledPosition( x, y, &x, &y );
004fd0c8 2625
51cc4dad 2626 /* Did we actually hit an item ? */
92976ab6 2627 long hitResult = 0;
1370703e 2628
cf1dfa6b
VZ
2629 size_t count = GetItemCount(),
2630 current;
2631
2632 if ( HasFlag(wxLC_REPORT) )
92976ab6 2633 {
5cd89174
VZ
2634 current = y / GetLineHeight();
2635 hitResult = HitTestLine(current, x, y);
cf1dfa6b
VZ
2636 }
2637 else // !report
2638 {
2639 // TODO: optimize it too! this is less simple than for report view but
2640 // enumerating all items is still not a way to do it!!
5cd89174 2641 for ( current = 0; current < count && !hitResult; current++ )
cf1dfa6b 2642 {
5cd89174 2643 hitResult = HitTestLine(current, x, y);
cf1dfa6b 2644 }
92976ab6 2645 }
bd8289c1 2646
fd9811b1 2647 if (event.Dragging())
92976ab6 2648 {
fd9811b1 2649 if (m_dragCount == 0)
bffa1c77
VZ
2650 m_dragStart = wxPoint(x,y);
2651
fd9811b1 2652 m_dragCount++;
bffa1c77 2653
cf1dfa6b
VZ
2654 if (m_dragCount != 3)
2655 return;
bffa1c77 2656
05a7f61d
VZ
2657 int command = event.RightIsDown() ? wxEVT_COMMAND_LIST_BEGIN_RDRAG
2658 : wxEVT_COMMAND_LIST_BEGIN_DRAG;
bffa1c77 2659
fd9811b1 2660 wxListEvent le( command, GetParent()->GetId() );
92976ab6 2661 le.SetEventObject( GetParent() );
bffa1c77
VZ
2662 le.m_pointDrag = m_dragStart;
2663 GetParent()->GetEventHandler()->ProcessEvent( le );
2664
2665 return;
92976ab6 2666 }
fd9811b1
RR
2667 else
2668 {
2669 m_dragCount = 0;
2670 }
bd8289c1 2671
cf1dfa6b
VZ
2672 if ( !hitResult )
2673 {
2674 // outside of any item
2675 return;
2676 }
bd8289c1 2677
efbb7287 2678 bool forceClick = FALSE;
92976ab6
RR
2679 if (event.ButtonDClick())
2680 {
92976ab6 2681 m_renameTimer->Stop();
efbb7287
VZ
2682 m_lastOnSame = FALSE;
2683
cf1dfa6b 2684 if ( current == m_lineBeforeLastClicked )
efbb7287 2685 {
cf1dfa6b 2686 SendNotify( current, wxEVT_COMMAND_LIST_ITEM_ACTIVATED );
004fd0c8 2687
efbb7287
VZ
2688 return;
2689 }
2690 else
2691 {
2692 // the first click was on another item, so don't interpret this as
2693 // a double click, but as a simple click instead
2694 forceClick = TRUE;
2695 }
92976ab6 2696 }
bd8289c1 2697
92976ab6 2698 if (event.LeftUp() && m_lastOnSame)
c801d85f 2699 {
cf1dfa6b 2700 if ((current == m_current) &&
92976ab6 2701 (hitResult == wxLIST_HITTEST_ONITEMLABEL) &&
cf1dfa6b 2702 HasFlag(wxLC_EDIT_LABELS) )
92976ab6
RR
2703 {
2704 m_renameTimer->Start( 100, TRUE );
2705 }
2706 m_lastOnSame = FALSE;
e1e955e1 2707 }
cf1dfa6b 2708 else if (event.RightDown())
b204641e 2709 {
cf1dfa6b 2710 SendNotify( current, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK,
05a7f61d 2711 event.GetPosition() );
b204641e 2712 }
cf1dfa6b 2713 else if (event.MiddleDown())
b204641e 2714 {
cf1dfa6b 2715 SendNotify( current, wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK );
92976ab6 2716 }
cf1dfa6b 2717 else if ( event.LeftDown() || forceClick )
92976ab6 2718 {
efbb7287 2719 m_lineBeforeLastClicked = m_lineLastClicked;
cf1dfa6b
VZ
2720 m_lineLastClicked = current;
2721
2722 size_t oldCurrent = m_current;
efbb7287 2723
b54e41c5 2724 if ( IsSingleSel() || !(event.ControlDown() || event.ShiftDown()) )
b204641e 2725 {
b54e41c5 2726 HighlightAll( FALSE );
cf1dfa6b 2727 m_current = current;
cf1dfa6b 2728
b54e41c5 2729 ReverseHighlight(m_current);
e1e955e1 2730 }
b54e41c5 2731 else // multi sel & either ctrl or shift is down
b204641e 2732 {
473d087e 2733 if (event.ControlDown())
92976ab6 2734 {
cf1dfa6b
VZ
2735 m_current = current;
2736
b54e41c5 2737 ReverseHighlight(m_current);
92976ab6 2738 }
473d087e 2739 else if (event.ShiftDown())
92976ab6 2740 {
cf1dfa6b 2741 m_current = current;
bffa1c77 2742
cf1dfa6b
VZ
2743 size_t lineFrom = oldCurrent,
2744 lineTo = current;
f6bcfd97 2745
cf1dfa6b 2746 if ( lineTo < lineFrom )
92976ab6 2747 {
cf1dfa6b
VZ
2748 lineTo = lineFrom;
2749 lineFrom = m_current;
92976ab6
RR
2750 }
2751
b54e41c5 2752 HighlightLines(lineFrom, lineTo);
92976ab6 2753 }
cf1dfa6b 2754 else // !ctrl, !shift
92976ab6 2755 {
cf1dfa6b
VZ
2756 // test in the enclosing if should make it impossible
2757 wxFAIL_MSG( _T("how did we get here?") );
92976ab6 2758 }
e1e955e1 2759 }
cf1dfa6b 2760
92976ab6
RR
2761 if (m_current != oldCurrent)
2762 {
2763 RefreshLine( oldCurrent );
cf1dfa6b
VZ
2764 OnUnfocusLine( oldCurrent );
2765 OnFocusLine( m_current );
92976ab6 2766 }
efbb7287
VZ
2767
2768 // forceClick is only set if the previous click was on another item
2769 m_lastOnSame = !forceClick && (m_current == oldCurrent);
e1e955e1 2770 }
e1e955e1 2771}
c801d85f 2772
e179bd65 2773void wxListMainWindow::MoveToFocus()
c801d85f 2774{
b54e41c5 2775 if ( !HasCurrent() )
cf1dfa6b 2776 return;
004fd0c8 2777
5cd89174 2778 wxRect rect = GetLineRect(m_current);
cf3da716 2779
cf1dfa6b 2780 int client_w, client_h;
cf3da716 2781 GetClientSize( &client_w, &client_h );
f6bcfd97 2782
cf3da716
RR
2783 int view_x = m_xScroll*GetScrollPos( wxHORIZONTAL );
2784 int view_y = m_yScroll*GetScrollPos( wxVERTICAL );
004fd0c8 2785
cf1dfa6b 2786 if ( HasFlag(wxLC_REPORT) )
92976ab6 2787 {
b54e41c5
VZ
2788 // the next we need the range of lines shown it might be different, so
2789 // recalculate it
2790 ResetVisibleLinesRange();
2791
cf1dfa6b
VZ
2792 if (rect.y < view_y )
2793 Scroll( -1, rect.y/m_yScroll );
2794 if (rect.y+rect.height+5 > view_y+client_h)
2795 Scroll( -1, (rect.y+rect.height-client_h+SCROLL_UNIT_Y)/m_yScroll );
92976ab6 2796 }
b54e41c5 2797 else // !report
92976ab6 2798 {
cf1dfa6b
VZ
2799 if (rect.x-view_x < 5)
2800 Scroll( (rect.x-5)/m_xScroll, -1 );
2801 if (rect.x+rect.width-5 > view_x+client_w)
2802 Scroll( (rect.x+rect.width-client_w+SCROLL_UNIT_X)/m_xScroll, -1 );
92976ab6 2803 }
e1e955e1 2804}
c801d85f 2805
cf1dfa6b
VZ
2806// ----------------------------------------------------------------------------
2807// keyboard handling
2808// ----------------------------------------------------------------------------
2809
2810void wxListMainWindow::OnArrowChar(size_t newCurrent, const wxKeyEvent& event)
c801d85f 2811{
cf1dfa6b
VZ
2812 wxCHECK_RET( newCurrent < (size_t)GetItemCount(),
2813 _T("invalid item index in OnArrowChar()") );
2814
2815 size_t oldCurrent = m_current;
2816
2817 // in single selection we just ignore Shift as we can't select several
2818 // items anyhow
b54e41c5 2819 if ( event.ShiftDown() && !IsSingleSel() )
cf1dfa6b
VZ
2820 {
2821 m_current = newCurrent;
2822
2823 // select all the items between the old and the new one
2824 if ( oldCurrent > newCurrent )
2825 {
2826 newCurrent = oldCurrent;
2827 oldCurrent = m_current;
2828 }
2829
b54e41c5 2830 HighlightLines(oldCurrent, newCurrent);
cf1dfa6b
VZ
2831 }
2832 else // !shift
2833 {
b54e41c5
VZ
2834 // all previously selected items are unselected unless ctrl is held
2835 if ( !event.ControlDown() )
2836 HighlightAll(FALSE);
2837
cf1dfa6b
VZ
2838 m_current = newCurrent;
2839
b54e41c5 2840 HighlightLine( oldCurrent, FALSE );
cf1dfa6b
VZ
2841 RefreshLine( oldCurrent );
2842
2843 if ( !event.ControlDown() )
2844 {
b54e41c5 2845 HighlightLine( m_current, TRUE );
cf1dfa6b
VZ
2846 }
2847 }
2848
2849 OnUnfocusLine( oldCurrent );
2850 OnFocusLine( m_current );
92976ab6 2851 RefreshLine( m_current );
cf1dfa6b 2852
cf3da716 2853 MoveToFocus();
e1e955e1 2854}
c801d85f 2855
3dfb93fd
RR
2856void wxListMainWindow::OnKeyDown( wxKeyEvent &event )
2857{
2858 wxWindow *parent = GetParent();
004fd0c8 2859
3dfb93fd
RR
2860 /* we propagate the key event up */
2861 wxKeyEvent ke( wxEVT_KEY_DOWN );
2862 ke.m_shiftDown = event.m_shiftDown;
2863 ke.m_controlDown = event.m_controlDown;
2864 ke.m_altDown = event.m_altDown;
2865 ke.m_metaDown = event.m_metaDown;
2866 ke.m_keyCode = event.m_keyCode;
2867 ke.m_x = event.m_x;
2868 ke.m_y = event.m_y;
2869 ke.SetEventObject( parent );
2870 if (parent->GetEventHandler()->ProcessEvent( ke )) return;
004fd0c8 2871
3dfb93fd
RR
2872 event.Skip();
2873}
004fd0c8 2874
c801d85f
KB
2875void wxListMainWindow::OnChar( wxKeyEvent &event )
2876{
51cc4dad 2877 wxWindow *parent = GetParent();
004fd0c8 2878
51cc4dad 2879 /* we send a list_key event up */
cf1dfa6b 2880 if ( HasCurrent() )
f6bcfd97
BP
2881 {
2882 wxListEvent le( wxEVT_COMMAND_LIST_KEY_DOWN, GetParent()->GetId() );
cf1dfa6b
VZ
2883 le.m_itemIndex = m_current;
2884 GetLine(m_current)->GetItem( 0, le.m_item );
f6bcfd97
BP
2885 le.m_code = (int)event.KeyCode();
2886 le.SetEventObject( parent );
2887 parent->GetEventHandler()->ProcessEvent( le );
2888 }
51cc4dad 2889
3dfb93fd
RR
2890 /* we propagate the char event up */
2891 wxKeyEvent ke( wxEVT_CHAR );
51cc4dad
RR
2892 ke.m_shiftDown = event.m_shiftDown;
2893 ke.m_controlDown = event.m_controlDown;
2894 ke.m_altDown = event.m_altDown;
2895 ke.m_metaDown = event.m_metaDown;
2896 ke.m_keyCode = event.m_keyCode;
2897 ke.m_x = event.m_x;
2898 ke.m_y = event.m_y;
2899 ke.SetEventObject( parent );
2900 if (parent->GetEventHandler()->ProcessEvent( ke )) return;
004fd0c8 2901
012a03e0
RR
2902 if (event.KeyCode() == WXK_TAB)
2903 {
2904 wxNavigationKeyEvent nevent;
c5145d41 2905 nevent.SetWindowChange( event.ControlDown() );
012a03e0 2906 nevent.SetDirection( !event.ShiftDown() );
8253c7fd 2907 nevent.SetEventObject( GetParent()->GetParent() );
012a03e0 2908 nevent.SetCurrentFocus( m_parent );
8253c7fd 2909 if (GetParent()->GetParent()->GetEventHandler()->ProcessEvent( nevent )) return;
012a03e0 2910 }
004fd0c8 2911
51cc4dad 2912 /* no item -> nothing to do */
cf1dfa6b 2913 if (!HasCurrent())
c801d85f 2914 {
51cc4dad
RR
2915 event.Skip();
2916 return;
e1e955e1 2917 }
51cc4dad
RR
2918
2919 switch (event.KeyCode())
c801d85f 2920 {
51cc4dad 2921 case WXK_UP:
cf1dfa6b
VZ
2922 if ( m_current > 0 )
2923 OnArrowChar( m_current - 1, event );
51cc4dad 2924 break;
cf1dfa6b 2925
51cc4dad 2926 case WXK_DOWN:
cf1dfa6b
VZ
2927 if ( m_current < (size_t)GetItemCount() - 1 )
2928 OnArrowChar( m_current + 1, event );
51cc4dad 2929 break;
cf1dfa6b 2930
51cc4dad 2931 case WXK_END:
1370703e 2932 if (!IsEmpty())
cf1dfa6b 2933 OnArrowChar( GetItemCount() - 1, event );
51cc4dad 2934 break;
cf1dfa6b 2935
51cc4dad 2936 case WXK_HOME:
1370703e 2937 if (!IsEmpty())
cf1dfa6b 2938 OnArrowChar( 0, event );
51cc4dad 2939 break;
cf1dfa6b 2940
51cc4dad 2941 case WXK_PRIOR:
f6bcfd97 2942 {
cf1dfa6b
VZ
2943 int steps = 0;
2944 if ( HasFlag(wxLC_REPORT) )
2945 {
2946 steps = m_linesPerPage - 1;
2947 }
2948 else
2949 {
2950 steps = m_current % m_linesPerPage;
2951 }
2952
2953 int index = m_current - steps;
2954 if (index < 0)
2955 index = 0;
2956
2957 OnArrowChar( index, event );
51cc4dad 2958 }
51cc4dad 2959 break;
cf1dfa6b 2960
51cc4dad 2961 case WXK_NEXT:
bffa1c77 2962 {
cf1dfa6b
VZ
2963 int steps = 0;
2964 if ( HasFlag(wxLC_REPORT) )
2965 {
2966 steps = m_linesPerPage - 1;
2967 }
2968 else
2969 {
2970 steps = m_linesPerPage - (m_current % m_linesPerPage) - 1;
2971 }
f6bcfd97 2972
cf1dfa6b
VZ
2973 size_t index = m_current + steps;
2974 size_t count = GetItemCount();
2975 if ( index >= count )
2976 index = count - 1;
2977
2978 OnArrowChar( index, event );
51cc4dad 2979 }
51cc4dad 2980 break;
cf1dfa6b 2981
51cc4dad 2982 case WXK_LEFT:
cf1dfa6b 2983 if ( !HasFlag(wxLC_REPORT) )
51cc4dad 2984 {
cf1dfa6b
VZ
2985 int index = m_current - m_linesPerPage;
2986 if (index < 0)
2987 index = 0;
2988
2989 OnArrowChar( index, event );
51cc4dad
RR
2990 }
2991 break;
cf1dfa6b 2992
51cc4dad 2993 case WXK_RIGHT:
cf1dfa6b 2994 if ( !HasFlag(wxLC_REPORT) )
51cc4dad 2995 {
cf1dfa6b
VZ
2996 size_t index = m_current + m_linesPerPage;
2997
2998 size_t count = GetItemCount();
2999 if ( index >= count )
3000 index = count - 1;
3001
3002 OnArrowChar( index, event );
51cc4dad
RR
3003 }
3004 break;
cf1dfa6b 3005
51cc4dad 3006 case WXK_SPACE:
b54e41c5 3007 if ( IsSingleSel() )
33d0e17c 3008 {
cf1dfa6b
VZ
3009 wxListEvent le( wxEVT_COMMAND_LIST_ITEM_ACTIVATED,
3010 GetParent()->GetId() );
33d0e17c 3011 le.SetEventObject( GetParent() );
cf1dfa6b
VZ
3012 le.m_itemIndex = m_current;
3013 GetLine(m_current)->GetItem( 0, le.m_item );
33d0e17c
RR
3014 GetParent()->GetEventHandler()->ProcessEvent( le );
3015 }
3016 else
3017 {
b54e41c5 3018 ReverseHighlight(m_current);
51cc4dad
RR
3019 }
3020 break;
cf1dfa6b 3021
51cc4dad
RR
3022 case WXK_RETURN:
3023 case WXK_EXECUTE:
cf1dfa6b
VZ
3024 {
3025 wxListEvent le( wxEVT_COMMAND_LIST_ITEM_ACTIVATED,
3026 GetParent()->GetId() );
3027 le.SetEventObject( GetParent() );
3028 le.m_itemIndex = m_current;
3029 GetLine(m_current)->GetItem( 0, le.m_item );
3030 GetParent()->GetEventHandler()->ProcessEvent( le );
3031 }
51cc4dad 3032 break;
cf1dfa6b 3033
51cc4dad 3034 default:
51cc4dad 3035 event.Skip();
e1e955e1 3036 }
e1e955e1 3037}
c801d85f 3038
cf1dfa6b
VZ
3039// ----------------------------------------------------------------------------
3040// focus handling
3041// ----------------------------------------------------------------------------
3042
cae5359f
RR
3043#ifdef __WXGTK__
3044extern wxWindow *g_focusWindow;
3045#endif
3046
c801d85f
KB
3047void wxListMainWindow::OnSetFocus( wxFocusEvent &WXUNUSED(event) )
3048{
63852e78 3049 m_hasFocus = TRUE;
bd8289c1 3050
cf1dfa6b
VZ
3051 if ( HasCurrent() )
3052 RefreshLine( m_current );
3053
3054 if (!GetParent())
3055 return;
004fd0c8 3056
cae5359f
RR
3057#ifdef __WXGTK__
3058 g_focusWindow = GetParent();
3059#endif
bd8289c1 3060
63852e78
RR
3061 wxFocusEvent event( wxEVT_SET_FOCUS, GetParent()->GetId() );
3062 event.SetEventObject( GetParent() );
3063 GetParent()->GetEventHandler()->ProcessEvent( event );
e1e955e1 3064}
c801d85f
KB
3065
3066void wxListMainWindow::OnKillFocus( wxFocusEvent &WXUNUSED(event) )
3067{
63852e78 3068 m_hasFocus = FALSE;
004fd0c8 3069
cf1dfa6b
VZ
3070 if ( HasCurrent() )
3071 RefreshLine( m_current );
e1e955e1 3072}
c801d85f 3073
1e6d9499 3074void wxListMainWindow::DrawImage( int index, wxDC *dc, int x, int y )
c801d85f 3075{
cf1dfa6b 3076 if ( HasFlag(wxLC_ICON) && (m_normal_image_list))
63852e78
RR
3077 {
3078 m_normal_image_list->Draw( index, *dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT );
63852e78 3079 }
cf1dfa6b 3080 else if ( HasFlag(wxLC_SMALL_ICON) && (m_small_image_list))
63852e78
RR
3081 {
3082 m_small_image_list->Draw( index, *dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT );
3083 }
cf1dfa6b 3084 else if ( HasFlag(wxLC_LIST) && (m_small_image_list))
0b855868
RR
3085 {
3086 m_small_image_list->Draw( index, *dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT );
3087 }
cf1dfa6b 3088 else if ( HasFlag(wxLC_REPORT) && (m_small_image_list))
63852e78
RR
3089 {
3090 m_small_image_list->Draw( index, *dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT );
63852e78 3091 }
e1e955e1 3092}
c801d85f 3093
5cd89174 3094void wxListMainWindow::GetImageSize( int index, int &width, int &height ) const
c801d85f 3095{
cf1dfa6b 3096 if ( HasFlag(wxLC_ICON) && m_normal_image_list )
63852e78
RR
3097 {
3098 m_normal_image_list->GetSize( index, width, height );
63852e78 3099 }
cf1dfa6b 3100 else if ( HasFlag(wxLC_SMALL_ICON) && m_small_image_list )
63852e78
RR
3101 {
3102 m_small_image_list->GetSize( index, width, height );
63852e78 3103 }
cf1dfa6b 3104 else if ( HasFlag(wxLC_LIST) && m_small_image_list )
0b855868
RR
3105 {
3106 m_small_image_list->GetSize( index, width, height );
0b855868 3107 }
cf1dfa6b 3108 else if ( HasFlag(wxLC_REPORT) && m_small_image_list )
63852e78
RR
3109 {
3110 m_small_image_list->GetSize( index, width, height );
63852e78 3111 }
cf1dfa6b
VZ
3112 else
3113 {
3114 width =
3115 height = 0;
3116 }
e1e955e1 3117}
c801d85f 3118
5cd89174 3119int wxListMainWindow::GetTextLength( const wxString &s ) const
c801d85f 3120{
5cd89174 3121 wxClientDC dc( wxConstCast(this, wxListMainWindow) );
cf1dfa6b 3122 dc.SetFont( GetFont() );
c801d85f 3123
cf1dfa6b
VZ
3124 wxCoord lw;
3125 dc.GetTextExtent( s, &lw, NULL );
3126
3127 return lw + AUTOSIZE_COL_MARGIN;
e1e955e1 3128}
c801d85f 3129
debe6624 3130void wxListMainWindow::SetImageList( wxImageList *imageList, int which )
c801d85f 3131{
139adb6a 3132 m_dirty = TRUE;
f6bcfd97
BP
3133
3134 // calc the spacing from the icon size
3135 int width = 0,
3136 height = 0;
3137 if ((imageList) && (imageList->GetImageCount()) )
3138 {
3139 imageList->GetSize(0, width, height);
3140 }
3141
3142 if (which == wxIMAGE_LIST_NORMAL)
3143 {
3144 m_normal_image_list = imageList;
3145 m_normal_spacing = width + 8;
3146 }
3147
3148 if (which == wxIMAGE_LIST_SMALL)
3149 {
3150 m_small_image_list = imageList;
3151 m_small_spacing = width + 14;
3152 }
e1e955e1 3153}
c801d85f 3154
debe6624 3155void wxListMainWindow::SetItemSpacing( int spacing, bool isSmall )
c801d85f 3156{
139adb6a
RR
3157 m_dirty = TRUE;
3158 if (isSmall)
3159 {
3160 m_small_spacing = spacing;
3161 }
3162 else
3163 {
3164 m_normal_spacing = spacing;
3165 }
e1e955e1 3166}
c801d85f 3167
debe6624 3168int wxListMainWindow::GetItemSpacing( bool isSmall )
c801d85f 3169{
f6bcfd97 3170 return isSmall ? m_small_spacing : m_normal_spacing;
e1e955e1 3171}
c801d85f 3172
cf1dfa6b
VZ
3173// ----------------------------------------------------------------------------
3174// columns
3175// ----------------------------------------------------------------------------
3176
debe6624 3177void wxListMainWindow::SetColumn( int col, wxListItem &item )
c801d85f 3178{
24b9f055 3179 wxListHeaderDataList::Node *node = m_columns.Item( col );
f6bcfd97 3180
cf1dfa6b
VZ
3181 wxCHECK_RET( node, _T("invalid column index in SetColumn") );
3182
3183 if ( item.m_width == wxLIST_AUTOSIZE_USEHEADER )
3184 item.m_width = GetTextLength( item.m_text );
3185
3186 wxListHeaderData *column = node->GetData();
3187 column->SetItem( item );
3188
3189 wxListHeaderWindow *headerWin = GetListCtrl()->m_headerWin;
f6bcfd97
BP
3190 if ( headerWin )
3191 headerWin->m_dirty = TRUE;
cf1dfa6b
VZ
3192
3193 m_dirty = TRUE;
3194
3195 // invalidate it as it has to be recalculated
3196 m_headerWidth = 0;
e1e955e1 3197}
c801d85f 3198
debe6624 3199void wxListMainWindow::SetColumnWidth( int col, int width )
c801d85f 3200{
cf1dfa6b
VZ
3201 wxCHECK_RET( col >= 0 && col < GetColumnCount(),
3202 _T("invalid column index") );
3203
3204 wxCHECK_RET( HasFlag(wxLC_REPORT),
f6bcfd97 3205 _T("SetColumnWidth() can only be called in report mode.") );
0208334d 3206
63852e78 3207 m_dirty = TRUE;
bd8289c1 3208
cf1dfa6b
VZ
3209 wxListHeaderDataList::Node *node = m_columns.Item( col );
3210 wxCHECK_RET( node, _T("no column?") );
3211
3212 wxListHeaderData *column = node->GetData();
3213
3214 size_t count = GetItemCount();
3215
f6bcfd97
BP
3216 if (width == wxLIST_AUTOSIZE_USEHEADER)
3217 {
cf1dfa6b 3218 width = GetTextLength(column->GetText());
f6bcfd97 3219 }
cf1dfa6b 3220 else if ( width == wxLIST_AUTOSIZE )
0180dad6 3221 {
cf1dfa6b
VZ
3222 if ( IsVirtual() )
3223 {
3224 // TODO: determine the max width somehow...
3225 width = WIDTH_COL_DEFAULT;
3226 }
3227 else // !virtual
0180dad6 3228 {
cf1dfa6b
VZ
3229 wxClientDC dc(this);
3230 dc.SetFont( GetFont() );
3231
3232 int max = AUTOSIZE_COL_MARGIN;
3233
3234 for ( size_t i = 0; i < count; i++ )
0180dad6 3235 {
cf1dfa6b
VZ
3236 wxListLineData *line = GetLine(i);
3237 wxListItemDataList::Node *n = line->m_items.Item( col );
3238
3239 wxCHECK_RET( n, _T("no subitem?") );
3240
2c1f73ee 3241 wxListItemData *item = n->GetData();
cf1dfa6b
VZ
3242 int current = 0;
3243
bffa1c77
VZ
3244 if (item->HasImage())
3245 {
cf1dfa6b 3246 int ix, iy;
0180dad6 3247 GetImageSize( item->GetImage(), ix, iy );
cf1dfa6b 3248 current += ix + 5;
bffa1c77 3249 }
cf1dfa6b 3250
bffa1c77
VZ
3251 if (item->HasText())
3252 {
cf1dfa6b
VZ
3253 wxCoord w;
3254 dc.GetTextExtent( item->GetText(), &w, NULL );
3255 current += w;
bffa1c77 3256 }
cf1dfa6b 3257
2c1f73ee
VZ
3258 if (current > max)
3259 max = current;
0180dad6 3260 }
cf1dfa6b
VZ
3261
3262 width = max + AUTOSIZE_COL_MARGIN;
0180dad6 3263 }
0180dad6
RR
3264 }
3265
cf1dfa6b 3266 column->SetWidth( width );
bd8289c1 3267
cf1dfa6b
VZ
3268 // invalidate it as it has to be recalculated
3269 m_headerWidth = 0;
3270}
3271
3272int wxListMainWindow::GetHeaderWidth() const
3273{
3274 if ( !m_headerWidth )
0208334d 3275 {
cf1dfa6b
VZ
3276 wxListMainWindow *self = wxConstCast(this, wxListMainWindow);
3277
3278 size_t count = GetColumnCount();
3279 for ( size_t col = 0; col < count; col++ )
63852e78 3280 {
cf1dfa6b 3281 self->m_headerWidth += GetColumnWidth(col);
63852e78 3282 }
0208334d 3283 }
bd8289c1 3284
cf1dfa6b 3285 return m_headerWidth;
e1e955e1 3286}
c801d85f 3287
cf1dfa6b 3288void wxListMainWindow::GetColumn( int col, wxListItem &item ) const
c801d85f 3289{
24b9f055 3290 wxListHeaderDataList::Node *node = m_columns.Item( col );
cf1dfa6b
VZ
3291 wxCHECK_RET( node, _T("invalid column index in GetColumn") );
3292
3293 wxListHeaderData *column = node->GetData();
3294 column->GetItem( item );
e1e955e1 3295}
c801d85f 3296
cf1dfa6b 3297int wxListMainWindow::GetColumnWidth( int col ) const
c801d85f 3298{
24b9f055
VZ
3299 wxListHeaderDataList::Node *node = m_columns.Item( col );
3300 wxCHECK_MSG( node, 0, _T("invalid column index") );
3301
3302 wxListHeaderData *column = node->GetData();
3303 return column->GetWidth();
e1e955e1 3304}
c801d85f 3305
cf1dfa6b
VZ
3306// ----------------------------------------------------------------------------
3307// item state
3308// ----------------------------------------------------------------------------
c801d85f
KB
3309
3310void wxListMainWindow::SetItem( wxListItem &item )
3311{
cf1dfa6b
VZ
3312 long id = item.m_itemId;
3313 wxCHECK_RET( id >= 0 && (size_t)id < GetItemCount(),
3314 _T("invalid item index in SetItem") );
3315
3316 if ( IsVirtual() )
3317 {
3318 // just refresh the line to show the new value of the text/image
3319 RefreshLine((size_t)id);
3320 }
3321 else // !virtual
92976ab6 3322 {
cf1dfa6b
VZ
3323 m_dirty = TRUE;
3324
3325 wxListLineData *line = GetLine((size_t)id);
3326 if ( HasFlag(wxLC_REPORT) )
3327 item.m_width = GetColumnWidth( item.m_col );
92976ab6
RR
3328 line->SetItem( item.m_col, item );
3329 }
e1e955e1 3330}
c801d85f 3331
cf1dfa6b 3332void wxListMainWindow::SetItemState( long litem, long state, long stateMask )
c801d85f 3333{
cf1dfa6b 3334 wxCHECK_RET( litem >= 0 && (size_t)litem < GetItemCount(),
54442116
VZ
3335 _T("invalid list ctrl item index in SetItem") );
3336
cf1dfa6b
VZ
3337 size_t oldCurrent = m_current;
3338 size_t item = (size_t)litem; // sdafe because of the check above
bd8289c1 3339
54442116 3340 if ( stateMask & wxLIST_STATE_FOCUSED )
c801d85f 3341 {
54442116 3342 if ( state & wxLIST_STATE_FOCUSED )
92976ab6 3343 {
54442116 3344 // don't do anything if this item is already focused
cf1dfa6b 3345 if ( item != m_current )
92976ab6 3346 {
cf1dfa6b
VZ
3347 OnUnfocusLine( m_current );
3348 m_current = item;
3349 OnFocusLine( m_current );
3350
b54e41c5 3351 if ( IsSingleSel() && (oldCurrent != (size_t)-1) )
cf1dfa6b 3352 {
b54e41c5 3353 HighlightLine(oldCurrent, FALSE);
cf1dfa6b
VZ
3354 RefreshLine(oldCurrent);
3355 }
54442116 3356
92976ab6 3357 RefreshLine( m_current );
92976ab6 3358 }
54442116
VZ
3359 }
3360 else // unfocus
3361 {
3362 // don't do anything if this item is not focused
cf1dfa6b 3363 if ( item == m_current )
bffa1c77 3364 {
cf1dfa6b
VZ
3365 OnUnfocusLine( m_current );
3366 m_current = (size_t)-1;
bffa1c77 3367 }
92976ab6 3368 }
e1e955e1 3369 }
54442116
VZ
3370
3371 if ( stateMask & wxLIST_STATE_SELECTED )
3372 {
3373 bool on = (state & wxLIST_STATE_SELECTED) != 0;
54442116 3374
b54e41c5 3375 if ( IsSingleSel() )
54442116 3376 {
cf1dfa6b
VZ
3377 if ( on )
3378 {
3379 // selecting the item also makes it the focused one in the
3380 // single sel mode
3381 if ( m_current != item )
3382 {
3383 OnUnfocusLine( m_current );
3384 m_current = item;
3385 OnFocusLine( m_current );
3386
3387 if ( oldCurrent != (size_t)-1 )
3388 {
b54e41c5 3389 HighlightLine( oldCurrent, FALSE );
cf1dfa6b
VZ
3390 RefreshLine( oldCurrent );
3391 }
3392 }
3393 }
3394 else // off
3395 {
3396 // only the current item may be selected anyhow
3397 if ( item != m_current )
3398 return;
3399 }
54442116
VZ
3400 }
3401
b54e41c5 3402 if ( HighlightLine(item, on) )
54442116 3403 {
cf1dfa6b 3404 RefreshLine(item);
54442116
VZ
3405 }
3406 }
e1e955e1 3407}
c801d85f 3408
debe6624 3409int wxListMainWindow::GetItemState( long item, long stateMask )
c801d85f 3410{
cf1dfa6b
VZ
3411 wxCHECK_MSG( item >= 0 && (size_t)item < GetItemCount(), 0,
3412 _T("invalid list ctrl item index in GetItemState()") );
3413
92976ab6 3414 int ret = wxLIST_STATE_DONTCARE;
cf1dfa6b
VZ
3415
3416 if ( stateMask & wxLIST_STATE_FOCUSED )
c801d85f 3417 {
cf1dfa6b
VZ
3418 if ( (size_t)item == m_current )
3419 ret |= wxLIST_STATE_FOCUSED;
e1e955e1 3420 }
cf1dfa6b
VZ
3421
3422 if ( stateMask & wxLIST_STATE_SELECTED )
c801d85f 3423 {
b54e41c5 3424 if ( IsHighlighted(item) )
cf1dfa6b 3425 ret |= wxLIST_STATE_SELECTED;
e1e955e1 3426 }
cf1dfa6b 3427
92976ab6 3428 return ret;
e1e955e1 3429}
c801d85f
KB
3430
3431void wxListMainWindow::GetItem( wxListItem &item )
3432{
cf1dfa6b
VZ
3433 wxCHECK_RET( item.m_itemId >= 0 && (size_t)item.m_itemId < GetItemCount(),
3434 _T("invalid item index in GetItem") );
3435
3436 wxListLineData *line = GetLine((size_t)item.m_itemId);
3437 line->GetItem( item.m_col, item );
e1e955e1 3438}
c801d85f 3439
cf1dfa6b
VZ
3440// ----------------------------------------------------------------------------
3441// item count
3442// ----------------------------------------------------------------------------
3443
3444size_t wxListMainWindow::GetItemCount() const
1370703e
VZ
3445{
3446 return IsVirtual() ? m_countVirt : m_lines.GetCount();
3447}
3448
3449void wxListMainWindow::SetItemCount(long count)
c801d85f 3450{
b54e41c5 3451 m_selStore.SetItemCount(count);
1370703e
VZ
3452 m_countVirt = count;
3453
3454 Refresh();
e1e955e1 3455}
c801d85f 3456
cf1dfa6b 3457int wxListMainWindow::GetSelectedItemCount()
c801d85f 3458{
cf1dfa6b 3459 // deal with the quick case first
b54e41c5 3460 if ( IsSingleSel() )
92976ab6 3461 {
b54e41c5 3462 return HasCurrent() ? IsHighlighted(m_current) : FALSE;
92976ab6 3463 }
cf1dfa6b
VZ
3464
3465 // virtual controls remmebers all its selections itself
3466 if ( IsVirtual() )
b54e41c5 3467 return m_selStore.GetSelectedCount();
cf1dfa6b
VZ
3468
3469 // TODO: we probably should maintain the number of items selected even for
3470 // non virtual controls as enumerating all lines is really slow...
3471 size_t countSel = 0;
3472 size_t count = GetItemCount();
3473 for ( size_t line = 0; line < count; line++ )
92976ab6 3474 {
b54e41c5 3475 if ( GetLine(line)->IsHighlighted() )
cf1dfa6b 3476 countSel++;
92976ab6 3477 }
c801d85f 3478
cf1dfa6b 3479 return countSel;
e1e955e1 3480}
e3e65dac 3481
cf1dfa6b
VZ
3482// ----------------------------------------------------------------------------
3483// item position/size
3484// ----------------------------------------------------------------------------
3485
3486void wxListMainWindow::GetItemRect( long index, wxRect &rect )
c801d85f 3487{
cf1dfa6b
VZ
3488 wxCHECK_RET( index >= 0 && (size_t)index < GetItemCount(),
3489 _T("invalid index in GetItemRect") );
3490
5cd89174 3491 rect = GetLineRect((size_t)index);
b54e41c5 3492
cf1dfa6b 3493 CalcScrolledPosition(rect.x, rect.y, &rect.x, &rect.y);
e1e955e1 3494}
c801d85f 3495
cf1dfa6b 3496bool wxListMainWindow::GetItemPosition(long item, wxPoint& pos)
c801d85f 3497{
cf1dfa6b
VZ
3498 wxRect rect;
3499 GetItemRect(item, rect);
bd8289c1 3500
cf1dfa6b
VZ
3501 pos.x = rect.x;
3502 pos.y = rect.y;
bd8289c1 3503
cf1dfa6b 3504 return TRUE;
e1e955e1 3505}
c801d85f 3506
cf1dfa6b
VZ
3507// ----------------------------------------------------------------------------
3508// geometry calculation
3509// ----------------------------------------------------------------------------
3510
b54e41c5 3511void wxListMainWindow::RecalculatePositions()
c801d85f 3512{
1370703e
VZ
3513 if ( IsEmpty() )
3514 return;
e487524e 3515
1e6d9499 3516 wxClientDC dc( this );
92976ab6 3517 dc.SetFont( GetFont() );
c801d85f 3518
cf1dfa6b
VZ
3519 int iconSpacing;
3520 if ( HasFlag(wxLC_ICON) )
3521 iconSpacing = m_normal_spacing;
3522 else if ( HasFlag(wxLC_SMALL_ICON) )
3523 iconSpacing = m_small_spacing;
3524 else
3525 iconSpacing = 0;
004fd0c8 3526
cf1dfa6b
VZ
3527 int clientWidth,
3528 clientHeight;
3529 GetClientSize( &clientWidth, &clientHeight );
004fd0c8 3530
cf1dfa6b
VZ
3531 if ( HasFlag(wxLC_REPORT) )
3532 {
3533 // all lines have the same height
b54e41c5 3534 int lineHeight = GetLineHeight();
c801d85f 3535
cf1dfa6b 3536 // scroll one line per step
b54e41c5 3537 m_yScroll = lineHeight;
bd8289c1 3538
cf1dfa6b 3539 size_t lineCount = GetItemCount();
b54e41c5 3540 int entireHeight = lineCount*lineHeight + LINE_SPACING;
bd8289c1 3541
b54e41c5
VZ
3542 m_linesPerPage = clientHeight / lineHeight;
3543
3544 ResetVisibleLinesRange();
2c1f73ee 3545
cf1dfa6b
VZ
3546 SetScrollbars( m_xScroll, m_yScroll,
3547 (GetHeaderWidth() + m_xScroll - 1)/m_xScroll,
3548 (entireHeight + m_yScroll - 1)/m_yScroll,
3549 GetScrollPos(wxHORIZONTAL),
3550 GetScrollPos(wxVERTICAL),
3551 TRUE );
92976ab6 3552
e9d9f136
VZ
3553 // FIXME: wxGTK::wxScrolledWindow doesn't have SetTargetRect()
3554#if !defined(__WXGTK__) || defined(__WXUNIVERSAL__)
b54e41c5
VZ
3555 // we must have an integer number of lines on screen and so we fit
3556 // the real control size to the line height
3557 wxRect rect;
3558 rect.x = 0;
3559 rect.y = LINE_SPACING;
3560 rect.width = clientWidth;
3561 rect.height = ((clientHeight - LINE_SPACING) / lineHeight)*lineHeight;
3562 SetTargetRect(rect);
e9d9f136 3563#endif
e1e955e1 3564 }
cf1dfa6b 3565 else // !report
92976ab6
RR
3566 {
3567 // at first we try without any scrollbar. if the items don't
3568 // fit into the window, we recalculate after subtracting an
3569 // approximated 15 pt for the horizontal scrollbar
004fd0c8 3570
bffa1c77 3571 clientHeight -= 4; // sunken frame
bd8289c1 3572
b54e41c5 3573 int entireWidth = 0;
bd8289c1 3574
92976ab6 3575 for (int tries = 0; tries < 2; tries++)
e487524e 3576 {
92976ab6 3577 entireWidth = 0;
5d25c050
RR
3578 int x = 2;
3579 int y = 2;
92976ab6 3580 int maxWidth = 0;
cf1dfa6b
VZ
3581 m_linesPerPage = 0;
3582 int currentlyVisibleLines = 0;
3583
3584 size_t count = GetItemCount();
3585 for (size_t i = 0; i < count; i++)
92976ab6 3586 {
cf1dfa6b
VZ
3587 currentlyVisibleLines++;
3588 wxListLineData *line = GetLine(i);
92976ab6 3589 line->CalculateSize( &dc, iconSpacing );
cf1dfa6b
VZ
3590 line->SetPosition( x, y, clientWidth, iconSpacing );
3591
5cd89174 3592 wxSize sizeLine = GetLineSize(i);
cf1dfa6b
VZ
3593
3594 if ( maxWidth < sizeLine.x )
3595 maxWidth = sizeLine.x;
3596
3597 y += sizeLine.y;
3598 if (currentlyVisibleLines > m_linesPerPage)
3599 m_linesPerPage = currentlyVisibleLines;
3600
3601 // assume that the size of the next one is the same... (FIXME)
3602 if ( y + sizeLine.y - 6 >= clientHeight )
92976ab6 3603 {
cf1dfa6b 3604 currentlyVisibleLines = 0;
e1208c31 3605 y = 2;
8b53e5a2
RR
3606 x += maxWidth+6;
3607 entireWidth += maxWidth+6;
92976ab6
RR
3608 maxWidth = 0;
3609 }
cf1dfa6b
VZ
3610 if ( i == count - 1 )
3611 entireWidth += maxWidth;
92976ab6
RR
3612 if ((tries == 0) && (entireWidth > clientWidth))
3613 {
3614 clientHeight -= 15; // scrollbar height
cf1dfa6b
VZ
3615 m_linesPerPage = 0;
3616 currentlyVisibleLines = 0;
92976ab6
RR
3617 break;
3618 }
cf1dfa6b
VZ
3619 if ( i == count - 1 )
3620 tries = 1; // everything fits, no second try required
92976ab6 3621 }
e487524e 3622 }
bffa1c77 3623
92976ab6 3624 int scroll_pos = GetScrollPos( wxHORIZONTAL );
cf1dfa6b 3625 SetScrollbars( m_xScroll, m_yScroll, (entireWidth+SCROLL_UNIT_X) / m_xScroll, 0, scroll_pos, 0, TRUE );
e1e955e1 3626 }
cf1dfa6b
VZ
3627
3628 // FIXME: why should we call it from here?
3629 UpdateCurrent();
b54e41c5
VZ
3630
3631 RefreshAll();
3632}
3633
3634void wxListMainWindow::RefreshAll()
3635{
3636 m_dirty = FALSE;
3637 Refresh();
3638
3639 wxListHeaderWindow *headerWin = GetListCtrl()->m_headerWin;
3640 if ( headerWin )
3641 {
3642 headerWin->m_dirty = FALSE;
3643 headerWin->Refresh();
3644 }
e1e955e1 3645}
c801d85f 3646
cf1dfa6b 3647void wxListMainWindow::UpdateCurrent()
c801d85f 3648{
b54e41c5 3649 if ( !HasCurrent() && !IsEmpty() )
92976ab6 3650 {
cf1dfa6b 3651 m_current = 0;
92976ab6 3652 }
cf1dfa6b
VZ
3653
3654 if ( m_current != (size_t)-1 )
92976ab6 3655 {
cf1dfa6b 3656 OnFocusLine( m_current );
92976ab6 3657 }
e1e955e1 3658}
c801d85f 3659
19695fbd
VZ
3660long wxListMainWindow::GetNextItem( long item,
3661 int WXUNUSED(geometry),
3662 int state )
c801d85f 3663{
d1022fd6
VZ
3664 long ret = item,
3665 max = GetItemCount();
3666 wxCHECK_MSG( (ret == -1) || (ret < max), -1,
13771c08 3667 _T("invalid listctrl index in GetNextItem()") );
19695fbd
VZ
3668
3669 // notice that we start with the next item (or the first one if item == -1)
3670 // and this is intentional to allow writing a simple loop to iterate over
3671 // all selected items
d1022fd6
VZ
3672 ret++;
3673 if ( ret == max )
3674 {
3675 // this is not an error because the index was ok initially, just no
3676 // such item
3677 return -1;
3678 }
3679
cf1dfa6b
VZ
3680 if ( !state )
3681 {
3682 // any will do
3683 return (size_t)ret;
3684 }
3685
3686 size_t count = GetItemCount();
3687 for ( size_t line = (size_t)ret; line < count; line++ )
63852e78 3688 {
cf1dfa6b
VZ
3689 if ( (state & wxLIST_STATE_FOCUSED) && (line == m_current) )
3690 return line;
3691
b54e41c5 3692 if ( (state & wxLIST_STATE_SELECTED) && IsHighlighted(line) )
cf1dfa6b 3693 return line;
63852e78 3694 }
19695fbd 3695
63852e78 3696 return -1;
e1e955e1 3697}
c801d85f 3698
cf1dfa6b
VZ
3699// ----------------------------------------------------------------------------
3700// deleting stuff
3701// ----------------------------------------------------------------------------
3702
b54e41c5 3703void wxListMainWindow::DeleteItem( long lindex )
c801d85f 3704{
cf1dfa6b
VZ
3705 size_t count = GetItemCount();
3706
b54e41c5 3707 wxCHECK_RET( (lindex >= 0) && ((size_t)lindex < count),
cf1dfa6b
VZ
3708 _T("invalid item index in DeleteItem") );
3709
b54e41c5
VZ
3710 size_t index = (size_t)lindex;
3711
63852e78 3712 m_dirty = TRUE;
cf1dfa6b
VZ
3713
3714 // select the next item when the selected one is deleted
b54e41c5 3715 if ( m_current == index )
cf1dfa6b
VZ
3716 {
3717 // the last valid index after deleting the item will be count-2
5cd89174 3718 if ( m_current == count - 1 )
cf1dfa6b 3719 {
5cd89174 3720 m_current--;
cf1dfa6b
VZ
3721 }
3722 }
3723
b54e41c5 3724 SendNotify( index, wxEVT_COMMAND_LIST_DELETE_ITEM );
cf1dfa6b 3725
b54e41c5 3726 if ( IsVirtual() )
63852e78 3727 {
b54e41c5
VZ
3728 if ( m_lineTo == --m_countVirt )
3729 {
3730 m_lineTo--;
3731 }
3732
3733 m_selStore.OnItemDelete(index);
3734 }
3735 else
3736 {
3737 m_lines.RemoveAt( index );
63852e78 3738 }
5cd89174
VZ
3739
3740 RefreshLines(index, GetItemCount() - 1);
e1e955e1 3741}
c801d85f 3742
debe6624 3743void wxListMainWindow::DeleteColumn( int col )
c801d85f 3744{
24b9f055
VZ
3745 wxListHeaderDataList::Node *node = m_columns.Item( col );
3746
3747 wxCHECK_RET( node, wxT("invalid column index in DeleteColumn()") );
bd8289c1 3748
5b077d48 3749 m_dirty = TRUE;
24b9f055 3750 m_columns.DeleteNode( node );
e1e955e1 3751}
c801d85f 3752
12c1b46a 3753void wxListMainWindow::DeleteAllItems()
c801d85f 3754{
cf1dfa6b
VZ
3755 if ( IsEmpty() )
3756 {
3757 // nothing to do - in particular, don't send the event
3758 return;
3759 }
3760
5b077d48 3761 m_dirty = TRUE;
b54e41c5
VZ
3762
3763 ResetCurrent();
7c0ea335
VZ
3764
3765 // to make the deletion of all items faster, we don't send the
cf1dfa6b
VZ
3766 // notifications for each item deletion in this case but only one event
3767 // for all of them: this is compatible with wxMSW and documented in
3768 // DeleteAllItems() description
bffa1c77 3769
12c1b46a
RR
3770 wxListEvent event( wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS, GetParent()->GetId() );
3771 event.SetEventObject( GetParent() );
3772 GetParent()->GetEventHandler()->ProcessEvent( event );
7c0ea335 3773
b54e41c5
VZ
3774 if ( IsVirtual() )
3775 {
3776 m_countVirt = 0;
3777
3778 ResetVisibleLinesRange();
3779 }
3780
5b077d48 3781 m_lines.Clear();
cf1dfa6b 3782
b54e41c5 3783 m_selStore.Clear();
e1e955e1 3784}
c801d85f 3785
12c1b46a 3786void wxListMainWindow::DeleteEverything()
c801d85f 3787{
12c1b46a 3788 DeleteAllItems();
f6bcfd97 3789
5b077d48 3790 m_columns.Clear();
e1e955e1 3791}
c801d85f 3792
cf1dfa6b
VZ
3793// ----------------------------------------------------------------------------
3794// scanning for an item
3795// ----------------------------------------------------------------------------
3796
debe6624 3797void wxListMainWindow::EnsureVisible( long index )
c801d85f 3798{
cf1dfa6b
VZ
3799 wxCHECK_RET( index >= 0 && (size_t)index < GetItemCount(),
3800 _T("invalid index in EnsureVisible") );
3801
3802 // We have to call this here because the label in question might just have
3803 // been added and no screen update taken place.
3804 if (m_dirty)
3805 wxSafeYield();
dc6c62a9 3806
cf1dfa6b
VZ
3807 size_t oldCurrent = m_current;
3808 m_current = (size_t)index;
3809 MoveToFocus();
5b077d48 3810 m_current = oldCurrent;
e1e955e1 3811}
c801d85f 3812
debe6624 3813long wxListMainWindow::FindItem(long start, const wxString& str, bool WXUNUSED(partial) )
c801d85f 3814{
5b077d48
RR
3815 long pos = start;
3816 wxString tmp = str;
cf1dfa6b
VZ
3817 if (pos < 0)
3818 pos = 0;
54442116 3819
cf1dfa6b
VZ
3820 size_t count = GetItemCount();
3821 for ( size_t i = (size_t)pos; i < count; i++ )
3822 {
3823 wxListLineData *line = GetLine(i);
3824 if ( line->GetText(0) == tmp )
3825 return i;
5b077d48 3826 }
cf1dfa6b
VZ
3827
3828 return wxNOT_FOUND;
e1e955e1 3829}
c801d85f 3830
debe6624 3831long wxListMainWindow::FindItem(long start, long data)
c801d85f 3832{
5b077d48 3833 long pos = start;
cf1dfa6b
VZ
3834 if (pos < 0)
3835 pos = 0;
3836
3837 size_t count = GetItemCount();
3838 for (size_t i = (size_t)pos; i < count; i++)
5b077d48 3839 {
cf1dfa6b 3840 wxListLineData *line = GetLine(i);
5b077d48
RR
3841 wxListItem item;
3842 line->GetItem( 0, item );
cf1dfa6b
VZ
3843 if (item.m_data == data)
3844 return i;
5b077d48 3845 }
cf1dfa6b
VZ
3846
3847 return wxNOT_FOUND;
e1e955e1 3848}
c801d85f 3849
debe6624 3850long wxListMainWindow::HitTest( int x, int y, int &flags )
c801d85f 3851{
aaef15bf 3852 CalcUnscrolledPosition( x, y, &x, &y );
e8741cca 3853
5cd89174 3854 if ( HasFlag(wxLC_REPORT) )
c801d85f 3855 {
5cd89174
VZ
3856 size_t current = y / GetLineHeight();
3857 flags = HitTestLine(current, x, y);
3858 if ( flags )
3859 return current;
3860 }
3861 else // !report
3862 {
3863 // TODO: optimize it too! this is less simple than for report view but
3864 // enumerating all items is still not a way to do it!!
3865 size_t count = GetItemCount();
3866 for ( size_t current = 0; current < count; current++ )
5b077d48 3867 {
5cd89174
VZ
3868 flags = HitTestLine(current, x, y);
3869 if ( flags )
3870 return current;
5b077d48 3871 }
e1e955e1 3872 }
cf1dfa6b
VZ
3873
3874 return wxNOT_FOUND;
e1e955e1 3875}
c801d85f 3876
cf1dfa6b
VZ
3877// ----------------------------------------------------------------------------
3878// adding stuff
3879// ----------------------------------------------------------------------------
3880
c801d85f
KB
3881void wxListMainWindow::InsertItem( wxListItem &item )
3882{
cf1dfa6b
VZ
3883 wxASSERT_MSG( !IsVirtual(), _T("can't be used with virtual control") );
3884
3885 size_t count = GetItemCount();
3886 wxCHECK_RET( item.m_itemId >= 0 && (size_t)item.m_itemId <= count,
3887 _T("invalid item index") );
3888
3889 size_t id = item.m_itemId;
3890
5b077d48 3891 m_dirty = TRUE;
cf1dfa6b 3892
5b077d48 3893 int mode = 0;
cf1dfa6b 3894 if ( HasFlag(wxLC_REPORT) )
1370703e 3895 mode = wxLC_REPORT;
cf1dfa6b 3896 else if ( HasFlag(wxLC_LIST) )
1370703e 3897 mode = wxLC_LIST;
cf1dfa6b 3898 else if ( HasFlag(wxLC_ICON) )
1370703e 3899 mode = wxLC_ICON;
cf1dfa6b 3900 else if ( HasFlag(wxLC_SMALL_ICON) )
1370703e
VZ
3901 mode = wxLC_ICON; // no typo
3902 else
3903 {
3904 wxFAIL_MSG( _T("unknown mode") );
3905 }
004fd0c8 3906
5cd89174 3907 wxListLineData *line = new wxListLineData(this);
004fd0c8 3908
5b077d48 3909 line->SetItem( 0, item );
cf1dfa6b
VZ
3910
3911 m_lines.Insert( line, id );
5cd89174
VZ
3912
3913 RefreshLines(id, GetItemCount() - 1);
e1e955e1 3914}
c801d85f 3915
debe6624 3916void wxListMainWindow::InsertColumn( long col, wxListItem &item )
c801d85f 3917{
5b077d48 3918 m_dirty = TRUE;
cf1dfa6b 3919 if ( HasFlag(wxLC_REPORT) )
3db7be80 3920 {
54442116
VZ
3921 if (item.m_width == wxLIST_AUTOSIZE_USEHEADER)
3922 item.m_width = GetTextLength( item.m_text );
5b077d48
RR
3923 wxListHeaderData *column = new wxListHeaderData( item );
3924 if ((col >= 0) && (col < (int)m_columns.GetCount()))
3925 {
24b9f055
VZ
3926 wxListHeaderDataList::Node *node = m_columns.Item( col );
3927 m_columns.Insert( node, column );
5b077d48
RR
3928 }
3929 else
3930 {
3931 m_columns.Append( column );
3932 }
3db7be80 3933 }
e1e955e1 3934}
c801d85f 3935
cf1dfa6b
VZ
3936// ----------------------------------------------------------------------------
3937// sorting
3938// ----------------------------------------------------------------------------
3939
c801d85f
KB
3940wxListCtrlCompare list_ctrl_compare_func_2;
3941long list_ctrl_compare_data;
3942
f6bcfd97 3943int LINKAGEMODE list_ctrl_compare_func_1( wxListLineData **arg1, wxListLineData **arg2 )
c801d85f 3944{
f6bcfd97
BP
3945 wxListLineData *line1 = *arg1;
3946 wxListLineData *line2 = *arg2;
5b077d48
RR
3947 wxListItem item;
3948 line1->GetItem( 0, item );
3949 long data1 = item.m_data;
3950 line2->GetItem( 0, item );
3951 long data2 = item.m_data;
3952 return list_ctrl_compare_func_2( data1, data2, list_ctrl_compare_data );
e1e955e1 3953}
c801d85f
KB
3954
3955void wxListMainWindow::SortItems( wxListCtrlCompare fn, long data )
3956{
5b077d48
RR
3957 list_ctrl_compare_func_2 = fn;
3958 list_ctrl_compare_data = data;
3959 m_lines.Sort( list_ctrl_compare_func_1 );
af7c1052 3960 m_dirty = TRUE;
e1e955e1 3961}
c801d85f 3962
cf1dfa6b
VZ
3963// ----------------------------------------------------------------------------
3964// scrolling
3965// ----------------------------------------------------------------------------
3966
7c74e7fe
SC
3967void wxListMainWindow::OnScroll(wxScrollWinEvent& event)
3968{
b54e41c5
VZ
3969 // update our idea of which lines are shown when we redraw the window the
3970 // next time
3971 ResetVisibleLinesRange();
cf1dfa6b 3972
29149a64 3973 // FIXME
3a8c693a 3974#if defined(__WXGTK__) && !defined(__WXUNIVERSAL__)
29149a64
VZ
3975 wxScrolledWindow::OnScroll(event);
3976#else
1e6feb95 3977 HandleOnScroll( event );
29149a64 3978#endif
30954328 3979
cf1dfa6b 3980 if ( event.GetOrientation() == wxHORIZONTAL && HasHeader() )
7c74e7fe 3981 {
cf1dfa6b
VZ
3982 wxListCtrl* lc = GetListCtrl();
3983 wxCHECK_RET( lc, _T("no listctrl window?") );
3984
3985 lc->m_headerWin->Refresh() ;
7c74e7fe 3986#ifdef __WXMAC__
cf1dfa6b 3987 lc->m_headerWin->MacUpdateImmediately() ;
7c74e7fe 3988#endif
7c74e7fe 3989 }
cf1dfa6b
VZ
3990}
3991
5cd89174
VZ
3992int wxListMainWindow::GetCountPerPage() const
3993{
3994 if ( !m_linesPerPage )
3995 {
3996 wxConstCast(this, wxListMainWindow)->
3997 m_linesPerPage = GetClientSize().y / GetLineHeight();
3998 }
3999
4000 return m_linesPerPage;
4001}
4002
b54e41c5 4003void wxListMainWindow::GetVisibleLinesRange(size_t *from, size_t *to)
cf1dfa6b 4004{
b54e41c5 4005 wxASSERT_MSG( HasFlag(wxLC_REPORT), _T("this is for report mode only") );
cf1dfa6b 4006
b54e41c5
VZ
4007 if ( m_lineFrom == (size_t)-1 )
4008 {
4009 m_lineFrom = GetScrollPos(wxVERTICAL);
cf1dfa6b 4010
b54e41c5 4011 size_t count = GetItemCount();
cf1dfa6b 4012
b54e41c5 4013 wxASSERT_MSG( m_lineFrom < count, _T("invalid scroll position?") );
cf1dfa6b 4014
b54e41c5
VZ
4015 m_lineTo = m_lineFrom + m_linesPerPage - 1;
4016 if ( m_lineTo >= count )
4017 m_lineTo = count - 1;
cf1dfa6b 4018 }
b54e41c5
VZ
4019
4020 if ( from )
4021 *from = m_lineFrom;
4022 if ( to )
4023 *to = m_lineTo;
7c74e7fe
SC
4024}
4025
c801d85f
KB
4026// -------------------------------------------------------------------------------------
4027// wxListItem
4028// -------------------------------------------------------------------------------------
4029
4030IMPLEMENT_DYNAMIC_CLASS(wxListItem, wxObject)
4031
fd9811b1 4032wxListItem::wxListItem()
c801d85f 4033{
63852e78
RR
4034 m_mask = 0;
4035 m_itemId = 0;
4036 m_col = 0;
4037 m_state = 0;
4038 m_stateMask = 0;
4039 m_image = 0;
4040 m_data = 0;
4041 m_format = wxLIST_FORMAT_CENTRE;
4042 m_width = 0;
aaa37c0d
VZ
4043
4044 m_attr = NULL;
c801d85f
KB
4045}
4046
9b00bb16
RR
4047void wxListItem::Clear()
4048{
4049 m_mask = 0;
4050 m_itemId = 0;
4051 m_col = 0;
4052 m_state = 0;
4053 m_stateMask = 0;
4054 m_image = 0;
4055 m_data = 0;
4056 m_format = wxLIST_FORMAT_CENTRE;
4057 m_width = 0;
54442116 4058 m_text = _T("");
9b00bb16 4059
cf1dfa6b 4060 ClearAttributes();
9b00bb16
RR
4061}
4062
4063void wxListItem::ClearAttributes()
4064{
cf1dfa6b
VZ
4065 if (m_attr)
4066 {
4067 delete m_attr;
4068 m_attr = NULL;
4069 }
9b00bb16
RR
4070}
4071
c801d85f
KB
4072// -------------------------------------------------------------------------------------
4073// wxListEvent
4074// -------------------------------------------------------------------------------------
4075
92976ab6 4076IMPLEMENT_DYNAMIC_CLASS(wxListEvent, wxNotifyEvent)
c801d85f 4077
cf1dfa6b
VZ
4078wxListEvent::wxListEvent( wxEventType commandType, int id )
4079 : wxNotifyEvent( commandType, id )
c801d85f 4080{
5b077d48
RR
4081 m_code = 0;
4082 m_itemIndex = 0;
4083 m_oldItemIndex = 0;
4084 m_col = 0;
4085 m_cancelled = FALSE;
4086 m_pointDrag.x = 0;
4087 m_pointDrag.y = 0;
e1e955e1 4088}
c801d85f 4089
72a7edf0
RR
4090void wxListEvent::CopyObject(wxObject& object_dest) const
4091{
4092 wxListEvent *obj = (wxListEvent *)&object_dest;
4093
4094 wxNotifyEvent::CopyObject(object_dest);
4095
4096 obj->m_code = m_code;
4097 obj->m_itemIndex = m_itemIndex;
4098 obj->m_oldItemIndex = m_oldItemIndex;
4099 obj->m_col = m_col;
4100 obj->m_cancelled = m_cancelled;
4101 obj->m_pointDrag = m_pointDrag;
4102 obj->m_item.m_mask = m_item.m_mask;
4103 obj->m_item.m_itemId = m_item.m_itemId;
4104 obj->m_item.m_col = m_item.m_col;
4105 obj->m_item.m_state = m_item.m_state;
4106 obj->m_item.m_stateMask = m_item.m_stateMask;
4107 obj->m_item.m_text = m_item.m_text;
4108 obj->m_item.m_image = m_item.m_image;
4109 obj->m_item.m_data = m_item.m_data;
4110 obj->m_item.m_format = m_item.m_format;
4111 obj->m_item.m_width = m_item.m_width;
aaa37c0d
VZ
4112
4113 if ( m_item.HasAttributes() )
4114 {
4115 obj->m_item.SetTextColour(m_item.GetTextColour());
4116 }
72a7edf0
RR
4117}
4118
c801d85f
KB
4119// -------------------------------------------------------------------------------------
4120// wxListCtrl
4121// -------------------------------------------------------------------------------------
4122
4123IMPLEMENT_DYNAMIC_CLASS(wxListCtrl, wxControl)
4124
4125BEGIN_EVENT_TABLE(wxListCtrl,wxControl)
cf1dfa6b
VZ
4126 EVT_SIZE(wxListCtrl::OnSize)
4127 EVT_IDLE(wxListCtrl::OnIdle)
c801d85f
KB
4128END_EVENT_TABLE()
4129
fd9811b1 4130wxListCtrl::wxListCtrl()
c801d85f 4131{
5b077d48
RR
4132 m_imageListNormal = (wxImageList *) NULL;
4133 m_imageListSmall = (wxImageList *) NULL;
4134 m_imageListState = (wxImageList *) NULL;
cf1dfa6b
VZ
4135
4136 m_ownsImageListNormal =
4137 m_ownsImageListSmall =
4138 m_ownsImageListState = FALSE;
4139
5b077d48
RR
4140 m_mainWin = (wxListMainWindow*) NULL;
4141 m_headerWin = (wxListHeaderWindow*) NULL;
c801d85f
KB
4142}
4143
fd9811b1 4144wxListCtrl::~wxListCtrl()
c801d85f 4145{
b54e41c5
VZ
4146 if ( m_mainWin )
4147 m_mainWin->ResetCurrent();
4148
cf1dfa6b
VZ
4149 if (m_ownsImageListNormal)
4150 delete m_imageListNormal;
4151 if (m_ownsImageListSmall)
4152 delete m_imageListSmall;
4153 if (m_ownsImageListState)
4154 delete m_imageListState;
4155}
4156
4157void wxListCtrl::CreateHeaderWindow()
4158{
4159 m_headerWin = new wxListHeaderWindow
4160 (
4161 this, -1, m_mainWin,
4162 wxPoint(0, 0),
4163 wxSize(GetClientSize().x, HEADER_HEIGHT),
4164 wxTAB_TRAVERSAL
4165 );
c801d85f
KB
4166}
4167
25e3a937
VZ
4168bool wxListCtrl::Create(wxWindow *parent,
4169 wxWindowID id,
4170 const wxPoint &pos,
4171 const wxSize &size,
4172 long style,
25e3a937 4173 const wxValidator &validator,
25e3a937 4174 const wxString &name)
c801d85f 4175{
cf1dfa6b
VZ
4176 m_imageListNormal =
4177 m_imageListSmall =
5b077d48 4178 m_imageListState = (wxImageList *) NULL;
cf1dfa6b
VZ
4179 m_ownsImageListNormal =
4180 m_ownsImageListSmall =
4181 m_ownsImageListState = FALSE;
4182
5b077d48
RR
4183 m_mainWin = (wxListMainWindow*) NULL;
4184 m_headerWin = (wxListHeaderWindow*) NULL;
bd8289c1 4185
b54e41c5 4186 if ( !(style & wxLC_MASK_TYPE) )
5b077d48 4187 {
25e3a937 4188 style = style | wxLC_LIST;
5b077d48 4189 }
f6bcfd97 4190
cf1dfa6b
VZ
4191 if ( !wxControl::Create( parent, id, pos, size, style, validator, name ) )
4192 return FALSE;
f6bcfd97 4193
b54e41c5
VZ
4194 // don't create the inner window with the border
4195 style &= ~wxSUNKEN_BORDER;
bd8289c1 4196
25e3a937 4197 m_mainWin = new wxListMainWindow( this, -1, wxPoint(0,0), size, style );
bd8289c1 4198
b54e41c5 4199 if ( HasFlag(wxLC_REPORT) )
ea451729 4200 {
cf1dfa6b
VZ
4201 CreateHeaderWindow();
4202
b54e41c5 4203 if ( HasFlag(wxLC_NO_HEADER) )
cf1dfa6b
VZ
4204 {
4205 // VZ: why do we create it at all then?
ea451729 4206 m_headerWin->Show( FALSE );
cf1dfa6b 4207 }
ea451729 4208 }
bd8289c1 4209
cf1dfa6b 4210 return TRUE;
e1e955e1 4211}
c801d85f 4212
debe6624 4213void wxListCtrl::SetSingleStyle( long style, bool add )
c801d85f 4214{
b54e41c5
VZ
4215 wxASSERT_MSG( !(style & wxLC_VIRTUAL),
4216 _T("wxLC_VIRTUAL can't be [un]set") );
4217
f03fc89f 4218 long flag = GetWindowStyle();
bd8289c1 4219
5b077d48
RR
4220 if (add)
4221 {
cf1dfa6b 4222 if (style & wxLC_MASK_TYPE)
b54e41c5 4223 flag &= ~(wxLC_MASK_TYPE | wxLC_VIRTUAL);
cf1dfa6b
VZ
4224 if (style & wxLC_MASK_ALIGN)
4225 flag &= ~wxLC_MASK_ALIGN;
4226 if (style & wxLC_MASK_SORT)
4227 flag &= ~wxLC_MASK_SORT;
5b077d48 4228 }
c801d85f 4229
5b077d48
RR
4230 if (add)
4231 {
4232 flag |= style;
4233 }
4234 else
4235 {
cf1dfa6b 4236 flag &= ~style;
5b077d48 4237 }
bd8289c1 4238
5b077d48 4239 SetWindowStyleFlag( flag );
e1e955e1 4240}
c801d85f 4241
debe6624 4242void wxListCtrl::SetWindowStyleFlag( long flag )
c801d85f 4243{
121a3581
RR
4244 if (m_mainWin)
4245 {
4246 m_mainWin->DeleteEverything();
c801d85f 4247
121a3581
RR
4248 int width = 0;
4249 int height = 0;
4250 GetClientSize( &width, &height );
c801d85f 4251
121a3581 4252 if (flag & wxLC_REPORT)
5b077d48 4253 {
121a3581 4254 if (!HasFlag(wxLC_REPORT))
5b077d48 4255 {
121a3581
RR
4256 if (!m_headerWin)
4257 {
cf1dfa6b
VZ
4258 CreateHeaderWindow();
4259
bffa1c77
VZ
4260 if (HasFlag(wxLC_NO_HEADER))
4261 m_headerWin->Show( FALSE );
121a3581
RR
4262 }
4263 else
004fd0c8 4264 {
bffa1c77
VZ
4265 if (flag & wxLC_NO_HEADER)
4266 m_headerWin->Show( FALSE );
4267 else
8636aed8 4268 m_headerWin->Show( TRUE );
004fd0c8 4269 }
5b077d48
RR
4270 }
4271 }
cf1dfa6b 4272 else // !report
5b077d48 4273 {
cf1dfa6b 4274 if ( m_mainWin->HasHeader() )
121a3581
RR
4275 {
4276 m_headerWin->Show( FALSE );
4277 }
bffa1c77 4278 }
e1e955e1 4279 }
004fd0c8 4280
5b077d48 4281 wxWindow::SetWindowStyleFlag( flag );
e1e955e1 4282}
c801d85f 4283
e487524e 4284bool wxListCtrl::GetColumn(int col, wxListItem &item) const
c801d85f 4285{
5b077d48
RR
4286 m_mainWin->GetColumn( col, item );
4287 return TRUE;
e1e955e1 4288}
c801d85f 4289
debe6624 4290bool wxListCtrl::SetColumn( int col, wxListItem& item )
c801d85f 4291{
5b077d48
RR
4292 m_mainWin->SetColumn( col, item );
4293 return TRUE;
e1e955e1 4294}
c801d85f 4295
e487524e 4296int wxListCtrl::GetColumnWidth( int col ) const
c801d85f 4297{
5b077d48 4298 return m_mainWin->GetColumnWidth( col );
e1e955e1 4299}
c801d85f 4300
debe6624 4301bool wxListCtrl::SetColumnWidth( int col, int width )
c801d85f 4302{
5b077d48
RR
4303 m_mainWin->SetColumnWidth( col, width );
4304 return TRUE;
e1e955e1 4305}
c801d85f 4306
fd9811b1 4307int wxListCtrl::GetCountPerPage() const
c801d85f
KB
4308{
4309 return m_mainWin->GetCountPerPage(); // different from Windows ?
e1e955e1 4310}
c801d85f 4311
e487524e 4312bool wxListCtrl::GetItem( wxListItem &info ) const
c801d85f 4313{
5b077d48
RR
4314 m_mainWin->GetItem( info );
4315 return TRUE;
e1e955e1 4316}
c801d85f
KB
4317
4318bool wxListCtrl::SetItem( wxListItem &info )
4319{
5b077d48
RR
4320 m_mainWin->SetItem( info );
4321 return TRUE;
e1e955e1 4322}
c801d85f 4323
debe6624 4324long wxListCtrl::SetItem( long index, int col, const wxString& label, int imageId )
c801d85f 4325{
5b077d48
RR
4326 wxListItem info;
4327 info.m_text = label;
4328 info.m_mask = wxLIST_MASK_TEXT;
4329 info.m_itemId = index;
4330 info.m_col = col;
4331 if ( imageId > -1 )
4332 {
4333 info.m_image = imageId;
4334 info.m_mask |= wxLIST_MASK_IMAGE;
4335 };
4336 m_mainWin->SetItem(info);
4337 return TRUE;
e1e955e1 4338}
c801d85f 4339
e487524e 4340int wxListCtrl::GetItemState( long item, long stateMask ) const
c801d85f 4341{
5b077d48 4342 return m_mainWin->GetItemState( item, stateMask );
e1e955e1 4343}
c801d85f 4344
debe6624 4345bool wxListCtrl::SetItemState( long item, long state, long stateMask )
c801d85f 4346{
5b077d48
RR
4347 m_mainWin->SetItemState( item, state, stateMask );
4348 return TRUE;
e1e955e1 4349}
c801d85f 4350
debe6624 4351bool wxListCtrl::SetItemImage( long item, int image, int WXUNUSED(selImage) )
c801d85f 4352{
5b077d48
RR
4353 wxListItem info;
4354 info.m_image = image;
4355 info.m_mask = wxLIST_MASK_IMAGE;
4356 info.m_itemId = item;
4357 m_mainWin->SetItem( info );
4358 return TRUE;
e1e955e1 4359}
c801d85f 4360
e487524e 4361wxString wxListCtrl::GetItemText( long item ) const
c801d85f 4362{
5b077d48
RR
4363 wxListItem info;
4364 info.m_itemId = item;
4365 m_mainWin->GetItem( info );
4366 return info.m_text;
e1e955e1 4367}
c801d85f 4368
debe6624 4369void wxListCtrl::SetItemText( long item, const wxString &str )
c801d85f 4370{
5b077d48
RR
4371 wxListItem info;
4372 info.m_mask = wxLIST_MASK_TEXT;
4373 info.m_itemId = item;
4374 info.m_text = str;
4375 m_mainWin->SetItem( info );
e1e955e1 4376}
c801d85f 4377
e487524e 4378long wxListCtrl::GetItemData( long item ) const
c801d85f 4379{
5b077d48
RR
4380 wxListItem info;
4381 info.m_itemId = item;
4382 m_mainWin->GetItem( info );
4383 return info.m_data;
e1e955e1 4384}
c801d85f 4385
debe6624 4386bool wxListCtrl::SetItemData( long item, long data )
c801d85f 4387{
5b077d48
RR
4388 wxListItem info;
4389 info.m_mask = wxLIST_MASK_DATA;
4390 info.m_itemId = item;
4391 info.m_data = data;
4392 m_mainWin->SetItem( info );
4393 return TRUE;
e1e955e1 4394}
c801d85f 4395
0a240683 4396bool wxListCtrl::GetItemRect( long item, wxRect &rect, int WXUNUSED(code) ) const
c801d85f 4397{
5b077d48
RR
4398 m_mainWin->GetItemRect( item, rect );
4399 return TRUE;
e1e955e1 4400}
c801d85f 4401
e487524e 4402bool wxListCtrl::GetItemPosition( long item, wxPoint& pos ) const
c801d85f 4403{
5b077d48
RR
4404 m_mainWin->GetItemPosition( item, pos );
4405 return TRUE;
e1e955e1 4406}
c801d85f 4407
debe6624 4408bool wxListCtrl::SetItemPosition( long WXUNUSED(item), const wxPoint& WXUNUSED(pos) )
c801d85f 4409{
5b077d48 4410 return 0;
e1e955e1 4411}
c801d85f 4412
fd9811b1 4413int wxListCtrl::GetItemCount() const
c801d85f 4414{
5b077d48 4415 return m_mainWin->GetItemCount();
e1e955e1 4416}
c801d85f 4417
fd9811b1 4418int wxListCtrl::GetColumnCount() const
92976ab6 4419{
5b077d48 4420 return m_mainWin->GetColumnCount();
92976ab6
RR
4421}
4422
33d0b396
RR
4423void wxListCtrl::SetItemSpacing( int spacing, bool isSmall )
4424{
5b077d48 4425 m_mainWin->SetItemSpacing( spacing, isSmall );
e1e955e1 4426}
33d0b396 4427
e487524e 4428int wxListCtrl::GetItemSpacing( bool isSmall ) const
c801d85f 4429{
5b077d48 4430 return m_mainWin->GetItemSpacing( isSmall );
e1e955e1 4431}
c801d85f 4432
fd9811b1 4433int wxListCtrl::GetSelectedItemCount() const
c801d85f 4434{
5b077d48 4435 return m_mainWin->GetSelectedItemCount();
e1e955e1 4436}
c801d85f 4437
fd9811b1 4438wxColour wxListCtrl::GetTextColour() const
c801d85f 4439{
0530737d 4440 return GetForegroundColour();
e1e955e1 4441}
c801d85f 4442
0530737d 4443void wxListCtrl::SetTextColour(const wxColour& col)
c801d85f 4444{
0530737d 4445 SetForegroundColour(col);
e1e955e1 4446}
c801d85f 4447
fd9811b1 4448long wxListCtrl::GetTopItem() const
c801d85f 4449{
5b077d48 4450 return 0;
e1e955e1 4451}
c801d85f 4452
6de97a3b 4453long wxListCtrl::GetNextItem( long item, int geom, int state ) const
c801d85f 4454{
5b077d48 4455 return m_mainWin->GetNextItem( item, geom, state );
e1e955e1 4456}
c801d85f 4457
e487524e 4458wxImageList *wxListCtrl::GetImageList(int which) const
c801d85f 4459{
5b077d48
RR
4460 if (which == wxIMAGE_LIST_NORMAL)
4461 {
4462 return m_imageListNormal;
4463 }
4464 else if (which == wxIMAGE_LIST_SMALL)
4465 {
4466 return m_imageListSmall;
4467 }
4468 else if (which == wxIMAGE_LIST_STATE)
4469 {
4470 return m_imageListState;
4471 }
4472 return (wxImageList *) NULL;
e1e955e1 4473}
c801d85f 4474
debe6624 4475void wxListCtrl::SetImageList( wxImageList *imageList, int which )
c801d85f 4476{
2e12c11a
VS
4477 if ( which == wxIMAGE_LIST_NORMAL )
4478 {
4479 if (m_ownsImageListNormal) delete m_imageListNormal;
4480 m_imageListNormal = imageList;
4481 m_ownsImageListNormal = FALSE;
4482 }
4483 else if ( which == wxIMAGE_LIST_SMALL )
4484 {
4485 if (m_ownsImageListSmall) delete m_imageListSmall;
4486 m_imageListSmall = imageList;
4487 m_ownsImageListSmall = FALSE;
4488 }
4489 else if ( which == wxIMAGE_LIST_STATE )
4490 {
4491 if (m_ownsImageListState) delete m_imageListState;
4492 m_imageListState = imageList;
4493 m_ownsImageListState = FALSE;
4494 }
4495
5b077d48 4496 m_mainWin->SetImageList( imageList, which );
e1e955e1 4497}
c801d85f 4498
2e12c11a
VS
4499void wxListCtrl::AssignImageList(wxImageList *imageList, int which)
4500{
4501 SetImageList(imageList, which);
4502 if ( which == wxIMAGE_LIST_NORMAL )
4503 m_ownsImageListNormal = TRUE;
4504 else if ( which == wxIMAGE_LIST_SMALL )
4505 m_ownsImageListSmall = TRUE;
4506 else if ( which == wxIMAGE_LIST_STATE )
4507 m_ownsImageListState = TRUE;
4508}
4509
debe6624 4510bool wxListCtrl::Arrange( int WXUNUSED(flag) )
c801d85f 4511{
5b077d48 4512 return 0;
e1e955e1 4513}
c801d85f 4514
debe6624 4515bool wxListCtrl::DeleteItem( long item )
c801d85f 4516{
5b077d48
RR
4517 m_mainWin->DeleteItem( item );
4518 return TRUE;
e1e955e1 4519}
c801d85f 4520
fd9811b1 4521bool wxListCtrl::DeleteAllItems()
c801d85f 4522{
5b077d48
RR
4523 m_mainWin->DeleteAllItems();
4524 return TRUE;
e1e955e1 4525}
c801d85f 4526
4f22cf8d 4527bool wxListCtrl::DeleteAllColumns()
bd8289c1 4528{
24b9f055
VZ
4529 size_t count = m_mainWin->m_columns.GetCount();
4530 for ( size_t n = 0; n < count; n++ )
bd8289c1 4531 DeleteColumn(n);
bffa1c77 4532
5b077d48 4533 return TRUE;
4f22cf8d
RR
4534}
4535
4536void wxListCtrl::ClearAll()
4537{
5b077d48 4538 m_mainWin->DeleteEverything();
bd8289c1
VZ
4539}
4540
debe6624 4541bool wxListCtrl::DeleteColumn( int col )
c801d85f 4542{
5b077d48
RR
4543 m_mainWin->DeleteColumn( col );
4544 return TRUE;
e1e955e1 4545}
c801d85f 4546
e179bd65 4547void wxListCtrl::Edit( long item )
c801d85f 4548{
cf1dfa6b 4549 m_mainWin->EditLabel( item );
e1e955e1 4550}
c801d85f 4551
debe6624 4552bool wxListCtrl::EnsureVisible( long item )
c801d85f 4553{
5b077d48
RR
4554 m_mainWin->EnsureVisible( item );
4555 return TRUE;
e1e955e1 4556}
c801d85f 4557
debe6624 4558long wxListCtrl::FindItem( long start, const wxString& str, bool partial )
c801d85f 4559{
5b077d48 4560 return m_mainWin->FindItem( start, str, partial );
e1e955e1 4561}
c801d85f 4562
debe6624 4563long wxListCtrl::FindItem( long start, long data )
c801d85f 4564{
5b077d48 4565 return m_mainWin->FindItem( start, data );
e1e955e1 4566}
c801d85f 4567
bd8289c1 4568long wxListCtrl::FindItem( long WXUNUSED(start), const wxPoint& WXUNUSED(pt),
debe6624 4569 int WXUNUSED(direction))
c801d85f 4570{
5b077d48 4571 return 0;
e1e955e1 4572}
c801d85f
KB
4573
4574long wxListCtrl::HitTest( const wxPoint &point, int &flags )
4575{
5b077d48 4576 return m_mainWin->HitTest( (int)point.x, (int)point.y, flags );
e1e955e1 4577}
c801d85f
KB
4578
4579long wxListCtrl::InsertItem( wxListItem& info )
4580{
5b077d48 4581 m_mainWin->InsertItem( info );
2ebcd5f5 4582 return info.m_itemId;
e1e955e1 4583}
c801d85f 4584
debe6624 4585long wxListCtrl::InsertItem( long index, const wxString &label )
c801d85f 4586{
51cc4dad
RR
4587 wxListItem info;
4588 info.m_text = label;
4589 info.m_mask = wxLIST_MASK_TEXT;
4590 info.m_itemId = index;
4591 return InsertItem( info );
e1e955e1 4592}
c801d85f 4593
debe6624 4594long wxListCtrl::InsertItem( long index, int imageIndex )
c801d85f 4595{
51cc4dad
RR
4596 wxListItem info;
4597 info.m_mask = wxLIST_MASK_IMAGE;
4598 info.m_image = imageIndex;
4599 info.m_itemId = index;
4600 return InsertItem( info );
e1e955e1 4601}
c801d85f 4602
debe6624 4603long wxListCtrl::InsertItem( long index, const wxString &label, int imageIndex )
c801d85f 4604{
51cc4dad
RR
4605 wxListItem info;
4606 info.m_text = label;
4607 info.m_image = imageIndex;
4608 info.m_mask = wxLIST_MASK_TEXT | wxLIST_MASK_IMAGE;
4609 info.m_itemId = index;
4610 return InsertItem( info );
e1e955e1 4611}
c801d85f 4612
debe6624 4613long wxListCtrl::InsertColumn( long col, wxListItem &item )
c801d85f 4614{
d3e90957 4615 wxASSERT( m_headerWin );
51cc4dad 4616 m_mainWin->InsertColumn( col, item );
d3e90957 4617 m_headerWin->Refresh();
25e3a937 4618
51cc4dad 4619 return 0;
e1e955e1 4620}
c801d85f 4621
debe6624
JS
4622long wxListCtrl::InsertColumn( long col, const wxString &heading,
4623 int format, int width )
c801d85f 4624{
51cc4dad
RR
4625 wxListItem item;
4626 item.m_mask = wxLIST_MASK_TEXT | wxLIST_MASK_FORMAT;
4627 item.m_text = heading;
4628 if (width >= -2)
4629 {
4630 item.m_mask |= wxLIST_MASK_WIDTH;
4631 item.m_width = width;
4632 }
4633 item.m_format = format;
c801d85f 4634
51cc4dad 4635 return InsertColumn( col, item );
e1e955e1 4636}
c801d85f 4637
debe6624 4638bool wxListCtrl::ScrollList( int WXUNUSED(dx), int WXUNUSED(dy) )
c801d85f 4639{
51cc4dad 4640 return 0;
e1e955e1 4641}
c801d85f
KB
4642
4643// Sort items.
4644// fn is a function which takes 3 long arguments: item1, item2, data.
4645// item1 is the long data associated with a first item (NOT the index).
4646// item2 is the long data associated with a second item (NOT the index).
4647// data is the same value as passed to SortItems.
4648// The return value is a negative number if the first item should precede the second
4649// item, a positive number of the second item should precede the first,
4650// or zero if the two items are equivalent.
4651// data is arbitrary data to be passed to the sort function.
4652
4653bool wxListCtrl::SortItems( wxListCtrlCompare fn, long data )
4654{
51cc4dad
RR
4655 m_mainWin->SortItems( fn, data );
4656 return TRUE;
e1e955e1 4657}
c801d85f 4658
cf1dfa6b 4659// ----------------------------------------------------------------------------
b54e41c5 4660// event handlers
cf1dfa6b
VZ
4661// ----------------------------------------------------------------------------
4662
b54e41c5 4663void wxListCtrl::OnSize(wxSizeEvent& event)
53010e52 4664{
b54e41c5 4665 if ( !m_mainWin )
cf1dfa6b 4666 return;
53010e52 4667
b54e41c5 4668 int cw, ch;
51cc4dad 4669 GetClientSize( &cw, &ch );
bd8289c1 4670
cf1dfa6b 4671 if ( m_mainWin->HasHeader() )
51cc4dad 4672 {
cf1dfa6b
VZ
4673 m_headerWin->SetSize( 0, 0, cw, HEADER_HEIGHT );
4674 m_mainWin->SetSize( 0, HEADER_HEIGHT + 1, cw, ch - HEADER_HEIGHT - 1 );
51cc4dad 4675 }
cf1dfa6b 4676 else // no header window
51cc4dad 4677 {
cf1dfa6b 4678 m_mainWin->SetSize( 0, 0, cw, ch );
51cc4dad 4679 }
bd8289c1 4680
b54e41c5
VZ
4681 m_mainWin->RecalculatePositions();
4682}
cf1dfa6b 4683
b54e41c5
VZ
4684void wxListCtrl::OnIdle( wxIdleEvent & event )
4685{
4686 event.Skip();
f6bcfd97 4687
b54e41c5
VZ
4688 // do it only if needed
4689 if ( !m_mainWin->m_dirty )
4690 return;
4691
4692 m_mainWin->RecalculatePositions();
e1e955e1 4693}
53010e52 4694
cf1dfa6b
VZ
4695// ----------------------------------------------------------------------------
4696// font/colours
4697// ----------------------------------------------------------------------------
4698
f03fc89f 4699bool wxListCtrl::SetBackgroundColour( const wxColour &colour )
bd8289c1 4700{
51cc4dad
RR
4701 if (m_mainWin)
4702 {
4703 m_mainWin->SetBackgroundColour( colour );
4704 m_mainWin->m_dirty = TRUE;
4705 }
004fd0c8 4706
f03fc89f 4707 return TRUE;
e4d06860
RR
4708}
4709
f03fc89f 4710bool wxListCtrl::SetForegroundColour( const wxColour &colour )
bd8289c1 4711{
f03fc89f
VZ
4712 if ( !wxWindow::SetForegroundColour( colour ) )
4713 return FALSE;
004fd0c8 4714
51cc4dad
RR
4715 if (m_mainWin)
4716 {
4717 m_mainWin->SetForegroundColour( colour );
4718 m_mainWin->m_dirty = TRUE;
4719 }
004fd0c8 4720
51cc4dad
RR
4721 if (m_headerWin)
4722 {
4723 m_headerWin->SetForegroundColour( colour );
4724 }
f03fc89f
VZ
4725
4726 return TRUE;
e4d06860 4727}
bd8289c1 4728
f03fc89f 4729bool wxListCtrl::SetFont( const wxFont &font )
bd8289c1 4730{
f03fc89f
VZ
4731 if ( !wxWindow::SetFont( font ) )
4732 return FALSE;
004fd0c8 4733
51cc4dad
RR
4734 if (m_mainWin)
4735 {
4736 m_mainWin->SetFont( font );
4737 m_mainWin->m_dirty = TRUE;
4738 }
004fd0c8 4739
51cc4dad
RR
4740 if (m_headerWin)
4741 {
4742 m_headerWin->SetFont( font );
4743 }
f03fc89f
VZ
4744
4745 return TRUE;
e4d06860 4746}
c801d85f 4747
cf1dfa6b
VZ
4748// ----------------------------------------------------------------------------
4749// methods forwarded to m_mainWin
4750// ----------------------------------------------------------------------------
4751
efbb7287
VZ
4752#if wxUSE_DRAG_AND_DROP
4753
4754void wxListCtrl::SetDropTarget( wxDropTarget *dropTarget )
4755{
4756 m_mainWin->SetDropTarget( dropTarget );
4757}
4758
4759wxDropTarget *wxListCtrl::GetDropTarget() const
4760{
4761 return m_mainWin->GetDropTarget();
4762}
4763
4764#endif // wxUSE_DRAG_AND_DROP
4765
4766bool wxListCtrl::SetCursor( const wxCursor &cursor )
4767{
4768 return m_mainWin ? m_mainWin->wxWindow::SetCursor(cursor) : FALSE;
4769}
4770
4771wxColour wxListCtrl::GetBackgroundColour() const
4772{
4773 return m_mainWin ? m_mainWin->GetBackgroundColour() : wxColour();
4774}
4775
4776wxColour wxListCtrl::GetForegroundColour() const
4777{
4778 return m_mainWin ? m_mainWin->GetForegroundColour() : wxColour();
4779}
4780
4781bool wxListCtrl::DoPopupMenu( wxMenu *menu, int x, int y )
4782{
3a8c693a 4783#if wxUSE_MENUS
efbb7287 4784 return m_mainWin->PopupMenu( menu, x, y );
3a8c693a
VZ
4785#else
4786 return FALSE;
4787#endif // wxUSE_MENUS
efbb7287
VZ
4788}
4789
4790void wxListCtrl::SetFocus()
4791{
4792 /* The test in window.cpp fails as we are a composite
4793 window, so it checks against "this", but not m_mainWin. */
4794 if ( FindFocus() != this )
4795 m_mainWin->SetFocus();
4796}
1e6feb95 4797
2c1f73ee
VZ
4798// ----------------------------------------------------------------------------
4799// virtual list control support
4800// ----------------------------------------------------------------------------
4801
4802wxString wxListCtrl::OnGetItemText(long item, long col) const
4803{
4804 // this is a pure virtual function, in fact - which is not really pure
4805 // because the controls which are not virtual don't need to implement it
4806 wxFAIL_MSG( _T("not supposed to be called") );
4807
4808 return wxEmptyString;
4809}
4810
4811int wxListCtrl::OnGetItemImage(long item) const
4812{
4813 // same as above
4814 wxFAIL_MSG( _T("not supposed to be called") );
4815
4816 return -1;
4817}
4818
4819void wxListCtrl::SetItemCount(long count)
4820{
4821 wxASSERT_MSG( IsVirtual(), _T("this is for virtual controls only") );
4822
4823 m_mainWin->SetItemCount(count);
4824}
4825
1e6feb95 4826#endif // wxUSE_LISTCTRL
5cd89174
VZ
4827
4828#endif