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