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