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