Audacity  2.2.2
ASlider.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4 
5  ASlider.cpp
6 
7  Dominic Mazzoni
8 
9 *******************************************************************//*******************************************************************/
30 
31 
32 #include "../Audacity.h"
33 
34 #include <math.h>
35 
36 #include <wx/defs.h>
37 #include <wx/dcbuffer.h>
38 #include <wx/dcclient.h>
39 #include <wx/dcmemory.h>
40 #include <wx/graphics.h>
41 #include <wx/image.h>
42 #include <wx/panel.h>
43 #include <wx/tooltip.h>
44 #include <wx/debug.h>
45 #include <wx/textctrl.h>
46 #include <wx/valtext.h>
47 #include <wx/dialog.h>
48 #include <wx/sizer.h>
49 #include <wx/button.h>
50 #include <wx/statline.h>
51 #include <wx/sizer.h>
52 #include <wx/settings.h>
53 #include <wx/popupwin.h>
54 #include <wx/window.h>
55 
56 #include "../Experimental.h"
57 #include "ASlider.h"
58 #include "Ruler.h"
59 
60 #include "../AColor.h"
61 #include "../ImageManipulation.h"
62 #include "../Project.h"
63 #include "../ShuttleGui.h"
64 
65 #include "../Theme.h"
66 #include "../AllThemeResources.h"
67 
68 #if defined __WXMSW__
69 const int sliderFontSize = 10;
70 #else
71 const int sliderFontSize = 12;
72 #endif
73 
74 #ifndef EXPERIMENTAL_DA
75 #define OPTIONAL_SLIDER_TICKS
76 #endif
77 
78 //
79 // TipPanel
80 //
81 
82 class TipPanel final : public wxFrame
83 {
84  public:
85  TipPanel(wxWindow *parent, const wxArrayString & labels);
86  virtual ~TipPanel() {}
87 
88  wxSize GetSize() const;
89  void SetPos(const wxPoint & pos);
90  void SetLabel(const wxString & label);
91 
92 private:
93  void OnPaint(wxPaintEvent & event);
94 #if defined(__WXGTK__)
95  void OnCreate(wxWindowCreateEvent & event);
96 #endif
97 
98 private:
99  wxString mLabel;
100  int mWidth;
101  int mHeight;
102 
103  DECLARE_EVENT_TABLE()
104 };
105 
106 BEGIN_EVENT_TABLE(TipPanel, wxFrame)
107  EVT_PAINT(TipPanel::OnPaint)
108 #if defined(__WXGTK__)
109  EVT_WINDOW_CREATE(TipPanel::OnCreate)
110 #endif
112 
113 TipPanel::TipPanel(wxWindow *parent, const wxArrayString & labels)
114 : wxFrame(parent, wxID_ANY, wxString{}, wxDefaultPosition, wxDefaultSize,
115  wxFRAME_SHAPED | wxFRAME_FLOAT_ON_PARENT)
116 {
117  SetBackgroundStyle(wxBG_STYLE_PAINT);
118 
119  wxFont labelFont(sliderFontSize, wxSWISS, wxNORMAL, wxNORMAL);
120  mWidth = mHeight = 0;
121  for ( const auto &label : labels ) {
122  int width, height;
123  GetTextExtent(label, &width, &height, NULL, NULL, &labelFont);
124  mWidth = std::max( mWidth, width );
125  mHeight = std::max( mHeight, height );
126  }
127 
128  mWidth += 8;
129  mHeight += 8;
130 
131 #if defined(__WXMSW__) || defined(__WXMAC__)
132  wxGraphicsPath path = wxGraphicsRenderer::GetDefaultRenderer()->CreatePath();
133  path.AddRoundedRectangle(0, 0, mWidth, mHeight, 5);
134  SetShape(path);
135 #endif
136 }
137 
138 wxSize TipPanel::GetSize() const
139 {
140  return wxSize(mWidth, mHeight);
141 }
142 
143 void TipPanel::SetPos(const wxPoint & pos)
144 {
145  SetSize(pos.x, pos.y, mWidth, mHeight);
146 }
147 
148 void TipPanel::SetLabel(const wxString & label)
149 {
150  mLabel = label;
151 }
152 
153 void TipPanel::OnPaint(wxPaintEvent & WXUNUSED(event))
154 {
155  wxAutoBufferedPaintDC dc(this);
156 
157  dc.SetPen(*wxBLACK_PEN);
158  dc.SetBrush(AColor::tooltipBrush);
159  dc.DrawRoundedRectangle(0, 0, mWidth, mHeight, 5);
160 
161  dc.SetFont(wxFont(sliderFontSize, wxSWISS, wxNORMAL, wxNORMAL));
162  dc.SetTextForeground(AColor::tooltipPen.GetColour());
163 
164  int textWidth, textHeight;
165  dc.GetTextExtent(mLabel, &textWidth, &textHeight);
166  dc.DrawText(mLabel, (mWidth - textWidth) / 2, (mHeight - textHeight) / 2);
167 }
168 
169 #if defined(__WXGTK__)
170 void TipPanel::OnCreate(wxWindowCreateEvent & WXUNUSED(event))
171 {
172  wxGraphicsPath path = wxGraphicsRenderer::GetDefaultRenderer()->CreatePath();
173  path.AddRoundedRectangle(0, 0, mWidth, mHeight, 5);
174  SetShape(path);
175 }
176 #endif
177 
178 //
179 // SliderDialog
180 //
181 
182 BEGIN_EVENT_TABLE(SliderDialog, wxDialogWrapper)
183  EVT_TEXT( wxID_ANY, SliderDialog::OnTextChange )
184  EVT_SLIDER(wxID_ANY,SliderDialog::OnSlider)
186 
187 SliderDialog::SliderDialog(wxWindow * parent, wxWindowID id,
188  const wxString & title,
189  wxPoint position,
190  wxSize size,
191  int style,
192  float value,
193  float line,
194  float page):
195  wxDialogWrapper(parent,id,title,position),
196  mStyle(style)
197 {
198  SetName(GetTitle());
199  ShuttleGui S(this, eIsCreating);
200 
201  S.StartVerticalLay();
202  {
203  mTextCtrl = S.AddTextBox( {},
204  wxEmptyString,
205  15);
206  mTextCtrl->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
207 
208  mSlider = safenew ASlider(this,
209  wxID_ANY,
210  title,
211  wxDefaultPosition,
212  size,
214  .Style( style ).Line( line ).Page( page ) );
215  S.AddWindow(mSlider, wxEXPAND);
216  }
217  S.EndVerticalLay();
218 
220 
221  Fit();
222 
223  mSlider->Set(value);
224 }
225 
227 {
228 }
229 
231 {
232  mTextCtrl->SetValue(wxString::Format(wxT("%g"), mSlider->Get(false)));
233  mTextCtrl->SetSelection(-1, -1);
234 
235  return true;
236 }
237 
239 {
240  double value;
241 
242  mTextCtrl->GetValue().ToDouble(&value);
243  if (mStyle == DB_SLIDER)
244  value = DB_TO_LINEAR(value);
245  mSlider->Set(value);
246 
247  return true;
248 }
249 
250 void SliderDialog::OnSlider(wxCommandEvent & event)
251 {
253  event.Skip(false);
254 }
255 
256 void SliderDialog::OnTextChange(wxCommandEvent & event)
257 {
259  event.Skip(false);
260 }
261 
263 {
264  return mSlider->Get(false);
265 }
266 
267 //
268 // LWSlider
269 //
270 
271 // Define the thumb outline
272 static const wxPoint2DDouble outer[] =
273 {
274  wxPoint2DDouble( 2, 0 ),
275  wxPoint2DDouble( 8, 0 ),
276  wxPoint2DDouble( 10, 2 ),
277  wxPoint2DDouble( 10, 8 ),
278  wxPoint2DDouble( 5, 13 ),
279  wxPoint2DDouble( 0, 8 ),
280  wxPoint2DDouble( 0, 2 ),
281  wxPoint2DDouble( 2, 0 )
282 };
283 
284 // Define the left and top interior components when enabled
285 static const wxPoint2DDouble enabledLeftBegin[] =
286 {
287  wxPoint2DDouble( 2, 1 ),
288  wxPoint2DDouble( 1, 2 ),
289  wxPoint2DDouble( 1, 8 ),
290  wxPoint2DDouble( 4, 4 ),
291  wxPoint2DDouble( 4, 7 )
292 };
293 static const wxPoint2DDouble enabledLeftEnd[] =
294 {
295  wxPoint2DDouble( 8, 1 ),
296  wxPoint2DDouble( 1, 8 ),
297  wxPoint2DDouble( 5, 12 ),
298  wxPoint2DDouble( 6, 4 ),
299  wxPoint2DDouble( 6, 7 )
300 };
301 
302 // Define right and bottom interior components when enabled
303 static const wxPoint2DDouble enabledRightBegin[] =
304 {
305  wxPoint2DDouble( 9, 2 ),
306  wxPoint2DDouble( 9, 8 ),
307  wxPoint2DDouble( 4, 5 ),
308  wxPoint2DDouble( 4, 8 ),
309 };
310 static const wxPoint2DDouble enabledRightEnd[] =
311 {
312  wxPoint2DDouble( 9, 8 ),
313  wxPoint2DDouble( 6, 11 ),
314  wxPoint2DDouble( 6, 5 ),
315  wxPoint2DDouble( 6, 8 )
316 };
317 
318 // Define the interior stripes when disabled
319 static const wxPoint2DDouble disabledStripesBegin[] =
320 {
321  wxPoint2DDouble( 3, 2 ),
322  wxPoint2DDouble( 5, 2 ),
323  wxPoint2DDouble( 7, 2 ),
324  wxPoint2DDouble( 2, 3 ),
325  wxPoint2DDouble( 2, 5 ),
326  wxPoint2DDouble( 2, 7 ),
327 };
328 static const wxPoint2DDouble disabledStripesEnd[] =
329 {
330  wxPoint2DDouble( 8, 7 ),
331  wxPoint2DDouble( 8, 5 ),
332  wxPoint2DDouble( 8, 3 ),
333  wxPoint2DDouble( 7, 8 ),
334  wxPoint2DDouble( 6, 9 ),
335  wxPoint2DDouble( 5, 10 ),
336 };
337 
338 // Define the right and bottom interior components when disabled
339 static const wxPoint2DDouble disabledRightBegin[] =
340 {
341  wxPoint2DDouble( 9, 2 ),
342  wxPoint2DDouble( 9, 8 ),
343 };
344 static const wxPoint2DDouble disabledRightEnd[] =
345 {
346  wxPoint2DDouble( 9, 8 ),
347  wxPoint2DDouble( 6, 11 ),
348 };
349 
350 // Construct customizable slider
351 LWSlider::LWSlider(wxWindow * parent,
352  const wxString &name,
353  const wxPoint &pos,
354  const wxSize &size,
355  float minValue,
356  float maxValue,
357  float stepValue,
358  bool canUseShift,
359  int style,
360  bool heavyweight /* = false */,
361  bool popup /* = true */,
362  int orientation /* = wxHORIZONTAL */) // wxHORIZONTAL or wxVERTICAL. wxVERTICAL is currently only for DB_SLIDER.
363 {
364  Init(parent, name, pos, size, minValue, maxValue,
365  stepValue, canUseShift, style, heavyweight, popup, 1.0, orientation);
366 }
367 
368 // Construct predefined slider
369 LWSlider::LWSlider(wxWindow *parent,
370  const wxString &name,
371  const wxPoint &pos,
372  const wxSize &size,
373  int style,
374  bool heavyweight /* = false */,
375  bool popup /* = true */,
376  int orientation /* = wxHORIZONTAL */) // wxHORIZONTAL or wxVERTICAL. wxVERTICAL is currently only for DB_SLIDER.
377 {
378  wxString leftLabel, rightLabel;
379 
380  float minValue, maxValue, stepValue;
381  float speed = 1.0;
382 
383  switch(style)
384  {
385  case PAN_SLIDER:
386  minValue = -1.0f;
387  maxValue = +1.0f;
388  stepValue = 0.1f;
389  orientation = wxHORIZONTAL; //v Vertical PAN_SLIDER currently not handled, forced to horizontal.
390  break;
391  case DB_SLIDER:
392  minValue = -36.0f;
393  //if (orientation == wxHORIZONTAL)
394  maxValue = 36.0f;
395  //else
396  //maxValue = 36.0f; // for MixerBoard //v Previously was 6dB for MixerBoard, but identical for now.
397  stepValue = 1.0f;
398  speed = 0.5;
399  break;
400  case FRAC_SLIDER:
401  minValue = 0.0f;
402  maxValue = 1.0f;
403  stepValue = STEP_CONTINUOUS;
404  break;
405  case SPEED_SLIDER:
406  minValue = 0.01f;
407  maxValue = 3.0f;
408  stepValue = STEP_CONTINUOUS;
409  break;
410 #ifdef EXPERIMENTAL_MIDI_OUT
411  case VEL_SLIDER:
412  minValue = VEL_MIN;
413  maxValue = VEL_MAX;
414  stepValue = 1.0f;
415  speed = 0.5;
416  break;
417 #endif
418  default:
419  minValue = 0.0f;
420  maxValue = 1.0f;
421  stepValue = 0.0f;
422  wxASSERT(false); // undefined style
423  }
424 
425  Init(parent, name, pos, size, minValue, maxValue, stepValue,
426  true, style, heavyweight, popup, speed, orientation);
427 }
428 
429 void LWSlider::Init(wxWindow * parent,
430  const wxString &name,
431  const wxPoint &pos,
432  const wxSize &size,
433  float minValue,
434  float maxValue,
435  float stepValue,
436  bool canUseShift,
437  int style,
438  bool heavyweight,
439  bool popup,
440  float speed,
441  int orientation /* = wxHORIZONTAL */) // wxHORIZONTAL or wxVERTICAL. wxVERTICAL is currently only for DB_SLIDER.
442 {
443  mEnabled = true;
444  mName = name;
445  mStyle = style;
446  mOrientation = orientation;
447  mIsDragging = false;
448  mParent = parent;
449  mHW = heavyweight;
450  mPopup = popup;
451  mSpeed = speed;
452  mID = wxID_ANY;
453  mMinValue = minValue;
454  mMaxValue = maxValue;
455  mStepValue = stepValue;
456  mCanUseShift = canUseShift;
457  mCurrentValue = 0.0f;
458  mDefaultValue = 0.0f;
459  mDefaultShortcut = false;
460  mBitmap = nullptr;
461  mThumbBitmap = nullptr;
462  mThumbBitmapHilited = nullptr;
463  mScrollLine = 1.0f;
464  mScrollPage = 5.0f;
465  mTipPanel = NULL;
466 
467  AdjustSize(size);
468 
469  Move(pos);
470 }
471 
473 {
474 }
475 
476 wxWindowID LWSlider::GetId()
477 {
478  return mID;
479 }
480 
481 void LWSlider::SetId(wxWindowID id)
482 {
483  mID = id;
484 }
485 
486 void LWSlider::SetDefaultValue(float value)
487 {
488  SetDefaultShortcut(true);
489  mDefaultValue = value;
490 }
491 
493 {
494  mDefaultShortcut = value;
495 }
496 
497 void LWSlider::GetScroll(float & line, float & page)
498 {
499  line = mScrollLine;
500  page = mScrollPage;
501 }
502 
503 void LWSlider::SetScroll(float line, float page)
504 {
505  mScrollLine = line;
506  mScrollPage = page;
507 }
508 
509 void LWSlider::Move(const wxPoint &newpos)
510 {
511  mLeft = newpos.x;
512  mTop = newpos.y;
513 }
514 
515 void LWSlider::AdjustSize(const wxSize & sz)
516 {
517  mWidth = sz.GetWidth();
518  mHeight = sz.GetHeight();
519 
520  if( mBitmap ){
521  mBitmap.reset();
522  }
523  mThumbWidth = 11;
524  mThumbHeight = 20;
525 
526  if (mOrientation == wxHORIZONTAL)
527  {
528  mCenterY = mHeight - 9;
529  }
530  else
531  {
532  mCenterX = mWidth - 9;
533  }
534 
535  if (mOrientation == wxHORIZONTAL)
536  {
537  mLeftX = mThumbWidth/2;
538  mRightX = mWidth - mThumbWidth/2 - 1;
539  mWidthX = mRightX - mLeftX;
540  }
541  else
542  {
543  mTopY = mThumbWidth/2;
544  mBottomY = mHeight - mThumbWidth/2 - 1;
545  mHeightY = mBottomY - mTopY;
546  }
547 
548  Refresh();
549 }
550 
551 void LWSlider::OnPaint(wxDC &dc, bool highlight)
552 {
553  // The dc will be a paint DC
555  {
556  DrawToBitmap(dc);
557  }
558 
559  //thumbPos should be in pixels
560  int thumbPos = ValueToPosition(mCurrentValue);
561  int thumbOrtho; // position in axis orthogonal to mOrientation
562  if (mOrientation == wxHORIZONTAL){
563  thumbOrtho = mCenterY - (mThumbHeight/2);
564  thumbPos += 1-mThumbWidth/2;
565  }
566  else{
567  thumbOrtho = mCenterX - (mThumbWidth/2);
568  thumbPos += 8-mThumbHeight/2;
569  }
570 
571  // Draw the background.
572  // If we are lightweight, this has already been done for us.
573  if( mHW ){
574  dc.SetBackground( wxBrush(mParent->GetBackgroundColour()) );
575  dc.Clear();
576  }
577 
578  dc.DrawBitmap(*mBitmap, mLeft, mTop, true);
579  const auto &thumbBitmap =
580  highlight ? *mThumbBitmapHilited : *mThumbBitmap;
581  if (mOrientation == wxHORIZONTAL)
582  {
583  dc.DrawBitmap(thumbBitmap, mLeft+thumbPos, mTop+thumbOrtho, true);
584  }
585  else
586  {
587  // TODO: Don't use pixel-count hack in positioning.
588  dc.DrawBitmap(thumbBitmap, mLeft+thumbOrtho-5, mTop+thumbPos, true);
589  }
590 
591  if (mTipPanel)
592  {
593  mTipPanel->Update();
594  }
595 }
596 
597 void LWSlider::OnSize( wxSizeEvent & event )
598 {
599  AdjustSize(event.GetSize());
600 
601  Refresh();
602 }
603 
604 // This function only uses the paintDC to determine what kind of bitmap
605 // to draw to and nothing else. It does not draw to the paintDC.
606 void LWSlider::DrawToBitmap(wxDC & paintDC)
607 {
608  // Get correctly oriented thumb.
609  if (mOrientation == wxVERTICAL){
610  mThumbBitmap = std::make_unique<wxBitmap>(wxBitmap( theTheme.Bitmap( bmpSliderThumbRotated )));
611  mThumbBitmapHilited = std::make_unique<wxBitmap>(wxBitmap( theTheme.Bitmap( bmpSliderThumbRotatedHilited )));
612  }
613  else {
614  mThumbBitmap = std::make_unique<wxBitmap>(wxBitmap( theTheme.Bitmap( bmpSliderThumb )));
615  mThumbBitmapHilited = std::make_unique<wxBitmap>(wxBitmap( theTheme.Bitmap( bmpSliderThumbHilited )));
616  }
617 
618  // Now the background bitmap
619  mBitmap = std::make_unique<wxBitmap>();
620  mBitmap->Create(mWidth, mHeight, paintDC);
621 
622  // Set up the memory DC
623  // We draw to it, not the paintDC.
624  wxMemoryDC dc;
625  dc.SelectObject(*mBitmap);
626 
627 
628  // The backgroundColour is the expected background colour.
629  // This bitmap is masked, so the colour affects anti-aliassing
630  // at the edges.
631  wxColour backgroundColour = theTheme.Colour(clrTrackInfo);
632  if( mHW )
633  backgroundColour = mParent->GetBackgroundColour();
634  dc.SetBackground(wxBrush(backgroundColour));
635  dc.Clear();
636 
637  // Draw the line along which the thumb moves.
638  AColor::UseThemeColour(&dc, clrSliderMain );
639 
640  if (mOrientation == wxHORIZONTAL)
641  {
644  }
645  else
646  {
649  }
650 
651  // Draw +/- or L/R first. We need to draw these before the tick marks.
652  if (mStyle == PAN_SLIDER)
653  {
654  //VJ Vertical PAN_SLIDER currently not handled, forced to horizontal.
655 
656  // sliderFontSize is for the tooltip.
657  // we need something smaller here...
658  int fontSize = 7;
659  wxFont labelFont(fontSize, wxSWISS, wxNORMAL, wxNORMAL);
660  dc.SetFont(labelFont);
661 
662  // Colors
663  dc.SetTextForeground( theTheme.Colour( clrTrackPanelText ));
664  dc.SetTextBackground( backgroundColour );
665  // Used to use wxSOLID here, but wxTRANSPARENT is better for mac, and
666  // works fine on windows.
667  dc.SetBackgroundMode( wxTRANSPARENT );
668 
669  /* i18n-hint: One-letter abbreviation for Left, in the Pan slider */
670  dc.DrawText(_("L"), mLeftX, 0);
671 
672  /* i18n-hint: One-letter abbreviation for Right, in the Pan slider */
673  dc.DrawText(_("R"), mRightX-6,0);
674  }
675  else
676  {
677  // draw the '-' and the '+'
678  // These are drawn with lines, rather tha nwith a font.
679  AColor::UseThemeColour(&dc, clrTrackPanelText );
680 
681  if (mOrientation == wxHORIZONTAL)
682  {
683  AColor::Line(dc, mLeftX, mCenterY-10, mLeftX+4, mCenterY-10);
684  AColor::Line(dc, mRightX-5, mCenterY-10, mRightX-1, mCenterY-10);
685  AColor::Line(dc, mRightX-3, mCenterY-12, mRightX-3, mCenterY-8);
686  }
687  else
688  {
689  // Vertical DB_SLIDER is for gain slider in MixerBoard.
690  // We use a Ruler instead of marks & ticks.
691  // Draw '+' and '-' only for other vertical sliders.
692  if (mStyle != DB_SLIDER)
693  {
695  AColor::Line(dc, mCenterX-12, mTopY+3, mCenterX-8, mTopY+3);
696  AColor::Line(dc, mCenterX-10, mTopY, mCenterX-10, mTopY+5);
697  }
698  }
699  }
700 
701  // Use special colour to indicate no ticks.
702  wxColour TickColour = theTheme.Colour( clrSliderLight );
703  bool bTicks = TickColour != wxColour(60,60,60);
704 
705  if( bTicks ) {
706  // tick marks
707  int divs = 10;
708  double upp;
709  if (mOrientation == wxHORIZONTAL)
710  {
711  upp = divs / (double)(mWidthX-1);
712  }
713  else
714  {
715  if (mStyle == DB_SLIDER)
716  divs = mMaxValue - mMinValue + 1;
717  upp = divs / (double)(mHeightY-1);
718  }
719 #ifdef OPTIONAL_SLIDER_TICKS
720  double d = 0.0;
721  int int_d = -1;
722  const int kMax = (mOrientation == wxHORIZONTAL) ? mWidthX : mHeightY;
723  for(int p = 0; p <= kMax; p++)
724  {
725  if (((int)d) > int_d)
726  {
727  int_d = (int)d;
728  int tickLength = ((int_d == 0) || (int_d == divs)) ? 5: 3; // longer ticks at extremes
729  AColor::UseThemeColour(&dc, clrSliderLight );
730 
731  if (mOrientation == wxHORIZONTAL)
732  {
733  AColor::Line(dc, mLeftX+p, mCenterY-tickLength, mLeftX+p, mCenterY-1); // ticks above
734  }
735  else
736  {
737  AColor::Line(dc, mCenterX-tickLength, mTopY+p, mCenterX-1, mTopY+p); // ticks at left
738  }
739 
740  AColor::UseThemeColour(&dc, clrSliderDark );
741 
742  if (mOrientation == wxHORIZONTAL)
743  {
744  AColor::Line(dc, mLeftX+p+1, mCenterY-tickLength+1, mLeftX+p+1, mCenterY-1); // ticks above
745  }
746  else
747  {
748  AColor::Line(dc, mCenterX-tickLength+1, mTopY+p+1, mCenterX-1, mTopY+p+1); // ticks at left
749  }
750  }
751  d += upp;
752  }
753 #endif
754  }
755 
756  dc.SelectObject(wxNullBitmap);
757 
758  // safenew, because SetMask takes ownership
759  // We always mask. If we are HeavyWeight, the ASlider draws the
760  // background.
761  mBitmap->SetMask(safenew wxMask(*mBitmap, backgroundColour));
762 }
763 
764 void LWSlider::SetToolTipTemplate(const wxString & tip)
765 {
766  mTipTemplate = tip;
767 }
768 
769 void LWSlider::ShowTip(bool show)
770 {
771  if (show)
772  {
773  if (mTipPanel)
774  {
775  if (mTipPanel->IsShownOnScreen())
776  {
777  return;
778  }
779 
780  mTipPanel.reset();
781  }
782 
783  CreatePopWin();
784  FormatPopWin();
786  mTipPanel->ShowWithoutActivating();
787  }
788  else
789  {
790  if (mTipPanel)
791  {
792  mTipPanel->Hide();
793  mTipPanel.reset();
794  }
795  }
796 }
797 
799 {
800  mTipPanel = std::make_unique<TipPanel>(mParent, GetWidestTips());
801 }
802 
804 {
805  if (mTipPanel)
806  {
807  wxSize sz = mTipPanel->GetSize();
808  wxPoint pt;
809 
810  if (mOrientation == wxHORIZONTAL)
811  {
812  pt.x = mLeft + ((mWidth - sz.x) / 2);
813  pt.y = mTop + mHeight + 1;
814  }
815  else
816  {
817  pt.x = mLeft + mWidth + 1;
818  pt.y = mTop + ((mHeight - sz.y) / 2);
819  }
820 
821  mTipPanel->SetPos(mParent->ClientToScreen(pt));
822  }
823 }
824 
826 {
827  if (!mTipPanel)
828  {
829  return;
830  }
831 
832  mTipPanel->SetLabel(GetTip(mCurrentValue));
833  mTipPanel->Refresh();
834 }
835 
836 wxString LWSlider::GetTip(float value) const
837 {
838  wxString label;
839 
840  if (mTipTemplate.IsEmpty())
841  {
842  wxString val;
843 
844  switch(mStyle)
845  {
846  case FRAC_SLIDER:
847  val.Printf( wxT("%.2f"), value );
848  break;
849 
850  case DB_SLIDER:
851  val.Printf( wxT("%+.1f dB"), value );
852  break;
853 
854  case PAN_SLIDER:
855  if (value == 0.0)
856  {
857  val = _("Center");
858  }
859  else
860  {
861  const auto v = 100.0f * fabsf(value);
862  if (value < 0.0)
863  /* i18n-hint: Stereo pan setting */
864  val = wxString::Format( _("%.0f%% Left"), v );
865  else
866  /* i18n-hint: Stereo pan setting */
867  val = wxString::Format( _("%.0f%% Right"), v );
868  }
869  break;
870 
871  case SPEED_SLIDER:
872  /* i18n-hint: "x" suggests a multiplicative factor */
873  val.Printf( wxT("%.2fx"), value );
874  break;
875 
876 #ifdef EXPERIMENTAL_MIDI_OUT
877  case VEL_SLIDER:
878  if (value > 0.0f)
879  // Signed
880  val.Printf( wxT("%+d"), (int) value );
881  else
882  // Zero, or signed negative
883  val.Printf( wxT("%d"), (int) value );
884  break;
885 #endif
886  }
887 
888  label.Printf(_("%s: %s"), mName, val);
889  }
890  else
891  {
892  label.Printf(mTipTemplate, value);
893  }
894 
895  return label;
896 }
897 
898 wxArrayString LWSlider::GetWidestTips() const
899 {
900  wxArrayString results;
901 
902  if (mTipTemplate.IsEmpty())
903  {
904  wxString val;
905 
906  switch(mStyle)
907  {
908  case FRAC_SLIDER:
909  results.push_back( GetTip( -1.99f ) );
910  break;
911 
912  case DB_SLIDER:
913  results.push_back( GetTip( -99.9f ) );
914  break;
915 
916  case PAN_SLIDER:
917  // Don't assume we know which of "Left", "Right", or "Center"
918  // is the longest string, when localized
919  results.push_back( GetTip( 0.f ) );
920  results.push_back( GetTip( 1.f ) );
921  results.push_back( GetTip( -1.f ) );
922  break;
923 
924  case SPEED_SLIDER:
925  results.push_back( GetTip( 9.99f ) );
926  break;
927 
928 #ifdef EXPERIMENTAL_MIDI_OUT
929  case VEL_SLIDER:
930  results.push_back( GetTip( 999.f ) );
931  break;
932 #endif
933  }
934  }
935  else
936  {
937  results.push_back( GetTip( floor(mMaxValue - mMinValue) + 0.999 ) );
938  }
939 
940  return results;
941 }
942 
944 {
945  return DoShowDialog( mParent->ClientToScreen(wxPoint( mLeft, mTop ) ) );
946 }
947 
948 bool LWSlider::ShowDialog(wxPoint pos)
949 {
950  return DoShowDialog( pos );
951 }
952 
953 bool LWSlider::DoShowDialog(wxPoint pos)
954 {
955  float value;
956  bool changed = false;
957 
958  SliderDialog dlg( NULL,
959  wxID_ANY,
960  mName,
961  pos,
962  wxSize( mWidth, mHeight ),
963  mStyle,
964  Get(),
965  mScrollLine,
966  mScrollPage);
967  if (pos == wxPoint(-1, -1)) {
968  dlg.Center();
969  }
970 
971  if( dlg.ShowModal() == wxID_OK )
972  {
973  value = dlg.Get();
974  if( value != mCurrentValue )
975  {
976  mCurrentValue = value;
977  changed = true;
978  }
979  }
980 
981  return changed;
982 }
983 
984 void LWSlider::OnMouseEvent(wxMouseEvent & event)
985 {
986  if (event.Entering())
987  {
988  // Display the tooltip in the status bar
989  wxString tip = GetTip(mCurrentValue);
991  Refresh();
992  }
993  else if (event.Leaving())
994  {
995  if (!mIsDragging)
996  {
997  ShowTip(false);
998  }
1000  Refresh();
1001  }
1002 
1003  // Events other than mouse-overs are ignored when we are disabled
1004  if (!mEnabled)
1005  return;
1006 
1007  // Windows sends a right button mouse event when you press the context menu
1008  // key, so ignore it.
1009  if ((event.RightDown() && !event.RightIsDown()) ||
1010  (event.RightUp() && event.GetPosition() == wxPoint(-1, -1)))
1011  {
1012  event.Skip(false);
1013  return;
1014  }
1015 
1016  float prevValue = mCurrentValue;
1017 
1018  // Figure out the thumb position
1019  wxRect r;
1020  if (mOrientation == wxHORIZONTAL)
1021  {
1023  r.y = mTop + (mCenterY - (mThumbHeight / 2));
1024  }
1025  else
1026  {
1027  r.x = mLeft + (mCenterX - (mThumbWidth / 2));
1029  }
1030  r.width = mThumbWidth;
1031  r.height = mThumbHeight;
1032 
1033  wxRect tolerantThumbRect = r;
1034  tolerantThumbRect.Inflate(3, 3);
1035 
1036  // Should probably use a right click instead/also
1037  if( event.ButtonDClick() && mPopup )
1038  {
1039  //On a double-click, we should pop up a dialog.
1040  DoShowDialog(mParent->ClientToScreen(wxPoint(event.m_x,event.m_y)));
1041  }
1042  else if( event.ButtonDown() )
1043  {
1044  if( mDefaultShortcut && event.ControlDown() )
1045  {
1047  }
1048 
1049  if( event.RightDown() ) {
1050  mParent->SetFocus();
1051  }
1052 
1053  // Thumb clicked?
1054  //
1055  // Do not change position until first drag. This helps
1056  // with unintended value changes.
1057  if( tolerantThumbRect.Contains( event.GetPosition() ) )
1058  {
1059  // Remember mouse position and current value
1060  mClickPos = (mOrientation == wxHORIZONTAL) ? event.m_x : event.m_y;
1062 
1063  mIsDragging = true;
1064  }
1065  // Clicked to set location?
1066  else
1067  {
1068  mCurrentValue =
1070  (mOrientation == wxHORIZONTAL) ? event.m_x : event.m_y,
1071  event.ShiftDown());
1072  }
1073 
1074  if (!mParent->HasCapture()) {
1075  mParent->CaptureMouse();
1076  }
1077 
1078  ShowTip(true);
1079  }
1080  else if( event.ButtonUp() )
1081  {
1082  mIsDragging = false;
1083  if (mParent->HasCapture())
1084  mParent->ReleaseMouse();
1085 
1086  ShowTip(false);
1087  }
1088  else if (event.Dragging() && mIsDragging)
1089  {
1090  if (mOrientation == wxHORIZONTAL)
1091  {
1092  if (event.m_y < (r.y - 2 * r.height) ||
1093  event.m_y > (r.y + 3 * r.height)) {
1094  // If the mouse y coordinate is relatively far from the slider,
1095  // snap back to the original position
1097  }
1098  else {
1099  // Otherwise, move the slider to the right position based
1100  // on the mouse position
1101  mCurrentValue = DragPositionToValue(event.m_x, event.ShiftDown());
1102  }
1103  }
1104  else // (mOrientation == wxVERTICAL)
1105  {
1106  if (event.m_x < (r.x - 2 * r.width) ||
1107  event.m_x > (r.x + 3 * r.width)) {
1108  // If the mouse x coordinate is relatively far from the slider,
1109  // snap back to the original position
1111  }
1112  else {
1113  // Otherwise, move the slider to the right position based
1114  // on the mouse position
1115  mCurrentValue = DragPositionToValue(event.m_y, event.ShiftDown());
1116  }
1117  }
1118  }
1119  else if( event.m_wheelRotation != 0 )
1120  {
1121  //Calculate the number of steps in a given direction this event
1122  //represents (allows for two or more clicks on a single event.)
1123  double steps = event.m_wheelRotation /
1124  (event.m_wheelDelta > 0 ? (double)event.m_wheelDelta : 120.0);
1125 
1126  if( steps < 0.0 )
1127  {
1128  Decrease( (float)-steps );
1129  }
1130  else
1131  {
1132  Increase( (float)steps );
1133  }
1135  }
1136 
1137  if( prevValue != mCurrentValue )
1139 }
1140 
1141 void LWSlider::OnKeyEvent(wxKeyEvent & event)
1142 {
1143  if (mEnabled)
1144  {
1145  switch( event.GetKeyCode() )
1146  {
1147  case WXK_TAB:
1148  mParent->Navigate(event.ShiftDown()
1149  ? wxNavigationKeyEvent::IsBackward
1150  : wxNavigationKeyEvent::IsForward);
1151  break;
1152 
1153  case WXK_RIGHT:
1154  case WXK_UP:
1155  Increase( mScrollLine );
1157  break;
1158 
1159  case WXK_LEFT:
1160  case WXK_DOWN:
1161  Decrease( mScrollLine );
1163  break;
1164 
1165  case WXK_PAGEUP:
1166  Increase( mScrollPage );
1168  break;
1169 
1170  case WXK_PAGEDOWN:
1171  Decrease( mScrollPage );
1173  break;
1174 
1175  case WXK_HOME:
1176  SendUpdate( mMinValue );
1177  break;
1178 
1179  case WXK_END:
1180  SendUpdate( mMaxValue );
1181  break;
1182 
1183  case WXK_RETURN:
1184  case WXK_NUMPAD_ENTER:
1185  {
1186  wxTopLevelWindow *tlw = wxDynamicCast(wxGetTopLevelParent(mParent), wxTopLevelWindow);
1187  wxWindow *def = tlw->GetDefaultItem();
1188  if (def && def->IsEnabled()) {
1189  wxCommandEvent cevent(wxEVT_COMMAND_BUTTON_CLICKED,
1190  def->GetId());
1191  mParent->GetEventHandler()->ProcessEvent(cevent);
1192  }
1193  }
1194 
1195  default:
1196  // Allow it to propagate
1197  event.Skip();
1198  break;
1199  }
1200  }
1201  else
1202  {
1203  event.Skip();
1204  }
1205 }
1206 
1207 void LWSlider::SendUpdate( float newValue )
1208 {
1209  mCurrentValue = newValue;
1210 
1211  FormatPopWin();
1212 
1213  Refresh();
1214 
1215  wxCommandEvent e( wxEVT_COMMAND_SLIDER_UPDATED, mID );
1216  int intValue = (int)( ( mCurrentValue - mMinValue ) * 1000.0f /
1217  ( mMaxValue - mMinValue ) );
1218  e.SetInt( intValue );
1219  mParent->GetEventHandler()->ProcessEvent(e);
1220 }
1221 
1223 {
1224  float fRange = mMaxValue - mMinValue;
1225  if (mOrientation == wxHORIZONTAL)
1226  return (int)rint((val - mMinValue) * mWidthX / fRange);
1227  else
1228  // low values at bottom
1229  return (int)rint((mMaxValue - val) * mHeightY / fRange);
1230 }
1231 
1232 void LWSlider::SetSpeed(float speed)
1233 {
1234  mSpeed = speed;
1235 }
1236 
1237 // Given the mouse slider coordinate in fromPos, compute the NEW value
1238 // of the slider when clicking to set a NEW position.
1239 float LWSlider::ClickPositionToValue(int fromPos, bool shiftDown)
1240 {
1241  int nSpan;
1242  int pos;
1243  if (mOrientation == wxHORIZONTAL)
1244  {
1245  pos = (fromPos - mLeft - (mThumbWidth / 2));
1246  nSpan = mWidthX;
1247  }
1248  else
1249  {
1250  // wxVERTICAL => Low values at bottom.
1251  pos = mBottomY - fromPos;
1252  nSpan = mHeightY;
1253  }
1254 
1255  // MM: Special cases: If position is at the very left or the
1256  // very right (or top/bottom for wxVERTICAL), set minimum/maximum value without other checks
1257  if (pos <= 0)
1258  return mMinValue;
1259  if (pos >= nSpan)
1260  return mMaxValue;
1261 
1262  float val = (pos / (float)nSpan)
1263  * (mMaxValue - mMinValue) + mMinValue;
1264 
1265  if (val < mMinValue)
1266  val = mMinValue;
1267  if (val > mMaxValue)
1268  val = mMaxValue;
1269 
1270  if (!(mCanUseShift && shiftDown) && mStepValue != STEP_CONTINUOUS)
1271  {
1272  // MM: If shift is not down, or we don't allow usage
1273  // of shift key at all, trim value to steps of
1274  // provided size.
1275  val = (int)(val / mStepValue + 0.5 * (val>0?1.0f:-1.0f)) * mStepValue;
1276  }
1277 
1278  return val;
1279 }
1280 
1281 // Given the mouse slider coordinate in fromPos, compute the NEW value
1282 // of the slider during a drag.
1283 float LWSlider::DragPositionToValue(int fromPos, bool shiftDown)
1284 {
1285  int delta = (fromPos - mClickPos);
1286 
1287  float speed = mSpeed;
1288  // Precision enhancement for Shift drags
1289  if (mCanUseShift && shiftDown)
1290  speed *= 0.4f;
1291 
1292  // wxVERTICAL => Low values at bottom, so throw in the minus sign here with -mHeightY.
1293  float denominator = (mOrientation == wxHORIZONTAL) ? mWidthX : -mHeightY;
1294  float val = mClickValue +
1295  speed * (delta / denominator) * (mMaxValue - mMinValue);
1296 
1297  if (val < mMinValue)
1298  val = mMinValue;
1299  if (val > mMaxValue)
1300  val = mMaxValue;
1301 
1302  if (!(mCanUseShift && shiftDown) && mStepValue != STEP_CONTINUOUS)
1303  {
1304  // MM: If shift is not down, or we don't allow usage
1305  // of shift key at all, and the slider has not continuous values,
1306  // trim value to steps of provided size.
1307  val = (int)(val / mStepValue + 0.5 * (val>0?1.0f:-1.0f)) * mStepValue;
1308  }
1309 
1310  return val;
1311 }
1312 
1313 float LWSlider::Get( bool convert )
1314 {
1315  if (mStyle == DB_SLIDER)
1316  return (convert ? DB_TO_LINEAR(mCurrentValue) : mCurrentValue);
1317  else
1318  return mCurrentValue;
1319 }
1320 
1321 void LWSlider::Set(float value)
1322 {
1323  if (mIsDragging)
1324  return;
1325  if (mStyle == DB_SLIDER)
1326  mCurrentValue = LINEAR_TO_DB(value);
1327  else
1328  mCurrentValue = value;
1329 
1330  if (mCurrentValue < mMinValue)
1332  if (mCurrentValue > mMaxValue)
1334 
1335  Refresh();
1336 }
1337 
1338 void LWSlider::Increase(float steps)
1339 {
1340  float stepValue = mStepValue;
1341 
1342  if ( stepValue == 0.0 )
1343  {
1344  stepValue = ( mMaxValue - mMinValue ) / 10.0;
1345  }
1346 
1347  mCurrentValue += ( steps * stepValue );
1348 
1349  if ( mCurrentValue < mMinValue )
1350  {
1352  }
1353  else if ( mCurrentValue > mMaxValue )
1354  {
1356  }
1357 
1358  Refresh();
1359 }
1360 
1361 void LWSlider::Decrease(float steps)
1362 {
1363  float stepValue = mStepValue;
1364 
1365  if ( stepValue == 0.0 )
1366  {
1367  stepValue = ( mMaxValue - mMinValue ) / 10.0;
1368  }
1369 
1370  mCurrentValue -= ( steps * stepValue );
1371 
1372  if ( mCurrentValue < mMinValue )
1373  {
1375  }
1376  else if ( mCurrentValue > mMaxValue )
1377  {
1379  }
1380 
1381  Refresh();
1382 }
1383 
1385 {
1386  if (mHW)
1387  mParent->Refresh(false);
1388 }
1389 
1391 {
1392  return mEnabled;
1393 }
1394 
1395 void LWSlider::SetEnabled(bool enabled)
1396 {
1397  mEnabled = enabled;
1398 
1399  mThumbBitmap.reset();
1400  mThumbBitmapHilited.reset();
1401 
1402  Refresh();
1403 }
1404 
1405 //
1406 // ASlider
1407 //
1408 
1409 BEGIN_EVENT_TABLE(ASlider, wxWindow)
1410  EVT_CHAR(ASlider::OnKeyEvent)
1411  EVT_MOUSE_EVENTS(ASlider::OnMouseEvent)
1412  EVT_MOUSE_CAPTURE_LOST(ASlider::OnCaptureLost)
1413  EVT_PAINT(ASlider::OnPaint)
1414  EVT_SIZE(ASlider::OnSize)
1415  EVT_ERASE_BACKGROUND(ASlider::OnErase)
1416  EVT_SLIDER(wxID_ANY, ASlider::OnSlider)
1417  EVT_SET_FOCUS(ASlider::OnSetFocus)
1418  EVT_KILL_FOCUS(ASlider::OnKillFocus)
1419  EVT_TIMER(wxID_ANY, ASlider::OnTimer)
1421 
1422 ASlider::ASlider( wxWindow * parent,
1423  wxWindowID id,
1424  const wxString &name,
1425  const wxPoint & pos,
1426  const wxSize & size,
1427  const Options &options)
1428 : wxPanel( parent, id, pos, size, wxWANTS_CHARS )
1429 {
1430  //wxColour Col(parent->GetBackgroundColour());
1431  //SetBackgroundColour( Col );
1432  SetBackgroundColour( theTheme.Colour( clrMedium ) );
1433  mLWSlider = std::make_unique<LWSlider>( this,
1434  name,
1435  wxPoint(0,0),
1436  size,
1437  options.style,
1438  true, // ASlider is always a heavyweight LWSlider
1439  options.popup,
1440  options.orientation);
1441  mLWSlider->mStepValue = options.stepValue;
1442  mLWSlider->SetId( id );
1443  SetName( name );
1444 
1445  mSliderIsFocused = false;
1446  mStyle = options.style;
1447 
1448  mTimer.SetOwner(this);
1449 
1450 #if wxUSE_ACCESSIBILITY
1451  SetAccessible( safenew ASliderAx( this ) );
1452 #endif
1453 
1454  mLWSlider->SetScroll( options.line, options.page );
1455 }
1456 
1457 
1459 {
1460  if(HasCapture())
1461  ReleaseMouse();
1462 }
1463 
1464 void ASlider::OnSlider(wxCommandEvent &event)
1465 {
1466 
1467  if ( event.GetId() == mLWSlider->GetId() )
1468  {
1469 #if wxUSE_ACCESSIBILITY
1470  GetAccessible()->NotifyEvent( wxACC_EVENT_OBJECT_VALUECHANGE,
1471  this,
1472  wxOBJID_CLIENT,
1473  wxACC_SELF );
1474 #endif
1475  }
1476 
1477  event.Skip();
1478 }
1479 
1480 void ASlider::OnSize(wxSizeEvent &event)
1481 {
1482  mLWSlider->OnSize( event );
1483 }
1484 
1485 void ASlider::OnErase(wxEraseEvent & WXUNUSED(event))
1486 {
1487  // Ignore it to prevent flashing
1488 }
1489 
1490 void ASlider::OnPaint(wxPaintEvent & WXUNUSED(event))
1491 {
1492  wxPaintDC dc(this);
1493 
1494  bool highlighted =
1495  GetClientRect().Contains(
1496  ScreenToClient(
1497  ::wxGetMousePosition() ) );
1498  mLWSlider->OnPaint(dc, highlighted);
1499 
1500  if ( mSliderIsFocused )
1501  {
1502  wxRect r( 0, 0, mLWSlider->mWidth, mLWSlider->mHeight );
1503 
1504  r.Deflate( 1, 1 );
1505 
1506  AColor::DrawFocus( dc, r );
1507  }
1508 }
1509 
1510 void ASlider::OnMouseEvent(wxMouseEvent &event)
1511 {
1512  if (event.Entering())
1513  {
1514  mTimer.StartOnce(1000);
1515  }
1516  else if (event.Leaving())
1517  {
1518  mTimer.Stop();
1519  }
1520 
1521  mLWSlider->OnMouseEvent(event);
1522 }
1523 
1524 void ASlider::OnCaptureLost(wxMouseCaptureLostEvent & WXUNUSED(event))
1525 {
1526  wxMouseEvent e(wxEVT_LEFT_UP);
1527  mLWSlider->OnMouseEvent(e);
1528 }
1529 
1530 void ASlider::OnKeyEvent(wxKeyEvent &event)
1531 {
1532  mLWSlider->OnKeyEvent(event);
1533 }
1534 
1535 void ASlider::OnSetFocus(wxFocusEvent & WXUNUSED(event))
1536 {
1537  mSliderIsFocused = true;
1538  Refresh();
1539 }
1540 
1541 void ASlider::OnKillFocus(wxFocusEvent & WXUNUSED(event))
1542 {
1543  mSliderIsFocused = false;
1544  Refresh();
1545 }
1546 
1547 void ASlider::OnTimer(wxTimerEvent & WXUNUSED(event))
1548 {
1549  mLWSlider->ShowTip(true);
1550 }
1551 
1552 void ASlider::GetScroll(float & line, float & page)
1553 {
1554  mLWSlider->GetScroll(line, page);
1555 }
1556 
1557 void ASlider::SetScroll(float line, float page)
1558 {
1559  mLWSlider->SetScroll(line, page);
1560 }
1561 
1562 void ASlider::SetToolTipTemplate(const wxString & tip)
1563 {
1564  mLWSlider->SetToolTipTemplate(tip);
1565 }
1566 
1567 float ASlider::Get( bool convert )
1568 {
1569  return mLWSlider->Get( convert );
1570 }
1571 
1572 void ASlider::Set(float value)
1573 {
1574  mLWSlider->Set(value);
1575 }
1576 
1577 void ASlider::Increase(float steps)
1578 {
1579  mLWSlider->Increase(steps);
1580 }
1581 
1582 void ASlider::Decrease(float steps)
1583 {
1584  mLWSlider->Decrease(steps);
1585 }
1586 
1587 bool ASlider::ShowDialog(wxPoint pos)
1588 {
1589  return mLWSlider->ShowDialog(pos);
1590 }
1591 
1592 void ASlider::SetSpeed(float speed)
1593 {
1594  mLWSlider->SetSpeed(speed);
1595 }
1596 
1597 bool ASlider::Enable(bool enable)
1598 {
1599  if (mLWSlider->GetEnabled() == enable)
1600  return false;
1601 
1602  mLWSlider->SetEnabled(enable);
1603 
1604  wxWindow::Enable(enable);
1605 
1606  return true;
1607 }
1608 
1610 {
1611  return mLWSlider->GetEnabled();
1612 }
1613 
1614 bool ASlider::s_AcceptsFocus{ false };
1615 
1617  s_AcceptsFocus = true;
1618  return TempAllowFocus{ &s_AcceptsFocus };
1619 }
1620 
1621 // This compensates for a but in wxWidgets 3.0.2 for mac:
1622 // Couldn't set focus from keyboard when AcceptsFocus returns false;
1623 // this bypasses that limitation
1625 {
1626  auto temp = TemporarilyAllowFocus();
1627  SetFocus();
1628 }
1629 
1630 #if wxUSE_ACCESSIBILITY
1631 
1632 ASliderAx::ASliderAx( wxWindow * window ) :
1633  WindowAccessible( window )
1634 {
1635 }
1636 
1637 ASliderAx::~ASliderAx()
1638 {
1639 }
1640 
1641 // Retrieves the address of an IDispatch interface for the specified child.
1642 // All objects must support this property.
1643 wxAccStatus ASliderAx::GetChild( int childId, wxAccessible** child )
1644 {
1645  if ( childId == wxACC_SELF )
1646  {
1647  *child = this;
1648  }
1649  else
1650  {
1651  *child = NULL;
1652  }
1653 
1654  return wxACC_OK;
1655 }
1656 
1657 // Gets the number of children.
1658 wxAccStatus ASliderAx::GetChildCount(int* childCount)
1659 {
1660  *childCount = 3;
1661 
1662  return wxACC_OK;
1663 }
1664 
1665 // Gets the default action for this object (0) or > 0 (the action for a child).
1666 // Return wxACC_OK even if there is no action. actionName is the action, or the empty
1667 // string if there is no action.
1668 // The retrieved string describes the action that is performed on an object,
1669 // not what the object does as a result. For example, a toolbar button that prints
1670 // a document has a default action of "Press" rather than "Prints the current document."
1671 wxAccStatus ASliderAx::GetDefaultAction( int WXUNUSED(childId), wxString *actionName )
1672 {
1673  actionName->Clear();
1674 
1675  return wxACC_OK;
1676 }
1677 
1678 // Returns the description for this object or a child.
1679 wxAccStatus ASliderAx::GetDescription( int WXUNUSED(childId), wxString *description )
1680 {
1681  description->Clear();
1682 
1683  return wxACC_OK;
1684 }
1685 
1686 // Gets the window with the keyboard focus.
1687 // If childId is 0 and child is NULL, no object in
1688 // this subhierarchy has the focus.
1689 // If this object has the focus, child should be 'this'.
1690 wxAccStatus ASliderAx::GetFocus(int* childId, wxAccessible** child)
1691 {
1692  *childId = 0;
1693  *child = this;
1694 
1695  return wxACC_OK;
1696 }
1697 
1698 // Returns help text for this object or a child, similar to tooltip text.
1699 wxAccStatus ASliderAx::GetHelpText( int WXUNUSED(childId), wxString *helpText )
1700 {
1701  helpText->Clear();
1702 
1703  return wxACC_OK;
1704 }
1705 
1706 // Returns the keyboard shortcut for this object or child.
1707 // Return e.g. ALT+K
1708 wxAccStatus ASliderAx::GetKeyboardShortcut( int WXUNUSED(childId), wxString *shortcut )
1709 {
1710  shortcut->Clear();
1711 
1712  return wxACC_OK;
1713 }
1714 
1715 // Returns the rectangle for this object (id = 0) or a child element (id > 0).
1716 // rect is in screen coordinates.
1717 wxAccStatus ASliderAx::GetLocation( wxRect& rect, int WXUNUSED(elementId) )
1718 {
1719  ASlider *as = wxDynamicCast( GetWindow(), ASlider );
1720 
1721  rect = as->GetRect();
1722  rect.SetPosition( as->GetParent()->ClientToScreen( rect.GetPosition() ) );
1723 
1724  return wxACC_OK;
1725 }
1726 
1727 // Gets the name of the specified object.
1728 wxAccStatus ASliderAx::GetName(int WXUNUSED(childId), wxString* name)
1729 {
1730  ASlider *as = wxDynamicCast( GetWindow(), ASlider );
1731 
1732  *name = as->GetName();
1733 
1734  return wxACC_OK;
1735 }
1736 
1737 // Returns a role constant.
1738 wxAccStatus ASliderAx::GetRole(int childId, wxAccRole* role)
1739 {
1740  switch( childId )
1741  {
1742  case 0:
1743  *role = wxROLE_SYSTEM_SLIDER;
1744  break;
1745 
1746  case 1:
1747  case 3:
1748  *role = wxROLE_SYSTEM_PUSHBUTTON;
1749  break;
1750 
1751  case 2:
1752  *role = wxROLE_SYSTEM_INDICATOR;
1753  break;
1754  }
1755 
1756  return wxACC_OK;
1757 }
1758 
1759 // Gets a variant representing the selected children
1760 // of this object.
1761 // Acceptable values:
1762 // - a null variant (IsNull() returns TRUE)
1763 // - a list variant (GetType() == wxT("list"))
1764 // - an integer representing the selected child element,
1765 // or 0 if this object is selected (GetType() == wxT("long"))
1766 // - a "void*" pointer to a wxAccessible child object
1767 wxAccStatus ASliderAx::GetSelections( wxVariant * WXUNUSED(selections) )
1768 {
1769  return wxACC_NOT_IMPLEMENTED;
1770 }
1771 
1772 // Returns a state constant.
1773 wxAccStatus ASliderAx::GetState(int childId, long* state)
1774 {
1775  ASlider *as = wxDynamicCast( GetWindow(), ASlider );
1776 
1777  switch( childId )
1778  {
1779  case 0:
1780  *state = wxACC_STATE_SYSTEM_FOCUSABLE;
1781  break;
1782 
1783  case 1:
1784  if ( as->mLWSlider->mCurrentValue == as->mLWSlider->mMinValue )
1785  {
1786  *state = wxACC_STATE_SYSTEM_INVISIBLE;
1787  }
1788  break;
1789 
1790  case 3:
1791  if ( as->mLWSlider->mCurrentValue == as->mLWSlider->mMaxValue )
1792  {
1793  *state = wxACC_STATE_SYSTEM_INVISIBLE;
1794  }
1795  break;
1796  }
1797 
1798  // Do not use mSliderIsFocused is not set until after this method
1799  // is called.
1800  *state |= ( as == wxWindow::FindFocus() ? wxACC_STATE_SYSTEM_FOCUSED : 0 );
1801 
1802  return wxACC_OK;
1803 }
1804 
1805 // Returns a localized string representing the value for the object
1806 // or child.
1807 wxAccStatus ASliderAx::GetValue(int childId, wxString* strValue)
1808 {
1809  ASlider *as = wxDynamicCast( GetWindow(), ASlider );
1810 
1811  if ( childId == 0 )
1812  {
1813  switch( as->mLWSlider->mStyle )
1814  {
1815  case FRAC_SLIDER:
1816  strValue->Printf( wxT("%.0f"), as->mLWSlider->mCurrentValue * 100 );
1817  break;
1818 
1819  case DB_SLIDER:
1820  strValue->Printf( wxT("%.0f"), as->mLWSlider->mCurrentValue );
1821  break;
1822 
1823  case PAN_SLIDER:
1824  strValue->Printf( wxT("%.0f"), as->mLWSlider->mCurrentValue * 100 );
1825  break;
1826 
1827  case SPEED_SLIDER:
1828  strValue->Printf( wxT("%.0f"), as->mLWSlider->mCurrentValue * 100 );
1829  break;
1830 #ifdef EXPERIMENTAL_MIDI_OUT
1831  case VEL_SLIDER:
1832  strValue->Printf( wxT("%.0f"), as->mLWSlider->mCurrentValue);
1833  break;
1834 #endif
1835  }
1836  return wxACC_OK;
1837  }
1838 
1839  return wxACC_NOT_SUPPORTED;
1840 }
1841 
1842 #endif
void SetScroll(float line, float page)
Definition: ASlider.cpp:503
void OnKillFocus(wxFocusEvent &event)
Definition: ASlider.cpp:1541
void OnMouseEvent(wxMouseEvent &event)
Definition: ASlider.cpp:984
float mMinValue
Definition: ASlider.h:214
wxWindow * mParent
Definition: ASlider.h:179
std::unique_ptr< wxBitmap > mBitmap
Definition: ASlider.h:236
void SetSpeed(float speed)
Definition: ASlider.cpp:1232
static wxPen tooltipPen
Definition: AColor.h:139
void DrawToBitmap(wxDC &dc)
Definition: ASlider.cpp:606
AUDACITY_DLL_API Theme theTheme
Definition: Theme.cpp:209
A wxPopupWindow used to give the numerical value of an LWSlider or ASlider.
Definition: ASlider.cpp:82
void OnSetFocus(wxFocusEvent &event)
Definition: ASlider.cpp:1535
ASlider * mSlider
Definition: ASlider.h:363
void Decrease(float steps)
Definition: ASlider.cpp:1361
int mLeftX
Definition: ASlider.h:196
int mClickPos
Definition: ASlider.h:212
bool GetEnabled()
Definition: ASlider.cpp:1390
void SetToolTipTemplate(const wxString &tip)
Definition: ASlider.cpp:764
Derived from ShuttleGuiBase, an Audacity specific class for shuttling data to and from GUI...
Definition: ShuttleGui.h:409
void Increase(float steps)
Definition: ASlider.cpp:1338
#define STEP_CONTINUOUS
Definition: ASlider.h:64
int mStyle
Definition: ASlider.h:365
const int sliderFontSize
Definition: ASlider.cpp:71
float mMaxValue
Definition: ASlider.h:215
static const wxPoint2DDouble enabledRightBegin[]
Definition: ASlider.cpp:303
wxArrayString GetWidestTips() const
Definition: ASlider.cpp:898
int mTopY
Definition: ASlider.h:203
void ShowTip(bool show)
Definition: ASlider.cpp:769
void OnPaint(wxPaintEvent &event)
Definition: ASlider.cpp:153
TipPanel(wxWindow *parent, const wxArrayString &labels)
Definition: ASlider.cpp:113
std::unique_ptr< LWSlider > mLWSlider
Definition: ASlider.h:322
float mScrollPage
Definition: ASlider.h:220
virtual ~LWSlider()
Definition: ASlider.cpp:472
bool TransferDataToWindow() override
Definition: ASlider.cpp:230
wxWindow * AddWindow(wxWindow *pWindow, int Flags=wxALIGN_CENTRE|wxALL)
Definition: ShuttleGui.cpp:288
static const wxPoint2DDouble enabledLeftBegin[]
Definition: ASlider.cpp:285
bool mDefaultShortcut
Definition: ASlider.h:224
void SetId(wxWindowID id)
Definition: ASlider.cpp:481
void FormatPopWin()
Definition: ASlider.cpp:825
float Get(bool convert=true)
Definition: ASlider.cpp:1567
static TempAllowFocus TemporarilyAllowFocus()
Definition: ASlider.cpp:1616
void SendUpdate(float newValue)
Definition: ASlider.cpp:1207
bool IsEnabled() const
Definition: ASlider.cpp:1609
static const wxPoint2DDouble disabledRightEnd[]
Definition: ASlider.cpp:344
int mHeight
Definition: ASlider.cpp:101
int mWidthX
Definition: ASlider.h:198
wxWindowID mID
Definition: ASlider.h:229
void SetFocusFromKbd() override
Definition: ASlider.cpp:1624
void SetToolTipTemplate(const wxString &tip)
Definition: ASlider.cpp:1562
wxString label
Definition: Tags.cpp:727
#define SPEED_SLIDER
Definition: ASlider.h:47
float DragPositionToValue(int fromPos, bool shiftDown)
Definition: ASlider.cpp:1283
virtual ~ASlider()
Definition: ASlider.cpp:1458
void Set(float value)
Definition: ASlider.cpp:1321
float mSpeed
Definition: ASlider.h:217
int mCenterY
Definition: ASlider.h:194
int mWidth
Definition: ASlider.cpp:100
int mStyle
Definition: ASlider.h:181
void SetPopWinPosition()
Definition: ASlider.cpp:803
void OnPaint(wxDC &dc, bool highlighted)
Definition: ASlider.cpp:551
int mRightX
Definition: ASlider.h:197
void Move(const wxPoint &newpos)
Definition: ASlider.cpp:509
Pop up dialog used with an LWSlider.
Definition: ASlider.h:341
int mWidth
Definition: ASlider.h:190
static void DrawFocus(wxDC &dc, wxRect &r)
Definition: AColor.cpp:171
bool mHW
Definition: ASlider.h:184
void OnTextChange(wxCommandEvent &event)
Definition: ASlider.cpp:256
#define safenew
Definition: Audacity.h:230
static const wxPoint2DDouble disabledStripesEnd[]
Definition: ASlider.cpp:328
Options & Page(float p)
Definition: ASlider.h:268
void OnSize(wxSizeEvent &event)
Definition: ASlider.cpp:597
wxBitmap & Bitmap(int iIndex)
Definition: Theme.cpp:1244
LWSlider(wxWindow *parent, const wxString &name, const wxPoint &pos, const wxSize &size, float minValue, float maxValue, float stepValue, bool canUseShift, int style, bool heavyweight=false, bool popup=true, int orientation=wxHORIZONTAL)
Definition: ASlider.cpp:351
An alternative to using wxWindowAccessible, which in wxWidgets 3.1.1 contained GetParent() which was ...
bool mCanUseShift
Definition: ASlider.h:227
void EndVerticalLay()
void OnCaptureLost(wxMouseCaptureLostEvent &event)
Definition: ASlider.cpp:1524
wxSize GetSize() const
Definition: ASlider.cpp:138
float Get(bool convert=true)
Definition: ASlider.cpp:1313
void OnMouseEvent(wxMouseEvent &event)
Definition: ASlider.cpp:1510
wxTextCtrl * AddTextBox(const wxString &Caption, const wxString &Value, const int nChars)
Definition: ShuttleGui.cpp:540
#define PAN_SLIDER
Definition: ASlider.h:46
void SetScroll(float line, float page)
Definition: ASlider.cpp:1557
int mHeight
Definition: ASlider.h:191
std::unique_ptr< wxBitmap > mThumbBitmap
Definition: ASlider.h:236
float mCurrentValue
Definition: ASlider.h:222
void SetEnabled(bool enabled)
Definition: ASlider.cpp:1395
std::unique_ptr< TipPanel > mTipPanel
Definition: ASlider.h:231
wxWindowID GetId()
Definition: ASlider.cpp:476
wxTimer mTimer
Definition: ASlider.h:324
int ValueToPosition(float val)
Definition: ASlider.cpp:1222
std::unique_ptr< bool, Resetter > TempAllowFocus
Definition: ASlider.h:316
static const wxPoint2DDouble enabledRightEnd[]
Definition: ASlider.cpp:310
bool mEnabled
Definition: ASlider.h:240
int mHeightY
Definition: ASlider.h:205
int mBottomY
Definition: ASlider.h:204
void Refresh()
Definition: ASlider.cpp:1384
float mDefaultValue
Definition: ASlider.h:225
wxString mTipTemplate
Definition: ASlider.h:232
void GetScroll(float &line, float &page)
Definition: ASlider.cpp:1552
void CreatePopWin()
Definition: ASlider.cpp:798
static bool s_AcceptsFocus
Definition: ASlider.h:314
static const wxPoint2DDouble disabledRightBegin[]
Definition: ASlider.cpp:339
static void UseThemeColour(wxDC *dc, int iBrush, int iPen=-1)
Definition: AColor.cpp:289
void Set(float value)
Definition: ASlider.cpp:1572
void TP_DisplayStatusMessage(const wxString &msg) override
Definition: Project.cpp:5349
static void Line(wxDC &dc, wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
Definition: AColor.cpp:122
virtual ~TipPanel()
Definition: ASlider.cpp:86
Options & Line(float l)
Definition: ASlider.h:267
void Init(wxWindow *parent, const wxString &name, const wxPoint &pos, const wxSize &size, float minValue, float maxValue, float stepValue, bool canUseShift, int style, bool heavyweight, bool popup, float speed, int orientation=wxHORIZONTAL)
Definition: ASlider.cpp:429
bool Enable(bool enable=true) override
Definition: ASlider.cpp:1597
void OnSize(wxSizeEvent &event)
Definition: ASlider.cpp:1480
wxTextCtrl * mTextCtrl
Definition: ASlider.h:364
#define DB_SLIDER
Definition: ASlider.h:45
void OnPaint(wxPaintEvent &event)
Definition: ASlider.cpp:1490
bool mSliderIsFocused
Definition: ASlider.h:323
#define VEL_SLIDER
Definition: ASlider.h:49
static wxBrush tooltipBrush
Definition: AColor.h:140
_("Move Track &Down")+wxT("\t")+(GetActiveProject() -> GetCommandManager() ->GetKeyFromName(wxT("TrackMoveDown")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveTopID, _("Move Track to &Top")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveTop")).Raw()), OnMoveTrack) POPUP_MENU_ITEM(OnMoveBottomID, _("Move Track to &Bottom")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveBottom")).Raw()), OnMoveTrack)#define SET_TRACK_NAME_PLUGIN_SYMBOLclass SetTrackNameCommand:public AudacityCommand
void SetDefaultValue(float value)
Definition: ASlider.cpp:486
float mClickValue
Definition: ASlider.h:211
std::unique_ptr< wxBitmap > mThumbBitmapHilited
Definition: ASlider.h:236
#define LINEAR_TO_DB(x)
Definition: Audacity.h:217
bool ShowDialog(wxPoint pos=wxPoint(-1,-1))
Definition: ASlider.cpp:1587
void GetScroll(float &line, float &page)
Definition: ASlider.cpp:497
bool TransferDataFromWindow() override
Definition: ASlider.cpp:238
ASlider is a custom slider, allowing for a slicker look and feel.
Definition: ASlider.h:243
const wxChar * name
Definition: Distortion.cpp:94
bool ShowDialog()
Definition: ASlider.cpp:943
void SetLabel(const wxString &label)
Definition: ASlider.cpp:148
void OnKeyEvent(wxKeyEvent &event)
Definition: ASlider.cpp:1141
int mThumbHeight
Definition: ASlider.h:209
AUDACITY_DLL_API AudacityProject * GetActiveProject()
Definition: Project.cpp:308
bool mIsDragging
Definition: ASlider.h:234
#define VEL_MIN
Definition: ASlider.h:57
wxString mName
Definition: ASlider.h:238
static const wxPoint2DDouble enabledLeftEnd[]
Definition: ASlider.cpp:293
void SetPos(const wxPoint &pos)
Definition: ASlider.cpp:143
bool mPopup
Definition: ASlider.h:185
static const wxPoint2DDouble outer[]
Definition: ASlider.cpp:272
void OnErase(wxEraseEvent &event)
Definition: ASlider.cpp:1485
void Increase(float steps)
Definition: ASlider.cpp:1577
float mScrollLine
Definition: ASlider.h:219
float Get()
Definition: ASlider.cpp:262
wxColour & Colour(int iIndex)
Definition: Theme.cpp:1225
void AddStandardButtons(long buttons=eOkButton|eCancelButton, wxButton *extra=NULL)
void AdjustSize(const wxSize &sz)
Definition: ASlider.cpp:515
float ClickPositionToValue(int fromPos, bool shiftDown)
Definition: ASlider.cpp:1239
int mOrientation
Definition: ASlider.h:182
wxString GetTip(float value) const
Definition: ASlider.cpp:836
static const wxPoint2DDouble disabledStripesBegin[]
Definition: ASlider.cpp:319
void OnSlider(wxCommandEvent &event)
Definition: ASlider.cpp:1464
Options & Style(int s)
Definition: ASlider.h:260
const double MIN_Threshold_Linear DB_TO_LINEAR(MIN_Threshold_dB)
int mCenterX
Definition: ASlider.h:201
int mTop
Definition: ASlider.h:188
#define VEL_MAX
Definition: ASlider.h:58
bool DoShowDialog(wxPoint pos)
Definition: ASlider.cpp:953
#define FRAC_SLIDER
Definition: ASlider.h:44
void SetDefaultShortcut(bool value)
Definition: ASlider.cpp:492
float mStepValue
Definition: ASlider.h:216
END_EVENT_TABLE()
int mThumbWidth
Definition: ASlider.h:208
void SetSpeed(float speed)
Definition: ASlider.cpp:1592
int mLeft
Definition: ASlider.h:187
wxString mLabel
Definition: ASlider.cpp:99
void OnSlider(wxCommandEvent &event)
Definition: ASlider.cpp:250
void OnTimer(wxTimerEvent &event)
Definition: ASlider.cpp:1547
void OnKeyEvent(wxKeyEvent &event)
Definition: ASlider.cpp:1530
void Decrease(float steps)
Definition: ASlider.cpp:1582
void StartVerticalLay(int iProp=1)