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