20#include "../KeyboardCapture.h"
31#include <wx/dcbuffer.h>
34#include <wx/stattext.h>
35#include <wx/tooltip.h>
36#include <wx/toplevel.h>
38#if wxUSE_ACCESSIBILITY
46 virtual ~ NumericTextCtrlAx();
52 wxAccStatus DoDefaultAction(
int childId)
override;
56 wxAccStatus GetChild(
int childId, wxAccessible **child)
override;
59 wxAccStatus GetChildCount(
int *childCount)
override;
67 wxAccStatus GetDefaultAction(
int childId, wxString *actionName)
override;
70 wxAccStatus GetDescription(
int childId, wxString *description)
override;
76 wxAccStatus GetFocus(
int *childId, wxAccessible **child)
override;
79 wxAccStatus GetHelpText(
int childId, wxString *helpText)
override;
83 wxAccStatus GetKeyboardShortcut(
int childId, wxString *shortcut)
override;
87 wxAccStatus GetLocation(wxRect & rect,
int elementId)
override;
90 wxAccStatus GetName(
int childId, wxString *
name)
override;
93 wxAccStatus GetRole(
int childId, wxAccRole *role)
override;
103 wxAccStatus GetSelections(wxVariant *selections)
override;
106 wxAccStatus GetState(
int childId,
long *state)
override;
110 wxAccStatus GetValue(
int childId, wxString *strValue)
override;
116 wxString mCachedName;
117 wxString mLastCtrlString;
152 wxControl(parent,
id, pos,
size, wxSUNKEN_BORDER | wxWANTS_CHARS),
158 mAutoPos(options.autoPos)
161 mAllowInvalidValue =
false;
171 mReadOnly = options.readOnly;
172 mMenuEnabled = options.menuEnabled;
173 mButtonWidth = mMenuEnabled ? 9 : 0;
175 SetLayoutDirection(wxLayout_LeftToRight);
186 mScrollRemainder = 0.0;
188#if wxUSE_ACCESSIBILITY
191 SetAccessible(
safenew NumericTextCtrlAx(
this));
194 if (options.hasInvalidValue)
195 SetInvalidValue( options.invalidValue );
197 if (!options.format.formatStr.empty())
198 SetFormatString( options.format );
200 if (options.hasValue)
201 SetValue( options.value );
285 wxString tip(
_(
"(Use context menu to change format.)"));
289 wxToolTip *tt = GetToolTip();
290 if (tt && tt->GetTip() == tip)
325 wxFont pf(wxSize(boxW, boxH), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
326 int fontSize = pf.GetPointSize();
332 dc.GetTextExtent(
wxT(
"0"), &strW, &strH);
333 while (strW > boxW || strH > boxH) {
334 dc.SetFont(wxFont(--fontSize, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL));
335 dc.GetTextExtent(
wxT(
"0"), &strW, &strH);
341 mDigitFont = std::make_unique<wxFont>(fontSize, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
349 std::unique_ptr<wxFont> labelFont = std::make_unique<wxFont>(fontSize - 1, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
352 dc.SetFont(*labelFont);
360 dc.GetTextExtent(
mPrefix, &strW, &strH);
374 for (
int i = 0, fcnt =
mFields.size(); i < fcnt; ++i) {
382 for (
int j = 0, dcnt =
mFields[i].digits; j < dcnt; ++j) {
399 pos +=
mFields[i].label.length();
404 for (
int i = 0, fcnt =
mFields.size(); i < fcnt; ++i) {
409 x += (boxW *
mFields[i].digits) + strW;
432 memDC.GetTextExtent(
mPrefix, &strW, &strH);
445 memDC.SetBrush(Brush);
446 memDC.SetPen(*wxTRANSPARENT_PEN);
451 memDC.GetTextExtent(
wxT(
"0"), &strW, &strH);
452 int labelTop = numberBottom - strH;
459 memDC.SetBrush(Brush);
461 for(i = 0; i <
mDigits.size(); i++)
462 memDC.DrawRectangle(
GetBox(i));
463 memDC.SetBrush( wxNullBrush );
465 for(i = 0; i <
mFields.size(); i++)
466 memDC.DrawText(
mFields[i].label,
472 memDC.SetBrush(*wxBLACK_BRUSH);
473 memDC.SetPen(*wxBLACK_PEN);
484 wxSize sz = GetSize();
485 wxSize csz = GetClientSize();
488 sz.y =
mHeight + (sz.y - csz.y);
500 wxBufferedPaintDC dc(
this);
510 dc.SetBrush(*wxTRANSPARENT_BRUSH);
512 dc.SetPen( wxNullPen );
519 dc.SetPen(*wxTRANSPARENT_PEN);
521 dc.SetBrush( Brush );
524 for(i = 0; i < (int)
mDigits.size(); i++) {
527 dc.DrawRectangle(box);
535 dc.DrawText(digit, x, y);
541 dc.SetPen( wxNullPen );
542 dc.SetBrush( wxNullBrush );
557 int currentSelection = -1;
562 currentSelection = i;
566 menu.Bind(wxEVT_MENU, [](
auto&){});
578 if (menu.IsChecked(
ID_MENU + i) && i != currentSelection) {
584 eventType = EVT_TIMETEXTCTRL_UPDATED;
587 eventType = EVT_FREQUENCYTEXTCTRL_UPDATED;
590 eventType = EVT_BANDWIDTHTEXTCTRL_UPDATED;
597 wxCommandEvent e(eventType, GetId());
600 GetParent()->GetEventHandler()->AddPendingEvent(e);
608 if (event.LeftDown() && event.GetX() >=
mWidth) {
609 wxContextMenuEvent e;
612 else if (event.LeftDown()) {
619 for(i = 0; i <
mDigits.size(); i++) {
620 int dist = abs(event.m_x - (
GetBox(i).x +
622 if (dist < bestDist) {
631 wxContextMenuEvent e;
634 else if(!
mReadOnly && event.m_wheelRotation != 0 ) {
635 double steps =
event.m_wheelRotation /
636 (
event.m_wheelDelta > 0 ? (double)event.m_wheelDelta : 120.0) +
639 steps = floor(steps);
641 Adjust((
int)fabs(steps), steps < 0.0 ? -1 : 1);
650 if (event.GetEventType() != wxEVT_KILL_FOCUS &&
659 wxKeyEvent *kevent = (wxKeyEvent *)event.GetEventObject();
660 int keyCode = kevent->GetKeyCode();
663 if ((keyCode >= WXK_NUMPAD0) && (keyCode <= WXK_NUMPAD9))
664 keyCode -= WXK_NUMPAD0 -
'0';
677 case WXK_NUMPAD_ENTER:
682 if (keyCode >=
'0' && keyCode <= '9' && !kevent->HasAnyModifiers())
693 int keyCode =
event.GetKeyCode();
697 if ((keyCode >= WXK_NUMPAD0) && (keyCode <= WXK_NUMPAD9))
698 keyCode -= WXK_NUMPAD0 -
'0';
700 if ((keyCode >=
'0' && keyCode <=
'9' && !event.HasAnyModifiers()) ||
701 (keyCode == WXK_DELETE) ||
702 (keyCode == WXK_BACK) ||
703 (keyCode == WXK_UP) ||
704 (keyCode == WXK_DOWN)) {
719 int keyCode =
event.GetKeyCode();
728 if ((keyCode >= WXK_NUMPAD0) && (keyCode <= WXK_NUMPAD9))
729 keyCode -= WXK_NUMPAD0 -
'0';
731 if (!
mReadOnly && (keyCode >=
'0' && keyCode <=
'9' && !event.HasAnyModifiers())) {
747 else if (!
mReadOnly && keyCode == WXK_DELETE) {
752 else if (!
mReadOnly && keyCode == WXK_BACK) {
758 if (theDigit != wxChar(
'-'))
766 else if (keyCode == WXK_LEFT) {
773 else if (keyCode == WXK_RIGHT) {
779 else if (keyCode == WXK_HOME) {
784 else if (keyCode == WXK_END) {
789 else if (!
mReadOnly && keyCode == WXK_UP) {
794 else if (!
mReadOnly && keyCode == WXK_DOWN) {
799 else if (keyCode == WXK_TAB) {
800#if defined(__WXMSW__)
803 wxWindow* parent = GetParent();
804 wxNavigationKeyEvent nevent;
805 nevent.SetWindowChange(event.ControlDown());
806 nevent.SetDirection(!event.ShiftDown());
807 nevent.SetEventObject(parent);
808 nevent.SetCurrentFocus(parent);
809 GetParent()->GetEventHandler()->ProcessEvent(nevent);
811 Navigate(event.ShiftDown()
812 ? wxNavigationKeyEvent::IsBackward
813 : wxNavigationKeyEvent::IsForward);
817 else if (keyCode == WXK_RETURN || keyCode == WXK_NUMPAD_ENTER) {
818 wxTopLevelWindow *tlw = wxDynamicCast(wxGetTopLevelParent(
this), wxTopLevelWindow);
819 wxWindow *def = tlw->GetDefaultItem();
820 if (def && def->IsEnabled()) {
823 cevent.SetEventObject( def );
824 GetParent()->GetEventHandler()->ProcessEvent(cevent);
840#if wxUSE_ACCESSIBILITY
849 GetAccessible()->NotifyEvent(wxACC_EVENT_OBJECT_FOCUS,
864 event.SetEventObject(
this);
865 GetEventHandler()->ProcessEvent(event);
867#if wxUSE_ACCESSIBILITY
877 GetAccessible()->NotifyEvent(wxACC_EVENT_OBJECT_FOCUS,
882 GetAccessible()->NotifyEvent(wxACC_EVENT_OBJECT_NAMECHANGE,
920#if wxUSE_ACCESSIBILITY
930NumericTextCtrlAx::~NumericTextCtrlAx()
938wxAccStatus NumericTextCtrlAx::DoDefaultAction(
int WXUNUSED(childId))
940 return wxACC_NOT_SUPPORTED;
945wxAccStatus NumericTextCtrlAx::GetChild(
int childId, wxAccessible **child)
947 if (childId == wxACC_SELF) {
958wxAccStatus NumericTextCtrlAx::GetChildCount(
int *childCount)
960 *childCount = mCtrl->mDigits.size();
972wxAccStatus NumericTextCtrlAx::GetDefaultAction(
int WXUNUSED(childId), wxString *actionName)
980wxAccStatus NumericTextCtrlAx::GetDescription(
int WXUNUSED(childId), wxString *description)
982 description->clear();
991wxAccStatus NumericTextCtrlAx::GetFocus(
int *childId, wxAccessible **child)
993 *childId = mCtrl->GetFocusedDigit();
1000wxAccStatus NumericTextCtrlAx::GetHelpText(
int WXUNUSED(childId), wxString *helpText)
1004 wxToolTip *pTip = mCtrl->GetToolTip();
1006 *helpText = pTip->GetTip();
1013 return wxACC_NOT_SUPPORTED;
1019wxAccStatus NumericTextCtrlAx::GetKeyboardShortcut(
int WXUNUSED(childId), wxString *shortcut)
1028wxAccStatus NumericTextCtrlAx::GetLocation(wxRect & rect,
int elementId)
1030 if ((elementId != wxACC_SELF) &&
1036 rect = mCtrl->GetBox(elementId - 1);
1037 rect.SetPosition(mCtrl->ClientToScreen(rect.GetPosition()));
1041 rect = mCtrl->GetRect();
1042 rect.SetPosition(mCtrl->GetParent()->ClientToScreen(rect.GetPosition()));
1048static void GetFraction( wxString &
label,
1050 bool isTime,
int digits )
1056 tr =
XO(
"centiseconds");
1057 else if (digits == 3)
1058 tr =
XO(
"milliseconds");
1065wxAccStatus NumericTextCtrlAx::GetName(
int childId, wxString *
name)
1068 std::vector<NumericField> & mFields = mCtrl->mFields;
1070 wxString ctrlString = mCtrl->GetString();
1071 int field = mCtrl->GetFocusedField();
1076 if ((childId == wxACC_SELF) ||
1081 *
name = mCtrl->GetName();
1083 *
name = mCtrl->GetLabel();
1096 else if (childId == mLastDigit && ctrlString.IsSameAs(mLastCtrlString)) {
1097 *
name = mCachedName;
1102 if (mLastField !=
field) {
1104 int cnt = mFields.size();
1105 wxString decimal = wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT, wxLOCALE_CAT_NUMBER);
1114 int digits = mFields[
field - 1].digits;
1115 GetFraction(
label, mCtrl->mFormatString,
1121 else if (
label == decimal &&
field == cnt - 1) {
1129 mCtrl->GetString().at(mCtrl->mDigits[childId - 1].pos);
1131 mLastDigit = childId;
1135 else if (mLastDigit != childId) {
1136 *
name = mCtrl->GetString().at(mCtrl->mDigits[childId - 1].pos);
1137 mLastDigit = childId;
1146 mCachedName = *
name;
1147 mLastCtrlString = ctrlString;
1154wxAccStatus NumericTextCtrlAx::GetRole(
int WXUNUSED(childId), wxAccRole *role)
1156 *role = wxROLE_SYSTEM_STATICTEXT;
1168wxAccStatus NumericTextCtrlAx::GetSelections(wxVariant * WXUNUSED(selections))
1170 return wxACC_NOT_IMPLEMENTED;
1174wxAccStatus NumericTextCtrlAx::GetState(
int WXUNUSED(childId),
long *state)
1176 *state = wxACC_STATE_SYSTEM_FOCUSABLE;
1184wxAccStatus NumericTextCtrlAx::GetValue(
int WXUNUSED(childId), wxString * WXUNUSED(strValue))
1186 return wxACC_NOT_IMPLEMENTED;
wxEVT_COMMAND_BUTTON_CLICKED
@ Internal
Indicates internal failure from Audacity.
const TranslatableString name
DEFINE_EVENT_TYPE(EVT_FREQWINDOW_RECALC)
EVT_COMMAND(wxID_ANY, EVT_FREQUENCYTEXTCTRL_UPDATED, LabelDialog::OnFreqUpdate) LabelDialog
wxEVT_COMMAND_TEXT_UPDATED
static void Arrow(wxDC &dc, wxCoord x, wxCoord y, int width, bool down=true)
static void Bevel(wxDC &dc, bool up, const wxRect &r)
void Popup(const BasicUI::WindowPlacement &window, const Point &pos={})
Display the menu at pos, invoke at most one action, then hide it.
ComponentInterfaceSymbol pairs a persistent string identifier used internally with an optional,...
const wxString Translation() const
NumericConverter provides the advanced formatting control used in the selection bar of Audacity.
FormatStrings mFormatString
virtual void ControlsToValue()
virtual void ValueToControls()
std::vector< DigitInfo > mDigits
void SetSampleRate(double sampleRate)
FormatStrings GetBuiltinFormat(const int index)
bool SetFormatString(const FormatStrings &formatString)
std::vector< NumericField > mFields
void SetValue(double newValue)
NumericFormatSymbol GetBuiltinName(const int index)
void Adjust(int steps, int dir)
void EnableMenu(bool enable=true)
void OnMouse(wxMouseEvent &event)
void OnContext(wxContextMenuEvent &event)
bool SetFormatString(const FormatStrings &formatString)
void OnFocus(wxFocusEvent &event)
void OnKeyDown(wxKeyEvent &event)
void SetReadOnly(bool readOnly=true)
void Updated(bool keyup=false)
std::unique_ptr< wxFont > mDigitFont
virtual ~NumericTextCtrl()
void SetInvalidValue(double invalidValue)
wxRect GetBox(size_t ii) const
void OnPaint(wxPaintEvent &event)
void SetSampleRate(double sampleRate)
void OnKeyUp(wxKeyEvent &event)
void OnErase(wxEraseEvent &event)
wxSize ComputeSizing(bool update=true, wxCoord digitW=0, wxCoord digitH=0)
void ValueToControls() override
void SetDigitSize(int width, int height)
std::vector< wxRect > mBoxes
std::unique_ptr< wxBitmap > mBackgroundBitmap
void SetName(const TranslatableString &name)
NumericConverter::Type mType
bool SetFormatName(const NumericFormatSymbol &formatName)
void ControlsToValue() override
void SetValue(double newValue)
std::unique_ptr< wxFont > mLabelFont
void OnCaptureKey(wxCommandEvent &event)
wxColour & Colour(int iIndex)
void SetBrushColour(wxBrush &Brush, int iIndex)
void SetPenColour(wxPen &Pen, int iIndex)
Holds a msgid for the translation catalog; may also bind format arguments.
wxString Translation() const
An alternative to using wxWindowAccessible, which in wxWidgets 3.1.1 contained GetParent() which was ...
void SetFocus(const WindowPlacement &focus)
Set the window that accepts keyboard input.
std::unique_ptr< WindowPlacement > FindFocus()
Find the window that is accepting keyboard input, if any.
void OnFocus(wxWindow &window, wxFocusEvent &event)
a function useful to implement a focus event handler The window releases the keyboard if the event is...