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