Repository: nvaccess/nvda

Issue:
Option to show Speech Viewer by default (and save dimensions and position of the window)
**Reported by jmuheim on 2015-04-23 06:41**
I'm a sighted user and I'm using NVDA only with "no speech" option and with the speech viewer open. This makes it much faster for me to use, as I can jump to the relevant parts of the output directly by scanning through the speech viewer visually.

I know that I can open the speech viewer using NVDA+N, then T, then S, but this is cumbersome. I'd like to have an option "Display speech viewer when starting NVDA", as I normally start NVDA only for a few seconds, and then I quit it again so it doesn't interfere my keyboard (and slow down my computer, which is a Windows 7 virtual machine on Mac OS X).

In addition, it would be very nice if the window's last dimensions (width/height) and position (x/y) were remembered, as I usually want it side by side with my browser so they don't overlap each other.

I really hope this will be implemented. I'm working for the best known accessibility consultancy in Switzerland, and we are trying to get our clients to use NVDA themselves to produce highly accessible websites themselves without our help. So it would really make sense to make NVDA appeal a little bit more to sighted users, as typically it's them who create the websites that blind people use.



Discussion:
Attachment t5050-1.patch added by cannona on 2015-05-13 20:18
Description:
WIP: everything except remembering size and position.

Comment 1 by jmuheim on 2015-04-23 06:41
This would maybe also help people asking for a shorter keyboard shortcut for the speech viewer:

http://community.nvda-project.org/ticket/1507

Comment 2 by leonarddr on 2015-04-23 06:47
it is intended to include #4898 in 2015.2, which add the possibility to set a toggle hotkey for speech viewer. In that case, you will only have to start nvda and press a second hotkey to start speech viewer. Would that be enough for you?

Comment 3 by jmuheim on 2015-04-23 06:49
If you add the remember dimension and position feature, I will be more than happy!

Comment 4 by cannona on 2015-05-13 20:27
This patch adds an option to general preferences and when set, auto-starts the speech viewer.

Questions for the devs:
1. Should this option be in General, or some other screen?
1. I'm uncertain as to how best to get/set the size and position.  Initial thoughts are to add some code in the deactivate method of the SpeechViewer class which records the current window size and position, and some coorisponding code which restores it in __init.  I think I can get this information from self.getPosition() and self.getSize(), but not entirely sure.  Any ideas on this?  Sound like the right track?
2. Once I have the position data, where should I store it?  In config?

Thanks for any feedback.

Comment 5 by nvdakor (in reply to comment 4) on 2015-05-13 20:44
Replying to [cannona](comment:4):

> 1. Should this option be in General, or some other screen?

I'd say general settings would be fine, but I'd say it should not be available in secure screens.

> 1. I'm uncertain as to how best to get/set the size and position.  Initial thoughts are to add some code in the deactivate method of the SpeechViewer class which records the current window size and position, and some coorisponding code which restores it in __init.  I think I can get this information from self.getPosition() and self.getSize(), but not entirely sure.  Any ideas on this?  Sound like the right track?

Few concerns:
1. What if someone attempts to launch NVDA on a computer with a different screen resolution? In my case, my desktop has a 720P screen, while my laptop uses 1080P resolution.
2. One needs to be careful about screen sizes, otherwise some parts of the viewer window might be cut off or may appear blurred.
I think storing percentages would be better (say, if I'm to look at this, it should be on the bottom right, say 10 percent from the right edge, 10 percent from the bottom edge). Then someone will come in and ask that foreground and background color be configurable, which is way off the scope of this ticket and cannot be implemented easily by a group of people who cannot see colors (well, they can get some sense of which color combinations will work best).

> 1. Once I have the position data, where should I store it?  In config?

I agree - what we have in config dictionary are keys that control things such as progress bar output interval, voice settings that'll apply on all synthesizers and so on. I think, for sake of clarity and to allow add-ons to work with speech viewer location, I'd say a separate section for storing speech viewer real estate percentages should be used unless if it can be incorporated into the main config sections.
More code reviews from others are welcome. Thanks.

Is there any progress on this? And is the shortcut for toggling the speech viewer already available?

PS: woohooo, github issues! Bye bye, Trac! :+1: 

I haven't reviewed this yet myself, but there was some code review above from nvdakor that hasn't been addressed yet.

#4898 was implemented, which means you can now bind your own shortcut in NVDA menu -> Preferences -> Input gestures. It is unbound by default.

> #4898 was implemented, which means you can now bind your own shortcut in NVDA menu -> Preferences -> Input gestures. It is unbound by default.

That's nice. Thank you! Still, remembering its position would be really useful (also between restarts), as the window doesn't react on standard Windows positioning possibilities, e.g. dragging it to the corner of the screen, etc.

Hi,

This is nvdakor…

I’m not sure if Aaron is part of committers list…

As Jamie mentioned, the points I raised in the code review (using percentages and config storage) were not acted upon yet.

Thanks.

From: James Teh [mailto:notifications@github.com] 
Sent: Wednesday, November 11, 2015 3:54 AM
To: nvaccess/nvda nvda@noreply.github.com
Subject: Re: [nvda] Option to show Speech Viewer by default (and save dimensions and position of the window) (#5050)

I haven't reviewed this yet myself, but there was some code review above from nvdakor that hasn't been addressed yet.

#4898 https://github.com/nvaccess/nvda/issues/4898  was implemented, which means you can now bind your own shortcut in NVDA menu -> Preferences -> Input gestures. It is unbound by default.

—
Reply to this email directly or view it on GitHub https://github.com/nvaccess/nvda/issues/5050#issuecomment-155753122 .

Is there any news on this? It would be really useful if the speech viewer remembered its position when closing and reopening it (also between restarts of NVDA).

Or at least make it possible to snap it to a corner of the screen by Windows' window snapping mechanism

So, was the shortcut for the speech viewer implemented or what? can't get it to work.

You will have to add one manually as @jcsteh noted above. It is in nvda menu>prefferences>input gestures>tools>Toggles the NVDA Speech viewer, a floating window that allows you to view all the text that NVDA is currently speaking


Resolving patch:
diff --git a/source/config/__init__.py b/source/config/__init__.py
--- a/source/config/__init__.py
+++ b/source/config/__init__.py
@@ -137,6 +137,13 @@ def validateConfig(configObj,validator,validationResult=None,keyList=None):
 
 [speechViewer]
 	showSpeechViewerAtStartup = boolean(default=false)
+	autoPositionWindow = boolean(default=True)
+	# values for positioning the window. Defaults are not used. They should not be read if autoPositionWindow is True
+	x = integer()
+	y = integer()
+	width = integer()
+	height = integer()
+	displays = string_list()
 
 #Keyboard settings
 [keyboard]
diff --git a/source/speechViewer.py b/source/speechViewer.py
--- a/source/speechViewer.py
+++ b/source/speechViewer.py
@@ -12,12 +12,19 @@
 class SpeechViewerFrame(wx.Dialog):
 
 	def __init__(self, onDestroyCallBack):
-		super(SpeechViewerFrame, self).__init__(gui.mainFrame, wx.ID_ANY, _("NVDA Speech Viewer"), style=wx.CAPTION | wx.RESIZE_BORDER | wx.STAY_ON_TOP)
+		dialogSize=wx.Size(w=500, h=500)
+		dialogPos=None
+		if not config.conf["speechViewer"]["autoPositionWindow"] and self.doDisplaysMatchConfig():
+			log.debug("Setting speechViewer window position")
+			speechViewSection = config.conf["speechViewer"]
+			dialogSize = wx.Size(w=speechViewSection["width"], h=speechViewSection["height"])
+			dialogPos = wx.Point(x=speechViewSection["x"], y=speechViewSection["y"])
+		super(SpeechViewerFrame, self).__init__(gui.mainFrame, wx.ID_ANY, _("NVDA Speech Viewer"), size=dialogSize, pos=dialogPos, style=wx.CAPTION | wx.RESIZE_BORDER | wx.STAY_ON_TOP)
 		self.onDestroyCallBack = onDestroyCallBack
 		self.Bind(wx.EVT_CLOSE, self.onClose)
 		self.Bind(wx.EVT_WINDOW_DESTROY, self.onDestroy)
 		sizer = wx.BoxSizer(wx.VERTICAL)
-		self.textCtrl = wx.TextCtrl(self, -1,size=(500,500),style=wx.TE_RICH2|wx.TE_READONLY|wx.TE_MULTILINE)
+		self.textCtrl = wx.TextCtrl(self, -1,style=wx.TE_RICH2|wx.TE_READONLY|wx.TE_MULTILINE)
 		sizer.Add(self.textCtrl, proportion=1, flag=wx.EXPAND)
 		# Translators: The label for a setting in the speech viewer that controls whether the speech viewer is shown at startup or not.
 		self.shouldShowOnStartupCheckBox = wx.CheckBox(self,wx.NewId(),label=_("&Show Speech Viewer on Startup"))
@@ -26,7 +33,6 @@ def __init__(self, onDestroyCallBack):
 		sizer.Add(self.shouldShowOnStartupCheckBox, border=5, flag=wx.ALL)
 		# set the check box as having focus, by default the textCtrl has focus which stops the speechviewer output (even if another window is in focus)
 		self.shouldShowOnStartupCheckBox.SetFocus()
-		sizer.Fit(self)
 		self.SetSizer(sizer)
 		self.Show(True)
 
@@ -43,7 +49,29 @@ def onShouldShowOnStartupChanged(self, evt):
 
 	def onDestroy(self, evt):
 		log.debug("SpeechViewer destroyed")
+		self.savePositionInformation()
 		self.onDestroyCallBack()
+		evt.Skip()
+
+	def doDisplaysMatchConfig(self):
+		configSizes = config.conf["speechViewer"]["displays"]
+		attachedSizes = self.getAttachedDisplaySizesAsStringArray()
+		return len(configSizes) == len(attachedSizes) and all( configSizes[i] == attachedSizes[i] for i in xrange(len(configSizes)))
+
+	def getAttachedDisplaySizesAsStringArray(self):
+		displays = ( wx.Display(i).GetGeometry().GetSize() for i in xrange(wx.Display.GetCount()) )
+		return [repr( (i.width, i.height) ) for i in displays]
+
+
+	def savePositionInformation(self):
+		position = self.GetPosition()
+		config.conf["speechViewer"]["x"] = position.x
+		config.conf["speechViewer"]["y"] = position.y
+		size = self.GetSize()
+		config.conf["speechViewer"]["width"] = size.width
+		config.conf["speechViewer"]["height"] = size.height
+		config.conf["speechViewer"]["displays"] = self.getAttachedDisplaySizesAsStringArray()
+		config.conf["speechViewer"]["autoPositionWindow"] = False
 
 _guiFrame=None
 isActive=False


Test patch: