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