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