Also do LayoutControls from EVT_SIZE handler
[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 if ( !wxTextCtrlBase::Create(parent, id, pos, size, wxSIMPLE_BORDER | style, validator, name) )
228 {
229 return false;
230 }
231
232 m_text = new wxSearchTextCtrl(this, value, style & ~wxBORDER_MASK);
233
234 wxSize sizeText = m_text->GetBestSize();
235
236 m_searchButton = new wxSearchButton(this,wxEVT_COMMAND_SEARCHCTRL_SEARCH_BTN,m_searchBitmap);
237 m_cancelButton = new wxSearchButton(this,wxEVT_COMMAND_SEARCHCTRL_CANCEL_BTN,m_cancelBitmap);
238
239 SetForegroundColour( m_text->GetForegroundColour() );
240 m_searchButton->SetForegroundColour( m_text->GetForegroundColour() );
241 m_cancelButton->SetForegroundColour( m_text->GetForegroundColour() );
242
243 SetBackgroundColour( m_text->GetBackgroundColour() );
244 m_searchButton->SetBackgroundColour( m_text->GetBackgroundColour() );
245 m_cancelButton->SetBackgroundColour( m_text->GetBackgroundColour() );
246
247 RecalcBitmaps();
248
249 SetInitialSize(size);
250 Move(pos);
251 return true;
252 }
253
254 wxSearchCtrl::~wxSearchCtrl()
255 {
256 delete m_text;
257 delete m_searchButton;
258 delete m_cancelButton;
259 delete m_menu;
260 }
261
262
263 // search control specific interfaces
264 void wxSearchCtrl::SetMenu( wxMenu* menu )
265 {
266 if ( menu == m_menu )
267 {
268 // no change
269 return;
270 }
271 bool hadMenu = (m_menu != NULL);
272 delete m_menu;
273 m_menu = menu;
274
275 if ( m_menu && !hadMenu )
276 {
277 m_searchButton->SetBitmapLabel(m_searchMenuBitmap);
278 m_searchButton->Refresh();
279 if ( !m_searchButtonVisible )
280 {
281 // adding the menu will force the search button to be visible
282 wxRect rect = GetRect();
283 LayoutControls(0, 0, rect.GetWidth(), rect.GetHeight());
284 }
285 }
286 else if ( !m_menu && hadMenu )
287 {
288 m_searchButton->SetBitmapLabel(m_searchBitmap);
289 if ( m_searchButtonVisible )
290 {
291 m_searchButton->Refresh();
292 }
293 else
294 {
295 wxRect rect = GetRect();
296 LayoutControls(0, 0, rect.GetWidth(), rect.GetHeight());
297 }
298 }
299 }
300
301 wxMenu* wxSearchCtrl::GetMenu()
302 {
303 return m_menu;
304 }
305
306 void wxSearchCtrl::ShowSearchButton( bool show )
307 {
308 if ( m_searchButtonVisible == show )
309 {
310 // no change
311 return;
312 }
313 m_searchButtonVisible = show;
314 if ( m_searchButtonVisible )
315 {
316 RecalcBitmaps();
317 }
318
319 wxRect rect = GetRect();
320 LayoutControls(0, 0, rect.GetWidth(), rect.GetHeight());
321 }
322
323 bool wxSearchCtrl::IsSearchButtonVisible() const
324 {
325 return m_searchButtonVisible;
326 }
327
328
329 void wxSearchCtrl::ShowCancelButton( bool show )
330 {
331 if ( m_cancelButtonVisible == show )
332 {
333 // no change
334 return;
335 }
336 m_cancelButtonVisible = show;
337
338 wxRect rect = GetRect();
339 LayoutControls(0, 0, rect.GetWidth(), rect.GetHeight());
340 }
341
342 bool wxSearchCtrl::IsCancelButtonVisible() const
343 {
344 return m_cancelButtonVisible;
345 }
346
347
348 // ----------------------------------------------------------------------------
349 // geometry
350 // ----------------------------------------------------------------------------
351
352 wxSize wxSearchCtrl::DoGetBestSize() const
353 {
354 wxSize sizeText = m_text->GetBestSize();
355 wxSize sizeSearch(0,0);
356 wxSize sizeCancel(0,0);
357 int searchMargin = 0;
358 int cancelMargin = 0;
359 if ( m_searchButtonVisible || m_menu )
360 {
361 sizeSearch = m_searchButton->GetBestSize();
362 searchMargin = MARGIN;
363 }
364 if ( m_cancelButtonVisible )
365 {
366 sizeCancel = m_cancelButton->GetBestSize();
367 cancelMargin = MARGIN;
368 }
369
370 int horizontalBorder = 1 + ( sizeText.y - sizeText.y * 14 / 21 ) / 2;
371
372 // buttons are square and equal to the height of the text control
373 int height = sizeText.y;
374 return wxSize(sizeSearch.x + searchMargin + sizeText.x + cancelMargin + sizeCancel.x + 2*horizontalBorder,
375 height + 2*BORDER);
376 }
377
378 void wxSearchCtrl::DoMoveWindow(int x, int y, int width, int height)
379 {
380 wxSearchCtrlBase::DoMoveWindow(x, y, width, height);
381
382 LayoutControls(0, 0, width, height);
383 }
384
385 void wxSearchCtrl::LayoutControls(int x, int y, int width, int height)
386 {
387 if ( !m_text )
388 return;
389
390 wxSize sizeText = m_text->GetBestSize();
391 // make room for the search menu & clear button
392 int horizontalBorder = 1 + ( sizeText.y - sizeText.y * 14 / 21 ) / 2;
393 x += horizontalBorder;
394 y += BORDER;
395 width -= horizontalBorder*2;
396 height -= BORDER*2;
397
398 wxSize sizeSearch(0,0);
399 wxSize sizeCancel(0,0);
400 int searchMargin = 0;
401 int cancelMargin = 0;
402 if ( m_searchButtonVisible || m_menu )
403 {
404 sizeSearch = m_searchButton->GetBestSize();
405 searchMargin = MARGIN;
406 }
407 if ( m_cancelButtonVisible )
408 {
409 sizeCancel = m_cancelButton->GetBestSize();
410 cancelMargin = MARGIN;
411 }
412 m_searchButton->Show( m_searchButtonVisible || m_menu );
413 m_cancelButton->Show( m_cancelButtonVisible );
414
415 if ( sizeSearch.x + sizeCancel.x > width )
416 {
417 sizeSearch.x = width/2;
418 sizeCancel.x = width/2;
419 searchMargin = 0;
420 cancelMargin = 0;
421 }
422 wxCoord textWidth = width - sizeSearch.x - sizeCancel.x - searchMargin - cancelMargin;
423
424 // position the subcontrols inside the client area
425
426 m_searchButton->SetSize(x, y + ICON_OFFSET, sizeSearch.x, height);
427 m_text->SetSize(x + sizeSearch.x + searchMargin, y + ICON_OFFSET, textWidth, height);
428 m_cancelButton->SetSize(x + sizeSearch.x + searchMargin + textWidth + cancelMargin,
429 y + ICON_OFFSET, sizeCancel.x, height);
430 }
431
432
433 // accessors
434 // ---------
435
436 wxString wxSearchCtrl::GetValue() const
437 {
438 return m_text->GetValue();
439 }
440 void wxSearchCtrl::SetValue(const wxString& value)
441 {
442 m_text->SetValue(value);
443 }
444
445 wxString wxSearchCtrl::GetRange(long from, long to) const
446 {
447 return m_text->GetRange(from, to);
448 }
449
450 int wxSearchCtrl::GetLineLength(long lineNo) const
451 {
452 return m_text->GetLineLength(lineNo);
453 }
454 wxString wxSearchCtrl::GetLineText(long lineNo) const
455 {
456 return m_text->GetLineText(lineNo);
457 }
458 int wxSearchCtrl::GetNumberOfLines() const
459 {
460 return m_text->GetNumberOfLines();
461 }
462
463 bool wxSearchCtrl::IsModified() const
464 {
465 return m_text->IsModified();
466 }
467 bool wxSearchCtrl::IsEditable() const
468 {
469 return m_text->IsEditable();
470 }
471
472 // more readable flag testing methods
473 bool wxSearchCtrl::IsSingleLine() const
474 {
475 return m_text->IsSingleLine();
476 }
477 bool wxSearchCtrl::IsMultiLine() const
478 {
479 return m_text->IsMultiLine();
480 }
481
482 // If the return values from and to are the same, there is no selection.
483 void wxSearchCtrl::GetSelection(long* from, long* to) const
484 {
485 m_text->GetSelection(from, to);
486 }
487
488 wxString wxSearchCtrl::GetStringSelection() const
489 {
490 return m_text->GetStringSelection();
491 }
492
493 // operations
494 // ----------
495
496 // editing
497 void wxSearchCtrl::Clear()
498 {
499 m_text->Clear();
500 }
501 void wxSearchCtrl::Replace(long from, long to, const wxString& value)
502 {
503 m_text->Replace(from, to, value);
504 }
505 void wxSearchCtrl::Remove(long from, long to)
506 {
507 m_text->Remove(from, to);
508 }
509
510 // load/save the controls contents from/to the file
511 bool wxSearchCtrl::LoadFile(const wxString& file)
512 {
513 return m_text->LoadFile(file);
514 }
515 bool wxSearchCtrl::SaveFile(const wxString& file)
516 {
517 return m_text->SaveFile(file);
518 }
519
520 // sets/clears the dirty flag
521 void wxSearchCtrl::MarkDirty()
522 {
523 m_text->MarkDirty();
524 }
525 void wxSearchCtrl::DiscardEdits()
526 {
527 m_text->DiscardEdits();
528 }
529
530 // set the max number of characters which may be entered in a single line
531 // text control
532 void wxSearchCtrl::SetMaxLength(unsigned long len)
533 {
534 m_text->SetMaxLength(len);
535 }
536
537 // writing text inserts it at the current position, appending always
538 // inserts it at the end
539 void wxSearchCtrl::WriteText(const wxString& text)
540 {
541 m_text->WriteText(text);
542 }
543 void wxSearchCtrl::AppendText(const wxString& text)
544 {
545 m_text->AppendText(text);
546 }
547
548 // insert the character which would have resulted from this key event,
549 // return true if anything has been inserted
550 bool wxSearchCtrl::EmulateKeyPress(const wxKeyEvent& event)
551 {
552 return m_text->EmulateKeyPress(event);
553 }
554
555 // text control under some platforms supports the text styles: these
556 // methods allow to apply the given text style to the given selection or to
557 // set/get the style which will be used for all appended text
558 bool wxSearchCtrl::SetStyle(long start, long end, const wxTextAttr& style)
559 {
560 return m_text->SetStyle(start, end, style);
561 }
562 bool wxSearchCtrl::GetStyle(long position, wxTextAttr& style)
563 {
564 return m_text->GetStyle(position, style);
565 }
566 bool wxSearchCtrl::SetDefaultStyle(const wxTextAttr& style)
567 {
568 return m_text->SetDefaultStyle(style);
569 }
570 const wxTextAttr& wxSearchCtrl::GetDefaultStyle() const
571 {
572 return m_text->GetDefaultStyle();
573 }
574
575 // translate between the position (which is just an index in the text ctrl
576 // considering all its contents as a single strings) and (x, y) coordinates
577 // which represent column and line.
578 long wxSearchCtrl::XYToPosition(long x, long y) const
579 {
580 return m_text->XYToPosition(x, y);
581 }
582 bool wxSearchCtrl::PositionToXY(long pos, long *x, long *y) const
583 {
584 return m_text->PositionToXY(pos, x, y);
585 }
586
587 void wxSearchCtrl::ShowPosition(long pos)
588 {
589 m_text->ShowPosition(pos);
590 }
591
592 // find the character at position given in pixels
593 //
594 // NB: pt is in device coords (not adjusted for the client area origin nor
595 // scrolling)
596 wxTextCtrlHitTestResult wxSearchCtrl::HitTest(const wxPoint& pt, long *pos) const
597 {
598 return m_text->HitTest(pt, pos);
599 }
600 wxTextCtrlHitTestResult wxSearchCtrl::HitTest(const wxPoint& pt,
601 wxTextCoord *col,
602 wxTextCoord *row) const
603 {
604 return m_text->HitTest(pt, col, row);
605 }
606
607 // Clipboard operations
608 void wxSearchCtrl::Copy()
609 {
610 m_text->Copy();
611 }
612 void wxSearchCtrl::Cut()
613 {
614 m_text->Cut();
615 }
616 void wxSearchCtrl::Paste()
617 {
618 m_text->Paste();
619 }
620
621 bool wxSearchCtrl::CanCopy() const
622 {
623 return m_text->CanCopy();
624 }
625 bool wxSearchCtrl::CanCut() const
626 {
627 return m_text->CanCut();
628 }
629 bool wxSearchCtrl::CanPaste() const
630 {
631 return m_text->CanPaste();
632 }
633
634 // Undo/redo
635 void wxSearchCtrl::Undo()
636 {
637 m_text->Undo();
638 }
639 void wxSearchCtrl::Redo()
640 {
641 m_text->Redo();
642 }
643
644 bool wxSearchCtrl::CanUndo() const
645 {
646 return m_text->CanUndo();
647 }
648 bool wxSearchCtrl::CanRedo() const
649 {
650 return m_text->CanRedo();
651 }
652
653 // Insertion point
654 void wxSearchCtrl::SetInsertionPoint(long pos)
655 {
656 m_text->SetInsertionPoint(pos);
657 }
658 void wxSearchCtrl::SetInsertionPointEnd()
659 {
660 m_text->SetInsertionPointEnd();
661 }
662 long wxSearchCtrl::GetInsertionPoint() const
663 {
664 return m_text->GetInsertionPoint();
665 }
666 wxTextPos wxSearchCtrl::GetLastPosition() const
667 {
668 return m_text->GetLastPosition();
669 }
670
671 void wxSearchCtrl::SetSelection(long from, long to)
672 {
673 m_text->SetSelection(from, to);
674 }
675 void wxSearchCtrl::SelectAll()
676 {
677 m_text->SelectAll();
678 }
679
680 void wxSearchCtrl::SetEditable(bool editable)
681 {
682 m_text->SetEditable(editable);
683 }
684
685 bool wxSearchCtrl::SetFont(const wxFont& font)
686 {
687 bool result = wxSearchCtrlBase::SetFont(font);
688 if ( result && m_text )
689 {
690 result = m_text->SetFont(font);
691 }
692 RecalcBitmaps();
693 return result;
694 }
695
696 // search control generic only
697 void wxSearchCtrl::SetSearchBitmap( const wxBitmap& bitmap )
698 {
699 m_searchBitmap = bitmap;
700 m_searchBitmapUser = bitmap.Ok();
701 if ( m_searchBitmapUser )
702 {
703 if ( m_searchButton && !m_menu )
704 {
705 m_searchButton->SetBitmapLabel( m_searchBitmap );
706 }
707 }
708 else
709 {
710 // the user bitmap was just cleared, generate one
711 RecalcBitmaps();
712 }
713 }
714
715 void wxSearchCtrl::SetSearchMenuBitmap( const wxBitmap& bitmap )
716 {
717 m_searchMenuBitmap = bitmap;
718 m_searchMenuBitmapUser = bitmap.Ok();
719 if ( m_searchMenuBitmapUser )
720 {
721 if ( m_searchButton && m_menu )
722 {
723 m_searchButton->SetBitmapLabel( m_searchMenuBitmap );
724 }
725 }
726 else
727 {
728 // the user bitmap was just cleared, generate one
729 RecalcBitmaps();
730 }
731 }
732
733 void wxSearchCtrl::SetCancelBitmap( const wxBitmap& bitmap )
734 {
735 m_cancelBitmap = bitmap;
736 m_cancelBitmapUser = bitmap.Ok();
737 if ( m_cancelBitmapUser )
738 {
739 if ( m_cancelButton )
740 {
741 m_cancelButton->SetBitmapLabel( m_cancelBitmap );
742 }
743 }
744 else
745 {
746 // the user bitmap was just cleared, generate one
747 RecalcBitmaps();
748 }
749 }
750
751 #if 0
752
753 // override streambuf method
754 #if wxHAS_TEXT_WINDOW_STREAM
755 int overflow(int i);
756 #endif // wxHAS_TEXT_WINDOW_STREAM
757
758 // stream-like insertion operators: these are always available, whether we
759 // were, or not, compiled with streambuf support
760 wxTextCtrl& operator<<(const wxString& s);
761 wxTextCtrl& operator<<(int i);
762 wxTextCtrl& operator<<(long i);
763 wxTextCtrl& operator<<(float f);
764 wxTextCtrl& operator<<(double d);
765 wxTextCtrl& operator<<(const wxChar c);
766 #endif
767
768 void wxSearchCtrl::DoSetValue(const wxString& value, int flags)
769 {
770 m_text->ChangeValue( value );
771 if ( flags & SetValue_SendEvent )
772 SendTextUpdatedEvent();
773 }
774
775 // do the window-specific processing after processing the update event
776 void wxSearchCtrl::DoUpdateWindowUI(wxUpdateUIEvent& event)
777 {
778 wxSearchCtrlBase::DoUpdateWindowUI(event);
779 }
780
781 bool wxSearchCtrl::ShouldInheritColours() const
782 {
783 return true;
784 }
785
786 // icons are rendered at 3-8 times larger than necessary and downscaled for
787 // antialiasing
788 static int GetMultiplier()
789 {
790 #ifdef __WXWINCE__
791 // speed up bitmap generation by using a small bitmap
792 return 3;
793 #else
794 int depth = ::wxDisplayDepth();
795
796 if ( depth >= 24 )
797 {
798 return 8;
799 }
800 return 6;
801 #endif
802 }
803
804 wxBitmap wxSearchCtrl::RenderSearchBitmap( int x, int y, bool renderDrop )
805 {
806 wxColour bg = GetBackgroundColour();
807 wxColour fg = GetForegroundColour();
808
809 //===============================================================================
810 // begin drawing code
811 //===============================================================================
812 // image stats
813
814 // force width:height ratio
815 if ( 14*x > y*20 )
816 {
817 // x is too big
818 x = y*20/14;
819 }
820 else
821 {
822 // y is too big
823 y = x*14/20;
824 }
825
826 // glass 11x11, top left corner
827 // handle (9,9)-(13,13)
828 // drop (13,16)-(19,6)-(16,9)
829
830 int multiplier = GetMultiplier();
831 int penWidth = multiplier * 2;
832
833 penWidth = penWidth * x / 20;
834
835 wxBitmap bitmap( multiplier*x, multiplier*y );
836 wxMemoryDC mem;
837 mem.SelectObject(bitmap);
838
839 // clear background
840 mem.SetBrush( wxBrush(bg) );
841 mem.SetPen( wxPen(bg) );
842 mem.DrawRectangle(0,0,bitmap.GetWidth(),bitmap.GetHeight());
843
844 // draw drop glass
845 mem.SetBrush( wxBrush(fg) );
846 mem.SetPen( wxPen(fg) );
847 int glassBase = 5 * x / 20;
848 int glassFactor = 2*glassBase + 1;
849 int radius = multiplier*glassFactor/2;
850 mem.DrawCircle(radius,radius,radius);
851 mem.SetBrush( wxBrush(bg) );
852 mem.SetPen( wxPen(bg) );
853 mem.DrawCircle(radius,radius,radius-penWidth);
854
855 // draw handle
856 int lineStart = radius + (radius-penWidth/2) * 707 / 1000; // 707 / 1000 = 0.707 = 1/sqrt(2);
857
858 mem.SetPen( wxPen(fg) );
859 mem.SetBrush( wxBrush(fg) );
860 int handleCornerShift = penWidth * 707 / 1000 / 2; // 707 / 1000 = 0.707 = 1/sqrt(2);
861 handleCornerShift = WXMAX( handleCornerShift, 1 );
862 int handleBase = 4 * x / 20;
863 int handleLength = 2*handleBase+1;
864 wxPoint handlePolygon[] =
865 {
866 wxPoint(-handleCornerShift,+handleCornerShift),
867 wxPoint(+handleCornerShift,-handleCornerShift),
868 wxPoint(multiplier*handleLength/2+handleCornerShift,multiplier*handleLength/2-handleCornerShift),
869 wxPoint(multiplier*handleLength/2-handleCornerShift,multiplier*handleLength/2+handleCornerShift),
870 };
871 mem.DrawPolygon(WXSIZEOF(handlePolygon),handlePolygon,lineStart,lineStart);
872
873 // draw drop triangle
874 int triangleX = 13 * x / 20;
875 int triangleY = 5 * x / 20;
876 int triangleBase = 3 * x / 20;
877 int triangleFactor = triangleBase*2+1;
878 if ( renderDrop )
879 {
880 wxPoint dropPolygon[] =
881 {
882 wxPoint(multiplier*0,multiplier*0), // triangle left
883 wxPoint(multiplier*triangleFactor-1,multiplier*0), // triangle right
884 wxPoint(multiplier*triangleFactor/2,multiplier*triangleFactor/2), // triangle bottom
885 };
886 mem.DrawPolygon(WXSIZEOF(dropPolygon),dropPolygon,multiplier*triangleX,multiplier*triangleY);
887 }
888
889 //===============================================================================
890 // end drawing code
891 //===============================================================================
892
893 if ( multiplier != 1 )
894 {
895 wxImage image = bitmap.ConvertToImage();
896 image.Rescale(x,y);
897 bitmap = wxBitmap( image );
898 }
899
900 return bitmap;
901 }
902
903 wxBitmap wxSearchCtrl::RenderCancelBitmap( int x, int y )
904 {
905 wxColour bg = GetBackgroundColour();
906 wxColour fg = GetForegroundColour();
907
908 //===============================================================================
909 // begin drawing code
910 //===============================================================================
911 // image stats
912
913 // total size 14x14
914 // force 1:1 ratio
915 if ( x > y )
916 {
917 // x is too big
918 x = y;
919 }
920 else
921 {
922 // y is too big
923 y = x;
924 }
925
926 // 14x14 circle
927 // cross line starts (4,4)-(10,10)
928 // drop (13,16)-(19,6)-(16,9)
929
930 int multiplier = GetMultiplier();
931
932 int penWidth = multiplier * x / 14;
933
934 wxBitmap bitmap( multiplier*x, multiplier*y );
935 wxMemoryDC mem;
936 mem.SelectObject(bitmap);
937
938 // clear background
939 mem.SetBrush( wxBrush(bg) );
940 mem.SetPen( wxPen(bg) );
941 mem.DrawRectangle(0,0,bitmap.GetWidth(),bitmap.GetHeight());
942
943 // draw drop glass
944 mem.SetBrush( wxBrush(fg) );
945 mem.SetPen( wxPen(fg) );
946 int radius = multiplier*x/2;
947 mem.DrawCircle(radius,radius,radius);
948
949 // draw cross
950 int lineStartBase = 4 * x / 14;
951 int lineLength = x - 2*lineStartBase;
952
953 mem.SetPen( wxPen(bg) );
954 mem.SetBrush( wxBrush(bg) );
955 int handleCornerShift = penWidth/2;
956 handleCornerShift = WXMAX( handleCornerShift, 1 );
957 wxPoint handlePolygon[] =
958 {
959 wxPoint(-handleCornerShift,+handleCornerShift),
960 wxPoint(+handleCornerShift,-handleCornerShift),
961 wxPoint(multiplier*lineLength+handleCornerShift,multiplier*lineLength-handleCornerShift),
962 wxPoint(multiplier*lineLength-handleCornerShift,multiplier*lineLength+handleCornerShift),
963 };
964 mem.DrawPolygon(WXSIZEOF(handlePolygon),handlePolygon,multiplier*lineStartBase,multiplier*lineStartBase);
965 wxPoint handlePolygon2[] =
966 {
967 wxPoint(+handleCornerShift,+handleCornerShift),
968 wxPoint(-handleCornerShift,-handleCornerShift),
969 wxPoint(multiplier*lineLength-handleCornerShift,-multiplier*lineLength-handleCornerShift),
970 wxPoint(multiplier*lineLength+handleCornerShift,-multiplier*lineLength+handleCornerShift),
971 };
972 mem.DrawPolygon(WXSIZEOF(handlePolygon2),handlePolygon2,multiplier*lineStartBase,multiplier*(x-lineStartBase));
973
974 //===============================================================================
975 // end drawing code
976 //===============================================================================
977
978 if ( multiplier != 1 )
979 {
980 wxImage image = bitmap.ConvertToImage();
981 image.Rescale(x,y);
982 bitmap = wxBitmap( image );
983 }
984
985 return bitmap;
986 }
987
988 void wxSearchCtrl::RecalcBitmaps()
989 {
990 if ( !m_text )
991 {
992 return;
993 }
994 wxSize sizeText = m_text->GetBestSize();
995
996 int bitmapHeight = sizeText.y - 2 * ICON_MARGIN;
997 int bitmapWidth = sizeText.y * 20 / 14;
998
999 if ( !m_searchBitmapUser )
1000 {
1001 if (
1002 !m_searchBitmap.Ok() ||
1003 m_searchBitmap.GetHeight() != bitmapHeight ||
1004 m_searchBitmap.GetWidth() != bitmapWidth
1005 )
1006 {
1007 m_searchBitmap = RenderSearchBitmap(bitmapWidth,bitmapHeight,false);
1008 if ( !m_menu )
1009 {
1010 m_searchButton->SetBitmapLabel(m_searchBitmap);
1011 }
1012 }
1013 // else this bitmap was set by user, don't alter
1014 }
1015
1016 if ( !m_searchMenuBitmapUser )
1017 {
1018 if (
1019 !m_searchMenuBitmap.Ok() ||
1020 m_searchMenuBitmap.GetHeight() != bitmapHeight ||
1021 m_searchMenuBitmap.GetWidth() != bitmapWidth
1022 )
1023 {
1024 m_searchMenuBitmap = RenderSearchBitmap(bitmapWidth,bitmapHeight,true);
1025 if ( m_menu )
1026 {
1027 m_searchButton->SetBitmapLabel(m_searchMenuBitmap);
1028 }
1029 }
1030 // else this bitmap was set by user, don't alter
1031 }
1032
1033 if ( !m_cancelBitmapUser )
1034 {
1035 if (
1036 !m_cancelBitmap.Ok() ||
1037 m_cancelBitmap.GetHeight() != bitmapHeight ||
1038 m_cancelBitmap.GetWidth() != bitmapHeight
1039 )
1040 {
1041 m_cancelBitmap = RenderCancelBitmap(bitmapHeight-BORDER,bitmapHeight-BORDER); // square
1042 m_cancelButton->SetBitmapLabel(m_cancelBitmap);
1043 }
1044 // else this bitmap was set by user, don't alter
1045 }
1046 }
1047
1048 void wxSearchCtrl::OnSearchButton( wxCommandEvent& event )
1049 {
1050 event.Skip();
1051 }
1052
1053 void wxSearchCtrl::OnSetFocus( wxFocusEvent& /*event*/ )
1054 {
1055 if ( m_text )
1056 {
1057 m_text->SetFocus();
1058 }
1059 }
1060
1061 void wxSearchCtrl::OnSize( wxSizeEvent& event )
1062 {
1063 int width, height;
1064 GetSize(&width, &height);
1065 LayoutControls(0, 0, width, height);
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 // !wxUSE_NATIVE_SEARCH_CONTROL
1078
1079 #endif // wxUSE_SEARCHCTRL