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.
(cherry picked from commit 5bff3c86ab
)
Co-authored-by: Tal Einat <taleinat+github@gmail.com>
This commit is contained in:
parent
ac4202ee4d
commit
0f31a2d3e8
|
@ -289,7 +289,10 @@ Show/Hide Code Context (Editor Window only)
|
|||
Zoom/Restore Height
|
||||
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
|
||||
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)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
|
@ -3,6 +3,14 @@ Released on 2019-06-24?
|
|||
======================================
|
||||
|
||||
|
||||
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
|
||||
.prompt_last_line. This finishes change started in bpo-31858.
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
|
||||
<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/pygments.css" type="text/css" />
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
|||
<script type="text/javascript" src="../_static/sidebar.js"></script>
|
||||
|
||||
<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"/>
|
||||
<link rel="author" title="About these documents" href="../about.html" />
|
||||
<link rel="index" title="Index" href="../genindex.html" />
|
||||
|
@ -50,6 +50,7 @@
|
|||
|
||||
|
||||
</head><body>
|
||||
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
|
@ -72,7 +73,7 @@
|
|||
|
||||
|
||||
<li>
|
||||
<a href="../index.html">3.8.0a4 Documentation</a> »
|
||||
<a href="../index.html">3.9.0a0 Documentation</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>
|
||||
<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
|
||||
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>
|
||||
</div>
|
||||
<div class="section" id="window-menu-shell-and-editor">
|
||||
|
@ -912,7 +916,7 @@ also used for testing.</p>
|
|||
|
||||
|
||||
<li>
|
||||
<a href="../index.html">3.8.0a4 Documentation</a> »
|
||||
<a href="../index.html">3.9.0a0 Documentation</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 />
|
||||
|
||||
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>?
|
||||
<br />
|
||||
|
||||
|
|
|
@ -2,42 +2,119 @@
|
|||
|
||||
import re
|
||||
import sys
|
||||
import tkinter
|
||||
|
||||
from idlelib import macosx
|
||||
|
||||
class WmInfoGatheringError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class ZoomHeight:
|
||||
# Cached values for maximized window dimensions, one for each set
|
||||
# of screen dimensions.
|
||||
_max_height_and_y_coords = {}
|
||||
|
||||
def __init__(self, editwin):
|
||||
self.editwin = editwin
|
||||
self.top = self.editwin.top
|
||||
|
||||
def zoom_height_event(self, event=None):
|
||||
top = self.editwin.top
|
||||
zoomed = zoom_height(top)
|
||||
zoomed = self.zoom_height()
|
||||
|
||||
if zoomed is None:
|
||||
self.top.bell()
|
||||
else:
|
||||
menu_status = 'Restore' if zoomed else 'Zoom'
|
||||
self.editwin.update_menu_label(menu='options', index='* Height',
|
||||
label=f'{menu_status} Height')
|
||||
|
||||
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()
|
||||
m = re.match(r"(\d+)x(\d+)\+(-?\d+)\+(-?\d+)", geom)
|
||||
if not m:
|
||||
top.bell()
|
||||
return
|
||||
width, height, x, y = map(int, m.groups())
|
||||
newheight = top.winfo_screenheight()
|
||||
return tuple(map(int, m.groups()))
|
||||
|
||||
# The constants below for Windows and Mac Aqua are visually determined
|
||||
# to avoid taskbar or menubar and app icons.
|
||||
newy, bot_y = ((0, 72) if sys.platform == 'win32' else
|
||||
(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 != ""
|
||||
|
||||
def set_window_geometry(top, geometry):
|
||||
top.wm_geometry("{:d}x{:d}+{:d}+{:d}".format(*geometry))
|
||||
|
||||
|
||||
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