void wxSpinCtrl::DoGetClientSize(int *x, int *y) const { RECT spinrect = wxGetClientRect(GetHwnd()); RECT textrect = wxGetClientRect(GetBuddyHwnd()); RECT ctrlrect; UnionRect(&ctrlrect,&textrect, &spinrect); if ( x ) *x = ctrlrect.right - ctrlrect.left; if ( y ) *y = ctrlrect.bottom - ctrlrect.top; }
// get total size of the control void wxSpinCtrl::DoGetSize(int *x, int *y) const { RECT spinrect, textrect, ctrlrect; GetWindowRect(GetHwnd(), &spinrect); GetWindowRect(GetBuddyHwnd(), &textrect); UnionRect(&ctrlrect,&textrect, &spinrect); if ( x ) *x = ctrlrect.right - ctrlrect.left; if ( y ) *y = ctrlrect.bottom - ctrlrect.top; }
bool wxSpinCtrl::Reparent(wxWindowBase *newParent) { // Reparenting both the updown control and its buddy does not seem to work: // they continue to be connected somehow, but visually there is no feedback // on the buddy edit control. To avoid this problem, we reparent the buddy // window normally, but we recreate the updown control and reassign its // buddy. if ( !wxWindowBase::Reparent(newParent) ) return false; newParent->GetChildren().DeleteObject(this); // preserve the old values const wxSize size = GetSize(); int value = GetValue(); const wxRect btnRect = wxRectFromRECT(wxGetWindowRect(GetHwnd())); // destroy the old spin button UnsubclassWin(); if ( !::DestroyWindow(GetHwnd()) ) wxLogLastError(wxT("DestroyWindow")); // create and initialize the new one if ( !wxSpinButton::Create(GetParent(), GetId(), btnRect.GetPosition(), btnRect.GetSize(), GetWindowStyle(), GetName()) ) return false; SetValue(value); SetRange(m_min, m_max); SetInitialSize(size); // associate it with the buddy control again ::SetParent(GetBuddyHwnd(), GetHwndOf(GetParent())); (void)::SendMessage(GetHwnd(), UDM_SETBUDDY, (WPARAM)GetBuddyHwnd(), 0); return true; }
int wxChoice::DoInsert(const wxString& item, int pos) { wxCHECK_MSG(!(GetWindowStyle() & wxCB_SORT), -1, wxT("can't insert into choice")); wxCHECK_MSG((pos>=0) && (pos<=GetCount()), -1, wxT("invalid index")); int n = (int)::SendMessage(GetBuddyHwnd(), LB_INSERTSTRING, pos, (LPARAM)item.c_str()); if ( n == LB_ERR ) { wxLogLastError(wxT("SendMessage(LB_INSERTSTRING)")); } return n; }
void wxSpinCtrl::SetLayoutDirection(wxLayoutDirection dir) { #ifndef __WXWINCE__ // Buddy text field is plain EDIT control so we need to set its layout // direction in a specific way. wxUpdateEditLayoutDirection(GetBuddyHwnd(), dir); #endif // !__WXWINCE__ wxSpinButton::SetLayoutDirection(dir); // Reposition the child windows according to the new layout. SetSize(-1, -1, -1, -1, wxSIZE_AUTO | wxSIZE_FORCE); }
bool wxSpinCtrl::SetFont(const wxFont& font) { if ( !wxWindowBase::SetFont(font) ) { // nothing to do return false; } WXHANDLE hFont = GetFont().GetResourceHandle(); (void)::SendMessage(GetBuddyHwnd(), WM_SETFONT, (WPARAM)hFont, TRUE); return true; }
bool wxTextCtrl::AdjustSpaceLimit() { unsigned int limit = ::SendMessage(GetBuddyHwnd(), EM_GETLIMITTEXT, 0, 0); // HACK: we try to automatically extend the limit for the amount of text // to allow (interactively) entering more than 64Kb of text under // Win9x but we shouldn't reset the text limit which was previously // set explicitly with SetMaxLength() // // we could solve this by storing the limit we set in wxTextCtrl but // to save space we prefer to simply test here the actual limit // value: we consider that SetMaxLength() can only be called for // values < 32Kb if ( limit < 0x8000 ) { // we've got more text than limit set by SetMaxLength() return false; } unsigned int len = ::GetWindowTextLength(GetBuddyHwnd()); if ( len >= limit ) { limit = len + 0x8000; // 32Kb if ( limit > 0xffff ) { // this will set it to a platform-dependent maximum (much more // than 64Kb under NT) limit = 0; } ::SendMessage(GetBuddyHwnd(), EM_LIMITTEXT, limit, 0L); } // we changed the limit return true; }
void wxSpinCtrl::SetValue(int val) { wxSpinButton::SetValue(val); // normally setting the value of the spin button is enough as it updates // its buddy control automatically ... if ( wxGetWindowText(m_hwndBuddy).empty() ) { // ... but sometimes it doesn't, notably when the value is 0 and the // text control is currently empty, the spin button seems to be happy // to leave it like this, while we really want to always show the // current value in the control, so do it manually ::SetWindowText(GetBuddyHwnd(), wxString::Format(_T("%d"), val)); } m_oldValue = GetValue(); }
// Make sure the window style (etc.) reflects the HWND style (roughly) void wxTextCtrl::AdoptAttributesFromHWND() { wxWindow::AdoptAttributesFromHWND(); long style = ::GetWindowLong(GetBuddyHwnd(), GWL_STYLE); if (style & ES_MULTILINE) m_windowStyle |= wxTE_MULTILINE; if (style & ES_PASSWORD) m_windowStyle |= wxTE_PASSWORD; if (style & ES_READONLY) m_windowStyle |= wxTE_READONLY; if (style & ES_WANTRETURN) m_windowStyle |= wxTE_PROCESS_ENTER; if (style & ES_CENTER) m_windowStyle |= wxTE_CENTRE; if (style & ES_RIGHT) m_windowStyle |= wxTE_RIGHT; }
void wxTextCtrl::DoMoveWindow(int x, int y, int width, int height) { int widthBtn = GetBestSpinnerSize(IsVertical(GetWindowStyle())).x / 2; int widthText = width - widthBtn - MARGIN_BETWEEN; if ( widthText <= 0 ) { wxLogDebug(_T("not enough space for wxSpinCtrl!")); } if ( !::MoveWindow(GetBuddyHwnd(), x, y, widthText, height, TRUE) ) { wxLogLastError(wxT("MoveWindow(buddy)")); } x += widthText + MARGIN_BETWEEN; if ( !::MoveWindow(GetHwnd(), x, y, widthBtn, height, TRUE) ) { wxLogLastError(wxT("MoveWindow")); } }
wxSize wxTextCtrl::DoGetBestSize() const { int cx, cy; wxGetCharSize(GetBuddyHwnd(), &cx, &cy, GetFont()); int wText = DEFAULT_ITEM_WIDTH; int hText = cy; if ( m_windowStyle & wxTE_MULTILINE ) { hText *= wxMax(GetNumberOfLines(), 5); } //else: for single line control everything is ok // we have to add the adjustments for the control height only once, not // once per line, so do it after multiplication above hText += EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy) - cy; return wxSize(wText, hText); }
void wxTextCtrl::SetEditable(bool editable) { ::SendMessage(GetBuddyHwnd(), EM_SETREADONLY, (WPARAM)!editable, (LPARAM)0L); }
bool wxTextCtrl::Create(wxWindow *parent, wxWindowID id, const wxString& value, const wxPoint& pos, const wxSize& size, long style, const wxValidator& validator, const wxString& name) { if ( (style & wxBORDER_MASK) == wxBORDER_DEFAULT ) style |= wxBORDER_SIMPLE; SetWindowStyle(style); WXDWORD exStyle = 0; WXDWORD msStyle = MSWGetStyle(GetWindowStyle(), & exStyle) ; wxSize sizeText(size), sizeBtn(size); sizeBtn.x = GetBestSpinnerSize(IsVertical(style)).x / 2; if ( sizeText.x == wxDefaultCoord ) { // DEFAULT_ITEM_WIDTH is the default width for the text control sizeText.x = DEFAULT_ITEM_WIDTH + MARGIN_BETWEEN + sizeBtn.x; } sizeText.x -= sizeBtn.x + MARGIN_BETWEEN; if ( sizeText.x <= 0 ) { wxLogDebug(_T("not enough space for wxSpinCtrl!")); } wxPoint posBtn(pos); posBtn.x += sizeText.x + MARGIN_BETWEEN; // we need to turn '\n's into "\r\n"s for the multiline controls wxString valueWin; if ( m_windowStyle & wxTE_MULTILINE ) { valueWin = wxTextFile::Translate(value, wxTextFileType_Dos); } else // single line { valueWin = value; } // we must create the list control before the spin button for the purpose // of the dialog navigation: if there is a static text just before the spin // control, activating it by Alt-letter should give focus to the text // control, not the spin and the dialog navigation code will give focus to // the next control (at Windows level), not the one after it // create the text window m_hwndBuddy = (WXHWND)::CreateWindowEx ( exStyle, // sunken border _T("EDIT"), // window class valueWin, // no window title msStyle, // style (will be shown later) pos.x, pos.y, // position 0, 0, // size (will be set later) GetHwndOf(parent), // parent (HMENU)-1, // control id wxGetInstance(), // app instance NULL // unused client data ); if ( !m_hwndBuddy ) { wxLogLastError(wxT("CreateWindow(buddy text window)")); return false; } // initialize wxControl if ( !CreateControl(parent, id, posBtn, sizeBtn, style, validator, name) ) return false; // now create the real HWND WXDWORD spiner_style = WS_VISIBLE | UDS_ALIGNRIGHT | UDS_EXPANDABLE | UDS_NOSCROLL; if ( !IsVertical(style) ) spiner_style |= UDS_HORZ; if ( style & wxSP_WRAP ) spiner_style |= UDS_WRAP; if ( !MSWCreateControl(UPDOWN_CLASS, spiner_style, posBtn, sizeBtn, _T(""), 0) ) return false; // subclass the text ctrl to be able to intercept some events wxSetWindowUserData(GetBuddyHwnd(), this); m_wndProcBuddy = (WXFARPROC)wxSetWindowProc(GetBuddyHwnd(), wxBuddyTextCtrlWndProc); // set up fonts and colours (This is nomally done in MSWCreateControl) InheritAttributes(); if (!m_hasFont) SetFont(GetDefaultAttributes().font); // set the size of the text window - can do it only now, because we // couldn't call DoGetBestSize() before as font wasn't set if ( sizeText.y <= 0 ) { int cx, cy; wxGetCharSize(GetHWND(), &cx, &cy, GetFont()); sizeText.y = EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy); } SetInitialSize(size); (void)::ShowWindow(GetBuddyHwnd(), SW_SHOW); // associate the list window with the spin button (void)::SendMessage(GetHwnd(), UDM_SETBUDDY, (WPARAM)GetBuddyHwnd(), 0); // do it after finishing with m_hwndBuddy creation to avoid generating // initial wxEVT_COMMAND_TEXT_UPDATED message ms_allTextSpins.Add(this); return true; }
int wxChoice::GetSelection() const { return (int)::SendMessage(GetBuddyHwnd(), LB_GETCURSEL, 0, 0); }
void wxChoice::Clear() { Free(); ::SendMessage(GetBuddyHwnd(), LB_RESETCONTENT, 0, 0); }
void wxTextCtrl::MarkDirty() { ::SendMessage(GetBuddyHwnd(), EM_SETMODIFY, TRUE, 0L); }
int wxTextCtrl::GetNumberOfLines() const { return (int)::SendMessage(GetBuddyHwnd(), EM_GETLINECOUNT, 0, 0L); }
long wxTextCtrl::GetInsertionPoint() const { DWORD Pos = (DWORD)::SendMessage(GetBuddyHwnd(), EM_GETSEL, 0, 0L); return Pos & 0xFFFF; }
bool wxSpinCtrl::Create(wxWindow *parent, wxWindowID id, const wxString& value, const wxPoint& pos, const wxSize& size, long style, int min, int max, int initial, const wxString& name) { // this should be in ctor/init function but I don't want to add one to 2.8 // to avoid problems with default ctor which can be inlined in the user // code and so might not get this fix without recompilation m_oldValue = INT_MIN; // before using DoGetBestSize(), have to set style to let the base class // know whether this is a horizontal or vertical control (we're always // vertical) style |= wxSP_VERTICAL; if ( (style & wxBORDER_MASK) == wxBORDER_DEFAULT ) #ifdef __WXWINCE__ style |= wxBORDER_SIMPLE; #else style |= wxBORDER_SUNKEN; #endif SetWindowStyle(style); WXDWORD exStyle = 0; WXDWORD msStyle = MSWGetStyle(GetWindowStyle(), & exStyle) ; // calculate the sizes: the size given is the toal size for both controls // and we need to fit them both in the given width (height is the same) wxSize sizeText(size), sizeBtn(size); sizeBtn.x = wxSpinButton::DoGetBestSize().x; if ( sizeText.x <= 0 ) { // DEFAULT_ITEM_WIDTH is the default width for the text control sizeText.x = DEFAULT_ITEM_WIDTH + MARGIN_BETWEEN + sizeBtn.x; } sizeText.x -= sizeBtn.x + MARGIN_BETWEEN; if ( sizeText.x <= 0 ) { wxLogDebug(_T("not enough space for wxSpinCtrl!")); } wxPoint posBtn(pos); posBtn.x += sizeText.x + MARGIN_BETWEEN; // we must create the text control before the spin button for the purpose // of the dialog navigation: if there is a static text just before the spin // control, activating it by Alt-letter should give focus to the text // control, not the spin and the dialog navigation code will give focus to // the next control (at Windows level), not the one after it // create the text window m_hwndBuddy = (WXHWND)::CreateWindowEx ( exStyle, // sunken border _T("EDIT"), // window class NULL, // no window title msStyle, // style (will be shown later) pos.x, pos.y, // position 0, 0, // size (will be set later) GetHwndOf(parent), // parent (HMENU)-1, // control id wxGetInstance(), // app instance NULL // unused client data ); if ( !m_hwndBuddy ) { wxLogLastError(wxT("CreateWindow(buddy text window)")); return false; } // create the spin button if ( !wxSpinButton::Create(parent, id, posBtn, sizeBtn, style, name) ) { return false; } wxSpinButtonBase::SetRange(min, max); // subclass the text ctrl to be able to intercept some events wxSetWindowUserData(GetBuddyHwnd(), this); m_wndProcBuddy = (WXFARPROC)wxSetWindowProc(GetBuddyHwnd(), wxBuddyTextWndProc); // set up fonts and colours (This is nomally done in MSWCreateControl) InheritAttributes(); if (!m_hasFont) SetFont(GetDefaultAttributes().font); // set the size of the text window - can do it only now, because we // couldn't call DoGetBestSize() before as font wasn't set if ( sizeText.y <= 0 ) { int cx, cy; wxGetCharSize(GetHWND(), &cx, &cy, GetFont()); sizeText.y = EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy); } SetInitialSize(size); (void)::ShowWindow(GetBuddyHwnd(), SW_SHOW); // associate the text window with the spin button (void)::SendMessage(GetHwnd(), UDM_SETBUDDY, (WPARAM)m_hwndBuddy, 0); SetValue(initial); // Set the range in the native control SetRange(min, max); if ( !value.empty() ) { SetValue(value); m_oldValue = (int) wxAtol(value); } else { SetValue(wxString::Format(wxT("%d"), initial)); m_oldValue = initial; } // do it after finishing with m_hwndBuddy creation to avoid generating // initial wxEVT_COMMAND_TEXT_UPDATED message ms_allSpins.Add(this); return true; }
bool wxSpinCtrl::Create(wxWindow *parent, wxWindowID id, const wxString& value, const wxPoint& pos, const wxSize& size, long style, int min, int max, int initial, const wxString& name) { // before using DoGetBestSize(), have to set style to let the base class // know whether this is a horizontal or vertical control (we're always // vertical) style |= wxSP_VERTICAL; if ( (style & wxBORDER_MASK) == wxBORDER_DEFAULT ) #ifdef __WXWINCE__ style |= wxBORDER_SIMPLE; #else style |= wxBORDER_SUNKEN; #endif SetWindowStyle(style); WXDWORD exStyle = 0; WXDWORD msStyle = MSWGetStyle(GetWindowStyle(), & exStyle) ; // Scroll text automatically if there is not enough space to show all of // it, this is better than not allowing to enter more digits at all. msStyle |= ES_AUTOHSCROLL; // propagate text alignment style to text ctrl if ( style & wxALIGN_RIGHT ) msStyle |= ES_RIGHT; else if ( style & wxALIGN_CENTER ) msStyle |= ES_CENTER; // calculate the sizes: the size given is the total size for both controls // and we need to fit them both in the given width (height is the same) wxSize sizeText(size), sizeBtn(size); sizeBtn.x = wxSpinButton::DoGetBestSize().x; if ( sizeText.x <= 0 ) { // DEFAULT_ITEM_WIDTH is the default width for the text control sizeText.x = DEFAULT_ITEM_WIDTH + MARGIN_BETWEEN + sizeBtn.x; } sizeText.x -= sizeBtn.x + MARGIN_BETWEEN; if ( sizeText.x <= 0 ) { wxLogDebug(wxT("not enough space for wxSpinCtrl!")); } wxPoint posBtn(pos); posBtn.x += sizeText.x + MARGIN_BETWEEN; // we must create the text control before the spin button for the purpose // of the dialog navigation: if there is a static text just before the spin // control, activating it by Alt-letter should give focus to the text // control, not the spin and the dialog navigation code will give focus to // the next control (at Windows level), not the one after it // create the text window m_hwndBuddy = (WXHWND)::CreateWindowEx ( exStyle, // sunken border wxT("EDIT"), // window class NULL, // no window title msStyle, // style (will be shown later) pos.x, pos.y, // position 0, 0, // size (will be set later) GetHwndOf(parent), // parent (HMENU)-1, // control id wxGetInstance(), // app instance NULL // unused client data ); if ( !m_hwndBuddy ) { wxLogLastError(wxT("CreateWindow(buddy text window)")); return false; } // create the spin button if ( !wxSpinButton::Create(parent, id, posBtn, sizeBtn, style, name) ) { return false; } wxSpinButtonBase::SetRange(min, max); // subclass the text ctrl to be able to intercept some events gs_spinForTextCtrl[GetBuddyHwnd()] = this; m_wndProcBuddy = (WXFARPROC)wxSetWindowProc(GetBuddyHwnd(), wxBuddyTextWndProc); // set up fonts and colours (This is nomally done in MSWCreateControl) InheritAttributes(); if (!m_hasFont) SetFont(GetDefaultAttributes().font); // set the size of the text window - can do it only now, because we // couldn't call DoGetBestSize() before as font wasn't set if ( sizeText.y <= 0 ) { int cx, cy; wxGetCharSize(GetHWND(), &cx, &cy, GetFont()); sizeText.y = EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy); } SetInitialSize(size); (void)::ShowWindow(GetBuddyHwnd(), SW_SHOW); // associate the text window with the spin button (void)::SendMessage(GetHwnd(), UDM_SETBUDDY, (WPARAM)m_hwndBuddy, 0); // If the initial text value is actually a number, it overrides the // "initial" argument specified later. long initialFromText; if ( value.ToLong(&initialFromText) ) initial = initialFromText; SetValue(initial); m_oldValue = initial; // Set the range in the native control SetRange(min, max); // Also set the text part of the control if it was specified independently // but don't generate an event for this, it would be unexpected. m_blockEvent = true; if ( !value.empty() ) SetValue(value); m_blockEvent = false; return true; }
void wxChoice::SetSelection(int n) { ::SendMessage(GetBuddyHwnd(), LB_SETCURSEL, n, 0); }
int wxChoice::GetCount() const { return (int)::SendMessage(GetBuddyHwnd(), LB_GETCOUNT, 0, 0); }
bool wxTextCtrl::IsModified() const { return ::SendMessage(GetBuddyHwnd(), EM_GETMODIFY, 0, 0) != 0; }
void wxTextCtrl::SetMaxLength(unsigned long len) { ::SendMessage(GetBuddyHwnd(), EM_LIMITTEXT, len, 0); }
void wxTextCtrl::DiscardEdits() { ::SendMessage(GetBuddyHwnd(), EM_SETMODIFY, FALSE, 0L); }
void wxChoice::DoDeleteOneItem(unsigned int n) { wxCHECK_RET( IsValid(n), wxT("invalid item index in wxChoice::Delete") ); ::SendMessage(GetBuddyHwnd(), LB_DELETESTRING, n, 0); }
long wxTextCtrl::GetLengthOfLineContainingPos(long pos) const { return ::SendMessage(GetBuddyHwnd(), EM_LINELENGTH, (WPARAM)pos, 0L); }
void wxChoice::DoClear() { ::SendMessage(GetBuddyHwnd(), LB_RESETCONTENT, 0, 0); }
bool wxTextCtrl::CanRedo() const { return ::SendMessage(GetBuddyHwnd(), EM_CANUNDO, 0, 0) != 0; }
void wxSpinCtrl::SetFocus() { ::SetFocus(GetBuddyHwnd()); }