Made wxSearchCtrl look like other text controls under GTK+.
[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 // Created: 2006-02-19
6 // RCS-ID: $Id$
7 // Copyright: Vince Harron
8 // License: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
10
11 // For compilers that support precompilation, includes "wx.h".
12 #include "wx/wxprec.h"
13
14 #ifdef __BORLANDC__
15 #pragma hdrstop
16 #endif
17
18 #if wxUSE_SEARCHCTRL
19
20 #include "wx/srchctrl.h"
21
22 #ifndef WX_PRECOMP
23 #include "wx/button.h"
24 #include "wx/dcclient.h"
25 #include "wx/menu.h"
26 #include "wx/dcmemory.h"
27 #endif //WX_PRECOMP
28
29 #if !wxUSE_NATIVE_SEARCH_CONTROL
30
31 #include "wx/image.h"
32
33 #define WXMAX(a,b) ((a)>(b)?(a):(b))
34
35 // ----------------------------------------------------------------------------
36 // constants
37 // ----------------------------------------------------------------------------
38
39 // the margin between the text control and the search/cancel buttons
40 static const wxCoord MARGIN = 2;
41
42 // border around all controls to compensate for wxSIMPLE_BORDER
43 #if defined(__WXMSW__)
44 static const wxCoord BORDER = 0;
45 static const wxCoord ICON_MARGIN = 2;
46 static const wxCoord ICON_OFFSET = 2;
47 #else
48 static const wxCoord BORDER = 2;
49 static const wxCoord ICON_MARGIN = 0;
50 static const wxCoord ICON_OFFSET = 0;
51 #endif
52
53 // ----------------------------------------------------------------------------
54 // wxSearchTextCtrl: text control used by search control
55 // ----------------------------------------------------------------------------
56
57 class wxSearchTextCtrl : public wxTextCtrl
58 {
59 public:
60 wxSearchTextCtrl(wxSearchCtrl *search, const wxString& value, int style)
61 : wxTextCtrl(search, wxID_ANY, value, wxDefaultPosition, wxDefaultSize,
62 style | wxNO_BORDER)
63 {
64 m_search = search;
65
66 // remove the default minsize, the searchctrl will have one instead
67 SetSizeHints(wxDefaultCoord,wxDefaultCoord);
68 }
69
70 protected:
71 void OnText(wxCommandEvent& eventText)
72 {
73 wxCommandEvent event(eventText);
74 event.SetEventObject(m_search);
75 event.SetId(m_search->GetId());
76
77 m_search->GetEventHandler()->ProcessEvent(event);
78 }
79
80 void OnTextUrl(wxTextUrlEvent& eventText)
81 {
82 // copy constructor is disabled for some reason?
83 //wxTextUrlEvent event(eventText);
84 wxTextUrlEvent event(
85 m_search->GetId(),
86 eventText.GetMouseEvent(),
87 eventText.GetURLStart(),
88 eventText.GetURLEnd()
89 );
90 event.SetEventObject(m_search);
91
92 m_search->GetEventHandler()->ProcessEvent(event);
93 }
94
95 private:
96 wxSearchCtrl* m_search;
97
98 DECLARE_EVENT_TABLE()
99 };
100
101 BEGIN_EVENT_TABLE(wxSearchTextCtrl, wxTextCtrl)
102 EVT_TEXT(wxID_ANY, wxSearchTextCtrl::OnText)
103 EVT_TEXT_ENTER(wxID_ANY, wxSearchTextCtrl::OnText)
104 EVT_TEXT_URL(wxID_ANY, wxSearchTextCtrl::OnTextUrl)
105 EVT_TEXT_MAXLEN(wxID_ANY, wxSearchTextCtrl::OnText)
106 END_EVENT_TABLE()
107
108 // ----------------------------------------------------------------------------
109 // wxSearchButton: search button used by search control
110 // ----------------------------------------------------------------------------
111
112 class wxSearchButton : public wxControl
113 {
114 public:
115 wxSearchButton(wxSearchCtrl *search, int eventType, const wxBitmap& bmp)
116 : wxControl(search, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER),
117 m_search(search),
118 m_eventType(eventType),
119 m_bmp(bmp)
120 { }
121
122 void SetBitmapLabel(const wxBitmap& label) { m_bmp = label; }
123
124
125 protected:
126 wxSize DoGetBestSize() const
127 {
128 return wxSize(m_bmp.GetWidth(), m_bmp.GetHeight());
129 }
130
131 void OnLeftUp(wxMouseEvent&)
132 {
133 wxCommandEvent event(m_eventType, m_search->GetId());
134 event.SetEventObject(m_search);
135
136 GetEventHandler()->ProcessEvent(event);
137
138 m_search->SetFocus();
139
140 if ( m_eventType == wxEVT_COMMAND_SEARCHCTRL_SEARCH_BTN )
141 {
142 // this happens automatically, just like on Mac OS X
143 m_search->PopupSearchMenu();
144 }
145 }
146
147 void OnPaint(wxPaintEvent&)
148 {
149 wxPaintDC dc(this);
150 dc.DrawBitmap(m_bmp, 0,0, true);
151 }
152
153
154 private:
155 wxSearchCtrl *m_search;
156 wxEventType m_eventType;
157 wxBitmap m_bmp;
158
159 DECLARE_EVENT_TABLE()
160 };
161
162 BEGIN_EVENT_TABLE(wxSearchButton, wxControl)
163 EVT_LEFT_UP(wxSearchButton::OnLeftUp)
164 EVT_PAINT(wxSearchButton::OnPaint)
165 END_EVENT_TABLE()
166
167 BEGIN_EVENT_TABLE(wxSearchCtrl, wxSearchCtrlBase)
168 EVT_SEARCHCTRL_SEARCH_BTN(wxID_ANY, wxSearchCtrl::OnSearchButton)
169 EVT_SET_FOCUS(wxSearchCtrl::OnSetFocus)
170 EVT_SIZE(wxSearchCtrl::OnSize)
171 END_EVENT_TABLE()
172
173 IMPLEMENT_DYNAMIC_CLASS(wxSearchCtrl, wxSearchCtrlBase)
174
175 // ============================================================================
176 // implementation
177 // ============================================================================
178
179 // ----------------------------------------------------------------------------
180 // wxSearchCtrl creation
181 // ----------------------------------------------------------------------------
182
183 // creation
184 // --------
185
186 wxSearchCtrl::wxSearchCtrl()
187 {
188 Init();
189 }
190
191 wxSearchCtrl::wxSearchCtrl(wxWindow *parent, wxWindowID id,
192 const wxString& value,
193 const wxPoint& pos,
194 const wxSize& size,
195 long style,
196 const wxValidator& validator,
197 const wxString& name)
198 {
199 Init();
200
201 Create(parent, id, value, pos, size, style, validator, name);
202 }
203
204 void wxSearchCtrl::Init()
205 {
206 m_text = 0;
207 m_searchButton = 0;
208 m_cancelButton = 0;
209 m_menu = 0;
210
211 m_searchButtonVisible = true;
212 m_cancelButtonVisible = false;
213
214 m_searchMenuBitmapUser = false;
215 m_searchBitmapUser = false;
216 m_cancelBitmapUser = false;
217 }
218
219 bool wxSearchCtrl::Create(wxWindow *parent, wxWindowID id,
220 const wxString& value,
221 const wxPoint& pos,
222 const wxSize& size,
223 long style,
224 const wxValidator& validator,
225 const wxString& name)
226 {
227 #ifdef __WXGTK__
228 if ( !wxTextCtrlBase::Create(parent, id, pos, size, wxSUNKEN_BORDER | style, validator, name) )
229 #else
230 if ( !wxTextCtrlBase::Create(parent, id, pos, size, wxSIMPLE_BORDER | style, validator, name) )
231 #endif
232 {
233 return false;
234 }
235
236 m_text = new wxSearchTextCtrl(this, value, style & ~wxBORDER_MASK);
237
238 wxSize sizeText = m_text->GetBestSize();
239
240 m_searchButton = new wxSearchButton(this,wxEVT_COMMAND_SEARCHCTRL_SEARCH_BTN,m_searchBitmap);
241 m_cancelButton = new wxSearchButton(this,wxEVT_COMMAND_SEARCHCTRL_CANCEL_BTN,m_cancelBitmap);
242
243 SetForegroundColour( m_text->GetForegroundColour() );
244 m_searchButton->SetForegroundColour( m_text->GetForegroundColour() );
245 m_cancelButton->SetForegroundColour( m_text->GetForegroundColour() );
246
247 SetBackgroundColour( m_text->GetBackgroundColour() );
248 m_searchButton->SetBackgroundColour( m_text->GetBackgroundColour() );
249 m_cancelButton->SetBackgroundColour( m_text->GetBackgroundColour() );
250
251 RecalcBitmaps();
252
253 SetInitialSize(size);
254 Move(pos);
255 return true;
256 }
257
258 wxSearchCtrl::~wxSearchCtrl()
259 {
260 delete m_text;
261 delete m_searchButton;
262 delete m_cancelButton;
263 delete m_menu;
264 }
265
266
267 // search control specific interfaces
268 void wxSearchCtrl::SetMenu( wxMenu* menu )
269 {
270 if ( menu == m_menu )
271 {
272 // no change
273 return;
274 }
275 bool hadMenu = (m_menu != NULL);
276 delete m_menu;
277 m_menu = menu;
278
279 if ( m_menu && !hadMenu )
280 {
281 m_searchButton->SetBitmapLabel(m_searchMenuBitmap);
282 m_searchButton->Refresh();
283 if ( !m_searchButtonVisible )
284 {
285 // adding the menu will force the search button to be visible
286 wxRect rect = GetRect();
287 LayoutControls(0, 0, rect.GetWidth(), rect.GetHeight());
288 }
289 }
290 else if ( !m_menu && hadMenu )
291 {
292 m_searchButton->SetBitmapLabel(m_searchBitmap);
293 if ( m_searchButtonVisible )
294 {
295 m_searchButton->Refresh();
296 }
297 else
298 {
299 wxRect rect = GetRect();
300 LayoutControls(0, 0, rect.GetWidth(), rect.GetHeight());
301 }
302 }
303 }
304
305 wxMenu* wxSearchCtrl::GetMenu()
306 {
307 return m_menu;
308 }
309
310 void wxSearchCtrl::ShowSearchButton( bool show )
311 {
312 if ( m_searchButtonVisible == show )
313 {
314 // no change
315 return;
316 }
317 m_searchButtonVisible = show;
318 if ( m_searchButtonVisible )
319 {
320 RecalcBitmaps();
321 }
322
323 wxRect rect = GetRect();
324 LayoutControls(0, 0, rect.GetWidth(), rect.GetHeight());
325 }
326
327 bool wxSearchCtrl::IsSearchButtonVisible() const
328 {
329 return m_searchButtonVisible;
330 }
331
332
333 void wxSearchCtrl::ShowCancelButton( bool show )
334 {
335 if ( m_cancelButtonVisible == show )
336 {
337 // no change
338 return;
339 }
340 m_cancelButtonVisible = show;
341
342 wxRect rect = GetRect();
343 LayoutControls(0, 0, rect.GetWidth(), rect.GetHeight());
344 }
345
346 bool wxSearchCtrl::IsCancelButtonVisible() const
347 {
348 return m_cancelButtonVisible;
349 }
350
351
352 // ----------------------------------------------------------------------------
353 // geometry
354 // ----------------------------------------------------------------------------
355
356 wxSize wxSearchCtrl::DoGetBestSize() const
357 {
358 wxSize sizeText = m_text->GetBestSize();
359 wxSize sizeSearch(0,0);
360 wxSize sizeCancel(0,0);
361 int searchMargin = 0;
362 int cancelMargin = 0;
363 if ( m_searchButtonVisible || m_menu )
364 {
365 sizeSearch = m_searchButton->GetBestSize();
366 searchMargin = MARGIN;
367 }
368 if ( m_cancelButtonVisible )
369 {
370 sizeCancel = m_cancelButton->GetBestSize();
371 cancelMargin = MARGIN;
372 }
373
374 int horizontalBorder = 1 + ( sizeText.y - sizeText.y * 14 / 21 ) / 2;
375
376 // buttons are square and equal to the height of the text control
377 int height = sizeText.y;
378 return wxSize(sizeSearch.x + searchMargin + sizeText.x + cancelMargin + sizeCancel.x + 2*horizontalBorder,
379 height + 2*BORDER);
380 }
381
382 void wxSearchCtrl::DoMoveWindow(int x, int y, int width, int height)
383 {
384 wxSearchCtrlBase::DoMoveWindow(x, y, width, height);
385
386 LayoutControls(0, 0, width, height);
387 }
388
389 void wxSearchCtrl::LayoutControls(int x, int y, int width, int height)
390 {
391 if ( !m_text )
392 return;
393
394 wxSize sizeText = m_text->GetBestSize();
395 // make room for the search menu & clear button
396 int horizontalBorder = 1 + ( sizeText.y - sizeText.y * 14 / 21 ) / 2;
397 x += horizontalBorder;
398 y += BORDER;
399 width -= horizontalBorder*2;
400 height -= BORDER*2;
401
402 wxSize sizeSearch(0,0);
403 wxSize sizeCancel(0,0);
404 int searchMargin = 0;
405 int cancelMargin = 0;
406 if ( m_searchButtonVisible || m_menu )
407 {
408 sizeSearch = m_searchButton->GetBestSize();
409 searchMargin = MARGIN;
410 }
411 if ( m_cancelButtonVisible )
412 {
413 sizeCancel = m_cancelButton->GetBestSize();
414 cancelMargin = MARGIN;
415 }
416 m_searchButton->Show( m_searchButtonVisible || m_menu );
417 m_cancelButton->Show( m_cancelButtonVisible );
418
419 if ( sizeSearch.x + sizeCancel.x > width )
420 {
421 sizeSearch.x = width/2;
422 sizeCancel.x = width/2;
423 searchMargin = 0;
424 cancelMargin = 0;
425 }
426 wxCoord textWidth = width - sizeSearch.x - sizeCancel.x - searchMargin - cancelMargin;
427
428 // position the subcontrols inside the client area
429
430 m_searchButton->SetSize(x, y + ICON_OFFSET, sizeSearch.x, height);
431 m_text->SetSize( x + sizeSearch.x + searchMargin,
432 y + ICON_OFFSET - BORDER,
433 textWidth,
434 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::OnSize( wxSizeEvent& event )
1069 {
1070 int width, height;
1071 GetSize(&width, &height);
1072 LayoutControls(0, 0, width, height);
1073 }
1074
1075 void wxSearchCtrl::PopupSearchMenu()
1076 {
1077 if ( m_menu )
1078 {
1079 wxSize size = GetSize();
1080 PopupMenu( m_menu, 0, size.y );
1081 }
1082 }
1083
1084 #endif // !wxUSE_NATIVE_SEARCH_CONTROL
1085
1086 #endif // wxUSE_SEARCHCTRL