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