bpo-37039: Make IDLE's Zoom Height adjust to users' screens (GH-13678)
Measure required height by quickly maximizing once per screen. A search for a better method failed.
This commit is contained in:
parent
a268edd6a4
commit
5bff3c86ab
|
@ -289,7 +289,10 @@ Show/Hide Code Context (Editor Window only)
|
||||||
Zoom/Restore Height
|
Zoom/Restore Height
|
||||||
Toggles the window between normal size and maximum height. The initial size
|
Toggles the window between normal size and maximum height. The initial size
|
||||||
defaults to 40 lines by 80 chars unless changed on the General tab of the
|
defaults to 40 lines by 80 chars unless changed on the General tab of the
|
||||||
Configure IDLE dialog.
|
Configure IDLE dialog. The maximum height for a screen is determined by
|
||||||
|
momentarily maximizing a window the first time one is zoomed on the screen.
|
||||||
|
Changing screen settings may invalidate the saved height. This toogle has
|
||||||
|
no effect when a window is maximized.
|
||||||
|
|
||||||
Window menu (Shell and Editor)
|
Window menu (Shell and Editor)
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
@ -3,6 +3,14 @@ Released on 2019-10-20?
|
||||||
======================================
|
======================================
|
||||||
|
|
||||||
|
|
||||||
|
bpo-37039: Adjust "Zoom Height" to individual screens by momemtarily
|
||||||
|
maximizing the window on first use with a particular screen. Changing
|
||||||
|
screen settings may invalidate the saved height. While a window is
|
||||||
|
maximized, "Zoom Height" has no effect.
|
||||||
|
|
||||||
|
bpo-35763: Make calltip reminder about '/' meaning positional-only less
|
||||||
|
obtrusive by only adding it when there is room on the first line.
|
||||||
|
|
||||||
bpo-35610: Replace now redundant editor.context_use_ps1 with
|
bpo-35610: Replace now redundant editor.context_use_ps1 with
|
||||||
.prompt_last_line. This finishes change started in bpo-31858.
|
.prompt_last_line. This finishes change started in bpo-31858.
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<head>
|
<head>
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
|
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||||
<title>IDLE — Python 3.8.0a4 documentation</title>
|
<title>IDLE — Python 3.9.0a0 documentation</title>
|
||||||
<link rel="stylesheet" href="../_static/pydoctheme.css" type="text/css" />
|
<link rel="stylesheet" href="../_static/pydoctheme.css" type="text/css" />
|
||||||
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
|
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@
|
||||||
<script type="text/javascript" src="../_static/sidebar.js"></script>
|
<script type="text/javascript" src="../_static/sidebar.js"></script>
|
||||||
|
|
||||||
<link rel="search" type="application/opensearchdescription+xml"
|
<link rel="search" type="application/opensearchdescription+xml"
|
||||||
title="Search within Python 3.8.0a4 documentation"
|
title="Search within Python 3.9.0a0 documentation"
|
||||||
href="../_static/opensearch.xml"/>
|
href="../_static/opensearch.xml"/>
|
||||||
<link rel="author" title="About these documents" href="../about.html" />
|
<link rel="author" title="About these documents" href="../about.html" />
|
||||||
<link rel="index" title="Index" href="../genindex.html" />
|
<link rel="index" title="Index" href="../genindex.html" />
|
||||||
|
@ -50,6 +50,7 @@
|
||||||
|
|
||||||
|
|
||||||
</head><body>
|
</head><body>
|
||||||
|
|
||||||
<div class="related" role="navigation" aria-label="related navigation">
|
<div class="related" role="navigation" aria-label="related navigation">
|
||||||
<h3>Navigation</h3>
|
<h3>Navigation</h3>
|
||||||
<ul>
|
<ul>
|
||||||
|
@ -72,7 +73,7 @@
|
||||||
|
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
<a href="../index.html">3.8.0a4 Documentation</a> »
|
<a href="../index.html">3.9.0a0 Documentation</a> »
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="nav-item nav-item-1"><a href="index.html" >The Python Standard Library</a> »</li>
|
<li class="nav-item nav-item-1"><a href="index.html" >The Python Standard Library</a> »</li>
|
||||||
|
@ -320,7 +321,10 @@ of the code which has scrolled above the top of the window. See
|
||||||
<dt>Zoom/Restore Height</dt>
|
<dt>Zoom/Restore Height</dt>
|
||||||
<dd>Toggles the window between normal size and maximum height. The initial size
|
<dd>Toggles the window between normal size and maximum height. The initial size
|
||||||
defaults to 40 lines by 80 chars unless changed on the General tab of the
|
defaults to 40 lines by 80 chars unless changed on the General tab of the
|
||||||
Configure IDLE dialog.</dd>
|
Configure IDLE dialog. The maximum height for a screen is determined by
|
||||||
|
momentarily maximizing a window the first time one is zoomed on the screen.
|
||||||
|
Changing screen settings may invalidate the saved height. This toogle has
|
||||||
|
no effect when a window is maximized.</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
<div class="section" id="window-menu-shell-and-editor">
|
<div class="section" id="window-menu-shell-and-editor">
|
||||||
|
@ -912,7 +916,7 @@ also used for testing.</p>
|
||||||
|
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
<a href="../index.html">3.8.0a4 Documentation</a> »
|
<a href="../index.html">3.9.0a0 Documentation</a> »
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="nav-item nav-item-1"><a href="index.html" >The Python Standard Library</a> »</li>
|
<li class="nav-item nav-item-1"><a href="index.html" >The Python Standard Library</a> »</li>
|
||||||
|
@ -943,7 +947,7 @@ also used for testing.</p>
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
Last updated on May 25, 2019.
|
Last updated on Jun 17, 2019.
|
||||||
<a href="https://docs.python.org/3/bugs.html">Found a bug</a>?
|
<a href="https://docs.python.org/3/bugs.html">Found a bug</a>?
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
|
|
|
@ -2,42 +2,119 @@
|
||||||
|
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
import tkinter
|
||||||
|
|
||||||
from idlelib import macosx
|
|
||||||
|
class WmInfoGatheringError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class ZoomHeight:
|
class ZoomHeight:
|
||||||
|
# Cached values for maximized window dimensions, one for each set
|
||||||
|
# of screen dimensions.
|
||||||
|
_max_height_and_y_coords = {}
|
||||||
|
|
||||||
def __init__(self, editwin):
|
def __init__(self, editwin):
|
||||||
self.editwin = editwin
|
self.editwin = editwin
|
||||||
|
self.top = self.editwin.top
|
||||||
|
|
||||||
def zoom_height_event(self, event=None):
|
def zoom_height_event(self, event=None):
|
||||||
top = self.editwin.top
|
zoomed = self.zoom_height()
|
||||||
zoomed = zoom_height(top)
|
|
||||||
menu_status = 'Restore' if zoomed else 'Zoom'
|
if zoomed is None:
|
||||||
self.editwin.update_menu_label(menu='options', index='* Height',
|
self.top.bell()
|
||||||
label=f'{menu_status} Height')
|
else:
|
||||||
|
menu_status = 'Restore' if zoomed else 'Zoom'
|
||||||
|
self.editwin.update_menu_label(menu='options', index='* Height',
|
||||||
|
label=f'{menu_status} Height')
|
||||||
|
|
||||||
return "break"
|
return "break"
|
||||||
|
|
||||||
|
def zoom_height(self):
|
||||||
|
top = self.top
|
||||||
|
|
||||||
def zoom_height(top):
|
width, height, x, y = get_window_geometry(top)
|
||||||
|
|
||||||
|
if top.wm_state() != 'normal':
|
||||||
|
# Can't zoom/restore window height for windows not in the 'normal'
|
||||||
|
# state, e.g. maximized and full-screen windows.
|
||||||
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
|
maxheight, maxy = self.get_max_height_and_y_coord()
|
||||||
|
except WmInfoGatheringError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if height != maxheight:
|
||||||
|
# Maximize the window's height.
|
||||||
|
set_window_geometry(top, (width, maxheight, x, maxy))
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
# Restore the window's height.
|
||||||
|
#
|
||||||
|
# .wm_geometry('') makes the window revert to the size requested
|
||||||
|
# by the widgets it contains.
|
||||||
|
top.wm_geometry('')
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_max_height_and_y_coord(self):
|
||||||
|
top = self.top
|
||||||
|
|
||||||
|
screen_dimensions = (top.winfo_screenwidth(),
|
||||||
|
top.winfo_screenheight())
|
||||||
|
if screen_dimensions not in self._max_height_and_y_coords:
|
||||||
|
orig_state = top.wm_state()
|
||||||
|
|
||||||
|
# Get window geometry info for maximized windows.
|
||||||
|
try:
|
||||||
|
top.wm_state('zoomed')
|
||||||
|
except tkinter.TclError:
|
||||||
|
# The 'zoomed' state is not supported by some esoteric WMs,
|
||||||
|
# such as Xvfb.
|
||||||
|
raise WmInfoGatheringError(
|
||||||
|
'Failed getting geometry of maximized windows, because ' +
|
||||||
|
'the "zoomed" window state is unavailable.')
|
||||||
|
top.update()
|
||||||
|
maxwidth, maxheight, maxx, maxy = get_window_geometry(top)
|
||||||
|
if sys.platform == 'win32':
|
||||||
|
# On Windows, the returned Y coordinate is the one before
|
||||||
|
# maximizing, so we use 0 which is correct unless a user puts
|
||||||
|
# their dock on the top of the screen (very rare).
|
||||||
|
maxy = 0
|
||||||
|
maxrooty = top.winfo_rooty()
|
||||||
|
|
||||||
|
# Get the "root y" coordinate for non-maximized windows with their
|
||||||
|
# y coordinate set to that of maximized windows. This is needed
|
||||||
|
# to properly handle different title bar heights for non-maximized
|
||||||
|
# vs. maximized windows, as seen e.g. in Windows 10.
|
||||||
|
top.wm_state('normal')
|
||||||
|
top.update()
|
||||||
|
orig_geom = get_window_geometry(top)
|
||||||
|
max_y_geom = orig_geom[:3] + (maxy,)
|
||||||
|
set_window_geometry(top, max_y_geom)
|
||||||
|
top.update()
|
||||||
|
max_y_geom_rooty = top.winfo_rooty()
|
||||||
|
|
||||||
|
# Adjust the maximum window height to account for the different
|
||||||
|
# title bar heights of non-maximized vs. maximized windows.
|
||||||
|
maxheight += maxrooty - max_y_geom_rooty
|
||||||
|
|
||||||
|
self._max_height_and_y_coords[screen_dimensions] = maxheight, maxy
|
||||||
|
|
||||||
|
set_window_geometry(top, orig_geom)
|
||||||
|
top.wm_state(orig_state)
|
||||||
|
|
||||||
|
return self._max_height_and_y_coords[screen_dimensions]
|
||||||
|
|
||||||
|
|
||||||
|
def get_window_geometry(top):
|
||||||
geom = top.wm_geometry()
|
geom = top.wm_geometry()
|
||||||
m = re.match(r"(\d+)x(\d+)\+(-?\d+)\+(-?\d+)", geom)
|
m = re.match(r"(\d+)x(\d+)\+(-?\d+)\+(-?\d+)", geom)
|
||||||
if not m:
|
return tuple(map(int, m.groups()))
|
||||||
top.bell()
|
|
||||||
return
|
|
||||||
width, height, x, y = map(int, m.groups())
|
|
||||||
newheight = top.winfo_screenheight()
|
|
||||||
|
|
||||||
# The constants below for Windows and Mac Aqua are visually determined
|
|
||||||
# to avoid taskbar or menubar and app icons.
|
def set_window_geometry(top, geometry):
|
||||||
newy, bot_y = ((0, 72) if sys.platform == 'win32' else
|
top.wm_geometry("{:d}x{:d}+{:d}+{:d}".format(*geometry))
|
||||||
(22, 88) if macosx.isAquaTk() else
|
|
||||||
(0, 88) ) # Guess for anything else.
|
|
||||||
newheight = newheight - newy - bot_y
|
|
||||||
newgeom = '' if height >= newheight else f"{width}x{newheight}+{x}+{newy}"
|
|
||||||
top.wm_geometry(newgeom)
|
|
||||||
return newgeom != ""
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
Adjust "Zoom Height" to individual screens by momemtarily maximizing the
|
||||||
|
window on first use with a particular screen. Changing screen settings
|
||||||
|
may invalidate the saved height. While a window is maximized,
|
||||||
|
"Zoom Height" has no effect.
|
Loading…
Reference in New Issue