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