So base classes will process the event too. This is need for (at least) wxGenericColourButton It has its own handler, but also needs to handle the DPI event in wxButtonImageData.
1226 lines
32 KiB
C++
1226 lines
32 KiB
C++
///////////////////////////////////////////////////////////////////////////////
|
|
// Name: src/generic/srchctlg.cpp
|
|
// Purpose: implements wxSearchCtrl as a composite control
|
|
// Author: Vince Harron
|
|
// Created: 2006-02-19
|
|
// Copyright: Vince Harron
|
|
// Licence: wxWindows licence
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// For compilers that support precompilation, includes "wx.h".
|
|
#include "wx/wxprec.h"
|
|
|
|
|
|
#if wxUSE_SEARCHCTRL
|
|
|
|
#include "wx/srchctrl.h"
|
|
|
|
#ifndef WX_PRECOMP
|
|
#include "wx/button.h"
|
|
#include "wx/dcclient.h"
|
|
#include "wx/menu.h"
|
|
#include "wx/dcmemory.h"
|
|
#endif //WX_PRECOMP
|
|
|
|
#if !wxUSE_NATIVE_SEARCH_CONTROL
|
|
|
|
#include "wx/image.h"
|
|
#include "wx/utils.h"
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// constants
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// the margin between the text control and the search/cancel buttons
|
|
static const wxCoord MARGIN = 2;
|
|
|
|
// arguments to wxColour::ChangeLightness() for making the search/cancel
|
|
// bitmaps foreground colour, respectively
|
|
static const int SEARCH_BITMAP_LIGHTNESS = 140; // slightly lighter
|
|
static const int CANCEL_BITMAP_LIGHTNESS = 160; // a bit more lighter
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// wxSearchTextCtrl: text control used by search control
|
|
// ----------------------------------------------------------------------------
|
|
|
|
class wxSearchTextCtrl : public wxTextCtrl
|
|
{
|
|
public:
|
|
wxSearchTextCtrl(wxSearchCtrl *search, const wxString& value, int style)
|
|
: wxTextCtrl(search, wxID_ANY, value, wxDefaultPosition, wxDefaultSize,
|
|
(style & ~wxBORDER_MASK) | wxNO_BORDER | wxTE_PROCESS_ENTER)
|
|
{
|
|
m_search = search;
|
|
|
|
SetHint(_("Search"));
|
|
|
|
// Ensure that our best size is recomputed using our overridden
|
|
// DoGetBestSize().
|
|
InvalidateBestSize();
|
|
}
|
|
|
|
virtual wxWindow* GetMainWindowOfCompositeControl() wxOVERRIDE
|
|
{
|
|
return m_search;
|
|
}
|
|
|
|
// provide access to the base class protected methods to wxSearchCtrl which
|
|
// needs to forward to them
|
|
void DoSetValue(const wxString& value, int flags) wxOVERRIDE
|
|
{
|
|
wxTextCtrl::DoSetValue(value, flags);
|
|
}
|
|
|
|
bool DoLoadFile(const wxString& file, int fileType) wxOVERRIDE
|
|
{
|
|
return wxTextCtrl::DoLoadFile(file, fileType);
|
|
}
|
|
|
|
bool DoSaveFile(const wxString& file, int fileType) wxOVERRIDE
|
|
{
|
|
return wxTextCtrl::DoSaveFile(file, fileType);
|
|
}
|
|
|
|
protected:
|
|
void OnText(wxCommandEvent& eventText)
|
|
{
|
|
wxCommandEvent event(eventText);
|
|
event.SetEventObject(m_search);
|
|
event.SetId(m_search->GetId());
|
|
|
|
m_search->GetEventHandler()->ProcessEvent(event);
|
|
}
|
|
|
|
void OnTextEnter(wxCommandEvent& WXUNUSED(event))
|
|
{
|
|
if ( !IsEmpty() )
|
|
{
|
|
wxCommandEvent event(wxEVT_SEARCH, m_search->GetId());
|
|
event.SetEventObject(m_search);
|
|
event.SetString(m_search->GetValue());
|
|
|
|
m_search->ProcessWindowEvent(event);
|
|
}
|
|
}
|
|
|
|
#ifdef __WXMSW__
|
|
// We increase the text control height to be the same as for the controls
|
|
// with border as this is what we actually need here because even though
|
|
// this control itself is borderless, it's inside wxSearchCtrl which does
|
|
// have the border and so should have the same height as the normal text
|
|
// entries with border.
|
|
//
|
|
// This is a bit ugly and it would arguably be better to use whatever size
|
|
// the base class version returns and just centre the text vertically in
|
|
// the search control but I failed to modify the code in LayoutControls()
|
|
// to do this easily and as there is much in that code I don't understand
|
|
// (notably what is the logic for buttons sizing?) I prefer to not touch it
|
|
// at all.
|
|
virtual wxSize DoGetBestSize() const wxOVERRIDE
|
|
{
|
|
const long flags = GetWindowStyleFlag();
|
|
wxSearchTextCtrl* const self = const_cast<wxSearchTextCtrl*>(this);
|
|
|
|
self->SetWindowStyleFlag((flags & ~wxBORDER_MASK) | wxBORDER_DEFAULT);
|
|
wxSize size = wxTextCtrl::DoGetBestSize();
|
|
|
|
// The calculation for no external borders in wxTextCtrl::DoGetSizeFromTextSize also
|
|
// removes any padding around the value, which is wrong for this situation. So we
|
|
// can't use wxBORDER_NONE to calculate a good height, in which case we just have to
|
|
// assume a border in the code above and then subtract the space that would be taken up
|
|
// by a themed border (the thin blue border and the white internal border).
|
|
// Don't use FromDIP(4), this seems not needed.
|
|
size.y -= 4;
|
|
|
|
self->SetWindowStyleFlag(flags);
|
|
|
|
return size;
|
|
}
|
|
#endif // __WXMSW__
|
|
|
|
private:
|
|
wxSearchCtrl* m_search;
|
|
|
|
wxDECLARE_EVENT_TABLE();
|
|
};
|
|
|
|
wxBEGIN_EVENT_TABLE(wxSearchTextCtrl, wxTextCtrl)
|
|
EVT_TEXT(wxID_ANY, wxSearchTextCtrl::OnText)
|
|
EVT_TEXT_ENTER(wxID_ANY, wxSearchTextCtrl::OnTextEnter)
|
|
EVT_TEXT_MAXLEN(wxID_ANY, wxSearchTextCtrl::OnText)
|
|
wxEND_EVENT_TABLE()
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// wxSearchButton: search button used by search control
|
|
// ----------------------------------------------------------------------------
|
|
|
|
class wxSearchButton : public wxControl
|
|
{
|
|
public:
|
|
wxSearchButton(wxSearchCtrl *search, int eventType, const wxBitmap& bmp)
|
|
: wxControl(search, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER),
|
|
m_search(search),
|
|
m_eventType(eventType),
|
|
m_bmp(bmp)
|
|
{
|
|
SetBackgroundStyle(wxBG_STYLE_PAINT);
|
|
}
|
|
|
|
void SetBitmapLabel(const wxBitmap& label)
|
|
{
|
|
m_bmp = label;
|
|
InvalidateBestSize();
|
|
}
|
|
|
|
// The buttons in wxSearchCtrl shouldn't accept focus from keyboard because
|
|
// this would interfere with the usual TAB processing: the user expects
|
|
// that pressing TAB in the search control should switch focus to the next
|
|
// control and not give it to the button inside the same control. Besides,
|
|
// the search button can be already activated by pressing "Enter" so there
|
|
// is really no reason for it to be able to get focus from keyboard.
|
|
virtual bool AcceptsFocusFromKeyboard() const wxOVERRIDE { return false; }
|
|
|
|
virtual wxWindow* GetMainWindowOfCompositeControl() wxOVERRIDE
|
|
{
|
|
return m_search;
|
|
}
|
|
|
|
protected:
|
|
wxSize DoGetBestSize() const wxOVERRIDE
|
|
{
|
|
return wxSize(m_bmp.GetWidth(), m_bmp.GetHeight());
|
|
}
|
|
|
|
void OnLeftUp(wxMouseEvent&)
|
|
{
|
|
wxCommandEvent event(m_eventType, m_search->GetId());
|
|
event.SetEventObject(m_search);
|
|
|
|
if ( m_eventType == wxEVT_SEARCH )
|
|
{
|
|
// it's convenient to have the string to search for directly in the
|
|
// event instead of having to retrieve it from the control in the
|
|
// event handler code later, so provide it here
|
|
event.SetString(m_search->GetValue());
|
|
}
|
|
|
|
GetEventHandler()->ProcessEvent(event);
|
|
|
|
m_search->SetFocus();
|
|
|
|
#if wxUSE_MENUS
|
|
if ( m_eventType == wxEVT_SEARCH )
|
|
{
|
|
// this happens automatically, just like on Mac OS X
|
|
m_search->PopupSearchMenu();
|
|
}
|
|
#endif // wxUSE_MENUS
|
|
}
|
|
|
|
void OnPaint(wxPaintEvent&)
|
|
{
|
|
wxPaintDC dc(this);
|
|
|
|
// Clear the background in case of a user bitmap with alpha channel
|
|
dc.SetBrush(m_search->GetBackgroundColour());
|
|
dc.Clear();
|
|
|
|
// Draw the bitmap
|
|
dc.DrawBitmap(m_bmp, 0,0, true);
|
|
}
|
|
|
|
|
|
private:
|
|
wxSearchCtrl *m_search;
|
|
wxEventType m_eventType;
|
|
wxBitmap m_bmp;
|
|
|
|
wxDECLARE_EVENT_TABLE();
|
|
};
|
|
|
|
wxBEGIN_EVENT_TABLE(wxSearchButton, wxControl)
|
|
EVT_LEFT_UP(wxSearchButton::OnLeftUp)
|
|
EVT_PAINT(wxSearchButton::OnPaint)
|
|
wxEND_EVENT_TABLE()
|
|
|
|
wxBEGIN_EVENT_TABLE(wxSearchCtrl, wxSearchCtrlBase)
|
|
EVT_SEARCH_CANCEL(wxID_ANY, wxSearchCtrl::OnCancelButton)
|
|
EVT_SIZE(wxSearchCtrl::OnSize)
|
|
EVT_DPI_CHANGED(wxSearchCtrl::OnDPIChanged)
|
|
wxEND_EVENT_TABLE()
|
|
|
|
wxIMPLEMENT_DYNAMIC_CLASS(wxSearchCtrl, wxSearchCtrlBase);
|
|
|
|
// ============================================================================
|
|
// implementation
|
|
// ============================================================================
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// wxSearchCtrl creation
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// creation
|
|
// --------
|
|
|
|
wxSearchCtrl::wxSearchCtrl()
|
|
{
|
|
Init();
|
|
}
|
|
|
|
wxSearchCtrl::wxSearchCtrl(wxWindow *parent, wxWindowID id,
|
|
const wxString& value,
|
|
const wxPoint& pos,
|
|
const wxSize& size,
|
|
long style,
|
|
const wxValidator& validator,
|
|
const wxString& name)
|
|
{
|
|
Init();
|
|
|
|
Create(parent, id, value, pos, size, style, validator, name);
|
|
}
|
|
|
|
void wxSearchCtrl::Init()
|
|
{
|
|
m_text = NULL;
|
|
m_searchButton = NULL;
|
|
m_cancelButton = NULL;
|
|
#if wxUSE_MENUS
|
|
m_menu = NULL;
|
|
#endif // wxUSE_MENUS
|
|
|
|
m_searchBitmapUser = false;
|
|
m_cancelBitmapUser = false;
|
|
#if wxUSE_MENUS
|
|
m_searchMenuBitmapUser = false;
|
|
#endif // wxUSE_MENUS
|
|
}
|
|
|
|
bool wxSearchCtrl::Create(wxWindow *parent, wxWindowID id,
|
|
const wxString& value,
|
|
const wxPoint& pos,
|
|
const wxSize& size,
|
|
long style,
|
|
const wxValidator& validator,
|
|
const wxString& name)
|
|
{
|
|
if ( !wxSearchCtrlBaseBaseClass::Create(parent, id, pos, size,
|
|
style, validator, name) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
m_text = new wxSearchTextCtrl(this, value, style);
|
|
|
|
m_searchButton = new wxSearchButton(this,
|
|
wxEVT_SEARCH,
|
|
m_searchBitmap);
|
|
|
|
SetBackgroundColour( m_text->GetBackgroundColour() );
|
|
m_text->SetBackgroundColour(wxColour());
|
|
|
|
RecalcBitmaps();
|
|
|
|
SetInitialSize(size);
|
|
Move(pos);
|
|
return true;
|
|
}
|
|
|
|
wxSearchCtrl::~wxSearchCtrl()
|
|
{
|
|
delete m_text;
|
|
delete m_searchButton;
|
|
delete m_cancelButton;
|
|
#if wxUSE_MENUS
|
|
delete m_menu;
|
|
#endif // wxUSE_MENUS
|
|
}
|
|
|
|
|
|
// search control specific interfaces
|
|
#if wxUSE_MENUS
|
|
|
|
void wxSearchCtrl::SetMenu( wxMenu* menu )
|
|
{
|
|
if ( menu == m_menu )
|
|
{
|
|
// no change
|
|
return;
|
|
}
|
|
bool hadMenu = (m_menu != NULL);
|
|
delete m_menu;
|
|
m_menu = menu;
|
|
|
|
if ( m_menu && !hadMenu )
|
|
{
|
|
m_searchButton->Show();
|
|
m_searchButton->SetBitmapLabel(m_searchMenuBitmap);
|
|
m_searchButton->Refresh();
|
|
}
|
|
else if ( !m_menu && hadMenu )
|
|
{
|
|
m_searchButton->SetBitmapLabel(m_searchBitmap);
|
|
if ( m_searchButton->IsShown() )
|
|
{
|
|
m_searchButton->Refresh();
|
|
}
|
|
}
|
|
LayoutControls();
|
|
}
|
|
|
|
wxMenu* wxSearchCtrl::GetMenu()
|
|
{
|
|
return m_menu;
|
|
}
|
|
|
|
#endif // wxUSE_MENUS
|
|
|
|
void wxSearchCtrl::ShowSearchButton( bool show )
|
|
{
|
|
if ( show == IsSearchButtonVisible() )
|
|
{
|
|
// no change
|
|
return;
|
|
}
|
|
if ( show )
|
|
{
|
|
RecalcBitmaps();
|
|
|
|
m_searchButton->Show();
|
|
}
|
|
else // Requested to hide it.
|
|
{
|
|
// Only hide the button if we don't need it for the menu, otherwise it
|
|
// needs to remain shown.
|
|
if ( !HasMenu() )
|
|
m_searchButton->Hide();
|
|
}
|
|
|
|
LayoutControls();
|
|
}
|
|
|
|
bool wxSearchCtrl::IsSearchButtonVisible() const
|
|
{
|
|
return m_searchButton->IsShown() || HasMenu();
|
|
}
|
|
|
|
|
|
void wxSearchCtrl::ShowCancelButton( bool show )
|
|
{
|
|
if ( show == IsCancelButtonVisible() )
|
|
{
|
|
// no change
|
|
return;
|
|
}
|
|
|
|
// This button is not shown initially, so create it on demand if necessary,
|
|
// i.e. if it's the first time we show it.
|
|
if ( !m_cancelButton )
|
|
{
|
|
m_cancelButton = new wxSearchButton(this,
|
|
wxEVT_SEARCH_CANCEL,
|
|
m_cancelBitmap);
|
|
RecalcBitmaps();
|
|
}
|
|
|
|
m_cancelButton->Show(show);
|
|
|
|
LayoutControls();
|
|
}
|
|
|
|
bool wxSearchCtrl::IsCancelButtonVisible() const
|
|
{
|
|
return m_cancelButton && m_cancelButton->IsShown();
|
|
}
|
|
|
|
void wxSearchCtrl::SetDescriptiveText(const wxString& text)
|
|
{
|
|
m_text->SetHint(text);
|
|
}
|
|
|
|
wxString wxSearchCtrl::GetDescriptiveText() const
|
|
{
|
|
return m_text->GetHint();
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// geometry
|
|
// ----------------------------------------------------------------------------
|
|
|
|
wxSize wxSearchCtrl::DoGetBestClientSize() const
|
|
{
|
|
wxSize size = m_text->GetBestSize();
|
|
|
|
if ( IsSearchButtonVisible() )
|
|
{
|
|
size.x += m_searchButton->GetBestSize().x + FromDIP(MARGIN);
|
|
}
|
|
if ( IsCancelButtonVisible() )
|
|
{
|
|
size.x += m_cancelButton->GetBestSize().x + FromDIP(MARGIN);
|
|
}
|
|
|
|
int horizontalBorder = FromDIP(1) + (size.y - size.y * 14 / 21 ) / 2;
|
|
size.x += 2 * horizontalBorder;
|
|
|
|
return size;
|
|
}
|
|
|
|
void wxSearchCtrl::LayoutControls()
|
|
{
|
|
if ( !m_text )
|
|
return;
|
|
|
|
const wxSize sizeTotal = GetClientSize();
|
|
int width = sizeTotal.x,
|
|
height = sizeTotal.y;
|
|
|
|
wxSize sizeText = m_text->GetBestSize();
|
|
// make room for the search menu & clear button
|
|
int horizontalBorder = FromDIP(1) + ( sizeText.y - sizeText.y * 14 / 21 ) / 2;
|
|
int x = 0;
|
|
int textWidth = width;
|
|
|
|
wxSize sizeSearch(0,0);
|
|
wxSize sizeCancel(0,0);
|
|
int searchMargin = 0;
|
|
int cancelMargin = 0;
|
|
if ( IsSearchButtonVisible() )
|
|
{
|
|
sizeSearch = m_searchButton->GetBestSize();
|
|
searchMargin = FromDIP(MARGIN);
|
|
x += horizontalBorder;
|
|
textWidth -= horizontalBorder;
|
|
}
|
|
if ( IsCancelButtonVisible() )
|
|
{
|
|
sizeCancel = m_cancelButton->GetBestSize();
|
|
cancelMargin = FromDIP(MARGIN);
|
|
textWidth -= horizontalBorder;
|
|
}
|
|
|
|
if ( sizeSearch.x + sizeCancel.x > width )
|
|
{
|
|
sizeSearch.x = width/2;
|
|
sizeCancel.x = width/2;
|
|
searchMargin = 0;
|
|
cancelMargin = 0;
|
|
}
|
|
textWidth -= sizeSearch.x + sizeCancel.x + searchMargin + cancelMargin + FromDIP(1);
|
|
if (textWidth < 0) textWidth = 0;
|
|
|
|
// position the subcontrols inside the client area
|
|
|
|
if ( IsSearchButtonVisible() )
|
|
{
|
|
m_searchButton->SetSize(x, (height - sizeSearch.y) / 2,
|
|
sizeSearch.x, sizeSearch.y);
|
|
x += sizeSearch.x;
|
|
x += searchMargin;
|
|
}
|
|
|
|
#ifdef __WXMSW__
|
|
// The text control is too high up on Windows; normally a text control looks OK because
|
|
// of the white border that's part of the theme border. We can also remove a pixel from
|
|
// the height to fit the text control in, because the padding in EDIT_HEIGHT_FROM_CHAR_HEIGHT
|
|
// is already generous.
|
|
int textY = FromDIP(1);
|
|
#else
|
|
int textY = 0;
|
|
#endif
|
|
|
|
m_text->SetSize(x, textY, textWidth, height-textY);
|
|
x += textWidth;
|
|
|
|
if ( IsCancelButtonVisible() )
|
|
{
|
|
x += cancelMargin;
|
|
m_cancelButton->SetSize(x, (height - sizeCancel.y) / 2,
|
|
sizeCancel.x, sizeCancel.y);
|
|
}
|
|
}
|
|
|
|
wxWindowList wxSearchCtrl::GetCompositeWindowParts() const
|
|
{
|
|
wxWindowList parts;
|
|
parts.push_back(m_text);
|
|
parts.push_back(m_searchButton);
|
|
parts.push_back(m_cancelButton);
|
|
return parts;
|
|
}
|
|
|
|
// accessors
|
|
// ---------
|
|
|
|
wxString wxSearchCtrl::DoGetValue() const
|
|
{
|
|
return m_text->GetValue();
|
|
}
|
|
wxString wxSearchCtrl::GetRange(long from, long to) const
|
|
{
|
|
return m_text->GetRange(from, to);
|
|
}
|
|
|
|
int wxSearchCtrl::GetLineLength(long lineNo) const
|
|
{
|
|
return m_text->GetLineLength(lineNo);
|
|
}
|
|
wxString wxSearchCtrl::GetLineText(long lineNo) const
|
|
{
|
|
return m_text->GetLineText(lineNo);
|
|
}
|
|
int wxSearchCtrl::GetNumberOfLines() const
|
|
{
|
|
return m_text->GetNumberOfLines();
|
|
}
|
|
|
|
bool wxSearchCtrl::IsModified() const
|
|
{
|
|
return m_text->IsModified();
|
|
}
|
|
bool wxSearchCtrl::IsEditable() const
|
|
{
|
|
return m_text->IsEditable();
|
|
}
|
|
|
|
// more readable flag testing methods
|
|
bool wxSearchCtrl::IsSingleLine() const
|
|
{
|
|
return m_text->IsSingleLine();
|
|
}
|
|
bool wxSearchCtrl::IsMultiLine() const
|
|
{
|
|
return m_text->IsMultiLine();
|
|
}
|
|
|
|
// If the return values from and to are the same, there is no selection.
|
|
void wxSearchCtrl::GetSelection(long* from, long* to) const
|
|
{
|
|
m_text->GetSelection(from, to);
|
|
}
|
|
|
|
wxString wxSearchCtrl::GetStringSelection() const
|
|
{
|
|
return m_text->GetStringSelection();
|
|
}
|
|
|
|
// operations
|
|
// ----------
|
|
|
|
// editing
|
|
void wxSearchCtrl::Clear()
|
|
{
|
|
m_text->Clear();
|
|
}
|
|
void wxSearchCtrl::Replace(long from, long to, const wxString& value)
|
|
{
|
|
m_text->Replace(from, to, value);
|
|
}
|
|
void wxSearchCtrl::Remove(long from, long to)
|
|
{
|
|
m_text->Remove(from, to);
|
|
}
|
|
|
|
// load/save the controls contents from/to the file
|
|
bool wxSearchCtrl::LoadFile(const wxString& file)
|
|
{
|
|
return m_text->LoadFile(file);
|
|
}
|
|
bool wxSearchCtrl::SaveFile(const wxString& file)
|
|
{
|
|
return m_text->SaveFile(file);
|
|
}
|
|
|
|
// sets/clears the dirty flag
|
|
void wxSearchCtrl::MarkDirty()
|
|
{
|
|
m_text->MarkDirty();
|
|
}
|
|
void wxSearchCtrl::DiscardEdits()
|
|
{
|
|
m_text->DiscardEdits();
|
|
}
|
|
|
|
// set the max number of characters which may be entered in a single line
|
|
// text control
|
|
void wxSearchCtrl::SetMaxLength(unsigned long len)
|
|
{
|
|
m_text->SetMaxLength(len);
|
|
}
|
|
|
|
// writing text inserts it at the current position, appending always
|
|
// inserts it at the end
|
|
void wxSearchCtrl::WriteText(const wxString& text)
|
|
{
|
|
m_text->WriteText(text);
|
|
}
|
|
void wxSearchCtrl::AppendText(const wxString& text)
|
|
{
|
|
m_text->AppendText(text);
|
|
}
|
|
|
|
// insert the character which would have resulted from this key event,
|
|
// return true if anything has been inserted
|
|
bool wxSearchCtrl::EmulateKeyPress(const wxKeyEvent& event)
|
|
{
|
|
return m_text->EmulateKeyPress(event);
|
|
}
|
|
|
|
// text control under some platforms supports the text styles: these
|
|
// methods allow to apply the given text style to the given selection or to
|
|
// set/get the style which will be used for all appended text
|
|
bool wxSearchCtrl::SetStyle(long start, long end, const wxTextAttr& style)
|
|
{
|
|
return m_text->SetStyle(start, end, style);
|
|
}
|
|
bool wxSearchCtrl::GetStyle(long position, wxTextAttr& style)
|
|
{
|
|
return m_text->GetStyle(position, style);
|
|
}
|
|
bool wxSearchCtrl::SetDefaultStyle(const wxTextAttr& style)
|
|
{
|
|
return m_text->SetDefaultStyle(style);
|
|
}
|
|
const wxTextAttr& wxSearchCtrl::GetDefaultStyle() const
|
|
{
|
|
return m_text->GetDefaultStyle();
|
|
}
|
|
|
|
// translate between the position (which is just an index in the text ctrl
|
|
// considering all its contents as a single strings) and (x, y) coordinates
|
|
// which represent column and line.
|
|
long wxSearchCtrl::XYToPosition(long x, long y) const
|
|
{
|
|
return m_text->XYToPosition(x, y);
|
|
}
|
|
bool wxSearchCtrl::PositionToXY(long pos, long *x, long *y) const
|
|
{
|
|
return m_text->PositionToXY(pos, x, y);
|
|
}
|
|
|
|
void wxSearchCtrl::ShowPosition(long pos)
|
|
{
|
|
m_text->ShowPosition(pos);
|
|
}
|
|
|
|
// find the character at position given in pixels
|
|
//
|
|
// NB: pt is in device coords (not adjusted for the client area origin nor
|
|
// scrolling)
|
|
wxTextCtrlHitTestResult wxSearchCtrl::HitTest(const wxPoint& pt, long *pos) const
|
|
{
|
|
return m_text->HitTest(pt, pos);
|
|
}
|
|
wxTextCtrlHitTestResult wxSearchCtrl::HitTest(const wxPoint& pt,
|
|
wxTextCoord *col,
|
|
wxTextCoord *row) const
|
|
{
|
|
return m_text->HitTest(pt, col, row);
|
|
}
|
|
|
|
// Clipboard operations
|
|
void wxSearchCtrl::Copy()
|
|
{
|
|
m_text->Copy();
|
|
}
|
|
void wxSearchCtrl::Cut()
|
|
{
|
|
m_text->Cut();
|
|
}
|
|
void wxSearchCtrl::Paste()
|
|
{
|
|
m_text->Paste();
|
|
}
|
|
|
|
bool wxSearchCtrl::CanCopy() const
|
|
{
|
|
return m_text->CanCopy();
|
|
}
|
|
bool wxSearchCtrl::CanCut() const
|
|
{
|
|
return m_text->CanCut();
|
|
}
|
|
bool wxSearchCtrl::CanPaste() const
|
|
{
|
|
return m_text->CanPaste();
|
|
}
|
|
|
|
// Undo/redo
|
|
void wxSearchCtrl::Undo()
|
|
{
|
|
m_text->Undo();
|
|
}
|
|
void wxSearchCtrl::Redo()
|
|
{
|
|
m_text->Redo();
|
|
}
|
|
|
|
bool wxSearchCtrl::CanUndo() const
|
|
{
|
|
return m_text->CanUndo();
|
|
}
|
|
bool wxSearchCtrl::CanRedo() const
|
|
{
|
|
return m_text->CanRedo();
|
|
}
|
|
|
|
// Insertion point
|
|
void wxSearchCtrl::SetInsertionPoint(long pos)
|
|
{
|
|
m_text->SetInsertionPoint(pos);
|
|
}
|
|
void wxSearchCtrl::SetInsertionPointEnd()
|
|
{
|
|
m_text->SetInsertionPointEnd();
|
|
}
|
|
long wxSearchCtrl::GetInsertionPoint() const
|
|
{
|
|
return m_text->GetInsertionPoint();
|
|
}
|
|
long wxSearchCtrl::GetLastPosition() const
|
|
{
|
|
return m_text->GetLastPosition();
|
|
}
|
|
|
|
void wxSearchCtrl::SetSelection(long from, long to)
|
|
{
|
|
m_text->SetSelection(from, to);
|
|
}
|
|
void wxSearchCtrl::SelectAll()
|
|
{
|
|
m_text->SelectAll();
|
|
}
|
|
|
|
void wxSearchCtrl::SetEditable(bool editable)
|
|
{
|
|
m_text->SetEditable(editable);
|
|
}
|
|
|
|
bool wxSearchCtrl::SetFont(const wxFont& font)
|
|
{
|
|
if ( !wxSearchCtrlBase::SetFont(font) )
|
|
return false;
|
|
|
|
// Recreate the bitmaps as their size may have changed.
|
|
RecalcBitmaps();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool wxSearchCtrl::SetBackgroundColour(const wxColour& colour)
|
|
{
|
|
if ( !wxSearchCtrlBase::SetBackgroundColour(colour) )
|
|
return false;
|
|
|
|
// When the background changes, re-render the bitmaps so that the correct
|
|
// colour shows in their "transparent" area.
|
|
RecalcBitmaps();
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
// Autocomplete
|
|
bool wxSearchCtrl::DoAutoCompleteStrings(const wxArrayString &choices)
|
|
{
|
|
return m_text->AutoComplete( choices );
|
|
}
|
|
|
|
bool wxSearchCtrl::DoAutoCompleteFileNames(int flags)
|
|
{
|
|
return flags == wxFILE ? m_text->AutoCompleteFileNames() : m_text->AutoCompleteDirectories();
|
|
}
|
|
|
|
bool wxSearchCtrl::DoAutoCompleteCustom(wxTextCompleter *completer)
|
|
{
|
|
return m_text->AutoComplete(completer);
|
|
}
|
|
|
|
|
|
// search control generic only
|
|
void wxSearchCtrl::SetSearchBitmap( const wxBitmap& bitmap )
|
|
{
|
|
m_searchBitmap = bitmap;
|
|
m_searchBitmapUser = bitmap.IsOk();
|
|
if ( m_searchBitmapUser )
|
|
{
|
|
if ( m_searchButton && !HasMenu() )
|
|
{
|
|
m_searchButton->SetBitmapLabel( m_searchBitmap );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// the user bitmap was just cleared, generate one
|
|
RecalcBitmaps();
|
|
}
|
|
}
|
|
|
|
#if wxUSE_MENUS
|
|
|
|
void wxSearchCtrl::SetSearchMenuBitmap( const wxBitmap& bitmap )
|
|
{
|
|
m_searchMenuBitmap = bitmap;
|
|
m_searchMenuBitmapUser = bitmap.IsOk();
|
|
if ( m_searchMenuBitmapUser )
|
|
{
|
|
if ( m_searchButton && m_menu )
|
|
{
|
|
m_searchButton->SetBitmapLabel( m_searchMenuBitmap );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// the user bitmap was just cleared, generate one
|
|
RecalcBitmaps();
|
|
}
|
|
}
|
|
|
|
#endif // wxUSE_MENUS
|
|
|
|
void wxSearchCtrl::SetCancelBitmap( const wxBitmap& bitmap )
|
|
{
|
|
m_cancelBitmap = bitmap;
|
|
m_cancelBitmapUser = bitmap.IsOk();
|
|
if ( m_cancelBitmapUser )
|
|
{
|
|
if ( m_cancelButton )
|
|
{
|
|
m_cancelButton->SetBitmapLabel( m_cancelBitmap );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// the user bitmap was just cleared, generate one
|
|
RecalcBitmaps();
|
|
}
|
|
}
|
|
|
|
// Note that overriding DoSetValue() is currently insufficient because the base
|
|
// class ChangeValue() only updates m_hintData of this object (which is null
|
|
// anyhow), instead of updating m_text->m_hintData, see #16998.
|
|
void wxSearchCtrl::ChangeValue(const wxString& value)
|
|
{
|
|
m_text->ChangeValue(value);
|
|
}
|
|
|
|
void wxSearchCtrl::DoSetValue(const wxString& value, int flags)
|
|
{
|
|
m_text->DoSetValue(value, flags);
|
|
}
|
|
|
|
bool wxSearchCtrl::DoLoadFile(const wxString& file, int fileType)
|
|
{
|
|
return m_text->DoLoadFile(file, fileType);
|
|
}
|
|
|
|
bool wxSearchCtrl::DoSaveFile(const wxString& file, int fileType)
|
|
{
|
|
return m_text->DoSaveFile(file, fileType);
|
|
}
|
|
|
|
bool wxSearchCtrl::ShouldInheritColours() const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// icons are rendered at 3-8 times larger than necessary and downscaled for
|
|
// antialiasing
|
|
static int GetMultiplier()
|
|
{
|
|
int depth = ::wxDisplayDepth();
|
|
|
|
if ( depth >= 24 )
|
|
{
|
|
return 8;
|
|
}
|
|
return 6;
|
|
}
|
|
|
|
wxBitmap wxSearchCtrl::RenderSearchBitmap( int x, int y, bool renderDrop )
|
|
{
|
|
wxColour bg = GetBackgroundColour();
|
|
wxColour fg = GetForegroundColour().ChangeLightness(SEARCH_BITMAP_LIGHTNESS);
|
|
|
|
//===============================================================================
|
|
// begin drawing code
|
|
//===============================================================================
|
|
// image stats
|
|
|
|
// force width:height ratio
|
|
if ( 14*x > y*20 )
|
|
{
|
|
// x is too big
|
|
x = y*20/14;
|
|
}
|
|
else
|
|
{
|
|
// y is too big
|
|
y = x*14/20;
|
|
}
|
|
|
|
// glass 11x11, top left corner
|
|
// handle (9,9)-(13,13)
|
|
// drop (13,16)-(19,6)-(16,9)
|
|
|
|
int multiplier = GetMultiplier();
|
|
int penWidth = multiplier * 2;
|
|
|
|
penWidth = penWidth * x / 20;
|
|
|
|
wxBitmap bitmap( multiplier*x, multiplier*y );
|
|
wxMemoryDC mem;
|
|
mem.SelectObject(bitmap);
|
|
|
|
// clear background
|
|
mem.SetBrush( wxBrush(bg) );
|
|
mem.SetPen( wxPen(bg) );
|
|
mem.DrawRectangle(0,0,bitmap.GetWidth(),bitmap.GetHeight());
|
|
|
|
// draw drop glass
|
|
mem.SetBrush( wxBrush(fg) );
|
|
mem.SetPen( wxPen(fg) );
|
|
int glassBase = 5 * x / 20;
|
|
int glassFactor = 2*glassBase + 1;
|
|
int radius = multiplier*glassFactor/2;
|
|
mem.DrawCircle(radius,radius,radius);
|
|
mem.SetBrush( wxBrush(bg) );
|
|
mem.SetPen( wxPen(bg) );
|
|
mem.DrawCircle(radius,radius,radius-penWidth);
|
|
|
|
// draw handle
|
|
int lineStart = radius + (radius-penWidth/2) * 707 / 1000; // 707 / 1000 = 0.707 = 1/sqrt(2);
|
|
|
|
mem.SetPen( wxPen(fg) );
|
|
mem.SetBrush( wxBrush(fg) );
|
|
int handleCornerShift = penWidth * 707 / 1000 / 2; // 707 / 1000 = 0.707 = 1/sqrt(2);
|
|
handleCornerShift = wxMax( handleCornerShift, 1 );
|
|
int handleBase = 4 * x / 20;
|
|
int handleLength = 2*handleBase+1;
|
|
wxPoint handlePolygon[] =
|
|
{
|
|
wxPoint(-handleCornerShift,+handleCornerShift),
|
|
wxPoint(+handleCornerShift,-handleCornerShift),
|
|
wxPoint(multiplier*handleLength/2+handleCornerShift,multiplier*handleLength/2-handleCornerShift),
|
|
wxPoint(multiplier*handleLength/2-handleCornerShift,multiplier*handleLength/2+handleCornerShift),
|
|
};
|
|
mem.DrawPolygon(WXSIZEOF(handlePolygon),handlePolygon,lineStart,lineStart);
|
|
|
|
// draw drop triangle
|
|
int triangleX = 13 * x / 20;
|
|
int triangleY = 5 * x / 20;
|
|
int triangleBase = 3 * x / 20;
|
|
int triangleFactor = triangleBase*2+1;
|
|
if ( renderDrop )
|
|
{
|
|
wxPoint dropPolygon[] =
|
|
{
|
|
wxPoint(multiplier*0,multiplier*0), // triangle left
|
|
wxPoint(multiplier*triangleFactor-1,multiplier*0), // triangle right
|
|
wxPoint(multiplier*triangleFactor/2,multiplier*triangleFactor/2), // triangle bottom
|
|
};
|
|
mem.DrawPolygon(WXSIZEOF(dropPolygon),dropPolygon,multiplier*triangleX,multiplier*triangleY);
|
|
}
|
|
mem.SelectObject(wxNullBitmap);
|
|
|
|
//===============================================================================
|
|
// end drawing code
|
|
//===============================================================================
|
|
|
|
if ( multiplier != 1 )
|
|
{
|
|
wxBitmap::Rescale(bitmap, wxSize(x, y));
|
|
}
|
|
if ( !renderDrop )
|
|
{
|
|
// Trim the edge where the arrow would have gone
|
|
bitmap = bitmap.GetSubBitmap(wxRect(0,0, y,y));
|
|
}
|
|
|
|
return bitmap;
|
|
}
|
|
|
|
wxBitmap wxSearchCtrl::RenderCancelBitmap( int x, int y )
|
|
{
|
|
wxColour bg = GetBackgroundColour();
|
|
wxColour fg = GetForegroundColour().ChangeLightness(CANCEL_BITMAP_LIGHTNESS);
|
|
|
|
//===============================================================================
|
|
// begin drawing code
|
|
//===============================================================================
|
|
// image stats
|
|
|
|
// total size 14x14
|
|
// force 1:1 ratio
|
|
if ( x > y )
|
|
{
|
|
// x is too big
|
|
x = y;
|
|
}
|
|
else
|
|
{
|
|
// y is too big
|
|
y = x;
|
|
}
|
|
|
|
// 14x14 circle
|
|
// cross line starts (4,4)-(10,10)
|
|
// drop (13,16)-(19,6)-(16,9)
|
|
|
|
int multiplier = GetMultiplier();
|
|
|
|
int penWidth = multiplier * x / 14;
|
|
|
|
wxBitmap bitmap( multiplier*x, multiplier*y );
|
|
wxMemoryDC mem;
|
|
mem.SelectObject(bitmap);
|
|
|
|
// clear background
|
|
mem.SetBrush( wxBrush(bg) );
|
|
mem.SetPen( wxPen(bg) );
|
|
mem.DrawRectangle(0,0,bitmap.GetWidth(),bitmap.GetHeight());
|
|
|
|
// draw drop glass
|
|
mem.SetBrush( wxBrush(fg) );
|
|
mem.SetPen( wxPen(fg) );
|
|
int radius = multiplier*x/2;
|
|
mem.DrawCircle(radius,radius,radius);
|
|
|
|
// draw cross
|
|
int lineStartBase = 4 * x / 14;
|
|
int lineLength = x - 2*lineStartBase;
|
|
|
|
mem.SetPen( wxPen(bg) );
|
|
mem.SetBrush( wxBrush(bg) );
|
|
int handleCornerShift = penWidth/2;
|
|
handleCornerShift = wxMax( handleCornerShift, 1 );
|
|
wxPoint handlePolygon[] =
|
|
{
|
|
wxPoint(-handleCornerShift,+handleCornerShift),
|
|
wxPoint(+handleCornerShift,-handleCornerShift),
|
|
wxPoint(multiplier*lineLength+handleCornerShift,multiplier*lineLength-handleCornerShift),
|
|
wxPoint(multiplier*lineLength-handleCornerShift,multiplier*lineLength+handleCornerShift),
|
|
};
|
|
mem.DrawPolygon(WXSIZEOF(handlePolygon),handlePolygon,multiplier*lineStartBase,multiplier*lineStartBase);
|
|
wxPoint handlePolygon2[] =
|
|
{
|
|
wxPoint(+handleCornerShift,+handleCornerShift),
|
|
wxPoint(-handleCornerShift,-handleCornerShift),
|
|
wxPoint(multiplier*lineLength-handleCornerShift,-multiplier*lineLength-handleCornerShift),
|
|
wxPoint(multiplier*lineLength+handleCornerShift,-multiplier*lineLength+handleCornerShift),
|
|
};
|
|
mem.DrawPolygon(WXSIZEOF(handlePolygon2),handlePolygon2,multiplier*lineStartBase,multiplier*(x-lineStartBase));
|
|
|
|
// Stop drawing on the bitmap before possibly calling wxBitmap::Rescale()
|
|
// below.
|
|
mem.SelectObject(wxNullBitmap);
|
|
|
|
//===============================================================================
|
|
// end drawing code
|
|
//===============================================================================
|
|
|
|
if ( multiplier != 1 )
|
|
{
|
|
wxBitmap::Rescale(bitmap, wxSize(x, y));
|
|
}
|
|
|
|
return bitmap;
|
|
}
|
|
|
|
void wxSearchCtrl::RecalcBitmaps()
|
|
{
|
|
if ( !m_text )
|
|
{
|
|
return;
|
|
}
|
|
wxSize sizeText = m_text->GetBestSize();
|
|
|
|
int bitmapHeight = sizeText.y - FromDIP(4);
|
|
int bitmapWidth = sizeText.y * 20 / 14;
|
|
|
|
if ( !m_searchBitmapUser )
|
|
{
|
|
if (
|
|
!m_searchBitmap.IsOk() ||
|
|
m_searchBitmap.GetHeight() != bitmapHeight ||
|
|
m_searchBitmap.GetWidth() != bitmapWidth
|
|
)
|
|
{
|
|
m_searchBitmap = RenderSearchBitmap(bitmapWidth,bitmapHeight,false);
|
|
if ( !HasMenu() )
|
|
{
|
|
m_searchButton->SetBitmapLabel(m_searchBitmap);
|
|
}
|
|
}
|
|
// else this bitmap was set by user, don't alter
|
|
}
|
|
|
|
#if wxUSE_MENUS
|
|
if ( !m_searchMenuBitmapUser )
|
|
{
|
|
if (
|
|
!m_searchMenuBitmap.IsOk() ||
|
|
m_searchMenuBitmap.GetHeight() != bitmapHeight ||
|
|
m_searchMenuBitmap.GetWidth() != bitmapWidth
|
|
)
|
|
{
|
|
m_searchMenuBitmap = RenderSearchBitmap(bitmapWidth,bitmapHeight,true);
|
|
if ( m_menu )
|
|
{
|
|
m_searchButton->SetBitmapLabel(m_searchMenuBitmap);
|
|
}
|
|
}
|
|
// else this bitmap was set by user, don't alter
|
|
}
|
|
#endif // wxUSE_MENUS
|
|
|
|
if ( m_cancelButton && !m_cancelBitmapUser )
|
|
{
|
|
if (
|
|
!m_cancelBitmap.IsOk() ||
|
|
m_cancelBitmap.GetHeight() != bitmapHeight ||
|
|
m_cancelBitmap.GetWidth() != bitmapWidth
|
|
)
|
|
{
|
|
m_cancelBitmap = RenderCancelBitmap(bitmapWidth,bitmapHeight);
|
|
m_cancelButton->SetBitmapLabel(m_cancelBitmap);
|
|
}
|
|
// else this bitmap was set by user, don't alter
|
|
}
|
|
}
|
|
|
|
void wxSearchCtrl::OnCancelButton( wxCommandEvent& event )
|
|
{
|
|
m_text->Clear();
|
|
event.Skip();
|
|
}
|
|
|
|
void wxSearchCtrl::OnSize( wxSizeEvent& WXUNUSED(event) )
|
|
{
|
|
LayoutControls();
|
|
}
|
|
|
|
void wxSearchCtrl::OnDPIChanged(wxDPIChangedEvent &event)
|
|
{
|
|
RecalcBitmaps();
|
|
|
|
event.Skip();
|
|
}
|
|
|
|
#if wxUSE_MENUS
|
|
|
|
void wxSearchCtrl::PopupSearchMenu()
|
|
{
|
|
if ( m_menu )
|
|
{
|
|
wxSize size = GetSize();
|
|
PopupMenu( m_menu, 0, size.y );
|
|
}
|
|
}
|
|
|
|
#endif // wxUSE_MENUS
|
|
|
|
#endif // !wxUSE_NATIVE_SEARCH_CONTROL
|
|
|
|
#endif // wxUSE_SEARCHCTRL
|