Skip to content

Commit

Permalink
NVDA can now indicate line indentation using tones. This can be confi…
Browse files Browse the repository at this point in the history
…gured using the "Report line indentation with" combo box in NVDA's Document Formatting preferences dialog.

Issue #5906. PR #6057.
  • Loading branch information
derekriemer authored and jcsteh committed Aug 29, 2016
1 parent ef66839 commit 3aa65e1
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 18 deletions.
1 change: 1 addition & 0 deletions source/config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ def validateConfig(configObj,validator,validationResult=None,keyList=None):
reportPage = boolean(default=true)
reportLineNumber = boolean(default=False)
reportLineIndentation = boolean(default=False)
reportLineIndentationWithTones = boolean(default=False)
reportParagraphIndentation = boolean(default=False)
reportTables = boolean(default=true)
includeLayoutTables = boolean(default=False)
Expand Down
6 changes: 3 additions & 3 deletions source/globalCommands.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#A part of NonVisual Desktop Access (NVDA)
#This file is covered by the GNU General Public License.
#See the file COPYING for more details.
#Copyright (C) 2006-2015 NV Access Limited, Peter Vágner, Aleksey Sadovoy, Rui Batista, Joseph Lee, Leonard de Ruijter
#Copyright (C) 2006-2016 NV Access Limited, Peter Vágner, Aleksey Sadovoy, Rui Batista, Joseph Lee, Leonard de Ruijter, Derek Riemer

import time
import itertools
Expand Down Expand Up @@ -1255,7 +1255,7 @@ def script_reportFormatting(self,gesture):
"detectFormatAfterCursor":False,
"reportFontName":True,"reportFontSize":True,"reportFontAttributes":True,"reportColor":True,"reportRevisions":False,"reportEmphasis":False,
"reportStyle":True,"reportAlignment":True,"reportSpellingErrors":True,
"reportPage":False,"reportLineNumber":False,"reportParagraphIndentation":True,"reportLineSpacing":True,"reportTables":False,
"reportPage":False,"reportLineNumber":False,"reportLineIndentation":True,"reportLineIndentationWithTones":False,"reportParagraphIndentation":True,"reportLineSpacing":True,"reportTables":False,
"reportLinks":False,"reportHeadings":False,"reportLists":False,
"reportBlockQuotes":False,"reportComments":False,
}
Expand All @@ -1267,7 +1267,7 @@ def script_reportFormatting(self,gesture):
line.expand(textInfos.UNIT_LINE)
indentation,content=speech.splitTextIndentation(line.text)
if indentation:
textList.append(speech.getIndentationSpeech(indentation))
textList.append(speech.getIndentationSpeech(indentation, formatConfig))

info.expand(textInfos.UNIT_CHARACTER)
formatField=textInfos.FormatField()
Expand Down
30 changes: 23 additions & 7 deletions source/gui/settingsDialogs.py
Original file line number Diff line number Diff line change
Expand Up @@ -1111,12 +1111,26 @@ def makeSettings(self, settingsSizer):
self.lineNumberCheckBox=wx.CheckBox(self,wx.NewId(),label=_("Report line &numbers"))
self.lineNumberCheckBox.SetValue(config.conf["documentFormatting"]["reportLineNumber"])
settingsSizer.Add(self.lineNumberCheckBox,border=10,flag=wx.BOTTOM)
# Translators: This message is presented in the document formatting settings dialogue
# If this option is selected, NVDA will cound the leading spaces and tabs of a line and speak it.
#
self.lineIndentationCheckBox=wx.CheckBox(self,wx.NewId(),label=_("Report l&ine indentation"))
self.lineIndentationCheckBox.SetValue(config.conf["documentFormatting"]["reportLineIndentation"])
settingsSizer.Add(self.lineIndentationCheckBox,border=10,flag=wx.BOTTOM)
sizer=wx.BoxSizer(wx.HORIZONTAL)
# Translators: This is the label for a combobox controlling the reporting of line indentation in the
# Document Formatting dialog (possible choices are Off, Speech, Tones, or Both.
sizer.Add(wx.StaticText(self,wx.ID_ANY,label=_("Report line &indentation with:")))
indentChoices=[
#Translators: A choice in a combo box in the document formatting dialog to report No line Indentation.
_("Off"),
#Translators: A choice in a combo box in the document formatting dialog to report indentation with Speech.
_("Speech"),
#Translators: A choice in a combo box in the document formatting dialog to report indentation with tones.
_("Tones"),
#Translators: A choice in a combo box in the document formatting dialog to report indentation with both Speech and tones.
_("Both Speech and Tones")
]
self.lineIndentationCombo = wx.Choice(self,wx.ID_ANY,choices=indentChoices)
#We use bitwise opperations because it saves us a four way if statement.
curChoice = config.conf["documentFormatting"]["reportLineIndentationWithTones"] << 1 | config.conf["documentFormatting"]["reportLineIndentation"]
self.lineIndentationCombo.SetSelection(curChoice)
sizer.Add(self.lineIndentationCombo)
settingsSizer.Add(sizer)
# Translators: This message is presented in the document formatting settings dialogue
# If this option is selected, NVDA will report paragraph indentation if available.
self.paragraphIndentationCheckBox=wx.CheckBox(self,wx.NewId(),label=_("Report &paragraph indentation"))
Expand Down Expand Up @@ -1195,7 +1209,9 @@ def onOk(self,evt):
config.conf["documentFormatting"]["reportSpellingErrors"]=self.spellingErrorsCheckBox.IsChecked()
config.conf["documentFormatting"]["reportPage"]=self.pageCheckBox.IsChecked()
config.conf["documentFormatting"]["reportLineNumber"]=self.lineNumberCheckBox.IsChecked()
config.conf["documentFormatting"]["reportLineIndentation"]=self.lineIndentationCheckBox.IsChecked()
choice = self.lineIndentationCombo.GetSelection()
config.conf["documentFormatting"]["reportLineIndentation"] = choice in (1, 3)
config.conf["documentFormatting"]["reportLineIndentationWithTones"] = choice in (2, 3)
config.conf["documentFormatting"]["reportParagraphIndentation"]=self.paragraphIndentationCheckBox.IsChecked()
config.conf["documentFormatting"]["reportLineSpacing"]=self.lineSpacingCheckBox.IsChecked()
config.conf["documentFormatting"]["reportTables"]=self.tablesCheckBox.IsChecked()
Expand Down
34 changes: 26 additions & 8 deletions source/speech.py
Original file line number Diff line number Diff line change
Expand Up @@ -406,23 +406,31 @@ def splitTextIndentation(text):
return RE_INDENTATION_SPLIT.match(text).groups()

RE_INDENTATION_CONVERT = re.compile(r"(?P<char>\s)(?P=char)*", re.UNICODE)
def getIndentationSpeech(indentation):
IDT_BASE_FREQUENCY = 220 #One octave below middle A.
IDT_TONE_DURATION = 80 #Milleseconds
IDT_MAX_SPACES = 72
def getIndentationSpeech(indentation, formatConfig):
"""Retrieves the phrase to be spoken for a given string of indentation.
@param indentation: The string of indentation.
@type indentation: unicode
@param formatConfig: The configuration to use.
@type formatConfig: dict
@return: The phrase to be spoken.
@rtype: unicode
"""
# Translators: no indent is spoken when the user moves from a line that has indentation, to one that
# does not.
speechIndentConfig = formatConfig["reportLineIndentation"]
toneIndentConfig = formatConfig["reportLineIndentationWithTones"] and speechMode == speechMode_talk
if not indentation:
if toneIndentConfig:
tones.beep(IDT_BASE_FREQUENCY, IDT_TONE_DURATION)
# Translators: This is spoken when the given line has no indentation.
return _("no indent")
return (_("no indent") if speechIndentConfig else "")

#The non-breaking space is semantically a space, so we replace it here.
indentation = indentation.replace(u"\xa0", u" ")
res = []
locale=languageHandler.getLanguage()
quarterTones = 0
for m in RE_INDENTATION_CONVERT.finditer(indentation):
raw = m.group()
symbol = characterProcessing.processSpeechSymbol(locale, raw[0])
Expand All @@ -434,8 +442,18 @@ def getIndentationSpeech(indentation):
res.append(symbol)
else:
res.append(u"{count} {symbol}".format(count=count, symbol=symbol))

return " ".join(res)
quarterTones += (count*4 if raw[0]== "\t" else count)

speak = speechIndentConfig
if toneIndentConfig:
if quarterTones <= IDT_MAX_SPACES:
#Remove me during speech refactor.
pitch = IDT_BASE_FREQUENCY*2**(quarterTones/24.0) #24 quarter tones per octave.
tones.beep(pitch, IDT_TONE_DURATION)
else:
#we have more than 72 spaces (18 tabs), and must speak it since we don't want to hurt the users ears.
speak = True
return (" ".join(res) if speak else "")

def speak(speechSequence,symbolLevel=None):
"""Speaks a sequence of text and speech commands
Expand Down Expand Up @@ -664,7 +682,7 @@ def speakTextInfo(info,useCache=True,formatConfig=None,unit=None,reason=controlT
if extraDetail:
formatConfig=formatConfig.copy()
formatConfig['extraDetail']=True
reportIndentation=unit==textInfos.UNIT_LINE and formatConfig["reportLineIndentation"]
reportIndentation=unit==textInfos.UNIT_LINE and ( formatConfig["reportLineIndentation"] or formatConfig["reportLineIndentationWithTones"])

speechSequence=[]
#Fetch the last controlFieldStack, or make a blank one
Expand Down Expand Up @@ -846,7 +864,7 @@ def speakTextInfo(info,useCache=True,formatConfig=None,unit=None,reason=controlT
relativeSpeechSequence.append(LangChangeCommand(newLanguage))
lastLanguage=newLanguage
if reportIndentation and speakTextInfoState and allIndentation!=speakTextInfoState.indentationCache:
indentationSpeech=getIndentationSpeech(allIndentation)
indentationSpeech=getIndentationSpeech(allIndentation, formatConfig)
if autoLanguageSwitching and speechSequence[-1].lang is not None:
# Indentation must be spoken in the default language,
# but the initial format field specified a different language.
Expand Down
11 changes: 11 additions & 0 deletions user_docs/en/userGuide.t2t
Original file line number Diff line number Diff line change
Expand Up @@ -1232,6 +1232,17 @@ By default, NVDA will detect the formatting at the position of the System caret

Enable this option while proof reading documents in applications such as Microsoft Word, where formatting is important.

==== Report line indentation with ====
This option allows you to configure how indentation at the beginning of lines is reported.
The Report line indentation with combo box has four options.

- Off: NVDA will not treat indentation specially.
- Speech: If speech is selected, when the amount of indentation changes, NVDA will say something like "twelve space" or "four tab."
- Tones: If Tones is selected, when the amount of indentation changes, tones indicate the amount of change in indent.
The tone will increase in pitch every space, and for a tab, it will increase in pitch the equivalent of 4 spaces.
- Both Speech and Tones: This option reads indentation using both of the above methods.
-

+++ Speech dictionaries +++
The speech dictionaries menu (found in the Preferences menu) contains dialogs that allow you to manage the way NVDA pronounces particular words or phrases.
There are currently three different types of speech dictionaries.
Expand Down

0 comments on commit 3aa65e1

Please sign in to comment.