[audacity4blind] Re: Labels

  • From: Robert Hänggi <aarjay.robert@xxxxxxxxx>
  • To: audacity4blind <audacity4blind@xxxxxxxxxxxxx>
  • Date: Thu, 27 Nov 2014 17:54:31 +0100

2014-11-27 15:40 GMT+01:00, David Bailes <david_bailes@xxxxxxxxxxx>:
> Hi Robert,
> why do you think that a properties dialog would not be helpful. I admit that
> it would need additional keystrokes, but it would make available information
> available which is not currently available.
> The problem of putting info in the help text is that it's going to cause
> verbosity problems for people using screen readers other than nvda, so I'm
> still not convinced that it's the best way of conveying the information. If
> nvda were the only screen reader, it might be a different story.
>
> David.
>
>
> On Monday, 17 November 2014, 20:21, Robert Hänggi <aarjay.robert@xxxxxxxxx>
> wrote:
> 2014-11-17 19:10 GMT+01:00, David Bailes <david_bailes@xxxxxxxxxxx>:
>> Hi Robert,
>> yes, I do build Audacity from source, as do at least a couple of others
>> on
>> the list.
>>
>> I'll reply to other points shortly, but this is just about helptext.
>> Unfortunately, I don't think it's going to be very usable to do this. If
>> you
>> include helptext, then by default jaws says "insert f1 help" after
>> reading
>> the name of the control, and this can get really annoying. You can switch
>> it
>> off either by changing the verbosity level to intermediate of advanced,
>> or
>> by setting smart help to off in the beginner verbosity settings. But I
>> don't
>> think that a user, especially a beginner should have to do this. As a far
>> more minor issue, narrator on window 8 reads out the help text, and I
>> don't
>> know of any way of switching it off. Not sure how voiceover handles help
>> text on the mac.
>> So mainly do the Jaws's behaviour, I don't think that help text if a
>> useful
>> route to go down.
>> As an alternative, perhaps a track could have a properties dialog?
>>
>> thanks for all you suggestions,
>> David.
>
> Hi David
>
> I'll attach the patch anyway.
> I believe that a property dialog isn't helpful either.
>
> I have the principle that all that is available to normal users with a
> single glance should also be available to us with a single key stroke
> or even automatically.
> The first line of the helptext string can as well be added to the
> normal name string itself.
> We can reduce the information overload by removing values that are
> common to the project settings.
> Thus, 44100 Hz and 32-bit float would never be displayed if the
> project has those values as default.
> We can also omit stereo, as it is probably the most common track type
> and there would be displayed Mono".
> Actually, "Left" and "Right" are already reported with the patch
> applied, I find that extremely useful after a "Split Stereo" to
> discriminate the two channels that do normally share a single name.
>
> The word "Label Track" could be replaced by the first line of the
> helptext for label tracks.
> E.g. "No Labels defined" etc.
>
>
> Robert
>
> The audacity4blind web site is at
> //www.freelists.org/webpage/audacity4blind
>
> Subscribe and unsubscribe information, message archives,
> Audacity keyboard commands, and more...
>
> To unsubscribe from audacity4blind, send an email to
> audacity4blind-request@xxxxxxxxxxxxx
> with subject line
> unsubscribe
>
>


-- 
Freundliche Grüsse

Robert J. Hänggi

Schulstr. 10
4247 Grindel

Email:   aarjay.robert@xxxxxxxxx
Mobile:   079 518 23 01
/**********************************************************************

  Audacity: A Digital Audio Editor

  TrackPanelAx.cpp

  Leland Lucius
  and lots of other contributors

******************************************************************//*!

\class TrackPanelAx
\brief Helper to TrackPanel to give accessibility.

*//*******************************************************************/

// For compilers that support precompilation, includes "wx/wx.h".
#include <wx/wxprec.h>

#ifndef WX_PRECOMP
// Include your minimal set of headers here, or wx.h
#include <wx/wx.h>
#endif


#include "Audacity.h"
#include "TrackPanelAx.h"
#include <wx/intl.h>
// RJH - added to get additional Label Track and Project info
#include "LabelTrack.h"
#include "Project.h"

TrackPanelAx::TrackPanelAx( wxWindow *window )
#if wxUSE_ACCESSIBILITY
   :wxWindowAccessible( window )
#endif
{
   mTrackPanel = wxDynamicCast( window, TrackPanel );
   mFocusedTrack = NULL;
}

TrackPanelAx::~TrackPanelAx()
{
}

// Returns currently focused track or first one if none focused
Track *TrackPanelAx::GetFocus()
{
   if( !mFocusedTrack )
   {
      SetFocus( NULL );
   }

   if( !TrackNum( mFocusedTrack ) )
   {
      mFocusedTrack = NULL;
   }

   return( mFocusedTrack );
}

// Changes focus to a specified track
void TrackPanelAx::SetFocus( Track *track )
{
#if wxUSE_ACCESSIBILITY
   if( mFocusedTrack != NULL )
   {
      NotifyEvent( wxACC_EVENT_OBJECT_SELECTIONREMOVE,
                   mTrackPanel,
                   wxOBJID_CLIENT,
                   TrackNum( mFocusedTrack ) );
   }
#endif

   if( track == NULL )
   {
      TrackListIterator iter( mTrackPanel->mTracks );
      track = iter.First();
   }

   mFocusedTrack = track;

#if wxUSE_ACCESSIBILITY
   if( mFocusedTrack != NULL )
   {
      int num = TrackNum( mFocusedTrack );

      NotifyEvent( wxACC_EVENT_OBJECT_FOCUS,
                   mTrackPanel,
                   wxOBJID_CLIENT,
                   num );

      if( mFocusedTrack->GetSelected() )
      {
         NotifyEvent( wxACC_EVENT_OBJECT_SELECTION,
                      mTrackPanel,
                      wxOBJID_CLIENT,
                      num );
      }
   }
#endif

   return;
}

// Returns TRUE if passed track has the focus
bool TrackPanelAx::IsFocused( Track *track )
{
   if( !mFocusedTrack )
   {
      SetFocus( NULL );
   }

   if( ( track == mFocusedTrack ) ||
       ( track == mFocusedTrack->GetLink() ) )
   {
      return true;
   }

   return false;
}

int TrackPanelAx::TrackNum( Track *target )
{
   TrackListIterator iter( mTrackPanel->mTracks );
   Track *t = iter.First();
   int ndx = 0;

   while( t != NULL )
   {
      ndx++;
      if( t == target )
      {
         return ndx;
      }

      t = iter.Next( true );
   }

   return 0;
}

Track *TrackPanelAx::FindTrack( int num )
{
   TrackListIterator iter( mTrackPanel->mTracks );
   Track *t = iter.First();
   int ndx = 0;

   while( t != NULL )
   {
      ndx++;
      if( ndx == num )
      {
         break;
      }

      t = iter.Next( true );
   }

   return t;
}

void TrackPanelAx::Updated()
{
#if wxUSE_ACCESSIBILITY
   Track *t = GetFocus();
   NotifyEvent(wxACC_EVENT_OBJECT_NAMECHANGE,
               mTrackPanel,
               wxOBJID_CLIENT,
               TrackNum(t));
   SetFocus(t);
#endif
}

#if wxUSE_ACCESSIBILITY

// Retrieves the address of an IDispatch interface for the specified child.
// All objects must support this property.
wxAccStatus TrackPanelAx::GetChild( int childId, wxAccessible** child )
{
   if( childId == wxACC_SELF )
   {
      *child = this;
   }
   else
   {
      *child = NULL;
   }

   return wxACC_OK;
}

// Gets the number of children.
wxAccStatus TrackPanelAx::GetChildCount( int* childCount )
{
   TrackListIterator iter( mTrackPanel->mTracks );
   Track *t = iter.First();
   int cnt = 0;

   while( t != NULL )
   {
      cnt++;

      if( t->GetLink() != NULL )
      {
         t = iter.Next();
      }

      t = iter.Next();
   }

   *childCount = cnt;

   return wxACC_OK;
}

// Gets the default action for this object (0) or > 0 (the action for a child).
// Return wxACC_OK even if there is no action. actionName is the action, or the 
empty
// string if there is no action.
// The retrieved string describes the action that is performed on an object,
// not what the object does as a result. For example, a toolbar button that 
prints
// a document has a default action of "Press" rather than "Prints the current 
document."
wxAccStatus TrackPanelAx::GetDefaultAction( int WXUNUSED(childId), wxString 
*actionName )
{
   actionName->Clear();
   
   return wxACC_OK;
}

// Returns the description for this object or a child.
wxAccStatus TrackPanelAx::GetDescription( int childId, wxString* description )
{
   description->Clear();
   if( childId != wxACC_SELF )
   {
      Track *t = FindTrack( childId );

      if( t == NULL )
      {
         return wxACC_FAIL;
      }
      else
      {
         // LLL: Remove these during "refactor"
         if (t->GetKind() == Track::Wave)
         {
            switch (t->GetChannel()) {
               case 0:
                  if (t->GetLinked()) {
                     *description = _( " Stereo");
                  }
                  else
                  {
                     *description = _( " Left");
                  }
                  break;
               case 1:
                  *description = _(" Right");
                  break;
            }
            AudacityProject *project = GetActiveProject();
            int TSRate = int(((WaveTrack *)t)->GetRate());
            if (TSRate != int(project->GetRate()))
               description->Printf(_("%s, %d Hz"), *description, TSRate);
            sampleFormat  TSFormat = ((WaveTrack *)t)->GetSampleFormat();
            if (TSFormat != project->GetDefaultFormat())
               description->Printf(_("%s, %s"), *description, 
GetSampleFormatStr(TSFormat));
         }
         if( t->GetKind() == Track::Label)
         {
            int ixLabel = ((LabelTrack *)t)->getSelectedIndex();
            if (ixLabel >= 0)
            {
               wxString LabelText = ((LabelTrack *)t)->GetLabel(ixLabel)->title;
               description->Printf(wxT(">%s<"), LabelText);
            }
            else
            {
               int numLabels = ((LabelTrack *)t)->GetNumLabels();
               switch (numLabels) {
               case 0:
                  description->Printf(_(", No Labels"));
                  break;
               case 1:
                  description->Printf(_(", Single Label"));
                  break;
               default:
                  description->Printf(_(", %d Labels"), numLabels);
                  break;
               }
            }
         }
      }
   }
   return wxACC_OK;
}

// Returns help text for this object or a child, similar to tooltip text.
wxAccStatus TrackPanelAx::GetHelpText(int WXUNUSED(childId), wxString *helpText)
{
   helpText->clear();

   return wxACC_OK;
}

// Returns the keyboard shortcut for this object or child.
// Return e.g. ALT+K
wxAccStatus TrackPanelAx::GetKeyboardShortcut( int WXUNUSED(childId), wxString 
*shortcut )
{
   shortcut->Clear();

   return wxACC_OK;
}

// Returns the rectangle for this object (id = 0) or a child element (id > 0).
// rect is in screen coordinates.
wxAccStatus TrackPanelAx::GetLocation( wxRect& rect, int elementId )
{
   wxRect client;

   if( elementId == wxACC_SELF )
   {
      rect = mTrackPanel->GetRect();
   }
   else
   {
      Track *t = FindTrack( elementId );

      if( t == NULL )
      {
         return wxACC_FAIL;
      }

      rect = mTrackPanel->FindTrackRect( t, true );
   }

   rect.SetPosition( mTrackPanel->GetParent()->ClientToScreen( 
rect.GetPosition() ) );

   return wxACC_OK;
}

// Gets the name of the specified object.
wxAccStatus TrackPanelAx::GetName( int childId, wxString* name )
{
#if defined(__WXMSW__)
   if( childId == wxACC_SELF )
   {
      *name = _( "TrackView" );
   }
   else
   {
      Track *t = FindTrack( childId );

      if( t == NULL )
      {
         return wxACC_FAIL;
      }
      else
      {
         *name = t->GetName();
         if( *name == t->GetDefaultName() )
         {
            /* i18n-hint: The %d is replaced by th enumber of the track.*/
            name->Printf(_("Track %d"), TrackNum( t ) );
         }

         // LLL: Remove these during "refactor"
         if (t->GetMute() && t->GetKind() == Track::Wave)
         {
            /* i18n-hint: This is for screen reader software and indicates that
               on this track mute is on.
               RJH - "Mute All" mutes label, time and note tracks too,
               the added second condition ensures that this state will be 
hidden for SRs
               Should be removed after the bug is fixed.*/
            name->Append( _( " Mute On" ) );
         }
         if( t->GetSolo() )
         {
            /* i18n-hint: This is for screen reader software and indicates that
               on this track solo is on.*/
            name->Append( _( " Solo On" ) );
         }
         if( t->GetKind() == Track::Label)
         {
            /* RJH-hint: This is for screen reader software and indicates that
               this is a label track.*/
            *name->Append(_("Label Track"));
            if (((LabelTrack *)t)->IsSelected())
               /* RJH-hint: This is for screen reader software and indicates 
that
               that the label track is in edit mode.*/
               name->Append(_(", Edit On"));
         }
         if( t->GetKind() == Track::Time)
         {
            /* RJH-hint: This is for screen reader software and indicates that
               this is the time track.*/
            name->Append( _( ", Time Track" ) );
         }
         if( t->GetKind() == Track::Note)
         {
            /* RJH-hint: This is for screen reader software and indicates that
               this is a note track.*/
            name->Append( _( ", Note Track" ) );
         }
         if (t->GetSelected())
         {
            /* i18n-hint: This is for screen reader software and indicates that
            this track is selected.*/
            name->Append(_(" Select On"));
         }
         if (t->IsSyncLockSelected())
         {
            /* i18n-hint: This is for screen reader software and indicates that
            this track is shown with a sync-locked icon.*/
            // The absence of a dash between Sync and Locked is deliberate -
            // if present, Jaws reads it as "dash".
            name->Append(_(" Sync Lock Selected"));
         }
      }
   }

   return wxACC_OK;
#endif

#if defined(__WXMAC__)
   return wxACC_NOT_IMPLEMENTED;
#endif
}

// Returns a role constant.
wxAccStatus TrackPanelAx::GetRole( int childId, wxAccRole* role )
{
#if defined(__WXMSW__)
   if( childId == wxACC_SELF )
   {
      //RJH - changed from Table/Row to List/listItem
      *role = wxROLE_SYSTEM_LIST;
   }
   else
   {
      *role = wxROLE_SYSTEM_LISTITEM;
   }
#endif

#if defined(__WXMAC__)
   if( childId == wxACC_SELF )
   {
      *role = wxROLE_SYSTEM_PANE;
   }
   else
   {
      *role = wxROLE_SYSTEM_STATICTEXT;
   }
#endif

   return wxACC_OK;
}

// Gets a variant representing the selected children
// of this object.
// Acceptable values:
// - a null variant (IsNull() returns TRUE)
// - a list variant (GetType() == wxT("list"))
// - an integer representing the selected child element,
//   or 0 if this object is selected (GetType() == wxT("long"))
// - a "void*" pointer to a wxAccessible child object
wxAccStatus TrackPanelAx::GetSelections( wxVariant * WXUNUSED(selections) )
{
   return wxACC_NOT_IMPLEMENTED;
}

// Returns a state constant.
wxAccStatus TrackPanelAx::GetState( int childId, long* state )
{
#if defined(__WXMSW__)
   if( childId > 0 )
   {
      Track *t = FindTrack( childId );

      *state = wxACC_STATE_SYSTEM_FOCUSABLE | wxACC_STATE_SYSTEM_SELECTABLE;
      if (t)
      {
         if( t == mFocusedTrack )
         {
            *state |= wxACC_STATE_SYSTEM_FOCUSED;
         }

         if( t->GetSelected() )
         {
            *state |= wxACC_STATE_SYSTEM_SELECTED;
         }
      }
   }
   else     // childId == wxACC_SELF
   {
      *state = wxACC_STATE_SYSTEM_FOCUSABLE + wxACC_STATE_SYSTEM_FOCUSED;
   }
#endif

#if defined(__WXMAC__)
   *state = wxACC_STATE_SYSTEM_FOCUSABLE | wxACC_STATE_SYSTEM_SELECTABLE;

   if( childId > 0 )
   {
      Track *t = FindTrack( childId );

      if (t)
      {
         if( t == mFocusedTrack )
         {
            *state |= wxACC_STATE_SYSTEM_FOCUSED;
         }

         if( t->GetSelected() )
         {
            *state |= wxACC_STATE_SYSTEM_SELECTED;
         }
      }
   }
#endif

   return wxACC_OK;
}

// Returns a localized string representing the value for the object
// or child.
wxAccStatus TrackPanelAx::GetValue( int childId, wxString* strValue )
{
#if defined(__WXMSW__)
   return wxACC_NOT_IMPLEMENTED;
#endif

#if defined(__WXMAC__)
   if( childId == wxACC_SELF )
   {
      *strValue = _( "TrackView" );
   }
   else
   {
      Track *t = FindTrack( childId );

      if( t == NULL )
      {
         return wxACC_FAIL;
      }
      else
      {
         *strValue = t->GetName();
         if( *strValue == t->GetDefaultName() )
         {
            strValue->Printf(_("Track %d"), TrackNum( t ) );
         }

         // LLL: Remove these during "refactor"
         if( t->GetMute() )
         {
            strValue->Append( _( " Mute On" ) );
         }

         if( t->GetSolo() )
         {
            strValue->Append( _( " Solo On" ) );
         }
         if( t->GetSelected() )
         {
            strValue->Append( _( " Select On" ) );
         }
      }
   }
   return wxACC_OK;
#endif
}

// Gets the window with the keyboard focus.
// If childId is 0 and child is NULL, no object in
// this subhierarchy has the focus.
// If this object has the focus, child should be 'this'.
wxAccStatus TrackPanelAx::GetFocus( int *childId, wxAccessible **child )
{
#if defined(__WXMSW__)

   if (mTrackPanel == wxWindow::FindFocus())
   {
      if (mFocusedTrack)
      {
         *childId = TrackNum(mFocusedTrack);
      }
      else
      {
         *child = this;
      }
   }

   return wxACC_OK;
#endif

#if defined(__WXMAC__)
   if( GetWindow() == wxWindow::FindFocus() )
   {
      if( mFocusedTrack )
      {
         *childId = TrackNum( mFocusedTrack );
      }
      else
      {
         *childId = wxACC_SELF;
}

      return wxACC_OK;
   }

   return wxACC_NOT_IMPLEMENTED;
#endif
}

#endif // wxUSE_ACCESSIBILITY

Other related posts: