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