Commit 5bff3c86 authored by Tal Einat's avatar Tal Einat Committed by Terry Jan Reedy

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.
parent a268edd6
......@@ -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-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
.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 &#8212; Python 3.8.0a4 documentation</title>
<title>IDLE &#8212; 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> &#187;
<a href="../index.html">3.9.0a0 Documentation</a> &#187;
</li>
<li class="nav-item nav-item-1"><a href="index.html" >The Python Standard Library</a> &#187;</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> &#187;
<a href="../index.html">3.9.0a0 Documentation</a> &#187;
</li>
<li class="nav-item nav-item-1"><a href="index.html" >The Python Standard Library</a> &#187;</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)
menu_status = 'Restore' if zoomed else 'Zoom'
self.editwin.update_menu_label(menu='options', index='* Height',
label=f'{menu_status} Height')
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
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()
def zoom_height(top):
# 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()
# 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 != ""
return tuple(map(int, m.groups()))
def set_window_geometry(top, geometry):
top.wm_geometry("{:d}x{:d}+{:d}+{:d}".format(*geometry))
if __name__ == "__main__":
......
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.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment