]> git.saurik.com Git - wxWidgets.git/blame - src/generic/listctrl.cpp
added untested implementation of wxEvtLoop for GTK+
[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 );
2400
2401 }
2402 else // !report
2403 {
2404 // TODO: how to do it more efficiently?
2405 m_dirty = TRUE;
2406 }
2407}
2408
cf1dfa6b
VZ
2409void wxListMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
2410{
2411 // Note: a wxPaintDC must be constructed even if no drawing is
2412 // done (a Windows requirement).
2413 wxPaintDC dc( this );
2414
cf1dfa6b
VZ
2415 if ( IsEmpty() )
2416 {
2417 // empty control. nothing to draw
2418 return;
2419 }
2420
2421 PrepareDC( dc );
2422
2423 int dev_x, dev_y;
2424 CalcScrolledPosition( 0, 0, &dev_x, &dev_y );
2425
2426 dc.BeginDrawing();
2427
2428 dc.SetFont( GetFont() );
2429
2430 if ( HasFlag(wxLC_REPORT) )
2431 {
b54e41c5 2432 int lineHeight = GetLineHeight();
cf1dfa6b 2433
b54e41c5
VZ
2434 size_t visibleFrom, visibleTo;
2435 GetVisibleLinesRange(&visibleFrom, &visibleTo);
2436 for ( size_t line = visibleFrom; line <= visibleTo; line++ )
cf1dfa6b 2437 {
5cd89174
VZ
2438 GetLine(line)->DrawInReportMode( &dc,
2439 GetLineRect(line),
2440 GetLineHighlightRect(line),
2441 IsHighlighted(line) );
cf1dfa6b
VZ
2442 }
2443
2444 if ( HasFlag(wxLC_HRULES) )
2445 {
b54e41c5 2446 wxPen pen(GetRuleColour(), 1, wxSOLID);
cf1dfa6b
VZ
2447 wxSize clientSize = GetClientSize();
2448
b54e41c5 2449 for ( size_t i = visibleFrom; i <= visibleTo; i++ )
cf1dfa6b
VZ
2450 {
2451 dc.SetPen(pen);
2452 dc.SetBrush( *wxTRANSPARENT_BRUSH );
b54e41c5
VZ
2453 dc.DrawLine(0 - dev_x, i*lineHeight,
2454 clientSize.x - dev_x, i*lineHeight);
cf1dfa6b
VZ
2455 }
2456
2457 // Draw last horizontal rule
b54e41c5 2458 if ( visibleTo > visibleFrom )
cf1dfa6b
VZ
2459 {
2460 dc.SetPen(pen);
2461 dc.SetBrush( *wxTRANSPARENT_BRUSH );
b54e41c5
VZ
2462 dc.DrawLine(0 - dev_x, m_lineTo*lineHeight,
2463 clientSize.x - dev_x , m_lineTo*lineHeight );
cf1dfa6b 2464 }
2c1f73ee 2465 }
206b0a67
JS
2466
2467 // Draw vertical rules if required
cf1dfa6b 2468 if ( HasFlag(wxLC_VRULES) && !IsEmpty() )
206b0a67 2469 {
b54e41c5 2470 wxPen pen(GetRuleColour(), 1, wxSOLID);
cf1dfa6b 2471
206b0a67
JS
2472 int col = 0;
2473 wxRect firstItemRect;
2474 wxRect lastItemRect;
2475 GetItemRect(0, firstItemRect);
2476 GetItemRect(GetItemCount() - 1, lastItemRect);
2477 int x = firstItemRect.GetX();
673dfcfa
JS
2478 dc.SetPen(pen);
2479 dc.SetBrush(* wxTRANSPARENT_BRUSH);
206b0a67
JS
2480 for (col = 0; col < GetColumnCount(); col++)
2481 {
2482 int colWidth = GetColumnWidth(col);
cf1dfa6b
VZ
2483 x += colWidth;
2484 dc.DrawLine(x - dev_x, firstItemRect.GetY() - 1 - dev_y,
2485 x - dev_x, lastItemRect.GetBottom() + 1 - dev_y);
206b0a67 2486 }
d786bf87 2487 }
139adb6a 2488 }
cf1dfa6b 2489 else // !report
139adb6a 2490 {
1370703e 2491 size_t count = GetItemCount();
cf1dfa6b
VZ
2492 for ( size_t i = 0; i < count; i++ )
2493 {
2494 GetLine(i)->Draw( &dc );
2495 }
139adb6a 2496 }
004fd0c8 2497
cf1dfa6b
VZ
2498 if ( HasCurrent() && m_hasFocus )
2499 {
4176fb7d
SC
2500#ifdef __WXMAC__
2501 // no rect outline, we already have the background color
2502#else
cf1dfa6b
VZ
2503 dc.SetPen( *wxBLACK_PEN );
2504 dc.SetBrush( *wxTRANSPARENT_BRUSH );
5cd89174 2505 dc.DrawRectangle( GetLineHighlightRect(m_current) );
4176fb7d 2506#endif
cf1dfa6b 2507 }
c801d85f 2508
139adb6a 2509 dc.EndDrawing();
e1e955e1 2510}
c801d85f 2511
b54e41c5 2512void wxListMainWindow::HighlightAll( bool on )
c801d85f 2513{
b54e41c5 2514 if ( IsSingleSel() )
c801d85f 2515 {
b54e41c5
VZ
2516 wxASSERT_MSG( !on, _T("can't do this in a single sel control") );
2517
2518 // we just have one item to turn off
2519 if ( HasCurrent() && IsHighlighted(m_current) )
139adb6a 2520 {
b54e41c5
VZ
2521 HighlightLine(m_current, FALSE);
2522 RefreshLine(m_current);
139adb6a 2523 }
e1e955e1 2524 }
b54e41c5 2525 else // multi sel
cf1dfa6b 2526 {
b54e41c5 2527 HighlightLines(0, GetItemCount() - 1, on);
cf1dfa6b 2528 }
e1e955e1 2529}
c801d85f 2530
cf1dfa6b 2531void wxListMainWindow::SendNotify( size_t line,
05a7f61d
VZ
2532 wxEventType command,
2533 wxPoint point )
c801d85f 2534{
139adb6a
RR
2535 wxListEvent le( command, GetParent()->GetId() );
2536 le.SetEventObject( GetParent() );
cf1dfa6b 2537 le.m_itemIndex = line;
05a7f61d
VZ
2538
2539 // set only for events which have position
2540 if ( point != wxDefaultPosition )
2541 le.m_pointDrag = point;
2542
cf1dfa6b 2543 GetLine(line)->GetItem( 0, le.m_item );
6e228e42 2544 GetParent()->GetEventHandler()->ProcessEvent( le );
e1e955e1 2545}
c801d85f 2546
cf1dfa6b 2547void wxListMainWindow::OnFocusLine( size_t WXUNUSED(line) )
c801d85f
KB
2548{
2549// SendNotify( line, wxEVT_COMMAND_LIST_ITEM_FOCUSSED );
e1e955e1 2550}
c801d85f 2551
cf1dfa6b 2552void wxListMainWindow::OnUnfocusLine( size_t WXUNUSED(line) )
c801d85f
KB
2553{
2554// SendNotify( line, wxEVT_COMMAND_LIST_ITEM_UNFOCUSSED );
e1e955e1 2555}
c801d85f 2556
5f1ea0ee 2557void wxListMainWindow::EditLabel( long item )
c801d85f 2558{
cf1dfa6b
VZ
2559 wxCHECK_RET( (item >= 0) && ((size_t)item < GetItemCount()),
2560 wxT("wrong index in wxListCtrl::EditLabel()") );
004fd0c8 2561
1370703e 2562 m_currentEdit = (size_t)item;
e179bd65 2563
fd9811b1 2564 wxListEvent le( wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT, GetParent()->GetId() );
139adb6a 2565 le.SetEventObject( GetParent() );
1370703e
VZ
2566 le.m_itemIndex = item;
2567 wxListLineData *data = GetLine(m_currentEdit);
2568 wxCHECK_RET( data, _T("invalid index in EditLabel()") );
2569 data->GetItem( 0, le.m_item );
139adb6a 2570 GetParent()->GetEventHandler()->ProcessEvent( le );
004fd0c8 2571
86f975a8 2572 if (!le.IsAllowed())
5f1ea0ee 2573 return;
004fd0c8 2574
cf1dfa6b
VZ
2575 // We have to call this here because the label in question might just have
2576 // been added and no screen update taken place.
2577 if (m_dirty)
2578 wxSafeYield();
004fd0c8 2579
92976ab6
RR
2580 wxClientDC dc(this);
2581 PrepareDC( dc );
bd8289c1 2582
cf1dfa6b 2583 wxString s = data->GetText(0);
5cd89174 2584 wxRect rectLabel = GetLineLabelRect(m_currentEdit);
cf1dfa6b
VZ
2585
2586 rectLabel.x = dc.LogicalToDeviceX( rectLabel.x );
2587 rectLabel.y = dc.LogicalToDeviceY( rectLabel.y );
2588
2589 wxListTextCtrl *text = new wxListTextCtrl
2590 (
2591 this, -1,
2592 &m_renameAccept,
2593 &m_renameRes,
2594 this,
2595 s,
2596 wxPoint(rectLabel.x-4,rectLabel.y-4),
2597 wxSize(rectLabel.width+11,rectLabel.height+8)
2598 );
92976ab6 2599 text->SetFocus();
e1e955e1 2600}
c801d85f 2601
e179bd65
RR
2602void wxListMainWindow::OnRenameTimer()
2603{
cf1dfa6b 2604 wxCHECK_RET( HasCurrent(), wxT("unexpected rename timer") );
004fd0c8 2605
cf1dfa6b 2606 EditLabel( m_current );
e179bd65
RR
2607}
2608
c801d85f
KB
2609void wxListMainWindow::OnRenameAccept()
2610{
e179bd65
RR
2611 wxListEvent le( wxEVT_COMMAND_LIST_END_LABEL_EDIT, GetParent()->GetId() );
2612 le.SetEventObject( GetParent() );
1370703e
VZ
2613 le.m_itemIndex = m_currentEdit;
2614
2615 wxListLineData *data = GetLine(m_currentEdit);
2616 wxCHECK_RET( data, _T("invalid index in OnRenameAccept()") );
2617
2618 data->GetItem( 0, le.m_item );
e179bd65
RR
2619 le.m_item.m_text = m_renameRes;
2620 GetParent()->GetEventHandler()->ProcessEvent( le );
004fd0c8 2621
e179bd65 2622 if (!le.IsAllowed()) return;
004fd0c8 2623
5f1ea0ee
RR
2624 wxListItem info;
2625 info.m_mask = wxLIST_MASK_TEXT;
2626 info.m_itemId = le.m_itemIndex;
2627 info.m_text = m_renameRes;
aaa37c0d 2628 info.SetTextColour(le.m_item.GetTextColour());
5f1ea0ee 2629 SetItem( info );
e1e955e1 2630}
c801d85f
KB
2631
2632void wxListMainWindow::OnMouse( wxMouseEvent &event )
2633{
3e1c4e00 2634 event.SetEventObject( GetParent() );
cf1dfa6b
VZ
2635 if ( GetParent()->GetEventHandler()->ProcessEvent( event) )
2636 return;
2637
2638 if ( !HasCurrent() || IsEmpty() )
2639 return;
2640
2641 if (m_dirty)
2642 return;
e3e65dac 2643
cf1dfa6b
VZ
2644 if ( !(event.Dragging() || event.ButtonDown() || event.LeftUp() ||
2645 event.ButtonDClick()) )
2646 return;
c801d85f 2647
aaef15bf
RR
2648 int x = event.GetX();
2649 int y = event.GetY();
2650 CalcUnscrolledPosition( x, y, &x, &y );
004fd0c8 2651
51cc4dad 2652 /* Did we actually hit an item ? */
92976ab6 2653 long hitResult = 0;
1370703e 2654
cf1dfa6b
VZ
2655 size_t count = GetItemCount(),
2656 current;
2657
2658 if ( HasFlag(wxLC_REPORT) )
92976ab6 2659 {
5cd89174
VZ
2660 current = y / GetLineHeight();
2661 hitResult = HitTestLine(current, x, y);
cf1dfa6b
VZ
2662 }
2663 else // !report
2664 {
2665 // TODO: optimize it too! this is less simple than for report view but
2666 // enumerating all items is still not a way to do it!!
5cd89174 2667 for ( current = 0; current < count && !hitResult; current++ )
cf1dfa6b 2668 {
5cd89174 2669 hitResult = HitTestLine(current, x, y);
cf1dfa6b 2670 }
92976ab6 2671 }
bd8289c1 2672
fd9811b1 2673 if (event.Dragging())
92976ab6 2674 {
fd9811b1 2675 if (m_dragCount == 0)
bffa1c77
VZ
2676 m_dragStart = wxPoint(x,y);
2677
fd9811b1 2678 m_dragCount++;
bffa1c77 2679
cf1dfa6b
VZ
2680 if (m_dragCount != 3)
2681 return;
bffa1c77 2682
05a7f61d
VZ
2683 int command = event.RightIsDown() ? wxEVT_COMMAND_LIST_BEGIN_RDRAG
2684 : wxEVT_COMMAND_LIST_BEGIN_DRAG;
bffa1c77 2685
fd9811b1 2686 wxListEvent le( command, GetParent()->GetId() );
92976ab6 2687 le.SetEventObject( GetParent() );
bffa1c77
VZ
2688 le.m_pointDrag = m_dragStart;
2689 GetParent()->GetEventHandler()->ProcessEvent( le );
2690
2691 return;
92976ab6 2692 }
fd9811b1
RR
2693 else
2694 {
2695 m_dragCount = 0;
2696 }
bd8289c1 2697
cf1dfa6b
VZ
2698 if ( !hitResult )
2699 {
2700 // outside of any item
2701 return;
2702 }
bd8289c1 2703
efbb7287 2704 bool forceClick = FALSE;
92976ab6
RR
2705 if (event.ButtonDClick())
2706 {
92976ab6 2707 m_renameTimer->Stop();
efbb7287
VZ
2708 m_lastOnSame = FALSE;
2709
cf1dfa6b 2710 if ( current == m_lineBeforeLastClicked )
efbb7287 2711 {
cf1dfa6b 2712 SendNotify( current, wxEVT_COMMAND_LIST_ITEM_ACTIVATED );
004fd0c8 2713
efbb7287
VZ
2714 return;
2715 }
2716 else
2717 {
2718 // the first click was on another item, so don't interpret this as
2719 // a double click, but as a simple click instead
2720 forceClick = TRUE;
2721 }
92976ab6 2722 }
bd8289c1 2723
92976ab6 2724 if (event.LeftUp() && m_lastOnSame)
c801d85f 2725 {
cf1dfa6b 2726 if ((current == m_current) &&
92976ab6 2727 (hitResult == wxLIST_HITTEST_ONITEMLABEL) &&
cf1dfa6b 2728 HasFlag(wxLC_EDIT_LABELS) )
92976ab6
RR
2729 {
2730 m_renameTimer->Start( 100, TRUE );
2731 }
2732 m_lastOnSame = FALSE;
e1e955e1 2733 }
cf1dfa6b 2734 else if (event.RightDown())
b204641e 2735 {
cf1dfa6b 2736 SendNotify( current, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK,
05a7f61d 2737 event.GetPosition() );
b204641e 2738 }
cf1dfa6b 2739 else if (event.MiddleDown())
b204641e 2740 {
cf1dfa6b 2741 SendNotify( current, wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK );
92976ab6 2742 }
cf1dfa6b 2743 else if ( event.LeftDown() || forceClick )
92976ab6 2744 {
efbb7287 2745 m_lineBeforeLastClicked = m_lineLastClicked;
cf1dfa6b
VZ
2746 m_lineLastClicked = current;
2747
2748 size_t oldCurrent = m_current;
efbb7287 2749
b54e41c5 2750 if ( IsSingleSel() || !(event.ControlDown() || event.ShiftDown()) )
b204641e 2751 {
b54e41c5 2752 HighlightAll( FALSE );
cf1dfa6b 2753 m_current = current;
cf1dfa6b 2754
b54e41c5 2755 ReverseHighlight(m_current);
e1e955e1 2756 }
b54e41c5 2757 else // multi sel & either ctrl or shift is down
b204641e 2758 {
473d087e 2759 if (event.ControlDown())
92976ab6 2760 {
cf1dfa6b
VZ
2761 m_current = current;
2762
b54e41c5 2763 ReverseHighlight(m_current);
92976ab6 2764 }
473d087e 2765 else if (event.ShiftDown())
92976ab6 2766 {
cf1dfa6b 2767 m_current = current;
bffa1c77 2768
cf1dfa6b
VZ
2769 size_t lineFrom = oldCurrent,
2770 lineTo = current;
f6bcfd97 2771
cf1dfa6b 2772 if ( lineTo < lineFrom )
92976ab6 2773 {
cf1dfa6b
VZ
2774 lineTo = lineFrom;
2775 lineFrom = m_current;
92976ab6
RR
2776 }
2777
b54e41c5 2778 HighlightLines(lineFrom, lineTo);
92976ab6 2779 }
cf1dfa6b 2780 else // !ctrl, !shift
92976ab6 2781 {
cf1dfa6b
VZ
2782 // test in the enclosing if should make it impossible
2783 wxFAIL_MSG( _T("how did we get here?") );
92976ab6 2784 }
e1e955e1 2785 }
cf1dfa6b 2786
92976ab6
RR
2787 if (m_current != oldCurrent)
2788 {
2789 RefreshLine( oldCurrent );
cf1dfa6b
VZ
2790 OnUnfocusLine( oldCurrent );
2791 OnFocusLine( m_current );
92976ab6 2792 }
efbb7287
VZ
2793
2794 // forceClick is only set if the previous click was on another item
2795 m_lastOnSame = !forceClick && (m_current == oldCurrent);
e1e955e1 2796 }
e1e955e1 2797}
c801d85f 2798
e179bd65 2799void wxListMainWindow::MoveToFocus()
c801d85f 2800{
b54e41c5 2801 if ( !HasCurrent() )
cf1dfa6b 2802 return;
004fd0c8 2803
5cd89174 2804 wxRect rect = GetLineRect(m_current);
cf3da716 2805
cf1dfa6b 2806 int client_w, client_h;
cf3da716 2807 GetClientSize( &client_w, &client_h );
f6bcfd97 2808
cf3da716
RR
2809 int view_x = m_xScroll*GetScrollPos( wxHORIZONTAL );
2810 int view_y = m_yScroll*GetScrollPos( wxVERTICAL );
004fd0c8 2811
cf1dfa6b 2812 if ( HasFlag(wxLC_REPORT) )
92976ab6 2813 {
b54e41c5
VZ
2814 // the next we need the range of lines shown it might be different, so
2815 // recalculate it
2816 ResetVisibleLinesRange();
2817
cf1dfa6b
VZ
2818 if (rect.y < view_y )
2819 Scroll( -1, rect.y/m_yScroll );
2820 if (rect.y+rect.height+5 > view_y+client_h)
2821 Scroll( -1, (rect.y+rect.height-client_h+SCROLL_UNIT_Y)/m_yScroll );
92976ab6 2822 }
b54e41c5 2823 else // !report
92976ab6 2824 {
cf1dfa6b
VZ
2825 if (rect.x-view_x < 5)
2826 Scroll( (rect.x-5)/m_xScroll, -1 );
2827 if (rect.x+rect.width-5 > view_x+client_w)
2828 Scroll( (rect.x+rect.width-client_w+SCROLL_UNIT_X)/m_xScroll, -1 );
92976ab6 2829 }
e1e955e1 2830}
c801d85f 2831
cf1dfa6b
VZ
2832// ----------------------------------------------------------------------------
2833// keyboard handling
2834// ----------------------------------------------------------------------------
2835
2836void wxListMainWindow::OnArrowChar(size_t newCurrent, const wxKeyEvent& event)
c801d85f 2837{
cf1dfa6b
VZ
2838 wxCHECK_RET( newCurrent < (size_t)GetItemCount(),
2839 _T("invalid item index in OnArrowChar()") );
2840
2841 size_t oldCurrent = m_current;
2842
2843 // in single selection we just ignore Shift as we can't select several
2844 // items anyhow
b54e41c5 2845 if ( event.ShiftDown() && !IsSingleSel() )
cf1dfa6b
VZ
2846 {
2847 m_current = newCurrent;
2848
2849 // select all the items between the old and the new one
2850 if ( oldCurrent > newCurrent )
2851 {
2852 newCurrent = oldCurrent;
2853 oldCurrent = m_current;
2854 }
2855
b54e41c5 2856 HighlightLines(oldCurrent, newCurrent);
cf1dfa6b
VZ
2857 }
2858 else // !shift
2859 {
b54e41c5
VZ
2860 // all previously selected items are unselected unless ctrl is held
2861 if ( !event.ControlDown() )
2862 HighlightAll(FALSE);
2863
cf1dfa6b
VZ
2864 m_current = newCurrent;
2865
b54e41c5 2866 HighlightLine( oldCurrent, FALSE );
cf1dfa6b
VZ
2867 RefreshLine( oldCurrent );
2868
2869 if ( !event.ControlDown() )
2870 {
b54e41c5 2871 HighlightLine( m_current, TRUE );
cf1dfa6b
VZ
2872 }
2873 }
2874
2875 OnUnfocusLine( oldCurrent );
2876 OnFocusLine( m_current );
92976ab6 2877 RefreshLine( m_current );
cf1dfa6b 2878
cf3da716 2879 MoveToFocus();
e1e955e1 2880}
c801d85f 2881
3dfb93fd
RR
2882void wxListMainWindow::OnKeyDown( wxKeyEvent &event )
2883{
2884 wxWindow *parent = GetParent();
004fd0c8 2885
3dfb93fd
RR
2886 /* we propagate the key event up */
2887 wxKeyEvent ke( wxEVT_KEY_DOWN );
2888 ke.m_shiftDown = event.m_shiftDown;
2889 ke.m_controlDown = event.m_controlDown;
2890 ke.m_altDown = event.m_altDown;
2891 ke.m_metaDown = event.m_metaDown;
2892 ke.m_keyCode = event.m_keyCode;
2893 ke.m_x = event.m_x;
2894 ke.m_y = event.m_y;
2895 ke.SetEventObject( parent );
2896 if (parent->GetEventHandler()->ProcessEvent( ke )) return;
004fd0c8 2897
3dfb93fd
RR
2898 event.Skip();
2899}
004fd0c8 2900
c801d85f
KB
2901void wxListMainWindow::OnChar( wxKeyEvent &event )
2902{
51cc4dad 2903 wxWindow *parent = GetParent();
004fd0c8 2904
51cc4dad 2905 /* we send a list_key event up */
cf1dfa6b 2906 if ( HasCurrent() )
f6bcfd97
BP
2907 {
2908 wxListEvent le( wxEVT_COMMAND_LIST_KEY_DOWN, GetParent()->GetId() );
cf1dfa6b
VZ
2909 le.m_itemIndex = m_current;
2910 GetLine(m_current)->GetItem( 0, le.m_item );
f6bcfd97
BP
2911 le.m_code = (int)event.KeyCode();
2912 le.SetEventObject( parent );
2913 parent->GetEventHandler()->ProcessEvent( le );
2914 }
51cc4dad 2915
3dfb93fd
RR
2916 /* we propagate the char event up */
2917 wxKeyEvent ke( wxEVT_CHAR );
51cc4dad
RR
2918 ke.m_shiftDown = event.m_shiftDown;
2919 ke.m_controlDown = event.m_controlDown;
2920 ke.m_altDown = event.m_altDown;
2921 ke.m_metaDown = event.m_metaDown;
2922 ke.m_keyCode = event.m_keyCode;
2923 ke.m_x = event.m_x;
2924 ke.m_y = event.m_y;
2925 ke.SetEventObject( parent );
2926 if (parent->GetEventHandler()->ProcessEvent( ke )) return;
004fd0c8 2927
012a03e0
RR
2928 if (event.KeyCode() == WXK_TAB)
2929 {
2930 wxNavigationKeyEvent nevent;
c5145d41 2931 nevent.SetWindowChange( event.ControlDown() );
012a03e0 2932 nevent.SetDirection( !event.ShiftDown() );
8253c7fd 2933 nevent.SetEventObject( GetParent()->GetParent() );
012a03e0 2934 nevent.SetCurrentFocus( m_parent );
8253c7fd 2935 if (GetParent()->GetParent()->GetEventHandler()->ProcessEvent( nevent )) return;
012a03e0 2936 }
004fd0c8 2937
51cc4dad 2938 /* no item -> nothing to do */
cf1dfa6b 2939 if (!HasCurrent())
c801d85f 2940 {
51cc4dad
RR
2941 event.Skip();
2942 return;
e1e955e1 2943 }
51cc4dad
RR
2944
2945 switch (event.KeyCode())
c801d85f 2946 {
51cc4dad 2947 case WXK_UP:
cf1dfa6b
VZ
2948 if ( m_current > 0 )
2949 OnArrowChar( m_current - 1, event );
51cc4dad 2950 break;
cf1dfa6b 2951
51cc4dad 2952 case WXK_DOWN:
cf1dfa6b
VZ
2953 if ( m_current < (size_t)GetItemCount() - 1 )
2954 OnArrowChar( m_current + 1, event );
51cc4dad 2955 break;
cf1dfa6b 2956
51cc4dad 2957 case WXK_END:
1370703e 2958 if (!IsEmpty())
cf1dfa6b 2959 OnArrowChar( GetItemCount() - 1, event );
51cc4dad 2960 break;
cf1dfa6b 2961
51cc4dad 2962 case WXK_HOME:
1370703e 2963 if (!IsEmpty())
cf1dfa6b 2964 OnArrowChar( 0, event );
51cc4dad 2965 break;
cf1dfa6b 2966
51cc4dad 2967 case WXK_PRIOR:
f6bcfd97 2968 {
cf1dfa6b
VZ
2969 int steps = 0;
2970 if ( HasFlag(wxLC_REPORT) )
2971 {
2972 steps = m_linesPerPage - 1;
2973 }
2974 else
2975 {
2976 steps = m_current % m_linesPerPage;
2977 }
2978
2979 int index = m_current - steps;
2980 if (index < 0)
2981 index = 0;
2982
2983 OnArrowChar( index, event );
51cc4dad 2984 }
51cc4dad 2985 break;
cf1dfa6b 2986
51cc4dad 2987 case WXK_NEXT:
bffa1c77 2988 {
cf1dfa6b
VZ
2989 int steps = 0;
2990 if ( HasFlag(wxLC_REPORT) )
2991 {
2992 steps = m_linesPerPage - 1;
2993 }
2994 else
2995 {
2996 steps = m_linesPerPage - (m_current % m_linesPerPage) - 1;
2997 }
f6bcfd97 2998
cf1dfa6b
VZ
2999 size_t index = m_current + steps;
3000 size_t count = GetItemCount();
3001 if ( index >= count )
3002 index = count - 1;
3003
3004 OnArrowChar( index, event );
51cc4dad 3005 }
51cc4dad 3006 break;
cf1dfa6b 3007
51cc4dad 3008 case WXK_LEFT:
cf1dfa6b 3009 if ( !HasFlag(wxLC_REPORT) )
51cc4dad 3010 {
cf1dfa6b
VZ
3011 int index = m_current - m_linesPerPage;
3012 if (index < 0)
3013 index = 0;
3014
3015 OnArrowChar( index, event );
51cc4dad
RR
3016 }
3017 break;
cf1dfa6b 3018
51cc4dad 3019 case WXK_RIGHT:
cf1dfa6b 3020 if ( !HasFlag(wxLC_REPORT) )
51cc4dad 3021 {
cf1dfa6b
VZ
3022 size_t index = m_current + m_linesPerPage;
3023
3024 size_t count = GetItemCount();
3025 if ( index >= count )
3026 index = count - 1;
3027
3028 OnArrowChar( index, event );
51cc4dad
RR
3029 }
3030 break;
cf1dfa6b 3031
51cc4dad 3032 case WXK_SPACE:
b54e41c5 3033 if ( IsSingleSel() )
33d0e17c 3034 {
cf1dfa6b
VZ
3035 wxListEvent le( wxEVT_COMMAND_LIST_ITEM_ACTIVATED,
3036 GetParent()->GetId() );
33d0e17c 3037 le.SetEventObject( GetParent() );
cf1dfa6b
VZ
3038 le.m_itemIndex = m_current;
3039 GetLine(m_current)->GetItem( 0, le.m_item );
33d0e17c
RR
3040 GetParent()->GetEventHandler()->ProcessEvent( le );
3041 }
3042 else
3043 {
b54e41c5 3044 ReverseHighlight(m_current);
51cc4dad
RR
3045 }
3046 break;
cf1dfa6b 3047
51cc4dad
RR
3048 case WXK_RETURN:
3049 case WXK_EXECUTE:
cf1dfa6b
VZ
3050 {
3051 wxListEvent le( wxEVT_COMMAND_LIST_ITEM_ACTIVATED,
3052 GetParent()->GetId() );
3053 le.SetEventObject( GetParent() );
3054 le.m_itemIndex = m_current;
3055 GetLine(m_current)->GetItem( 0, le.m_item );
3056 GetParent()->GetEventHandler()->ProcessEvent( le );
3057 }
51cc4dad 3058 break;
cf1dfa6b 3059
51cc4dad 3060 default:
51cc4dad 3061 event.Skip();
e1e955e1 3062 }
e1e955e1 3063}
c801d85f 3064
cf1dfa6b
VZ
3065// ----------------------------------------------------------------------------
3066// focus handling
3067// ----------------------------------------------------------------------------
3068
cae5359f
RR
3069#ifdef __WXGTK__
3070extern wxWindow *g_focusWindow;
3071#endif
3072
c801d85f
KB
3073void wxListMainWindow::OnSetFocus( wxFocusEvent &WXUNUSED(event) )
3074{
63852e78 3075 m_hasFocus = TRUE;
bd8289c1 3076
cf1dfa6b
VZ
3077 if ( HasCurrent() )
3078 RefreshLine( m_current );
3079
3080 if (!GetParent())
3081 return;
004fd0c8 3082
cae5359f
RR
3083#ifdef __WXGTK__
3084 g_focusWindow = GetParent();
3085#endif
bd8289c1 3086
63852e78
RR
3087 wxFocusEvent event( wxEVT_SET_FOCUS, GetParent()->GetId() );
3088 event.SetEventObject( GetParent() );
3089 GetParent()->GetEventHandler()->ProcessEvent( event );
e1e955e1 3090}
c801d85f
KB
3091
3092void wxListMainWindow::OnKillFocus( wxFocusEvent &WXUNUSED(event) )
3093{
63852e78 3094 m_hasFocus = FALSE;
004fd0c8 3095
cf1dfa6b
VZ
3096 if ( HasCurrent() )
3097 RefreshLine( m_current );
e1e955e1 3098}
c801d85f 3099
1e6d9499 3100void wxListMainWindow::DrawImage( int index, wxDC *dc, int x, int y )
c801d85f 3101{
cf1dfa6b 3102 if ( HasFlag(wxLC_ICON) && (m_normal_image_list))
63852e78
RR
3103 {
3104 m_normal_image_list->Draw( index, *dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT );
63852e78 3105 }
cf1dfa6b 3106 else if ( HasFlag(wxLC_SMALL_ICON) && (m_small_image_list))
63852e78
RR
3107 {
3108 m_small_image_list->Draw( index, *dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT );
3109 }
cf1dfa6b 3110 else if ( HasFlag(wxLC_LIST) && (m_small_image_list))
0b855868
RR
3111 {
3112 m_small_image_list->Draw( index, *dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT );
3113 }
cf1dfa6b 3114 else if ( HasFlag(wxLC_REPORT) && (m_small_image_list))
63852e78
RR
3115 {
3116 m_small_image_list->Draw( index, *dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT );
63852e78 3117 }
e1e955e1 3118}
c801d85f 3119
5cd89174 3120void wxListMainWindow::GetImageSize( int index, int &width, int &height ) const
c801d85f 3121{
cf1dfa6b 3122 if ( HasFlag(wxLC_ICON) && m_normal_image_list )
63852e78
RR
3123 {
3124 m_normal_image_list->GetSize( index, width, height );
63852e78 3125 }
cf1dfa6b 3126 else if ( HasFlag(wxLC_SMALL_ICON) && m_small_image_list )
63852e78
RR
3127 {
3128 m_small_image_list->GetSize( index, width, height );
63852e78 3129 }
cf1dfa6b 3130 else if ( HasFlag(wxLC_LIST) && m_small_image_list )
0b855868
RR
3131 {
3132 m_small_image_list->GetSize( index, width, height );
0b855868 3133 }
cf1dfa6b 3134 else if ( HasFlag(wxLC_REPORT) && m_small_image_list )
63852e78
RR
3135 {
3136 m_small_image_list->GetSize( index, width, height );
63852e78 3137 }
cf1dfa6b
VZ
3138 else
3139 {
3140 width =
3141 height = 0;
3142 }
e1e955e1 3143}
c801d85f 3144
5cd89174 3145int wxListMainWindow::GetTextLength( const wxString &s ) const
c801d85f 3146{
5cd89174 3147 wxClientDC dc( wxConstCast(this, wxListMainWindow) );
cf1dfa6b 3148 dc.SetFont( GetFont() );
c801d85f 3149
cf1dfa6b
VZ
3150 wxCoord lw;
3151 dc.GetTextExtent( s, &lw, NULL );
3152
3153 return lw + AUTOSIZE_COL_MARGIN;
e1e955e1 3154}
c801d85f 3155
debe6624 3156void wxListMainWindow::SetImageList( wxImageList *imageList, int which )
c801d85f 3157{
139adb6a 3158 m_dirty = TRUE;
f6bcfd97
BP
3159
3160 // calc the spacing from the icon size
3161 int width = 0,
3162 height = 0;
3163 if ((imageList) && (imageList->GetImageCount()) )
3164 {
3165 imageList->GetSize(0, width, height);
3166 }
3167
3168 if (which == wxIMAGE_LIST_NORMAL)
3169 {
3170 m_normal_image_list = imageList;
3171 m_normal_spacing = width + 8;
3172 }
3173
3174 if (which == wxIMAGE_LIST_SMALL)
3175 {
3176 m_small_image_list = imageList;
3177 m_small_spacing = width + 14;
3178 }
e1e955e1 3179}
c801d85f 3180
debe6624 3181void wxListMainWindow::SetItemSpacing( int spacing, bool isSmall )
c801d85f 3182{
139adb6a
RR
3183 m_dirty = TRUE;
3184 if (isSmall)
3185 {
3186 m_small_spacing = spacing;
3187 }
3188 else
3189 {
3190 m_normal_spacing = spacing;
3191 }
e1e955e1 3192}
c801d85f 3193
debe6624 3194int wxListMainWindow::GetItemSpacing( bool isSmall )
c801d85f 3195{
f6bcfd97 3196 return isSmall ? m_small_spacing : m_normal_spacing;
e1e955e1 3197}
c801d85f 3198
cf1dfa6b
VZ
3199// ----------------------------------------------------------------------------
3200// columns
3201// ----------------------------------------------------------------------------
3202
debe6624 3203void wxListMainWindow::SetColumn( int col, wxListItem &item )
c801d85f 3204{
24b9f055 3205 wxListHeaderDataList::Node *node = m_columns.Item( col );
f6bcfd97 3206
cf1dfa6b
VZ
3207 wxCHECK_RET( node, _T("invalid column index in SetColumn") );
3208
3209 if ( item.m_width == wxLIST_AUTOSIZE_USEHEADER )
3210 item.m_width = GetTextLength( item.m_text );
3211
3212 wxListHeaderData *column = node->GetData();
3213 column->SetItem( item );
3214
3215 wxListHeaderWindow *headerWin = GetListCtrl()->m_headerWin;
f6bcfd97
BP
3216 if ( headerWin )
3217 headerWin->m_dirty = TRUE;
cf1dfa6b
VZ
3218
3219 m_dirty = TRUE;
3220
3221 // invalidate it as it has to be recalculated
3222 m_headerWidth = 0;
e1e955e1 3223}
c801d85f 3224
debe6624 3225void wxListMainWindow::SetColumnWidth( int col, int width )
c801d85f 3226{
cf1dfa6b
VZ
3227 wxCHECK_RET( col >= 0 && col < GetColumnCount(),
3228 _T("invalid column index") );
3229
3230 wxCHECK_RET( HasFlag(wxLC_REPORT),
f6bcfd97 3231 _T("SetColumnWidth() can only be called in report mode.") );
0208334d 3232
63852e78 3233 m_dirty = TRUE;
bd8289c1 3234
cf1dfa6b
VZ
3235 wxListHeaderDataList::Node *node = m_columns.Item( col );
3236 wxCHECK_RET( node, _T("no column?") );
3237
3238 wxListHeaderData *column = node->GetData();
3239
3240 size_t count = GetItemCount();
3241
f6bcfd97
BP
3242 if (width == wxLIST_AUTOSIZE_USEHEADER)
3243 {
cf1dfa6b 3244 width = GetTextLength(column->GetText());
f6bcfd97 3245 }
cf1dfa6b 3246 else if ( width == wxLIST_AUTOSIZE )
0180dad6 3247 {
cf1dfa6b
VZ
3248 if ( IsVirtual() )
3249 {
3250 // TODO: determine the max width somehow...
3251 width = WIDTH_COL_DEFAULT;
3252 }
3253 else // !virtual
0180dad6 3254 {
cf1dfa6b
VZ
3255 wxClientDC dc(this);
3256 dc.SetFont( GetFont() );
3257
3258 int max = AUTOSIZE_COL_MARGIN;
3259
3260 for ( size_t i = 0; i < count; i++ )
0180dad6 3261 {
cf1dfa6b
VZ
3262 wxListLineData *line = GetLine(i);
3263 wxListItemDataList::Node *n = line->m_items.Item( col );
3264
3265 wxCHECK_RET( n, _T("no subitem?") );
3266
2c1f73ee 3267 wxListItemData *item = n->GetData();
cf1dfa6b
VZ
3268 int current = 0;
3269
bffa1c77
VZ
3270 if (item->HasImage())
3271 {
cf1dfa6b 3272 int ix, iy;
0180dad6 3273 GetImageSize( item->GetImage(), ix, iy );
cf1dfa6b 3274 current += ix + 5;
bffa1c77 3275 }
cf1dfa6b 3276
bffa1c77
VZ
3277 if (item->HasText())
3278 {
cf1dfa6b
VZ
3279 wxCoord w;
3280 dc.GetTextExtent( item->GetText(), &w, NULL );
3281 current += w;
bffa1c77 3282 }
cf1dfa6b 3283
2c1f73ee
VZ
3284 if (current > max)
3285 max = current;
0180dad6 3286 }
cf1dfa6b
VZ
3287
3288 width = max + AUTOSIZE_COL_MARGIN;
0180dad6 3289 }
0180dad6
RR
3290 }
3291
cf1dfa6b 3292 column->SetWidth( width );
bd8289c1 3293
cf1dfa6b
VZ
3294 // invalidate it as it has to be recalculated
3295 m_headerWidth = 0;
3296}
3297
3298int wxListMainWindow::GetHeaderWidth() const
3299{
3300 if ( !m_headerWidth )
0208334d 3301 {
cf1dfa6b
VZ
3302 wxListMainWindow *self = wxConstCast(this, wxListMainWindow);
3303
3304 size_t count = GetColumnCount();
3305 for ( size_t col = 0; col < count; col++ )
63852e78 3306 {
cf1dfa6b 3307 self->m_headerWidth += GetColumnWidth(col);
63852e78 3308 }
0208334d 3309 }
bd8289c1 3310
cf1dfa6b 3311 return m_headerWidth;
e1e955e1 3312}
c801d85f 3313
cf1dfa6b 3314void wxListMainWindow::GetColumn( int col, wxListItem &item ) const
c801d85f 3315{
24b9f055 3316 wxListHeaderDataList::Node *node = m_columns.Item( col );
cf1dfa6b
VZ
3317 wxCHECK_RET( node, _T("invalid column index in GetColumn") );
3318
3319 wxListHeaderData *column = node->GetData();
3320 column->GetItem( item );
e1e955e1 3321}
c801d85f 3322
cf1dfa6b 3323int wxListMainWindow::GetColumnWidth( int col ) const
c801d85f 3324{
24b9f055
VZ
3325 wxListHeaderDataList::Node *node = m_columns.Item( col );
3326 wxCHECK_MSG( node, 0, _T("invalid column index") );
3327
3328 wxListHeaderData *column = node->GetData();
3329 return column->GetWidth();
e1e955e1 3330}
c801d85f 3331
cf1dfa6b
VZ
3332// ----------------------------------------------------------------------------
3333// item state
3334// ----------------------------------------------------------------------------
c801d85f
KB
3335
3336void wxListMainWindow::SetItem( wxListItem &item )
3337{
cf1dfa6b
VZ
3338 long id = item.m_itemId;
3339 wxCHECK_RET( id >= 0 && (size_t)id < GetItemCount(),
3340 _T("invalid item index in SetItem") );
3341
3342 if ( IsVirtual() )
3343 {
3344 // just refresh the line to show the new value of the text/image
3345 RefreshLine((size_t)id);
3346 }
3347 else // !virtual
92976ab6 3348 {
cf1dfa6b
VZ
3349 m_dirty = TRUE;
3350
3351 wxListLineData *line = GetLine((size_t)id);
3352 if ( HasFlag(wxLC_REPORT) )
3353 item.m_width = GetColumnWidth( item.m_col );
92976ab6
RR
3354 line->SetItem( item.m_col, item );
3355 }
e1e955e1 3356}
c801d85f 3357
cf1dfa6b 3358void wxListMainWindow::SetItemState( long litem, long state, long stateMask )
c801d85f 3359{
cf1dfa6b 3360 wxCHECK_RET( litem >= 0 && (size_t)litem < GetItemCount(),
54442116
VZ
3361 _T("invalid list ctrl item index in SetItem") );
3362
cf1dfa6b
VZ
3363 size_t oldCurrent = m_current;
3364 size_t item = (size_t)litem; // sdafe because of the check above
bd8289c1 3365
54442116 3366 if ( stateMask & wxLIST_STATE_FOCUSED )
c801d85f 3367 {
54442116 3368 if ( state & wxLIST_STATE_FOCUSED )
92976ab6 3369 {
54442116 3370 // don't do anything if this item is already focused
cf1dfa6b 3371 if ( item != m_current )
92976ab6 3372 {
cf1dfa6b
VZ
3373 OnUnfocusLine( m_current );
3374 m_current = item;
3375 OnFocusLine( m_current );
3376
b54e41c5 3377 if ( IsSingleSel() && (oldCurrent != (size_t)-1) )
cf1dfa6b 3378 {
b54e41c5 3379 HighlightLine(oldCurrent, FALSE);
cf1dfa6b
VZ
3380 RefreshLine(oldCurrent);
3381 }
54442116 3382
92976ab6 3383 RefreshLine( m_current );
92976ab6 3384 }
54442116
VZ
3385 }
3386 else // unfocus
3387 {
3388 // don't do anything if this item is not focused
cf1dfa6b 3389 if ( item == m_current )
bffa1c77 3390 {
cf1dfa6b
VZ
3391 OnUnfocusLine( m_current );
3392 m_current = (size_t)-1;
bffa1c77 3393 }
92976ab6 3394 }
e1e955e1 3395 }
54442116
VZ
3396
3397 if ( stateMask & wxLIST_STATE_SELECTED )
3398 {
3399 bool on = (state & wxLIST_STATE_SELECTED) != 0;
54442116 3400
b54e41c5 3401 if ( IsSingleSel() )
54442116 3402 {
cf1dfa6b
VZ
3403 if ( on )
3404 {
3405 // selecting the item also makes it the focused one in the
3406 // single sel mode
3407 if ( m_current != item )
3408 {
3409 OnUnfocusLine( m_current );
3410 m_current = item;
3411 OnFocusLine( m_current );
3412
3413 if ( oldCurrent != (size_t)-1 )
3414 {
b54e41c5 3415 HighlightLine( oldCurrent, FALSE );
cf1dfa6b
VZ
3416 RefreshLine( oldCurrent );
3417 }
3418 }
3419 }
3420 else // off
3421 {
3422 // only the current item may be selected anyhow
3423 if ( item != m_current )
3424 return;
3425 }
54442116
VZ
3426 }
3427
b54e41c5 3428 if ( HighlightLine(item, on) )
54442116 3429 {
cf1dfa6b 3430 RefreshLine(item);
54442116
VZ
3431 }
3432 }
e1e955e1 3433}
c801d85f 3434
debe6624 3435int wxListMainWindow::GetItemState( long item, long stateMask )
c801d85f 3436{
cf1dfa6b
VZ
3437 wxCHECK_MSG( item >= 0 && (size_t)item < GetItemCount(), 0,
3438 _T("invalid list ctrl item index in GetItemState()") );
3439
92976ab6 3440 int ret = wxLIST_STATE_DONTCARE;
cf1dfa6b
VZ
3441
3442 if ( stateMask & wxLIST_STATE_FOCUSED )
c801d85f 3443 {
cf1dfa6b
VZ
3444 if ( (size_t)item == m_current )
3445 ret |= wxLIST_STATE_FOCUSED;
e1e955e1 3446 }
cf1dfa6b
VZ
3447
3448 if ( stateMask & wxLIST_STATE_SELECTED )
c801d85f 3449 {
b54e41c5 3450 if ( IsHighlighted(item) )
cf1dfa6b 3451 ret |= wxLIST_STATE_SELECTED;
e1e955e1 3452 }
cf1dfa6b 3453
92976ab6 3454 return ret;
e1e955e1 3455}
c801d85f
KB
3456
3457void wxListMainWindow::GetItem( wxListItem &item )
3458{
cf1dfa6b
VZ
3459 wxCHECK_RET( item.m_itemId >= 0 && (size_t)item.m_itemId < GetItemCount(),
3460 _T("invalid item index in GetItem") );
3461
3462 wxListLineData *line = GetLine((size_t)item.m_itemId);
3463 line->GetItem( item.m_col, item );
e1e955e1 3464}
c801d85f 3465
cf1dfa6b
VZ
3466// ----------------------------------------------------------------------------
3467// item count
3468// ----------------------------------------------------------------------------
3469
3470size_t wxListMainWindow::GetItemCount() const
1370703e
VZ
3471{
3472 return IsVirtual() ? m_countVirt : m_lines.GetCount();
3473}
3474
3475void wxListMainWindow::SetItemCount(long count)
c801d85f 3476{
b54e41c5 3477 m_selStore.SetItemCount(count);
1370703e
VZ
3478 m_countVirt = count;
3479
3480 Refresh();
e1e955e1 3481}
c801d85f 3482
cf1dfa6b 3483int wxListMainWindow::GetSelectedItemCount()
c801d85f 3484{
cf1dfa6b 3485 // deal with the quick case first
b54e41c5 3486 if ( IsSingleSel() )
92976ab6 3487 {
b54e41c5 3488 return HasCurrent() ? IsHighlighted(m_current) : FALSE;
92976ab6 3489 }
cf1dfa6b
VZ
3490
3491 // virtual controls remmebers all its selections itself
3492 if ( IsVirtual() )
b54e41c5 3493 return m_selStore.GetSelectedCount();
cf1dfa6b
VZ
3494
3495 // TODO: we probably should maintain the number of items selected even for
3496 // non virtual controls as enumerating all lines is really slow...
3497 size_t countSel = 0;
3498 size_t count = GetItemCount();
3499 for ( size_t line = 0; line < count; line++ )
92976ab6 3500 {
b54e41c5 3501 if ( GetLine(line)->IsHighlighted() )
cf1dfa6b 3502 countSel++;
92976ab6 3503 }
c801d85f 3504
cf1dfa6b 3505 return countSel;
e1e955e1 3506}
e3e65dac 3507
cf1dfa6b
VZ
3508// ----------------------------------------------------------------------------
3509// item position/size
3510// ----------------------------------------------------------------------------
3511
3512void wxListMainWindow::GetItemRect( long index, wxRect &rect )
c801d85f 3513{
cf1dfa6b
VZ
3514 wxCHECK_RET( index >= 0 && (size_t)index < GetItemCount(),
3515 _T("invalid index in GetItemRect") );
3516
5cd89174 3517 rect = GetLineRect((size_t)index);
b54e41c5 3518
cf1dfa6b 3519 CalcScrolledPosition(rect.x, rect.y, &rect.x, &rect.y);
e1e955e1 3520}
c801d85f 3521
cf1dfa6b 3522bool wxListMainWindow::GetItemPosition(long item, wxPoint& pos)
c801d85f 3523{
cf1dfa6b
VZ
3524 wxRect rect;
3525 GetItemRect(item, rect);
bd8289c1 3526
cf1dfa6b
VZ
3527 pos.x = rect.x;
3528 pos.y = rect.y;
bd8289c1 3529
cf1dfa6b 3530 return TRUE;
e1e955e1 3531}
c801d85f 3532
cf1dfa6b
VZ
3533// ----------------------------------------------------------------------------
3534// geometry calculation
3535// ----------------------------------------------------------------------------
3536
b54e41c5 3537void wxListMainWindow::RecalculatePositions()
c801d85f 3538{
1370703e
VZ
3539 if ( IsEmpty() )
3540 return;
e487524e 3541
1e6d9499 3542 wxClientDC dc( this );
92976ab6 3543 dc.SetFont( GetFont() );
c801d85f 3544
cf1dfa6b
VZ
3545 int iconSpacing;
3546 if ( HasFlag(wxLC_ICON) )
3547 iconSpacing = m_normal_spacing;
3548 else if ( HasFlag(wxLC_SMALL_ICON) )
3549 iconSpacing = m_small_spacing;
3550 else
3551 iconSpacing = 0;
004fd0c8 3552
cf1dfa6b
VZ
3553 int clientWidth,
3554 clientHeight;
3555 GetClientSize( &clientWidth, &clientHeight );
004fd0c8 3556
cf1dfa6b
VZ
3557 if ( HasFlag(wxLC_REPORT) )
3558 {
3559 // all lines have the same height
b54e41c5 3560 int lineHeight = GetLineHeight();
c801d85f 3561
cf1dfa6b 3562 // scroll one line per step
b54e41c5 3563 m_yScroll = lineHeight;
bd8289c1 3564
cf1dfa6b 3565 size_t lineCount = GetItemCount();
b54e41c5 3566 int entireHeight = lineCount*lineHeight + LINE_SPACING;
bd8289c1 3567
b54e41c5
VZ
3568 m_linesPerPage = clientHeight / lineHeight;
3569
3570 ResetVisibleLinesRange();
2c1f73ee 3571
cf1dfa6b
VZ
3572 SetScrollbars( m_xScroll, m_yScroll,
3573 (GetHeaderWidth() + m_xScroll - 1)/m_xScroll,
3574 (entireHeight + m_yScroll - 1)/m_yScroll,
3575 GetScrollPos(wxHORIZONTAL),
3576 GetScrollPos(wxVERTICAL),
3577 TRUE );
e1e955e1 3578 }
cf1dfa6b 3579 else // !report
92976ab6
RR
3580 {
3581 // at first we try without any scrollbar. if the items don't
3582 // fit into the window, we recalculate after subtracting an
3583 // approximated 15 pt for the horizontal scrollbar
004fd0c8 3584
bffa1c77 3585 clientHeight -= 4; // sunken frame
bd8289c1 3586
b54e41c5 3587 int entireWidth = 0;
bd8289c1 3588
92976ab6 3589 for (int tries = 0; tries < 2; tries++)
e487524e 3590 {
92976ab6 3591 entireWidth = 0;
5d25c050
RR
3592 int x = 2;
3593 int y = 2;
92976ab6 3594 int maxWidth = 0;
cf1dfa6b
VZ
3595 m_linesPerPage = 0;
3596 int currentlyVisibleLines = 0;
3597
3598 size_t count = GetItemCount();
3599 for (size_t i = 0; i < count; i++)
92976ab6 3600 {
cf1dfa6b
VZ
3601 currentlyVisibleLines++;
3602 wxListLineData *line = GetLine(i);
92976ab6 3603 line->CalculateSize( &dc, iconSpacing );
cf1dfa6b
VZ
3604 line->SetPosition( x, y, clientWidth, iconSpacing );
3605
5cd89174 3606 wxSize sizeLine = GetLineSize(i);
cf1dfa6b
VZ
3607
3608 if ( maxWidth < sizeLine.x )
3609 maxWidth = sizeLine.x;
3610
3611 y += sizeLine.y;
3612 if (currentlyVisibleLines > m_linesPerPage)
3613 m_linesPerPage = currentlyVisibleLines;
3614
3615 // assume that the size of the next one is the same... (FIXME)
3616 if ( y + sizeLine.y - 6 >= clientHeight )
92976ab6 3617 {
cf1dfa6b 3618 currentlyVisibleLines = 0;
e1208c31 3619 y = 2;
8b53e5a2
RR
3620 x += maxWidth+6;
3621 entireWidth += maxWidth+6;
92976ab6
RR
3622 maxWidth = 0;
3623 }
cf1dfa6b
VZ
3624 if ( i == count - 1 )
3625 entireWidth += maxWidth;
92976ab6
RR
3626 if ((tries == 0) && (entireWidth > clientWidth))
3627 {
3628 clientHeight -= 15; // scrollbar height
cf1dfa6b
VZ
3629 m_linesPerPage = 0;
3630 currentlyVisibleLines = 0;
92976ab6
RR
3631 break;
3632 }
cf1dfa6b
VZ
3633 if ( i == count - 1 )
3634 tries = 1; // everything fits, no second try required
92976ab6 3635 }
e487524e 3636 }
bffa1c77 3637
92976ab6 3638 int scroll_pos = GetScrollPos( wxHORIZONTAL );
cf1dfa6b 3639 SetScrollbars( m_xScroll, m_yScroll, (entireWidth+SCROLL_UNIT_X) / m_xScroll, 0, scroll_pos, 0, TRUE );
e1e955e1 3640 }
cf1dfa6b
VZ
3641
3642 // FIXME: why should we call it from here?
3643 UpdateCurrent();
b54e41c5
VZ
3644
3645 RefreshAll();
3646}
3647
3648void wxListMainWindow::RefreshAll()
3649{
3650 m_dirty = FALSE;
3651 Refresh();
3652
3653 wxListHeaderWindow *headerWin = GetListCtrl()->m_headerWin;
3654 if ( headerWin )
3655 {
3656 headerWin->m_dirty = FALSE;
3657 headerWin->Refresh();
3658 }
e1e955e1 3659}
c801d85f 3660
cf1dfa6b 3661void wxListMainWindow::UpdateCurrent()
c801d85f 3662{
b54e41c5 3663 if ( !HasCurrent() && !IsEmpty() )
92976ab6 3664 {
cf1dfa6b 3665 m_current = 0;
92976ab6 3666 }
cf1dfa6b
VZ
3667
3668 if ( m_current != (size_t)-1 )
92976ab6 3669 {
cf1dfa6b 3670 OnFocusLine( m_current );
92976ab6 3671 }
e1e955e1 3672}
c801d85f 3673
19695fbd
VZ
3674long wxListMainWindow::GetNextItem( long item,
3675 int WXUNUSED(geometry),
3676 int state )
c801d85f 3677{
d1022fd6
VZ
3678 long ret = item,
3679 max = GetItemCount();
3680 wxCHECK_MSG( (ret == -1) || (ret < max), -1,
13771c08 3681 _T("invalid listctrl index in GetNextItem()") );
19695fbd
VZ
3682
3683 // notice that we start with the next item (or the first one if item == -1)
3684 // and this is intentional to allow writing a simple loop to iterate over
3685 // all selected items
d1022fd6
VZ
3686 ret++;
3687 if ( ret == max )
3688 {
3689 // this is not an error because the index was ok initially, just no
3690 // such item
3691 return -1;
3692 }
3693
cf1dfa6b
VZ
3694 if ( !state )
3695 {
3696 // any will do
3697 return (size_t)ret;
3698 }
3699
3700 size_t count = GetItemCount();
3701 for ( size_t line = (size_t)ret; line < count; line++ )
63852e78 3702 {
cf1dfa6b
VZ
3703 if ( (state & wxLIST_STATE_FOCUSED) && (line == m_current) )
3704 return line;
3705
b54e41c5 3706 if ( (state & wxLIST_STATE_SELECTED) && IsHighlighted(line) )
cf1dfa6b 3707 return line;
63852e78 3708 }
19695fbd 3709
63852e78 3710 return -1;
e1e955e1 3711}
c801d85f 3712
cf1dfa6b
VZ
3713// ----------------------------------------------------------------------------
3714// deleting stuff
3715// ----------------------------------------------------------------------------
3716
b54e41c5 3717void wxListMainWindow::DeleteItem( long lindex )
c801d85f 3718{
cf1dfa6b
VZ
3719 size_t count = GetItemCount();
3720
b54e41c5 3721 wxCHECK_RET( (lindex >= 0) && ((size_t)lindex < count),
cf1dfa6b
VZ
3722 _T("invalid item index in DeleteItem") );
3723
b54e41c5
VZ
3724 size_t index = (size_t)lindex;
3725
63852e78 3726 m_dirty = TRUE;
cf1dfa6b
VZ
3727
3728 // select the next item when the selected one is deleted
b54e41c5 3729 if ( m_current == index )
cf1dfa6b
VZ
3730 {
3731 // the last valid index after deleting the item will be count-2
5cd89174 3732 if ( m_current == count - 1 )
cf1dfa6b 3733 {
5cd89174 3734 m_current--;
cf1dfa6b
VZ
3735 }
3736 }
3737
b54e41c5 3738 SendNotify( index, wxEVT_COMMAND_LIST_DELETE_ITEM );
cf1dfa6b 3739
938b652b 3740 if ( InReportView() )
63852e78 3741 {
6b4a8d93 3742 ResetVisibleLinesRange();
938b652b
VZ
3743 }
3744
938b652b
VZ
3745 if ( IsVirtual() )
3746 {
3747 m_countVirt--;
b54e41c5
VZ
3748
3749 m_selStore.OnItemDelete(index);
3750 }
3751 else
3752 {
3753 m_lines.RemoveAt( index );
63852e78 3754 }
6b4a8d93
VZ
3755
3756 RefreshAfter(index);
e1e955e1 3757}
c801d85f 3758
debe6624 3759void wxListMainWindow::DeleteColumn( int col )
c801d85f 3760{
24b9f055
VZ
3761 wxListHeaderDataList::Node *node = m_columns.Item( col );
3762
3763 wxCHECK_RET( node, wxT("invalid column index in DeleteColumn()") );
bd8289c1 3764
5b077d48 3765 m_dirty = TRUE;
24b9f055 3766 m_columns.DeleteNode( node );
e1e955e1 3767}
c801d85f 3768
12c1b46a 3769void wxListMainWindow::DeleteAllItems()
c801d85f 3770{
cf1dfa6b
VZ
3771 if ( IsEmpty() )
3772 {
3773 // nothing to do - in particular, don't send the event
3774 return;
3775 }
3776
5b077d48 3777 m_dirty = TRUE;
b54e41c5
VZ
3778
3779 ResetCurrent();
7c0ea335
VZ
3780
3781 // to make the deletion of all items faster, we don't send the
cf1dfa6b
VZ
3782 // notifications for each item deletion in this case but only one event
3783 // for all of them: this is compatible with wxMSW and documented in
3784 // DeleteAllItems() description
bffa1c77 3785
12c1b46a
RR
3786 wxListEvent event( wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS, GetParent()->GetId() );
3787 event.SetEventObject( GetParent() );
3788 GetParent()->GetEventHandler()->ProcessEvent( event );
7c0ea335 3789
b54e41c5
VZ
3790 if ( IsVirtual() )
3791 {
3792 m_countVirt = 0;
3793
3794 ResetVisibleLinesRange();
3795 }
3796
6b4a8d93
VZ
3797 if ( InReportView() )
3798 {
3799 ResetVisibleLinesRange();
3800 }
3801
5b077d48 3802 m_lines.Clear();
cf1dfa6b 3803
b54e41c5 3804 m_selStore.Clear();
e1e955e1 3805}
c801d85f 3806
12c1b46a 3807void wxListMainWindow::DeleteEverything()
c801d85f 3808{
12c1b46a 3809 DeleteAllItems();
f6bcfd97 3810
5b077d48 3811 m_columns.Clear();
e1e955e1 3812}
c801d85f 3813
cf1dfa6b
VZ
3814// ----------------------------------------------------------------------------
3815// scanning for an item
3816// ----------------------------------------------------------------------------
3817
debe6624 3818void wxListMainWindow::EnsureVisible( long index )
c801d85f 3819{
cf1dfa6b
VZ
3820 wxCHECK_RET( index >= 0 && (size_t)index < GetItemCount(),
3821 _T("invalid index in EnsureVisible") );
3822
3823 // We have to call this here because the label in question might just have
3824 // been added and no screen update taken place.
3825 if (m_dirty)
3826 wxSafeYield();
dc6c62a9 3827
cf1dfa6b
VZ
3828 size_t oldCurrent = m_current;
3829 m_current = (size_t)index;
3830 MoveToFocus();
5b077d48 3831 m_current = oldCurrent;
e1e955e1 3832}
c801d85f 3833
debe6624 3834long wxListMainWindow::FindItem(long start, const wxString& str, bool WXUNUSED(partial) )
c801d85f 3835{
5b077d48
RR
3836 long pos = start;
3837 wxString tmp = str;
cf1dfa6b
VZ
3838 if (pos < 0)
3839 pos = 0;
54442116 3840
cf1dfa6b
VZ
3841 size_t count = GetItemCount();
3842 for ( size_t i = (size_t)pos; i < count; i++ )
3843 {
3844 wxListLineData *line = GetLine(i);
3845 if ( line->GetText(0) == tmp )
3846 return i;
5b077d48 3847 }
cf1dfa6b
VZ
3848
3849 return wxNOT_FOUND;
e1e955e1 3850}
c801d85f 3851
debe6624 3852long wxListMainWindow::FindItem(long start, long data)
c801d85f 3853{
5b077d48 3854 long pos = start;
cf1dfa6b
VZ
3855 if (pos < 0)
3856 pos = 0;
3857
3858 size_t count = GetItemCount();
3859 for (size_t i = (size_t)pos; i < count; i++)
5b077d48 3860 {
cf1dfa6b 3861 wxListLineData *line = GetLine(i);
5b077d48
RR
3862 wxListItem item;
3863 line->GetItem( 0, item );
cf1dfa6b
VZ
3864 if (item.m_data == data)
3865 return i;
5b077d48 3866 }
cf1dfa6b
VZ
3867
3868 return wxNOT_FOUND;
e1e955e1 3869}
c801d85f 3870
debe6624 3871long wxListMainWindow::HitTest( int x, int y, int &flags )
c801d85f 3872{
aaef15bf 3873 CalcUnscrolledPosition( x, y, &x, &y );
e8741cca 3874
5cd89174 3875 if ( HasFlag(wxLC_REPORT) )
c801d85f 3876 {
5cd89174
VZ
3877 size_t current = y / GetLineHeight();
3878 flags = HitTestLine(current, x, y);
3879 if ( flags )
3880 return current;
3881 }
3882 else // !report
3883 {
3884 // TODO: optimize it too! this is less simple than for report view but
3885 // enumerating all items is still not a way to do it!!
3886 size_t count = GetItemCount();
3887 for ( size_t current = 0; current < count; current++ )
5b077d48 3888 {
5cd89174
VZ
3889 flags = HitTestLine(current, x, y);
3890 if ( flags )
3891 return current;
5b077d48 3892 }
e1e955e1 3893 }
cf1dfa6b
VZ
3894
3895 return wxNOT_FOUND;
e1e955e1 3896}
c801d85f 3897
cf1dfa6b
VZ
3898// ----------------------------------------------------------------------------
3899// adding stuff
3900// ----------------------------------------------------------------------------
3901
c801d85f
KB
3902void wxListMainWindow::InsertItem( wxListItem &item )
3903{
cf1dfa6b
VZ
3904 wxASSERT_MSG( !IsVirtual(), _T("can't be used with virtual control") );
3905
3906 size_t count = GetItemCount();
3907 wxCHECK_RET( item.m_itemId >= 0 && (size_t)item.m_itemId <= count,
3908 _T("invalid item index") );
3909
3910 size_t id = item.m_itemId;
3911
5b077d48 3912 m_dirty = TRUE;
cf1dfa6b 3913
5b077d48 3914 int mode = 0;
cf1dfa6b 3915 if ( HasFlag(wxLC_REPORT) )
1370703e 3916 mode = wxLC_REPORT;
cf1dfa6b 3917 else if ( HasFlag(wxLC_LIST) )
1370703e 3918 mode = wxLC_LIST;
cf1dfa6b 3919 else if ( HasFlag(wxLC_ICON) )
1370703e 3920 mode = wxLC_ICON;
cf1dfa6b 3921 else if ( HasFlag(wxLC_SMALL_ICON) )
1370703e
VZ
3922 mode = wxLC_ICON; // no typo
3923 else
3924 {
3925 wxFAIL_MSG( _T("unknown mode") );
3926 }
004fd0c8 3927
5cd89174 3928 wxListLineData *line = new wxListLineData(this);
004fd0c8 3929
5b077d48 3930 line->SetItem( 0, item );
cf1dfa6b
VZ
3931
3932 m_lines.Insert( line, id );
5cd89174
VZ
3933
3934 RefreshLines(id, GetItemCount() - 1);
e1e955e1 3935}
c801d85f 3936
debe6624 3937void wxListMainWindow::InsertColumn( long col, wxListItem &item )
c801d85f 3938{
5b077d48 3939 m_dirty = TRUE;
cf1dfa6b 3940 if ( HasFlag(wxLC_REPORT) )
3db7be80 3941 {
54442116
VZ
3942 if (item.m_width == wxLIST_AUTOSIZE_USEHEADER)
3943 item.m_width = GetTextLength( item.m_text );
5b077d48
RR
3944 wxListHeaderData *column = new wxListHeaderData( item );
3945 if ((col >= 0) && (col < (int)m_columns.GetCount()))
3946 {
24b9f055
VZ
3947 wxListHeaderDataList::Node *node = m_columns.Item( col );
3948 m_columns.Insert( node, column );
5b077d48
RR
3949 }
3950 else
3951 {
3952 m_columns.Append( column );
3953 }
3db7be80 3954 }
e1e955e1 3955}
c801d85f 3956
cf1dfa6b
VZ
3957// ----------------------------------------------------------------------------
3958// sorting
3959// ----------------------------------------------------------------------------
3960
c801d85f
KB
3961wxListCtrlCompare list_ctrl_compare_func_2;
3962long list_ctrl_compare_data;
3963
f6bcfd97 3964int LINKAGEMODE list_ctrl_compare_func_1( wxListLineData **arg1, wxListLineData **arg2 )
c801d85f 3965{
f6bcfd97
BP
3966 wxListLineData *line1 = *arg1;
3967 wxListLineData *line2 = *arg2;
5b077d48
RR
3968 wxListItem item;
3969 line1->GetItem( 0, item );
3970 long data1 = item.m_data;
3971 line2->GetItem( 0, item );
3972 long data2 = item.m_data;
3973 return list_ctrl_compare_func_2( data1, data2, list_ctrl_compare_data );
e1e955e1 3974}
c801d85f
KB
3975
3976void wxListMainWindow::SortItems( wxListCtrlCompare fn, long data )
3977{
5b077d48
RR
3978 list_ctrl_compare_func_2 = fn;
3979 list_ctrl_compare_data = data;
3980 m_lines.Sort( list_ctrl_compare_func_1 );
af7c1052 3981 m_dirty = TRUE;
e1e955e1 3982}
c801d85f 3983
cf1dfa6b
VZ
3984// ----------------------------------------------------------------------------
3985// scrolling
3986// ----------------------------------------------------------------------------
3987
7c74e7fe
SC
3988void wxListMainWindow::OnScroll(wxScrollWinEvent& event)
3989{
b54e41c5
VZ
3990 // update our idea of which lines are shown when we redraw the window the
3991 // next time
3992 ResetVisibleLinesRange();
cf1dfa6b 3993
29149a64 3994 // FIXME
3a8c693a 3995#if defined(__WXGTK__) && !defined(__WXUNIVERSAL__)
29149a64
VZ
3996 wxScrolledWindow::OnScroll(event);
3997#else
1e6feb95 3998 HandleOnScroll( event );
29149a64 3999#endif
30954328 4000
cf1dfa6b 4001 if ( event.GetOrientation() == wxHORIZONTAL && HasHeader() )
7c74e7fe 4002 {
cf1dfa6b
VZ
4003 wxListCtrl* lc = GetListCtrl();
4004 wxCHECK_RET( lc, _T("no listctrl window?") );
4005
4006 lc->m_headerWin->Refresh() ;
7c74e7fe 4007#ifdef __WXMAC__
cf1dfa6b 4008 lc->m_headerWin->MacUpdateImmediately() ;
7c74e7fe 4009#endif
7c74e7fe 4010 }
cf1dfa6b
VZ
4011}
4012
5cd89174
VZ
4013int wxListMainWindow::GetCountPerPage() const
4014{
4015 if ( !m_linesPerPage )
4016 {
4017 wxConstCast(this, wxListMainWindow)->
4018 m_linesPerPage = GetClientSize().y / GetLineHeight();
4019 }
4020
4021 return m_linesPerPage;
4022}
4023
b54e41c5 4024void wxListMainWindow::GetVisibleLinesRange(size_t *from, size_t *to)
cf1dfa6b 4025{
b54e41c5 4026 wxASSERT_MSG( HasFlag(wxLC_REPORT), _T("this is for report mode only") );
cf1dfa6b 4027
b54e41c5
VZ
4028 if ( m_lineFrom == (size_t)-1 )
4029 {
b54e41c5 4030 size_t count = GetItemCount();
6522713c
VZ
4031 if ( count )
4032 {
4033 m_lineFrom = GetScrollPos(wxVERTICAL);
cf1dfa6b 4034
6522713c 4035 wxASSERT_MSG( m_lineFrom < count, _T("invalid scroll position?") );
cf1dfa6b 4036
6522713c
VZ
4037 // we redraw one extra line but this is needed to make the redrawing
4038 // logic work when there is a fractional number of lines on screen
4039 m_lineTo = m_lineFrom + m_linesPerPage;
4040 if ( m_lineTo >= count )
4041 m_lineTo = count - 1;
4042 }
4043 else // empty control
4044 {
4045 m_lineFrom = 0;
4046 m_lineTo = (size_t)-1;
4047 }
cf1dfa6b 4048 }
b54e41c5 4049
6b4a8d93
VZ
4050 wxASSERT_MSG( m_lineFrom <= m_lineTo && m_lineTo < GetItemCount(),
4051 _T("GetVisibleLinesRange() returns incorrect result") );
4052
b54e41c5
VZ
4053 if ( from )
4054 *from = m_lineFrom;
4055 if ( to )
4056 *to = m_lineTo;
7c74e7fe
SC
4057}
4058
c801d85f
KB
4059// -------------------------------------------------------------------------------------
4060// wxListItem
4061// -------------------------------------------------------------------------------------
4062
4063IMPLEMENT_DYNAMIC_CLASS(wxListItem, wxObject)
4064
fd9811b1 4065wxListItem::wxListItem()
c801d85f 4066{
63852e78
RR
4067 m_mask = 0;
4068 m_itemId = 0;
4069 m_col = 0;
4070 m_state = 0;
4071 m_stateMask = 0;
4072 m_image = 0;
4073 m_data = 0;
4074 m_format = wxLIST_FORMAT_CENTRE;
4075 m_width = 0;
aaa37c0d
VZ
4076
4077 m_attr = NULL;
c801d85f
KB
4078}
4079
9b00bb16
RR
4080void wxListItem::Clear()
4081{
4082 m_mask = 0;
4083 m_itemId = 0;
4084 m_col = 0;
4085 m_state = 0;
4086 m_stateMask = 0;
4087 m_image = 0;
4088 m_data = 0;
4089 m_format = wxLIST_FORMAT_CENTRE;
4090 m_width = 0;
54442116 4091 m_text = _T("");
9b00bb16 4092
cf1dfa6b 4093 ClearAttributes();
9b00bb16
RR
4094}
4095
4096void wxListItem::ClearAttributes()
4097{
cf1dfa6b
VZ
4098 if (m_attr)
4099 {
4100 delete m_attr;
4101 m_attr = NULL;
4102 }
9b00bb16
RR
4103}
4104
c801d85f
KB
4105// -------------------------------------------------------------------------------------
4106// wxListEvent
4107// -------------------------------------------------------------------------------------
4108
92976ab6 4109IMPLEMENT_DYNAMIC_CLASS(wxListEvent, wxNotifyEvent)
c801d85f 4110
cf1dfa6b
VZ
4111wxListEvent::wxListEvent( wxEventType commandType, int id )
4112 : wxNotifyEvent( commandType, id )
c801d85f 4113{
5b077d48
RR
4114 m_code = 0;
4115 m_itemIndex = 0;
4116 m_oldItemIndex = 0;
4117 m_col = 0;
4118 m_cancelled = FALSE;
4119 m_pointDrag.x = 0;
4120 m_pointDrag.y = 0;
e1e955e1 4121}
c801d85f 4122
72a7edf0
RR
4123void wxListEvent::CopyObject(wxObject& object_dest) const
4124{
4125 wxListEvent *obj = (wxListEvent *)&object_dest;
4126
4127 wxNotifyEvent::CopyObject(object_dest);
4128
4129 obj->m_code = m_code;
4130 obj->m_itemIndex = m_itemIndex;
4131 obj->m_oldItemIndex = m_oldItemIndex;
4132 obj->m_col = m_col;
4133 obj->m_cancelled = m_cancelled;
4134 obj->m_pointDrag = m_pointDrag;
4135 obj->m_item.m_mask = m_item.m_mask;
4136 obj->m_item.m_itemId = m_item.m_itemId;
4137 obj->m_item.m_col = m_item.m_col;
4138 obj->m_item.m_state = m_item.m_state;
4139 obj->m_item.m_stateMask = m_item.m_stateMask;
4140 obj->m_item.m_text = m_item.m_text;
4141 obj->m_item.m_image = m_item.m_image;
4142 obj->m_item.m_data = m_item.m_data;
4143 obj->m_item.m_format = m_item.m_format;
4144 obj->m_item.m_width = m_item.m_width;
aaa37c0d
VZ
4145
4146 if ( m_item.HasAttributes() )
4147 {
4148 obj->m_item.SetTextColour(m_item.GetTextColour());
4149 }
72a7edf0
RR
4150}
4151
c801d85f
KB
4152// -------------------------------------------------------------------------------------
4153// wxListCtrl
4154// -------------------------------------------------------------------------------------
4155
4156IMPLEMENT_DYNAMIC_CLASS(wxListCtrl, wxControl)
4157
4158BEGIN_EVENT_TABLE(wxListCtrl,wxControl)
cf1dfa6b
VZ
4159 EVT_SIZE(wxListCtrl::OnSize)
4160 EVT_IDLE(wxListCtrl::OnIdle)
c801d85f
KB
4161END_EVENT_TABLE()
4162
fd9811b1 4163wxListCtrl::wxListCtrl()
c801d85f 4164{
5b077d48
RR
4165 m_imageListNormal = (wxImageList *) NULL;
4166 m_imageListSmall = (wxImageList *) NULL;
4167 m_imageListState = (wxImageList *) NULL;
cf1dfa6b
VZ
4168
4169 m_ownsImageListNormal =
4170 m_ownsImageListSmall =
4171 m_ownsImageListState = FALSE;
4172
5b077d48
RR
4173 m_mainWin = (wxListMainWindow*) NULL;
4174 m_headerWin = (wxListHeaderWindow*) NULL;
c801d85f
KB
4175}
4176
fd9811b1 4177wxListCtrl::~wxListCtrl()
c801d85f 4178{
b54e41c5
VZ
4179 if ( m_mainWin )
4180 m_mainWin->ResetCurrent();
4181
cf1dfa6b
VZ
4182 if (m_ownsImageListNormal)
4183 delete m_imageListNormal;
4184 if (m_ownsImageListSmall)
4185 delete m_imageListSmall;
4186 if (m_ownsImageListState)
4187 delete m_imageListState;
4188}
4189
4190void wxListCtrl::CreateHeaderWindow()
4191{
4192 m_headerWin = new wxListHeaderWindow
4193 (
4194 this, -1, m_mainWin,
4195 wxPoint(0, 0),
4196 wxSize(GetClientSize().x, HEADER_HEIGHT),
4197 wxTAB_TRAVERSAL
4198 );
c801d85f
KB
4199}
4200
25e3a937
VZ
4201bool wxListCtrl::Create(wxWindow *parent,
4202 wxWindowID id,
4203 const wxPoint &pos,
4204 const wxSize &size,
4205 long style,
25e3a937 4206 const wxValidator &validator,
25e3a937 4207 const wxString &name)
c801d85f 4208{
cf1dfa6b
VZ
4209 m_imageListNormal =
4210 m_imageListSmall =
5b077d48 4211 m_imageListState = (wxImageList *) NULL;
cf1dfa6b
VZ
4212 m_ownsImageListNormal =
4213 m_ownsImageListSmall =
4214 m_ownsImageListState = FALSE;
4215
5b077d48
RR
4216 m_mainWin = (wxListMainWindow*) NULL;
4217 m_headerWin = (wxListHeaderWindow*) NULL;
bd8289c1 4218
b54e41c5 4219 if ( !(style & wxLC_MASK_TYPE) )
5b077d48 4220 {
25e3a937 4221 style = style | wxLC_LIST;
5b077d48 4222 }
f6bcfd97 4223
cf1dfa6b
VZ
4224 if ( !wxControl::Create( parent, id, pos, size, style, validator, name ) )
4225 return FALSE;
f6bcfd97 4226
b54e41c5
VZ
4227 // don't create the inner window with the border
4228 style &= ~wxSUNKEN_BORDER;
bd8289c1 4229
25e3a937 4230 m_mainWin = new wxListMainWindow( this, -1, wxPoint(0,0), size, style );
bd8289c1 4231
b54e41c5 4232 if ( HasFlag(wxLC_REPORT) )
ea451729 4233 {
cf1dfa6b
VZ
4234 CreateHeaderWindow();
4235
b54e41c5 4236 if ( HasFlag(wxLC_NO_HEADER) )
cf1dfa6b
VZ
4237 {
4238 // VZ: why do we create it at all then?
ea451729 4239 m_headerWin->Show( FALSE );
cf1dfa6b 4240 }
ea451729 4241 }
bd8289c1 4242
cf1dfa6b 4243 return TRUE;
e1e955e1 4244}
c801d85f 4245
debe6624 4246void wxListCtrl::SetSingleStyle( long style, bool add )
c801d85f 4247{
b54e41c5
VZ
4248 wxASSERT_MSG( !(style & wxLC_VIRTUAL),
4249 _T("wxLC_VIRTUAL can't be [un]set") );
4250
f03fc89f 4251 long flag = GetWindowStyle();
bd8289c1 4252
5b077d48
RR
4253 if (add)
4254 {
cf1dfa6b 4255 if (style & wxLC_MASK_TYPE)
b54e41c5 4256 flag &= ~(wxLC_MASK_TYPE | wxLC_VIRTUAL);
cf1dfa6b
VZ
4257 if (style & wxLC_MASK_ALIGN)
4258 flag &= ~wxLC_MASK_ALIGN;
4259 if (style & wxLC_MASK_SORT)
4260 flag &= ~wxLC_MASK_SORT;
5b077d48 4261 }
c801d85f 4262
5b077d48
RR
4263 if (add)
4264 {
4265 flag |= style;
4266 }
4267 else
4268 {
cf1dfa6b 4269 flag &= ~style;
5b077d48 4270 }
bd8289c1 4271
5b077d48 4272 SetWindowStyleFlag( flag );
e1e955e1 4273}
c801d85f 4274
debe6624 4275void wxListCtrl::SetWindowStyleFlag( long flag )
c801d85f 4276{
121a3581
RR
4277 if (m_mainWin)
4278 {
4279 m_mainWin->DeleteEverything();
c801d85f 4280
121a3581
RR
4281 int width = 0;
4282 int height = 0;
4283 GetClientSize( &width, &height );
c801d85f 4284
121a3581 4285 if (flag & wxLC_REPORT)
5b077d48 4286 {
121a3581 4287 if (!HasFlag(wxLC_REPORT))
5b077d48 4288 {
121a3581
RR
4289 if (!m_headerWin)
4290 {
cf1dfa6b
VZ
4291 CreateHeaderWindow();
4292
bffa1c77
VZ
4293 if (HasFlag(wxLC_NO_HEADER))
4294 m_headerWin->Show( FALSE );
121a3581
RR
4295 }
4296 else
004fd0c8 4297 {
bffa1c77
VZ
4298 if (flag & wxLC_NO_HEADER)
4299 m_headerWin->Show( FALSE );
4300 else
8636aed8 4301 m_headerWin->Show( TRUE );
004fd0c8 4302 }
5b077d48
RR
4303 }
4304 }
cf1dfa6b 4305 else // !report
5b077d48 4306 {
cf1dfa6b 4307 if ( m_mainWin->HasHeader() )
121a3581
RR
4308 {
4309 m_headerWin->Show( FALSE );
4310 }
bffa1c77 4311 }
e1e955e1 4312 }
004fd0c8 4313
5b077d48 4314 wxWindow::SetWindowStyleFlag( flag );
e1e955e1 4315}
c801d85f 4316
e487524e 4317bool wxListCtrl::GetColumn(int col, wxListItem &item) const
c801d85f 4318{
5b077d48
RR
4319 m_mainWin->GetColumn( col, item );
4320 return TRUE;
e1e955e1 4321}
c801d85f 4322
debe6624 4323bool wxListCtrl::SetColumn( int col, wxListItem& item )
c801d85f 4324{
5b077d48
RR
4325 m_mainWin->SetColumn( col, item );
4326 return TRUE;
e1e955e1 4327}
c801d85f 4328
e487524e 4329int wxListCtrl::GetColumnWidth( int col ) const
c801d85f 4330{
5b077d48 4331 return m_mainWin->GetColumnWidth( col );
e1e955e1 4332}
c801d85f 4333
debe6624 4334bool wxListCtrl::SetColumnWidth( int col, int width )
c801d85f 4335{
5b077d48
RR
4336 m_mainWin->SetColumnWidth( col, width );
4337 return TRUE;
e1e955e1 4338}
c801d85f 4339
fd9811b1 4340int wxListCtrl::GetCountPerPage() const
c801d85f
KB
4341{
4342 return m_mainWin->GetCountPerPage(); // different from Windows ?
e1e955e1 4343}
c801d85f 4344
e487524e 4345bool wxListCtrl::GetItem( wxListItem &info ) const
c801d85f 4346{
5b077d48
RR
4347 m_mainWin->GetItem( info );
4348 return TRUE;
e1e955e1 4349}
c801d85f
KB
4350
4351bool wxListCtrl::SetItem( wxListItem &info )
4352{
5b077d48
RR
4353 m_mainWin->SetItem( info );
4354 return TRUE;
e1e955e1 4355}
c801d85f 4356
debe6624 4357long wxListCtrl::SetItem( long index, int col, const wxString& label, int imageId )
c801d85f 4358{
5b077d48
RR
4359 wxListItem info;
4360 info.m_text = label;
4361 info.m_mask = wxLIST_MASK_TEXT;
4362 info.m_itemId = index;
4363 info.m_col = col;
4364 if ( imageId > -1 )
4365 {
4366 info.m_image = imageId;
4367 info.m_mask |= wxLIST_MASK_IMAGE;
4368 };
4369 m_mainWin->SetItem(info);
4370 return TRUE;
e1e955e1 4371}
c801d85f 4372
e487524e 4373int wxListCtrl::GetItemState( long item, long stateMask ) const
c801d85f 4374{
5b077d48 4375 return m_mainWin->GetItemState( item, stateMask );
e1e955e1 4376}
c801d85f 4377
debe6624 4378bool wxListCtrl::SetItemState( long item, long state, long stateMask )
c801d85f 4379{
5b077d48
RR
4380 m_mainWin->SetItemState( item, state, stateMask );
4381 return TRUE;
e1e955e1 4382}
c801d85f 4383
debe6624 4384bool wxListCtrl::SetItemImage( long item, int image, int WXUNUSED(selImage) )
c801d85f 4385{
5b077d48
RR
4386 wxListItem info;
4387 info.m_image = image;
4388 info.m_mask = wxLIST_MASK_IMAGE;
4389 info.m_itemId = item;
4390 m_mainWin->SetItem( info );
4391 return TRUE;
e1e955e1 4392}
c801d85f 4393
e487524e 4394wxString wxListCtrl::GetItemText( long item ) const
c801d85f 4395{
5b077d48
RR
4396 wxListItem info;
4397 info.m_itemId = item;
4398 m_mainWin->GetItem( info );
4399 return info.m_text;
e1e955e1 4400}
c801d85f 4401
debe6624 4402void wxListCtrl::SetItemText( long item, const wxString &str )
c801d85f 4403{
5b077d48
RR
4404 wxListItem info;
4405 info.m_mask = wxLIST_MASK_TEXT;
4406 info.m_itemId = item;
4407 info.m_text = str;
4408 m_mainWin->SetItem( info );
e1e955e1 4409}
c801d85f 4410
e487524e 4411long wxListCtrl::GetItemData( long item ) const
c801d85f 4412{
5b077d48
RR
4413 wxListItem info;
4414 info.m_itemId = item;
4415 m_mainWin->GetItem( info );
4416 return info.m_data;
e1e955e1 4417}
c801d85f 4418
debe6624 4419bool wxListCtrl::SetItemData( long item, long data )
c801d85f 4420{
5b077d48
RR
4421 wxListItem info;
4422 info.m_mask = wxLIST_MASK_DATA;
4423 info.m_itemId = item;
4424 info.m_data = data;
4425 m_mainWin->SetItem( info );
4426 return TRUE;
e1e955e1 4427}
c801d85f 4428
0a240683 4429bool wxListCtrl::GetItemRect( long item, wxRect &rect, int WXUNUSED(code) ) const
c801d85f 4430{
5b077d48
RR
4431 m_mainWin->GetItemRect( item, rect );
4432 return TRUE;
e1e955e1 4433}
c801d85f 4434
e487524e 4435bool wxListCtrl::GetItemPosition( long item, wxPoint& pos ) const
c801d85f 4436{
5b077d48
RR
4437 m_mainWin->GetItemPosition( item, pos );
4438 return TRUE;
e1e955e1 4439}
c801d85f 4440
debe6624 4441bool wxListCtrl::SetItemPosition( long WXUNUSED(item), const wxPoint& WXUNUSED(pos) )
c801d85f 4442{
5b077d48 4443 return 0;
e1e955e1 4444}
c801d85f 4445
fd9811b1 4446int wxListCtrl::GetItemCount() const
c801d85f 4447{
5b077d48 4448 return m_mainWin->GetItemCount();
e1e955e1 4449}
c801d85f 4450
fd9811b1 4451int wxListCtrl::GetColumnCount() const
92976ab6 4452{
5b077d48 4453 return m_mainWin->GetColumnCount();
92976ab6
RR
4454}
4455
33d0b396
RR
4456void wxListCtrl::SetItemSpacing( int spacing, bool isSmall )
4457{
5b077d48 4458 m_mainWin->SetItemSpacing( spacing, isSmall );
e1e955e1 4459}
33d0b396 4460
e487524e 4461int wxListCtrl::GetItemSpacing( bool isSmall ) const
c801d85f 4462{
5b077d48 4463 return m_mainWin->GetItemSpacing( isSmall );
e1e955e1 4464}
c801d85f 4465
fd9811b1 4466int wxListCtrl::GetSelectedItemCount() const
c801d85f 4467{
5b077d48 4468 return m_mainWin->GetSelectedItemCount();
e1e955e1 4469}
c801d85f 4470
fd9811b1 4471wxColour wxListCtrl::GetTextColour() const
c801d85f 4472{
0530737d 4473 return GetForegroundColour();
e1e955e1 4474}
c801d85f 4475
0530737d 4476void wxListCtrl::SetTextColour(const wxColour& col)
c801d85f 4477{
0530737d 4478 SetForegroundColour(col);
e1e955e1 4479}
c801d85f 4480
fd9811b1 4481long wxListCtrl::GetTopItem() const
c801d85f 4482{
5b077d48 4483 return 0;
e1e955e1 4484}
c801d85f 4485
6de97a3b 4486long wxListCtrl::GetNextItem( long item, int geom, int state ) const
c801d85f 4487{
5b077d48 4488 return m_mainWin->GetNextItem( item, geom, state );
e1e955e1 4489}
c801d85f 4490
e487524e 4491wxImageList *wxListCtrl::GetImageList(int which) const
c801d85f 4492{
5b077d48
RR
4493 if (which == wxIMAGE_LIST_NORMAL)
4494 {
4495 return m_imageListNormal;
4496 }
4497 else if (which == wxIMAGE_LIST_SMALL)
4498 {
4499 return m_imageListSmall;
4500 }
4501 else if (which == wxIMAGE_LIST_STATE)
4502 {
4503 return m_imageListState;
4504 }
4505 return (wxImageList *) NULL;
e1e955e1 4506}
c801d85f 4507
debe6624 4508void wxListCtrl::SetImageList( wxImageList *imageList, int which )
c801d85f 4509{
2e12c11a
VS
4510 if ( which == wxIMAGE_LIST_NORMAL )
4511 {
4512 if (m_ownsImageListNormal) delete m_imageListNormal;
4513 m_imageListNormal = imageList;
4514 m_ownsImageListNormal = FALSE;
4515 }
4516 else if ( which == wxIMAGE_LIST_SMALL )
4517 {
4518 if (m_ownsImageListSmall) delete m_imageListSmall;
4519 m_imageListSmall = imageList;
4520 m_ownsImageListSmall = FALSE;
4521 }
4522 else if ( which == wxIMAGE_LIST_STATE )
4523 {
4524 if (m_ownsImageListState) delete m_imageListState;
4525 m_imageListState = imageList;
4526 m_ownsImageListState = FALSE;
4527 }
4528
5b077d48 4529 m_mainWin->SetImageList( imageList, which );
e1e955e1 4530}
c801d85f 4531
2e12c11a
VS
4532void wxListCtrl::AssignImageList(wxImageList *imageList, int which)
4533{
4534 SetImageList(imageList, which);
4535 if ( which == wxIMAGE_LIST_NORMAL )
4536 m_ownsImageListNormal = TRUE;
4537 else if ( which == wxIMAGE_LIST_SMALL )
4538 m_ownsImageListSmall = TRUE;
4539 else if ( which == wxIMAGE_LIST_STATE )
4540 m_ownsImageListState = TRUE;
4541}
4542
debe6624 4543bool wxListCtrl::Arrange( int WXUNUSED(flag) )
c801d85f 4544{
5b077d48 4545 return 0;
e1e955e1 4546}
c801d85f 4547
debe6624 4548bool wxListCtrl::DeleteItem( long item )
c801d85f 4549{
5b077d48
RR
4550 m_mainWin->DeleteItem( item );
4551 return TRUE;
e1e955e1 4552}
c801d85f 4553
fd9811b1 4554bool wxListCtrl::DeleteAllItems()
c801d85f 4555{
5b077d48
RR
4556 m_mainWin->DeleteAllItems();
4557 return TRUE;
e1e955e1 4558}
c801d85f 4559
4f22cf8d 4560bool wxListCtrl::DeleteAllColumns()
bd8289c1 4561{
24b9f055
VZ
4562 size_t count = m_mainWin->m_columns.GetCount();
4563 for ( size_t n = 0; n < count; n++ )
bd8289c1 4564 DeleteColumn(n);
bffa1c77 4565
5b077d48 4566 return TRUE;
4f22cf8d
RR
4567}
4568
4569void wxListCtrl::ClearAll()
4570{
5b077d48 4571 m_mainWin->DeleteEverything();
bd8289c1
VZ
4572}
4573
debe6624 4574bool wxListCtrl::DeleteColumn( int col )
c801d85f 4575{
5b077d48
RR
4576 m_mainWin->DeleteColumn( col );
4577 return TRUE;
e1e955e1 4578}
c801d85f 4579
e179bd65 4580void wxListCtrl::Edit( long item )
c801d85f 4581{
cf1dfa6b 4582 m_mainWin->EditLabel( item );
e1e955e1 4583}
c801d85f 4584
debe6624 4585bool wxListCtrl::EnsureVisible( long item )
c801d85f 4586{
5b077d48
RR
4587 m_mainWin->EnsureVisible( item );
4588 return TRUE;
e1e955e1 4589}
c801d85f 4590
debe6624 4591long wxListCtrl::FindItem( long start, const wxString& str, bool partial )
c801d85f 4592{
5b077d48 4593 return m_mainWin->FindItem( start, str, partial );
e1e955e1 4594}
c801d85f 4595
debe6624 4596long wxListCtrl::FindItem( long start, long data )
c801d85f 4597{
5b077d48 4598 return m_mainWin->FindItem( start, data );
e1e955e1 4599}
c801d85f 4600
bd8289c1 4601long wxListCtrl::FindItem( long WXUNUSED(start), const wxPoint& WXUNUSED(pt),
debe6624 4602 int WXUNUSED(direction))
c801d85f 4603{
5b077d48 4604 return 0;
e1e955e1 4605}
c801d85f
KB
4606
4607long wxListCtrl::HitTest( const wxPoint &point, int &flags )
4608{
5b077d48 4609 return m_mainWin->HitTest( (int)point.x, (int)point.y, flags );
e1e955e1 4610}
c801d85f
KB
4611
4612long wxListCtrl::InsertItem( wxListItem& info )
4613{
5b077d48 4614 m_mainWin->InsertItem( info );
2ebcd5f5 4615 return info.m_itemId;
e1e955e1 4616}
c801d85f 4617
debe6624 4618long wxListCtrl::InsertItem( long index, const wxString &label )
c801d85f 4619{
51cc4dad
RR
4620 wxListItem info;
4621 info.m_text = label;
4622 info.m_mask = wxLIST_MASK_TEXT;
4623 info.m_itemId = index;
4624 return InsertItem( info );
e1e955e1 4625}
c801d85f 4626
debe6624 4627long wxListCtrl::InsertItem( long index, int imageIndex )
c801d85f 4628{
51cc4dad
RR
4629 wxListItem info;
4630 info.m_mask = wxLIST_MASK_IMAGE;
4631 info.m_image = imageIndex;
4632 info.m_itemId = index;
4633 return InsertItem( info );
e1e955e1 4634}
c801d85f 4635
debe6624 4636long wxListCtrl::InsertItem( long index, const wxString &label, int imageIndex )
c801d85f 4637{
51cc4dad
RR
4638 wxListItem info;
4639 info.m_text = label;
4640 info.m_image = imageIndex;
4641 info.m_mask = wxLIST_MASK_TEXT | wxLIST_MASK_IMAGE;
4642 info.m_itemId = index;
4643 return InsertItem( info );
e1e955e1 4644}
c801d85f 4645
debe6624 4646long wxListCtrl::InsertColumn( long col, wxListItem &item )
c801d85f 4647{
d3e90957 4648 wxASSERT( m_headerWin );
51cc4dad 4649 m_mainWin->InsertColumn( col, item );
d3e90957 4650 m_headerWin->Refresh();
25e3a937 4651
51cc4dad 4652 return 0;
e1e955e1 4653}
c801d85f 4654
debe6624
JS
4655long wxListCtrl::InsertColumn( long col, const wxString &heading,
4656 int format, int width )
c801d85f 4657{
51cc4dad
RR
4658 wxListItem item;
4659 item.m_mask = wxLIST_MASK_TEXT | wxLIST_MASK_FORMAT;
4660 item.m_text = heading;
4661 if (width >= -2)
4662 {
4663 item.m_mask |= wxLIST_MASK_WIDTH;
4664 item.m_width = width;
4665 }
4666 item.m_format = format;
c801d85f 4667
51cc4dad 4668 return InsertColumn( col, item );
e1e955e1 4669}
c801d85f 4670
debe6624 4671bool wxListCtrl::ScrollList( int WXUNUSED(dx), int WXUNUSED(dy) )
c801d85f 4672{
51cc4dad 4673 return 0;
e1e955e1 4674}
c801d85f
KB
4675
4676// Sort items.
4677// fn is a function which takes 3 long arguments: item1, item2, data.
4678// item1 is the long data associated with a first item (NOT the index).
4679// item2 is the long data associated with a second item (NOT the index).
4680// data is the same value as passed to SortItems.
4681// The return value is a negative number if the first item should precede the second
4682// item, a positive number of the second item should precede the first,
4683// or zero if the two items are equivalent.
4684// data is arbitrary data to be passed to the sort function.
4685
4686bool wxListCtrl::SortItems( wxListCtrlCompare fn, long data )
4687{
51cc4dad
RR
4688 m_mainWin->SortItems( fn, data );
4689 return TRUE;
e1e955e1 4690}
c801d85f 4691
cf1dfa6b 4692// ----------------------------------------------------------------------------
b54e41c5 4693// event handlers
cf1dfa6b
VZ
4694// ----------------------------------------------------------------------------
4695
b54e41c5 4696void wxListCtrl::OnSize(wxSizeEvent& event)
53010e52 4697{
b54e41c5 4698 if ( !m_mainWin )
cf1dfa6b 4699 return;
53010e52 4700
b54e41c5 4701 int cw, ch;
51cc4dad 4702 GetClientSize( &cw, &ch );
bd8289c1 4703
cf1dfa6b 4704 if ( m_mainWin->HasHeader() )
51cc4dad 4705 {
cf1dfa6b
VZ
4706 m_headerWin->SetSize( 0, 0, cw, HEADER_HEIGHT );
4707 m_mainWin->SetSize( 0, HEADER_HEIGHT + 1, cw, ch - HEADER_HEIGHT - 1 );
51cc4dad 4708 }
cf1dfa6b 4709 else // no header window
51cc4dad 4710 {
cf1dfa6b 4711 m_mainWin->SetSize( 0, 0, cw, ch );
51cc4dad 4712 }
bd8289c1 4713
b54e41c5
VZ
4714 m_mainWin->RecalculatePositions();
4715}
cf1dfa6b 4716
b54e41c5
VZ
4717void wxListCtrl::OnIdle( wxIdleEvent & event )
4718{
4719 event.Skip();
f6bcfd97 4720
b54e41c5
VZ
4721 // do it only if needed
4722 if ( !m_mainWin->m_dirty )
4723 return;
4724
4725 m_mainWin->RecalculatePositions();
e1e955e1 4726}
53010e52 4727
cf1dfa6b
VZ
4728// ----------------------------------------------------------------------------
4729// font/colours
4730// ----------------------------------------------------------------------------
4731
f03fc89f 4732bool wxListCtrl::SetBackgroundColour( const wxColour &colour )
bd8289c1 4733{
51cc4dad
RR
4734 if (m_mainWin)
4735 {
4736 m_mainWin->SetBackgroundColour( colour );
4737 m_mainWin->m_dirty = TRUE;
4738 }
004fd0c8 4739
f03fc89f 4740 return TRUE;
e4d06860
RR
4741}
4742
f03fc89f 4743bool wxListCtrl::SetForegroundColour( const wxColour &colour )
bd8289c1 4744{
f03fc89f
VZ
4745 if ( !wxWindow::SetForegroundColour( colour ) )
4746 return FALSE;
004fd0c8 4747
51cc4dad
RR
4748 if (m_mainWin)
4749 {
4750 m_mainWin->SetForegroundColour( colour );
4751 m_mainWin->m_dirty = TRUE;
4752 }
004fd0c8 4753
51cc4dad
RR
4754 if (m_headerWin)
4755 {
4756 m_headerWin->SetForegroundColour( colour );
4757 }
f03fc89f
VZ
4758
4759 return TRUE;
e4d06860 4760}
bd8289c1 4761
f03fc89f 4762bool wxListCtrl::SetFont( const wxFont &font )
bd8289c1 4763{
f03fc89f
VZ
4764 if ( !wxWindow::SetFont( font ) )
4765 return FALSE;
004fd0c8 4766
51cc4dad
RR
4767 if (m_mainWin)
4768 {
4769 m_mainWin->SetFont( font );
4770 m_mainWin->m_dirty = TRUE;
4771 }
004fd0c8 4772
51cc4dad
RR
4773 if (m_headerWin)
4774 {
4775 m_headerWin->SetFont( font );
4776 }
f03fc89f
VZ
4777
4778 return TRUE;
e4d06860 4779}
c801d85f 4780
cf1dfa6b
VZ
4781// ----------------------------------------------------------------------------
4782// methods forwarded to m_mainWin
4783// ----------------------------------------------------------------------------
4784
efbb7287
VZ
4785#if wxUSE_DRAG_AND_DROP
4786
4787void wxListCtrl::SetDropTarget( wxDropTarget *dropTarget )
4788{
4789 m_mainWin->SetDropTarget( dropTarget );
4790}
4791
4792wxDropTarget *wxListCtrl::GetDropTarget() const
4793{
4794 return m_mainWin->GetDropTarget();
4795}
4796
4797#endif // wxUSE_DRAG_AND_DROP
4798
4799bool wxListCtrl::SetCursor( const wxCursor &cursor )
4800{
4801 return m_mainWin ? m_mainWin->wxWindow::SetCursor(cursor) : FALSE;
4802}
4803
4804wxColour wxListCtrl::GetBackgroundColour() const
4805{
4806 return m_mainWin ? m_mainWin->GetBackgroundColour() : wxColour();
4807}
4808
4809wxColour wxListCtrl::GetForegroundColour() const
4810{
4811 return m_mainWin ? m_mainWin->GetForegroundColour() : wxColour();
4812}
4813
4814bool wxListCtrl::DoPopupMenu( wxMenu *menu, int x, int y )
4815{
3a8c693a 4816#if wxUSE_MENUS
efbb7287 4817 return m_mainWin->PopupMenu( menu, x, y );
3a8c693a
VZ
4818#else
4819 return FALSE;
4820#endif // wxUSE_MENUS
efbb7287
VZ
4821}
4822
4823void wxListCtrl::SetFocus()
4824{
4825 /* The test in window.cpp fails as we are a composite
4826 window, so it checks against "this", but not m_mainWin. */
4827 if ( FindFocus() != this )
4828 m_mainWin->SetFocus();
4829}
1e6feb95 4830
2c1f73ee
VZ
4831// ----------------------------------------------------------------------------
4832// virtual list control support
4833// ----------------------------------------------------------------------------
4834
4835wxString wxListCtrl::OnGetItemText(long item, long col) const
4836{
4837 // this is a pure virtual function, in fact - which is not really pure
4838 // because the controls which are not virtual don't need to implement it
4839 wxFAIL_MSG( _T("not supposed to be called") );
4840
4841 return wxEmptyString;
4842}
4843
4844int wxListCtrl::OnGetItemImage(long item) const
4845{
4846 // same as above
4847 wxFAIL_MSG( _T("not supposed to be called") );
4848
4849 return -1;
4850}
4851
4852void wxListCtrl::SetItemCount(long count)
4853{
4854 wxASSERT_MSG( IsVirtual(), _T("this is for virtual controls only") );
4855
4856 m_mainWin->SetItemCount(count);
4857}
4858
1e6feb95 4859#endif // wxUSE_LISTCTRL