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