ยปCore Development>Code coverage>Lib/turtledemo/__main__.py

Python code coverage for Lib/turtledemo/__main__.py

#countcontent
1n/a#!/usr/bin/env python3
2n/a
3n/a"""
4n/a ----------------------------------------------
5n/a turtleDemo - Help
6n/a ----------------------------------------------
7n/a
8n/a This document has two sections:
9n/a
10n/a (1) How to use the demo viewer
11n/a (2) How to add your own demos to the demo repository
12n/a
13n/a
14n/a (1) How to use the demo viewer.
15n/a
16n/a Select a demoscript from the example menu.
17n/a The (syntax colored) source code appears in the left
18n/a source code window. IT CANNOT BE EDITED, but ONLY VIEWED!
19n/a
20n/a The demo viewer windows can be resized. The divider between text
21n/a and canvas can be moved by grabbing it with the mouse. The text font
22n/a size can be changed from the menu and with Control/Command '-'/'+'.
23n/a It can also be changed on most systems with Control-mousewheel
24n/a when the mouse is over the text.
25n/a
26n/a Press START button to start the demo.
27n/a Stop execution by pressing the STOP button.
28n/a Clear screen by pressing the CLEAR button.
29n/a Restart by pressing the START button again.
30n/a
31n/a SPECIAL demos, such as clock.py are those which run EVENTDRIVEN.
32n/a
33n/a Press START button to start the demo.
34n/a
35n/a - Until the EVENTLOOP is entered everything works
36n/a as in an ordinary demo script.
37n/a
38n/a - When the EVENTLOOP is entered, you control the
39n/a application by using the mouse and/or keys (or it's
40n/a controlled by some timer events)
41n/a To stop it you can and must press the STOP button.
42n/a
43n/a While the EVENTLOOP is running, the examples menu is disabled.
44n/a
45n/a - Only after having pressed the STOP button, you may
46n/a restart it or choose another example script.
47n/a
48n/a * * * * * * * *
49n/a In some rare situations there may occur interferences/conflicts
50n/a between events concerning the demo script and those concerning the
51n/a demo-viewer. (They run in the same process.) Strange behaviour may be
52n/a the consequence and in the worst case you must close and restart the
53n/a viewer.
54n/a * * * * * * * *
55n/a
56n/a
57n/a (2) How to add your own demos to the demo repository
58n/a
59n/a - Place the file in the same directory as turtledemo/__main__.py
60n/a IMPORTANT! When imported, the demo should not modify the system
61n/a by calling functions in other modules, such as sys, tkinter, or
62n/a turtle. Global variables should be initialized in main().
63n/a
64n/a - The code must contain a main() function which will
65n/a be executed by the viewer (see provided example scripts).
66n/a It may return a string which will be displayed in the Label below
67n/a the source code window (when execution has finished.)
68n/a
69n/a - In order to run mydemo.py by itself, such as during development,
70n/a add the following at the end of the file:
71n/a
72n/a if __name__ == '__main__':
73n/a main()
74n/a mainloop() # keep window open
75n/a
76n/a python -m turtledemo.mydemo # will then run it
77n/a
78n/a - If the demo is EVENT DRIVEN, main must return the string
79n/a "EVENTLOOP". This informs the demo viewer that the script is
80n/a still running and must be stopped by the user!
81n/a
82n/a If an "EVENTLOOP" demo runs by itself, as with clock, which uses
83n/a ontimer, or minimal_hanoi, which loops by recursion, then the
84n/a code should catch the turtle.Terminator exception that will be
85n/a raised when the user presses the STOP button. (Paint is not such
86n/a a demo; it only acts in response to mouse clicks and movements.)
87n/a"""
88n/aimport sys
89n/aimport os
90n/a
91n/afrom tkinter import *
92n/afrom idlelib.colorizer import ColorDelegator, color_config
93n/afrom idlelib.percolator import Percolator
94n/afrom idlelib.textview import view_text
95n/afrom turtledemo import __doc__ as about_turtledemo
96n/a
97n/aimport turtle
98n/a
99n/ademo_dir = os.path.dirname(os.path.abspath(__file__))
100n/adarwin = sys.platform == 'darwin'
101n/a
102n/aSTARTUP = 1
103n/aREADY = 2
104n/aRUNNING = 3
105n/aDONE = 4
106n/aEVENTDRIVEN = 5
107n/a
108n/amenufont = ("Arial", 12, NORMAL)
109n/abtnfont = ("Arial", 12, 'bold')
110n/atxtfont = ['Lucida Console', 10, 'normal']
111n/a
112n/aMINIMUM_FONT_SIZE = 6
113n/aMAXIMUM_FONT_SIZE = 100
114n/afont_sizes = [8, 9, 10, 11, 12, 14, 18, 20, 22, 24, 30]
115n/a
116n/adef getExampleEntries():
117n/a return [entry[:-3] for entry in os.listdir(demo_dir) if
118n/a entry.endswith(".py") and entry[0] != '_']
119n/a
120n/ahelp_entries = ( # (help_label, help_doc)
121n/a ('Turtledemo help', __doc__),
122n/a ('About turtledemo', about_turtledemo),
123n/a ('About turtle module', turtle.__doc__),
124n/a )
125n/a
126n/a
127n/a
128n/aclass DemoWindow(object):
129n/a
130n/a def __init__(self, filename=None):
131n/a self.root = root = turtle._root = Tk()
132n/a root.title('Python turtle-graphics examples')
133n/a root.wm_protocol("WM_DELETE_WINDOW", self._destroy)
134n/a
135n/a if darwin:
136n/a import subprocess
137n/a # Make sure we are the currently activated OS X application
138n/a # so that our menu bar appears.
139n/a p = subprocess.Popen(
140n/a [
141n/a 'osascript',
142n/a '-e', 'tell application "System Events"',
143n/a '-e', 'set frontmost of the first process whose '
144n/a 'unix id is {} to true'.format(os.getpid()),
145n/a '-e', 'end tell',
146n/a ],
147n/a stderr=subprocess.DEVNULL,
148n/a stdout=subprocess.DEVNULL,)
149n/a
150n/a root.grid_rowconfigure(0, weight=1)
151n/a root.grid_columnconfigure(0, weight=1)
152n/a root.grid_columnconfigure(1, minsize=90, weight=1)
153n/a root.grid_columnconfigure(2, minsize=90, weight=1)
154n/a root.grid_columnconfigure(3, minsize=90, weight=1)
155n/a
156n/a self.mBar = Menu(root, relief=RAISED, borderwidth=2)
157n/a self.mBar.add_cascade(menu=self.makeLoadDemoMenu(self.mBar),
158n/a label='Examples', underline=0)
159n/a self.mBar.add_cascade(menu=self.makeFontMenu(self.mBar),
160n/a label='Fontsize', underline=0)
161n/a self.mBar.add_cascade(menu=self.makeHelpMenu(self.mBar),
162n/a label='Help', underline=0)
163n/a root['menu'] = self.mBar
164n/a
165n/a pane = PanedWindow(orient=HORIZONTAL, sashwidth=5,
166n/a sashrelief=SOLID, bg='#ddd')
167n/a pane.add(self.makeTextFrame(pane))
168n/a pane.add(self.makeGraphFrame(pane))
169n/a pane.grid(row=0, columnspan=4, sticky='news')
170n/a
171n/a self.output_lbl = Label(root, height= 1, text=" --- ", bg="#ddf",
172n/a font=("Arial", 16, 'normal'), borderwidth=2,
173n/a relief=RIDGE)
174n/a self.start_btn = Button(root, text=" START ", font=btnfont,
175n/a fg="white", disabledforeground = "#fed",
176n/a command=self.startDemo)
177n/a self.stop_btn = Button(root, text=" STOP ", font=btnfont,
178n/a fg="white", disabledforeground = "#fed",
179n/a command=self.stopIt)
180n/a self.clear_btn = Button(root, text=" CLEAR ", font=btnfont,
181n/a fg="white", disabledforeground="#fed",
182n/a command = self.clearCanvas)
183n/a self.output_lbl.grid(row=1, column=0, sticky='news', padx=(0,5))
184n/a self.start_btn.grid(row=1, column=1, sticky='ew')
185n/a self.stop_btn.grid(row=1, column=2, sticky='ew')
186n/a self.clear_btn.grid(row=1, column=3, sticky='ew')
187n/a
188n/a Percolator(self.text).insertfilter(ColorDelegator())
189n/a self.dirty = False
190n/a self.exitflag = False
191n/a if filename:
192n/a self.loadfile(filename)
193n/a self.configGUI(DISABLED, DISABLED, DISABLED,
194n/a "Choose example from menu", "black")
195n/a self.state = STARTUP
196n/a
197n/a
198n/a def onResize(self, event):
199n/a cwidth = self._canvas.winfo_width()
200n/a cheight = self._canvas.winfo_height()
201n/a self._canvas.xview_moveto(0.5*(self.canvwidth-cwidth)/self.canvwidth)
202n/a self._canvas.yview_moveto(0.5*(self.canvheight-cheight)/self.canvheight)
203n/a
204n/a def makeTextFrame(self, root):
205n/a self.text_frame = text_frame = Frame(root)
206n/a self.text = text = Text(text_frame, name='text', padx=5,
207n/a wrap='none', width=45)
208n/a color_config(text)
209n/a
210n/a self.vbar = vbar = Scrollbar(text_frame, name='vbar')
211n/a vbar['command'] = text.yview
212n/a vbar.pack(side=LEFT, fill=Y)
213n/a self.hbar = hbar = Scrollbar(text_frame, name='hbar', orient=HORIZONTAL)
214n/a hbar['command'] = text.xview
215n/a hbar.pack(side=BOTTOM, fill=X)
216n/a text['yscrollcommand'] = vbar.set
217n/a text['xscrollcommand'] = hbar.set
218n/a
219n/a text['font'] = tuple(txtfont)
220n/a shortcut = 'Command' if darwin else 'Control'
221n/a text.bind_all('<%s-minus>' % shortcut, self.decrease_size)
222n/a text.bind_all('<%s-underscore>' % shortcut, self.decrease_size)
223n/a text.bind_all('<%s-equal>' % shortcut, self.increase_size)
224n/a text.bind_all('<%s-plus>' % shortcut, self.increase_size)
225n/a text.bind('<Control-MouseWheel>', self.update_mousewheel)
226n/a text.bind('<Control-Button-4>', self.increase_size)
227n/a text.bind('<Control-Button-5>', self.decrease_size)
228n/a
229n/a text.pack(side=LEFT, fill=BOTH, expand=1)
230n/a return text_frame
231n/a
232n/a def makeGraphFrame(self, root):
233n/a turtle._Screen._root = root
234n/a self.canvwidth = 1000
235n/a self.canvheight = 800
236n/a turtle._Screen._canvas = self._canvas = canvas = turtle.ScrolledCanvas(
237n/a root, 800, 600, self.canvwidth, self.canvheight)
238n/a canvas.adjustScrolls()
239n/a canvas._rootwindow.bind('<Configure>', self.onResize)
240n/a canvas._canvas['borderwidth'] = 0
241n/a
242n/a self.screen = _s_ = turtle.Screen()
243n/a turtle.TurtleScreen.__init__(_s_, _s_._canvas)
244n/a self.scanvas = _s_._canvas
245n/a turtle.RawTurtle.screens = [_s_]
246n/a return canvas
247n/a
248n/a def set_txtsize(self, size):
249n/a txtfont[1] = size
250n/a self.text['font'] = tuple(txtfont)
251n/a self.output_lbl['text'] = 'Font size %d' % size
252n/a
253n/a def decrease_size(self, dummy=None):
254n/a self.set_txtsize(max(txtfont[1] - 1, MINIMUM_FONT_SIZE))
255n/a return 'break'
256n/a
257n/a def increase_size(self, dummy=None):
258n/a self.set_txtsize(min(txtfont[1] + 1, MAXIMUM_FONT_SIZE))
259n/a return 'break'
260n/a
261n/a def update_mousewheel(self, event):
262n/a # For wheel up, event.delte = 120 on Windows, -1 on darwin.
263n/a # X-11 sends Control-Button-4 event instead.
264n/a if (event.delta < 0) == (not darwin):
265n/a return self.decrease_size()
266n/a else:
267n/a return self.increase_size()
268n/a
269n/a def configGUI(self, start, stop, clear, txt="", color="blue"):
270n/a self.start_btn.config(state=start,
271n/a bg="#d00" if start == NORMAL else "#fca")
272n/a self.stop_btn.config(state=stop,
273n/a bg="#d00" if stop == NORMAL else "#fca")
274n/a self.clear_btn.config(state=clear,
275n/a bg="#d00" if clear == NORMAL else"#fca")
276n/a self.output_lbl.config(text=txt, fg=color)
277n/a
278n/a def makeLoadDemoMenu(self, master):
279n/a menu = Menu(master)
280n/a
281n/a for entry in getExampleEntries():
282n/a def load(entry=entry):
283n/a self.loadfile(entry)
284n/a menu.add_command(label=entry, underline=0,
285n/a font=menufont, command=load)
286n/a return menu
287n/a
288n/a def makeFontMenu(self, master):
289n/a menu = Menu(master)
290n/a menu.add_command(label="Decrease (C-'-')", command=self.decrease_size,
291n/a font=menufont)
292n/a menu.add_command(label="Increase (C-'+')", command=self.increase_size,
293n/a font=menufont)
294n/a menu.add_separator()
295n/a
296n/a for size in font_sizes:
297n/a def resize(size=size):
298n/a self.set_txtsize(size)
299n/a menu.add_command(label=str(size), underline=0,
300n/a font=menufont, command=resize)
301n/a return menu
302n/a
303n/a def makeHelpMenu(self, master):
304n/a menu = Menu(master)
305n/a
306n/a for help_label, help_file in help_entries:
307n/a def show(help_label=help_label, help_file=help_file):
308n/a view_text(self.root, help_label, help_file)
309n/a menu.add_command(label=help_label, font=menufont, command=show)
310n/a return menu
311n/a
312n/a def refreshCanvas(self):
313n/a if self.dirty:
314n/a self.screen.clear()
315n/a self.dirty=False
316n/a
317n/a def loadfile(self, filename):
318n/a self.clearCanvas()
319n/a turtle.TurtleScreen._RUNNING = False
320n/a modname = 'turtledemo.' + filename
321n/a __import__(modname)
322n/a self.module = sys.modules[modname]
323n/a with open(self.module.__file__, 'r') as f:
324n/a chars = f.read()
325n/a self.text.delete("1.0", "end")
326n/a self.text.insert("1.0", chars)
327n/a self.root.title(filename + " - a Python turtle graphics example")
328n/a self.configGUI(NORMAL, DISABLED, DISABLED,
329n/a "Press start button", "red")
330n/a self.state = READY
331n/a
332n/a def startDemo(self):
333n/a self.refreshCanvas()
334n/a self.dirty = True
335n/a turtle.TurtleScreen._RUNNING = True
336n/a self.configGUI(DISABLED, NORMAL, DISABLED,
337n/a "demo running...", "black")
338n/a self.screen.clear()
339n/a self.screen.mode("standard")
340n/a self.state = RUNNING
341n/a
342n/a try:
343n/a result = self.module.main()
344n/a if result == "EVENTLOOP":
345n/a self.state = EVENTDRIVEN
346n/a else:
347n/a self.state = DONE
348n/a except turtle.Terminator:
349n/a if self.root is None:
350n/a return
351n/a self.state = DONE
352n/a result = "stopped!"
353n/a if self.state == DONE:
354n/a self.configGUI(NORMAL, DISABLED, NORMAL,
355n/a result)
356n/a elif self.state == EVENTDRIVEN:
357n/a self.exitflag = True
358n/a self.configGUI(DISABLED, NORMAL, DISABLED,
359n/a "use mouse/keys or STOP", "red")
360n/a
361n/a def clearCanvas(self):
362n/a self.refreshCanvas()
363n/a self.screen._delete("all")
364n/a self.scanvas.config(cursor="")
365n/a self.configGUI(NORMAL, DISABLED, DISABLED)
366n/a
367n/a def stopIt(self):
368n/a if self.exitflag:
369n/a self.clearCanvas()
370n/a self.exitflag = False
371n/a self.configGUI(NORMAL, DISABLED, DISABLED,
372n/a "STOPPED!", "red")
373n/a turtle.TurtleScreen._RUNNING = False
374n/a
375n/a def _destroy(self):
376n/a turtle.TurtleScreen._RUNNING = False
377n/a self.root.destroy()
378n/a self.root = None
379n/a
380n/a
381n/adef main():
382n/a demo = DemoWindow()
383n/a demo.root.mainloop()
384n/a
385n/aif __name__ == '__main__':
386n/a main()