Modified form of Patch #1611222, adds wxSearchCtrl (generic & native carbon HISearchF...
[wxWidgets.git] / src / generic / srchctlg.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/generic/srchctlg.cpp
3 // Purpose: implements wxSearchCtrl as a composite control
4 // Author: Vince Harron
5 // Modified by:
6 // Created: 2006-02-19
7 // RCS-ID:
8 // Copyright: Vince Harron
9 // License: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "srchctlg.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28 #pragma hdrstop
29 #endif
30
31 #ifndef WX_PRECOMP
32 #include "wx/button.h"
33 #endif //WX_PRECOMP
34
35 #if wxUSE_SEARCHCTRL
36
37 #include "wx/srchctrl.h"
38
39 #if !USE_NATIVE_SEARCH_CONTROL
40
41 #include "wx/image.h"
42
43 #define WXMIN(a,b) (a)<(b)?(a):(b)
44 #define WXMAX(a,b) (a)>(b)?(a):(b)
45
46 // ----------------------------------------------------------------------------
47 // constants
48 // ----------------------------------------------------------------------------
49
50 // the margin between the text control and the search/cancel buttons
51 static const wxCoord MARGIN = 2;
52
53 // border around all controls to compensate for wxSIMPLE_BORDER
54 #if defined(__WXMSW__)
55 static const wxCoord BORDER = 0;
56 static const wxCoord ICON_MARGIN = 2;
57 static const wxCoord ICON_OFFSET = 2;
58 #else
59 static const wxCoord BORDER = 2;
60 static const wxCoord ICON_MARGIN = 0;
61 static const wxCoord ICON_OFFSET = 0;
62 #endif
63
64 // ----------------------------------------------------------------------------
65 // wxSearchTextCtrl: text control used by search control
66 // ----------------------------------------------------------------------------
67
68 class wxSearchTextCtrl : public wxTextCtrl
69 {
70 public:
71 wxSearchTextCtrl(wxSearchCtrl *search, const wxString& value, int style)
72 : wxTextCtrl(search, wxID_ANY, value, wxDefaultPosition, wxDefaultSize,
73 style | wxNO_BORDER)
74 {
75 m_search = search;
76
77 // remove the default minsize, the searchctrl will have one instead
78 SetSizeHints(wxDefaultCoord,wxDefaultCoord);
79 }
80
81 protected:
82 void OnText(wxCommandEvent& eventText)
83 {
84 wxCommandEvent event(eventText);
85 event.SetEventObject(m_search);
86 event.SetId(m_search->GetId());
87
88 m_search->GetEventHandler()->ProcessEvent(event);
89 }
90
91 void OnTextUrl(wxTextUrlEvent& eventText)
92 {
93 // copy constructor is disabled for some reason?
94 //wxTextUrlEvent event(eventText);
95 wxTextUrlEvent event(
96 m_search->GetId(),
97 eventText.GetMouseEvent(),
98 eventText.GetURLStart(),
99 eventText.GetURLEnd()
100 );
101 event.SetEventObject(m_search);
102
103 m_search->GetEventHandler()->ProcessEvent(event);
104 }
105
106 private:
107 wxSearchCtrl* m_search;
108
109 DECLARE_EVENT_TABLE()
110 };
111
112 BEGIN_EVENT_TABLE(wxSearchTextCtrl, wxTextCtrl)
113 EVT_TEXT(wxID_ANY, wxSearchTextCtrl::OnText)
114 EVT_TEXT_ENTER(wxID_ANY, wxSearchTextCtrl::OnText)
115 EVT_TEXT_URL(wxID_ANY, wxSearchTextCtrl::OnTextUrl)
116 EVT_TEXT_MAXLEN(wxID_ANY, wxSearchTextCtrl::OnText)
117 END_EVENT_TABLE()
118
119 // ----------------------------------------------------------------------------
120 // wxSearchButton: search button used by search control
121 // ----------------------------------------------------------------------------
122
123 class wxSearchButton : public wxControl
124 {
125 public:
126 wxSearchButton(wxSearchCtrl *search, int eventType, const wxBitmap& bmp)
127 : wxControl(search, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER),
128 m_search(search),
129 m_eventType(eventType),
130 m_bmp(bmp)
131 { }
132
133 void SetBitmapLabel(const wxBitmap& label) { m_bmp = label; }
134
135
136 protected:
137 wxSize DoGetBestSize() const
138 {
139 return wxSize(m_bmp.GetWidth(), m_bmp.GetHeight());
140 }
141
142 void OnLeftUp(wxMouseEvent&)
143 {
144 wxCommandEvent event(m_eventType, m_search->GetId());
145 event.SetEventObject(m_search);
146
147 GetEventHandler()->ProcessEvent(event);
148
149 m_search->SetFocus();
150
151 if ( m_eventType == wxEVT_COMMAND_SEARCHCTRL_SEARCH )
152 {
153 // this happens automatically, just like on Mac OS X
154 m_search->PopupSearchMenu();
155 }
156 }
157
158 void OnPaint(wxPaintEvent&)
159 {
160 wxPaintDC dc(this);
161 dc.DrawBitmap(m_bmp, 0,0, true);
162 }
163
164
165 private:
166 wxSearchCtrl *m_search;
167 wxEventType m_eventType;
168 wxBitmap m_bmp;
169
170 DECLARE_EVENT_TABLE()
171 };
172
173 BEGIN_EVENT_TABLE(wxSearchButton, wxButton)
174 EVT_LEFT_UP(wxSearchButton::OnLeftUp)
175 EVT_PAINT(wxSearchButton::OnPaint)
176 END_EVENT_TABLE()
177
178 BEGIN_EVENT_TABLE(wxSearchCtrl, wxSearchCtrlBase)
179 EVT_SEARCHCTRL_SEARCH(wxID_ANY, wxSearchCtrl::OnSearchButton)
180 EVT_SET_FOCUS(wxSearchCtrl::OnSetFocus)
181 END_EVENT_TABLE()
182
183 IMPLEMENT_DYNAMIC_CLASS(wxSearchCtrl, wxSearchCtrlBase)
184
185 // ============================================================================
186 // implementation
187 // ============================================================================
188
189 // ----------------------------------------------------------------------------
190 // wxSearchCtrl creation
191 // ----------------------------------------------------------------------------
192
193 // creation
194 // --------
195
196 wxSearchCtrl::wxSearchCtrl()
197 {
198 Init();
199 }
200
201 wxSearchCtrl::wxSearchCtrl(wxWindow *parent, wxWindowID id,
202 const wxString& value,
203 const wxPoint& pos,
204 const wxSize& size,
205 long style,
206 const wxValidator& validator,
207 const wxString& name)
208 {
209 Init();
210
211 Create(parent, id, value, pos, size, style, validator, name);
212 }
213
214 void wxSearchCtrl::Init()
215 {
216 m_text = 0;
217 m_searchButton = 0;
218 m_cancelButton = 0;
219 m_menu = 0;
220
221 m_searchButtonVisible = true;
222 m_cancelButtonVisible = false;
223
224 m_searchMenuBitmapUser = false;
225 m_searchBitmapUser = false;
226 m_cancelBitmapUser = false;
227 }
228
229 bool wxSearchCtrl::Create(wxWindow *parent, wxWindowID id,
230 const wxString& value,
231 const wxPoint& pos,
232 const wxSize& size,
233 long style,
234 const wxValidator& validator,
235 const wxString& name)
236 {
237 if ( !wxTextCtrlBase::Create(parent, id, pos, size, wxSIMPLE_BORDER | style, validator, name) )
238 {
239 return false;
240 }
241
242 m_text = new wxSearchTextCtrl(this, value, style & ~wxBORDER_MASK);
243
244 wxSize sizeText = m_text->GetBestSize();
245
246 m_searchButton = new wxSearchButton(this,wxEVT_COMMAND_SEARCHCTRL_SEARCH,m_searchBitmap);
247 m_cancelButton = new wxSearchButton(this,wxEVT_COMMAND_SEARCHCTRL_CANCEL,m_cancelBitmap);
248
249 SetForegroundColour( m_text->GetForegroundColour() );
250 m_searchButton->SetForegroundColour( m_text->GetForegroundColour() );
251 m_cancelButton->SetForegroundColour( m_text->GetForegroundColour() );
252
253 SetBackgroundColour( m_text->GetBackgroundColour() );
254 m_searchButton->SetBackgroundColour( m_text->GetBackgroundColour() );
255 m_cancelButton->SetBackgroundColour( m_text->GetBackgroundColour() );
256
257 RecalcBitmaps();
258
259 SetInitialSize(size);
260 Move(pos);
261 return true;
262 }
263
264 wxSearchCtrl::~wxSearchCtrl()
265 {
266 delete m_text;
267 delete m_searchButton;
268 delete m_cancelButton;
269 delete m_menu;
270 }
271
272
273 // search control specific interfaces
274 void wxSearchCtrl::SetMenu( wxMenu* menu )
275 {
276 if ( menu == m_menu )
277 {
278 // no change
279 return;
280 }
281 delete m_menu;
282 bool hadMenu = (m_menu!=0);
283 m_menu = menu;
284
285 if ( m_menu && !hadMenu )
286 {
287 m_searchButton->SetBitmapLabel(m_searchMenuBitmap);
288 m_searchButton->Refresh();
289 if ( !m_searchButtonVisible )
290 {
291 // adding the menu will force the search button to be visible
292 wxRect rect = GetRect();
293 LayoutControls(0, 0, rect.GetWidth(), rect.GetHeight());
294 }
295 }
296 else if ( !m_menu && hadMenu )
297 {
298 m_searchButton->SetBitmapLabel(m_searchBitmap);
299 if ( m_searchButtonVisible )
300 {
301 m_searchButton->Refresh();
302 }
303 else
304 {
305 wxRect rect = GetRect();
306 LayoutControls(0, 0, rect.GetWidth(), rect.GetHeight());
307 }
308 }
309 }
310
311 wxMenu* wxSearchCtrl::GetMenu()
312 {
313 return m_menu;
314 }
315
316 void wxSearchCtrl::SetSearchButtonVisible( bool show )
317 {
318 if ( m_searchButtonVisible == show )
319 {
320 // no change
321 return;
322 }
323 m_searchButtonVisible = show;
324 if ( m_searchButtonVisible )
325 {
326 RecalcBitmaps();
327 }
328
329 wxRect rect = GetRect();
330 LayoutControls(0, 0, rect.GetWidth(), rect.GetHeight());
331 }
332
333 bool wxSearchCtrl::GetSearchButtonVisible() const
334 {
335 return m_searchButtonVisible;
336 }
337
338
339 void wxSearchCtrl::SetCancelButtonVisible( bool show )
340 {
341 if ( m_cancelButtonVisible == show )
342 {
343 // no change
344 return;
345 }
346 m_cancelButtonVisible = show;
347
348 wxRect rect = GetRect();
349 LayoutControls(0, 0, rect.GetWidth(), rect.GetHeight());
350 }
351
352 bool wxSearchCtrl::GetCancelButtonVisible() const
353 {
354 return m_cancelButtonVisible;
355 }
356
357
358 // ----------------------------------------------------------------------------
359 // geometry
360 // ----------------------------------------------------------------------------
361
362 wxSize wxSearchCtrl::DoGetBestSize() const
363 {
364 wxSize sizeText = m_text->GetBestSize();
365 wxSize sizeSearch(0,0);
366 wxSize sizeCancel(0,0);
367 int searchMargin = 0;
368 int cancelMargin = 0;
369 if ( m_searchButtonVisible || m_menu )
370 {
371 sizeSearch = m_searchButton->GetBestSize();
372 searchMargin = MARGIN;
373 }
374 if ( m_cancelButtonVisible )
375 {
376 sizeCancel = m_cancelButton->GetBestSize();
377 cancelMargin = MARGIN;
378 }
379
380 int horizontalBorder = 1 + ( sizeText.y - sizeText.y * 14 / 21 ) / 2;
381
382 // buttons are square and equal to the height of the text control
383 int height = sizeText.y;
384 return wxSize(sizeSearch.x + searchMargin + sizeText.x + cancelMargin + sizeCancel.x + 2*horizontalBorder,
385 height + 2*BORDER);
386 }
387
388 void wxSearchCtrl::DoMoveWindow(int x, int y, int width, int height)
389 {
390 wxSearchCtrlBase::DoMoveWindow(x, y, width, height);
391
392 LayoutControls(0, 0, width, height);
393 }
394
395 void wxSearchCtrl::LayoutControls(int x, int y, int width, int height)
396 {
397 wxSize sizeText = m_text->GetBestSize();
398 // make room for the search menu & clear button
399 int horizontalBorder = 1 + ( sizeText.y - sizeText.y * 14 / 21 ) / 2;
400 x += horizontalBorder;
401 y += BORDER;
402 width -= horizontalBorder*2;
403 height -= BORDER*2;
404
405 wxSize sizeSearch(0,0);
406 wxSize sizeCancel(0,0);
407 int searchMargin = 0;
408 int cancelMargin = 0;
409 if ( m_searchButtonVisible || m_menu )
410 {
411 sizeSearch = m_searchButton->GetBestSize();
412 searchMargin = MARGIN;
413 }
414 if ( m_cancelButtonVisible )
415 {
416 sizeCancel = m_cancelButton->GetBestSize();
417 cancelMargin = MARGIN;
418 }
419 m_searchButton->Show( m_searchButtonVisible || m_menu );
420 m_cancelButton->Show( m_cancelButtonVisible );
421
422 if ( sizeSearch.x + sizeCancel.x > width )
423 {
424 sizeSearch.x = width/2;
425 sizeCancel.x = width/2;
426 searchMargin = 0;
427 cancelMargin = 0;
428 }
429 wxCoord textWidth = width - sizeSearch.x - sizeCancel.x - searchMargin - cancelMargin;
430
431 // position the subcontrols inside the client area
432
433 m_searchButton->SetSize(x, y + ICON_OFFSET, sizeSearch.x, height);
434 m_text->SetSize(x + sizeSearch.x + searchMargin, y + ICON_OFFSET, textWidth, height);
435 m_cancelButton->SetSize(x + sizeSearch.x + searchMargin + textWidth + cancelMargin,
436 y + ICON_OFFSET, sizeCancel.x, height);
437 }
438
439
440 // accessors
441 // ---------
442
443 wxString wxSearchCtrl::GetValue() const
444 {
445 return m_text->GetValue();
446 }
447 void wxSearchCtrl::SetValue(const wxString& value)
448 {
449 m_text->SetValue(value);
450 }
451
452 wxString wxSearchCtrl::GetRange(long from, long to) const
453 {
454 return m_text->GetRange(from, to);
455 }
456
457 int wxSearchCtrl::GetLineLength(long lineNo) const
458 {
459 return m_text->GetLineLength(lineNo);
460 }
461 wxString wxSearchCtrl::GetLineText(long lineNo) const
462 {
463 return m_text->GetLineText(lineNo);
464 }
465 int wxSearchCtrl::GetNumberOfLines() const
466 {
467 return m_text->GetNumberOfLines();
468 }
469
470 bool wxSearchCtrl::IsModified() const
471 {
472 return m_text->IsModified();
473 }
474 bool wxSearchCtrl::IsEditable() const
475 {
476 return m_text->IsEditable();
477 }
478
479 // more readable flag testing methods
480 bool wxSearchCtrl::IsSingleLine() const
481 {
482 return m_text->IsSingleLine();
483 }
484 bool wxSearchCtrl::IsMultiLine() const
485 {
486 return m_text->IsMultiLine();
487 }
488
489 // If the return values from and to are the same, there is no selection.
490 void wxSearchCtrl::GetSelection(long* from, long* to) const
491 {
492 m_text->GetSelection(from, to);
493 }
494
495 wxString wxSearchCtrl::GetStringSelection() const
496 {
497 return m_text->GetStringSelection();
498 }
499
500 // operations
501 // ----------
502
503 // editing
504 void wxSearchCtrl::Clear()
505 {
506 m_text->Clear();
507 }
508 void wxSearchCtrl::Replace(long from, long to, const wxString& value)
509 {
510 m_text->Replace(from, to, value);
511 }
512 void wxSearchCtrl::Remove(long from, long to)
513 {
514 m_text->Remove(from, to);
515 }
516
517 // load/save the controls contents from/to the file
518 bool wxSearchCtrl::LoadFile(const wxString& file)
519 {
520 return m_text->LoadFile(file);
521 }
522 bool wxSearchCtrl::SaveFile(const wxString& file)
523 {
524 return m_text->SaveFile(file);
525 }
526
527 // sets/clears the dirty flag
528 void wxSearchCtrl::MarkDirty()
529 {
530 m_text->MarkDirty();
531 }
532 void wxSearchCtrl::DiscardEdits()
533 {
534 m_text->DiscardEdits();
535 }
536
537 // set the max number of characters which may be entered in a single line
538 // text control
539 void wxSearchCtrl::SetMaxLength(unsigned long len)
540 {
541 m_text->SetMaxLength(len);
542 }
543
544 // writing text inserts it at the current position, appending always
545 // inserts it at the end
546 void wxSearchCtrl::WriteText(const wxString& text)
547 {
548 m_text->WriteText(text);
549 }
550 void wxSearchCtrl::AppendText(const wxString& text)
551 {
552 m_text->AppendText(text);
553 }
554
555 // insert the character which would have resulted from this key event,
556 // return true if anything has been inserted
557 bool wxSearchCtrl::EmulateKeyPress(const wxKeyEvent& event)
558 {
559 return m_text->EmulateKeyPress(event);
560 }
561
562 // text control under some platforms supports the text styles: these
563 // methods allow to apply the given text style to the given selection or to
564 // set/get the style which will be used for all appended text
565 bool wxSearchCtrl::SetStyle(long start, long end, const wxTextAttr& style)
566 {
567 return m_text->SetStyle(start, end, style);
568 }
569 bool wxSearchCtrl::GetStyle(long position, wxTextAttr& style)
570 {
571 return m_text->GetStyle(position, style);
572 }
573 bool wxSearchCtrl::SetDefaultStyle(const wxTextAttr& style)
574 {
575 return m_text->SetDefaultStyle(style);
576 }
577 const wxTextAttr& wxSearchCtrl::GetDefaultStyle() const
578 {
579 return m_text->GetDefaultStyle();
580 }
581
582 // translate between the position (which is just an index in the text ctrl
583 // considering all its contents as a single strings) and (x, y) coordinates
584 // which represent column and line.
585 long wxSearchCtrl::XYToPosition(long x, long y) const
586 {
587 return m_text->XYToPosition(x, y);
588 }
589 bool wxSearchCtrl::PositionToXY(long pos, long *x, long *y) const
590 {
591 return m_text->PositionToXY(pos, x, y);
592 }
593
594 void wxSearchCtrl::ShowPosition(long pos)
595 {
596 m_text->ShowPosition(pos);
597 }
598
599 // find the character at position given in pixels
600 //
601 // NB: pt is in device coords (not adjusted for the client area origin nor
602 // scrolling)
603 wxTextCtrlHitTestResult wxSearchCtrl::HitTest(const wxPoint& pt, long *pos) const
604 {
605 return m_text->HitTest(pt, pos);
606 }
607 wxTextCtrlHitTestResult wxSearchCtrl::HitTest(const wxPoint& pt,
608 wxTextCoord *col,
609 wxTextCoord *row) const
610 {
611 return m_text->HitTest(pt, col, row);
612 }
613
614 // Clipboard operations
615 void wxSearchCtrl::Copy()
616 {
617 m_text->Copy();
618 }
619 void wxSearchCtrl::Cut()
620 {
621 m_text->Cut();
622 }
623 void wxSearchCtrl::Paste()
624 {
625 m_text->Paste();
626 }
627
628 bool wxSearchCtrl::CanCopy() const
629 {
630 return m_text->CanCopy();
631 }
632 bool wxSearchCtrl::CanCut() const
633 {
634 return m_text->CanCut();
635 }
636 bool wxSearchCtrl::CanPaste() const
637 {
638 return m_text->CanPaste();
639 }
640
641 // Undo/redo
642 void wxSearchCtrl::Undo()
643 {
644 m_text->Undo();
645 }
646 void wxSearchCtrl::Redo()
647 {
648 m_text->Redo();
649 }
650
651 bool wxSearchCtrl::CanUndo() const
652 {
653 return m_text->CanUndo();
654 }
655 bool wxSearchCtrl::CanRedo() const
656 {
657 return m_text->CanRedo();
658 }
659
660 // Insertion point
661 void wxSearchCtrl::SetInsertionPoint(long pos)
662 {
663 m_text->SetInsertionPoint(pos);
664 }
665 void wxSearchCtrl::SetInsertionPointEnd()
666 {
667 m_text->SetInsertionPointEnd();
668 }
669 long wxSearchCtrl::GetInsertionPoint() const
670 {
671 return m_text->GetInsertionPoint();
672 }
673 wxTextPos wxSearchCtrl::GetLastPosition() const
674 {
675 return m_text->GetLastPosition();
676 }
677
678 void wxSearchCtrl::SetSelection(long from, long to)
679 {
680 m_text->SetSelection(from, to);
681 }
682 void wxSearchCtrl::SelectAll()
683 {
684 m_text->SelectAll();
685 }
686
687 void wxSearchCtrl::SetEditable(bool editable)
688 {
689 m_text->SetEditable(editable);
690 }
691
692 bool wxSearchCtrl::SetFont(const wxFont& font)
693 {
694 bool result = wxSearchCtrlBase::SetFont(font);
695 if ( result && m_text )
696 {
697 result &= m_text->SetFont(font);
698 }
699 RecalcBitmaps();
700 return result;
701 }
702
703 // search control generic only
704 void wxSearchCtrl::SetSearchBitmap( const wxBitmap& bitmap )
705 {
706 m_searchBitmap = bitmap;
707 m_searchBitmapUser = bitmap.Ok();
708 if ( m_searchBitmapUser )
709 {
710 if ( m_searchButton && !m_menu )
711 {
712 m_searchButton->SetBitmapLabel( m_searchBitmap );
713 }
714 }
715 else
716 {
717 // the user bitmap was just cleared, generate one
718 RecalcBitmaps();
719 }
720 }
721
722 void wxSearchCtrl::SetSearchMenuBitmap( const wxBitmap& bitmap )
723 {
724 m_searchMenuBitmap = bitmap;
725 m_searchMenuBitmapUser = bitmap.Ok();
726 if ( m_searchMenuBitmapUser )
727 {
728 if ( m_searchButton && m_menu )
729 {
730 m_searchButton->SetBitmapLabel( m_searchMenuBitmap );
731 }
732 }
733 else
734 {
735 // the user bitmap was just cleared, generate one
736 RecalcBitmaps();
737 }
738 }
739
740 void wxSearchCtrl::SetCancelBitmap( const wxBitmap& bitmap )
741 {
742 m_cancelBitmap = bitmap;
743 m_cancelBitmapUser = bitmap.Ok();
744 if ( m_cancelBitmapUser )
745 {
746 if ( m_cancelButton )
747 {
748 m_cancelButton->SetBitmapLabel( m_cancelBitmap );
749 }
750 }
751 else
752 {
753 // the user bitmap was just cleared, generate one
754 RecalcBitmaps();
755 }
756 }
757
758 #if 0
759
760 // override streambuf method
761 #if wxHAS_TEXT_WINDOW_STREAM
762 int overflow(int i);
763 #endif // wxHAS_TEXT_WINDOW_STREAM
764
765 // stream-like insertion operators: these are always available, whether we
766 // were, or not, compiled with streambuf support
767 wxTextCtrl& operator<<(const wxString& s);
768 wxTextCtrl& operator<<(int i);
769 wxTextCtrl& operator<<(long i);
770 wxTextCtrl& operator<<(float f);
771 wxTextCtrl& operator<<(double d);
772 wxTextCtrl& operator<<(const wxChar c);
773 #endif
774
775 void wxSearchCtrl::DoSetValue(const wxString& value, int flags)
776 {
777 m_text->ChangeValue( value );
778 if ( flags & SetValue_SendEvent )
779 SendTextUpdatedEvent();
780 }
781
782 // do the window-specific processing after processing the update event
783 void wxSearchCtrl::DoUpdateWindowUI(wxUpdateUIEvent& event)
784 {
785 wxSearchCtrlBase::DoUpdateWindowUI(event);
786 }
787
788 bool wxSearchCtrl::ShouldInheritColours() const
789 {
790 return true;
791 }
792
793 // icons are rendered at 3-8 times larger than necessary and downscaled for
794 // antialiasing
795 static int GetMultiplier()
796 {
797 #ifdef __WXWINCE__
798 // speed up bitmap generation by using a small bitmap
799 return 3;
800 #else
801 int depth = ::wxDisplayDepth();
802
803 if ( depth >= 24 )
804 {
805 return 8;
806 }
807 return 6;
808 #endif
809 }
810
811 wxBitmap wxSearchCtrl::RenderSearchBitmap( int x, int y, bool renderDrop )
812 {
813 wxColour bg = GetBackgroundColour();
814 wxColour fg = GetForegroundColour();
815
816 //===============================================================================
817 // begin drawing code
818 //===============================================================================
819 // image stats
820
821 // force width:height ratio
822 if ( 14*x > y*20 )
823 {
824 // x is too big
825 x = y*20/14;
826 }
827 else
828 {
829 // y is too big
830 y = x*14/20;
831 }
832
833 // glass 11x11, top left corner
834 // handle (9,9)-(13,13)
835 // drop (13,16)-(19,6)-(16,9)
836
837 int multiplier = GetMultiplier();
838 int penWidth = multiplier * 2;
839
840 penWidth = penWidth * x / 20;
841
842 wxBitmap bitmap( multiplier*x, multiplier*y );
843 wxMemoryDC mem;
844 mem.SelectObject(bitmap);
845
846 // clear background
847 mem.SetBrush( wxBrush(bg) );
848 mem.SetPen( wxPen(bg) );
849 mem.DrawRectangle(0,0,bitmap.GetWidth(),bitmap.GetHeight());
850
851 // draw drop glass
852 mem.SetBrush( wxBrush(fg) );
853 mem.SetPen( wxPen(fg) );
854 int glassBase = 5 * x / 20;
855 int glassFactor = 2*glassBase + 1;
856 int radius = multiplier*glassFactor/2;
857 mem.DrawCircle(radius,radius,radius);
858 mem.SetBrush( wxBrush(bg) );
859 mem.SetPen( wxPen(bg) );
860 mem.DrawCircle(radius,radius,radius-penWidth);
861
862 // draw handle
863 int lineStart = radius + (radius-penWidth/2) * 707 / 1000; // 707 / 1000 = 0.707 = 1/sqrt(2);
864
865 mem.SetPen( wxPen(fg) );
866 mem.SetBrush( wxBrush(fg) );
867 int handleCornerShift = penWidth * 707 / 1000 / 2; // 707 / 1000 = 0.707 = 1/sqrt(2);
868 handleCornerShift = WXMAX( handleCornerShift, 1 );
869 int handleBase = 4 * x / 20;
870 int handleLength = 2*handleBase+1;
871 wxPoint handlePolygon[] =
872 {
873 wxPoint(-handleCornerShift,+handleCornerShift),
874 wxPoint(+handleCornerShift,-handleCornerShift),
875 wxPoint(multiplier*handleLength/2+handleCornerShift,multiplier*handleLength/2-handleCornerShift),
876 wxPoint(multiplier*handleLength/2-handleCornerShift,multiplier*handleLength/2+handleCornerShift),
877 };
878 mem.DrawPolygon(WXSIZEOF(handlePolygon),handlePolygon,lineStart,lineStart);
879
880 // draw drop triangle
881 int triangleX = 13 * x / 20;
882 int triangleY = 5 * x / 20;
883 int triangleBase = 3 * x / 20;
884 int triangleFactor = triangleBase*2+1;
885 if ( renderDrop )
886 {
887 wxPoint dropPolygon[] =
888 {
889 wxPoint(multiplier*0,multiplier*0), // triangle left
890 wxPoint(multiplier*triangleFactor-1,multiplier*0), // triangle right
891 wxPoint(multiplier*triangleFactor/2,multiplier*triangleFactor/2), // triangle bottom
892 };
893 mem.DrawPolygon(WXSIZEOF(dropPolygon),dropPolygon,multiplier*triangleX,multiplier*triangleY);
894 }
895
896 //===============================================================================
897 // end drawing code
898 //===============================================================================
899
900 if ( multiplier != 1 )
901 {
902 wxImage image = bitmap.ConvertToImage();
903 image.Rescale(x,y);
904 bitmap = wxBitmap( image );
905 }
906
907 return bitmap;
908 }
909
910 wxBitmap wxSearchCtrl::RenderCancelBitmap( int x, int y )
911 {
912 wxColour bg = GetBackgroundColour();
913 wxColour fg = GetForegroundColour();
914
915 //===============================================================================
916 // begin drawing code
917 //===============================================================================
918 // image stats
919
920 // total size 14x14
921 // force 1:1 ratio
922 if ( x > y )
923 {
924 // x is too big
925 x = y;
926 }
927 else
928 {
929 // y is too big
930 y = x;
931 }
932
933 // 14x14 circle
934 // cross line starts (4,4)-(10,10)
935 // drop (13,16)-(19,6)-(16,9)
936
937 int multiplier = GetMultiplier();
938
939 int penWidth = multiplier * x / 14;
940
941 wxBitmap bitmap( multiplier*x, multiplier*y );
942 wxMemoryDC mem;
943 mem.SelectObject(bitmap);
944
945 // clear background
946 mem.SetBrush( wxBrush(bg) );
947 mem.SetPen( wxPen(bg) );
948 mem.DrawRectangle(0,0,bitmap.GetWidth(),bitmap.GetHeight());
949
950 // draw drop glass
951 mem.SetBrush( wxBrush(fg) );
952 mem.SetPen( wxPen(fg) );
953 int radius = multiplier*x/2;
954 mem.DrawCircle(radius,radius,radius);
955
956 // draw cross
957 int lineStartBase = 4 * x / 14;
958 int lineLength = x - 2*lineStartBase;
959
960 mem.SetPen( wxPen(bg) );
961 mem.SetBrush( wxBrush(bg) );
962 int handleCornerShift = penWidth/2;
963 handleCornerShift = WXMAX( handleCornerShift, 1 );
964 wxPoint handlePolygon[] =
965 {
966 wxPoint(-handleCornerShift,+handleCornerShift),
967 wxPoint(+handleCornerShift,-handleCornerShift),
968 wxPoint(multiplier*lineLength+handleCornerShift,multiplier*lineLength-handleCornerShift),
969 wxPoint(multiplier*lineLength-handleCornerShift,multiplier*lineLength+handleCornerShift),
970 };
971 mem.DrawPolygon(WXSIZEOF(handlePolygon),handlePolygon,multiplier*lineStartBase,multiplier*lineStartBase);
972 wxPoint handlePolygon2[] =
973 {
974 wxPoint(+handleCornerShift,+handleCornerShift),
975 wxPoint(-handleCornerShift,-handleCornerShift),
976 wxPoint(multiplier*lineLength-handleCornerShift,-multiplier*lineLength-handleCornerShift),
977 wxPoint(multiplier*lineLength+handleCornerShift,-multiplier*lineLength+handleCornerShift),
978 };
979 mem.DrawPolygon(WXSIZEOF(handlePolygon2),handlePolygon2,multiplier*lineStartBase,multiplier*(x-lineStartBase));
980
981 //===============================================================================
982 // end drawing code
983 //===============================================================================
984
985 if ( multiplier != 1 )
986 {
987 wxImage image = bitmap.ConvertToImage();
988 image.Rescale(x,y);
989 bitmap = wxBitmap( image );
990 }
991
992 return bitmap;
993 }
994
995 void wxSearchCtrl::RecalcBitmaps()
996 {
997 if ( !m_text )
998 {
999 return;
1000 }
1001 wxSize sizeText = m_text->GetBestSize();
1002
1003 int bitmapHeight = sizeText.y - 2 * ICON_MARGIN;
1004 int bitmapWidth = sizeText.y * 20 / 14;
1005
1006 if ( !m_searchBitmapUser )
1007 {
1008 if (
1009 !m_searchBitmap.Ok() ||
1010 m_searchBitmap.GetHeight() != bitmapHeight ||
1011 m_searchBitmap.GetWidth() != bitmapWidth
1012 )
1013 {
1014 m_searchBitmap = RenderSearchBitmap(bitmapWidth,bitmapHeight,false);
1015 if ( !m_menu )
1016 {
1017 m_searchButton->SetBitmapLabel(m_searchBitmap);
1018 }
1019 }
1020 // else this bitmap was set by user, don't alter
1021 }
1022
1023 if ( !m_searchMenuBitmapUser )
1024 {
1025 if (
1026 !m_searchMenuBitmap.Ok() ||
1027 m_searchMenuBitmap.GetHeight() != bitmapHeight ||
1028 m_searchMenuBitmap.GetWidth() != bitmapWidth
1029 )
1030 {
1031 m_searchMenuBitmap = RenderSearchBitmap(bitmapWidth,bitmapHeight,true);
1032 if ( m_menu )
1033 {
1034 m_searchButton->SetBitmapLabel(m_searchMenuBitmap);
1035 }
1036 }
1037 // else this bitmap was set by user, don't alter
1038 }
1039
1040 if ( !m_cancelBitmapUser )
1041 {
1042 if (
1043 !m_cancelBitmap.Ok() ||
1044 m_cancelBitmap.GetHeight() != bitmapHeight ||
1045 m_cancelBitmap.GetWidth() != bitmapHeight
1046 )
1047 {
1048 m_cancelBitmap = RenderCancelBitmap(bitmapHeight-BORDER,bitmapHeight-BORDER); // square
1049 m_cancelButton->SetBitmapLabel(m_cancelBitmap);
1050 }
1051 // else this bitmap was set by user, don't alter
1052 }
1053 }
1054
1055 void wxSearchCtrl::OnSearchButton( wxCommandEvent& event )
1056 {
1057 event.Skip();
1058 }
1059
1060 void wxSearchCtrl::OnSetFocus( wxFocusEvent& /*event*/ )
1061 {
1062 if ( m_text )
1063 {
1064 m_text->SetFocus();
1065 }
1066 }
1067
1068 void wxSearchCtrl::PopupSearchMenu()
1069 {
1070 if ( m_menu )
1071 {
1072 wxSize size = GetSize();
1073 PopupMenu( m_menu, 0, size.y );
1074 }
1075 }
1076
1077 #endif // !USE_NATIVE_SEARCH_CONTROL
1078
1079 #endif // wxUSE_SEARCHCTRL