1from paida.paida_core.PAbsorber import *
2from paida.paida_core.IFillStyle import *
3from paida.paida_core.ILineStyle import *
4from paida.paida_core.ITextStyle import *
5
6from Tkinter import Tk, Toplevel, Button, PhotoImage, Frame, Canvas, Scrollbar, VERTICAL, HORIZONTAL
7import Tkinter
8import tkFont
9try:
10	import threading
11except ImportError:
12	import dummy_threading as threading
13import time
14import math
15
16N = Tkinter.N
17NE = Tkinter.NE
18E = Tkinter.E
19SE = Tkinter.SE
20S = Tkinter.S
21SW = Tkinter.SW
22W = Tkinter.W
23NW = Tkinter.NW
24CENTER = Tkinter.CENTER
25
26def createRoot():
27	global _guiRoot
28	_guiRoot = _Root()
29	_guiRoot.setDaemon(True)
30
31def startRoot():
32	global _guiRoot
33	_guiRoot.start()
34
35def getRoot():
36	global _guiRoot
37	return _guiRoot
38
39def getFontList(_defaultCandidates):
40	_fontRoot = Tk()
41	_fontRoot.withdraw()
42	_fontRoot.tk.call('tk', 'useinputmethods', 'False')
43	_fontRoot.tk.call('tk', 'scaling', '1.0')
44	fontList = list(tkFont.families(_fontRoot))
45	fontList.sort()
46	defaultFont = Button(_fontRoot).cget('font')
47
48	if not defaultFont in fontList:
49		fontList.append(defaultFont)
50	for _defaultCandidate in _defaultCandidates:
51		if _defaultCandidate in fontList:
52			defaultFont = _defaultCandidate
53
54	_fontRoot.destroy()
55	return fontList, defaultFont
56
57
58
59class _Root(threading.Thread):
60	def __init__(self):
61		threading.Thread.__init__(self)
62		self._setRootCondition(threading.Condition())
63
64	def run(self):
65		rootCondition = self._getRootCondition()
66		rootCondition.acquire()
67		self._setRoot(Tk())
68		root = self._getRoot()
69		root.withdraw()
70		root.tk.call('tk', 'useinputmethods', 'False')
71		root.tk.call('tk', 'scaling', '1.0')
72		root.grid()
73
74		self._trees = []
75		self._plotters = []
76		self._requestedTrees = []
77		self._requestedPlotters = []
78		self._setQuitLoop(False)
79
80		self._setLock(threading.RLock())
81		self._setTreeCondition(threading.Condition())
82		self._setPlotterCondition(threading.Condition())
83
84		rootCondition.notifyAll()
85		rootCondition.release()
86		self._mainloop()
87
88		while 1:
89			if self._getQuitLoop():
90				rootCondition = self._getRootCondition()
91				rootCondition.acquire()
92				### Wait other threads.
93				lock = self._getLock()
94				lock.acquire()
95				lock.release()
96				rootCondition.notifyAll()
97				rootCondition.release()
98				break
99			root.update()
100			time.sleep(0.1)
101
102	def _mainloop(self):
103		lock = self._getLock()
104		if lock.acquire(blocking = 0):
105			self._check()
106			lock.release()
107		self._getRoot().after(300, self._mainloop)
108
109	def _setLock(self, lock):
110		self._lock = lock
111
112	def _getLock(self):
113		return  self._lock
114
115	def _setRootCondition(self, Condition):
116		self._rootCondition = Condition
117
118	def _getRootCondition(self):
119		return self._rootCondition
120
121	def _setTreeCondition(self, Condition):
122		self._treeCondition = Condition
123
124	def _getTreeCondition(self):
125		return self._treeCondition
126
127	def _setPlotterCondition(self, Condition):
128		self._plotterCondition = Condition
129
130	def _getPlotterCondition(self):
131		return self._plotterCondition
132
133	def _setQuitLoop(self, boolean):
134		self._quitLoop = boolean
135
136	def _getQuitLoop(self):
137		return self._quitLoop
138
139	def _setRoot(self, root):
140		self._root = root
141
142	def _getRoot(self):
143		return self._root
144
145	def _appendTree(self, tree):
146		self._trees.append(tree)
147
148	def _getTrees(self):
149		return self._trees
150
151	def _removeTree(self, tree):
152		self._getTrees().remove(tree)
153
154	def _appendPlotter(self, plotter):
155		self._plotters.append(plotter)
156
157	def _getPlotters(self):
158		return self._plotters
159
160	def _removePlotter(self, plotter):
161		self._getPlotters().remove(plotter)
162
163	def _requestTree(self):
164		treeCondition = self._getTreeCondition()
165		treeCondition.acquire()
166		bridge = []
167		self._requestedTrees.append(bridge)
168		treeCondition.wait()
169		treeCondition.release()
170		return bridge[0][0]
171
172	def _requestPlotter(self, viewWidth, viewHeight, width, height):
173		plotterCondition = self._getPlotterCondition()
174		plotterCondition.acquire()
175		bridge = []
176		self._requestedPlotters.append((bridge, viewWidth, viewHeight, width, height))
177		plotterCondition.wait()
178		plotterCondition.release()
179		return bridge[0][0]
180
181	def _check(self):
182		self._updateTrees()
183		self._updatePlotters()
184
185	def _updateTrees(self):
186		if self._requestedTrees:
187			treeCondition = self._getTreeCondition()
188			treeCondition.acquire()
189			for bridge in self._requestedTrees:
190				_tree = _Tree(self._getLock())
191				bridge.append([_tree])
192				self._appendTree(_tree)
193				_tree.update()
194			self._requestedTrees = []
195			treeCondition.notifyAll()
196			treeCondition.release()
197			return
198
199		for tree in self._getTrees():
200			tree.update()
201
202	def _updatePlotters(self):
203		if self._requestedPlotters:
204			plotterCondition = self._getPlotterCondition()
205			plotterCondition.acquire()
206			for (bridge, viewWidth, viewHeight, width, height) in self._requestedPlotters:
207				_plotter = _Plotter(self._getLock(), viewWidth, viewHeight, width, height)
208				bridge.append([_plotter])
209				self._appendPlotter(_plotter)
210				_plotter.update()
211			self._requestedPlotters = []
212			plotterCondition.notifyAll()
213			plotterCondition.release()
214			return
215
216		for plotter in self._getPlotters():
217			plotter.update()
218
219class _Base:
220	def __init__(self, lock):
221		self._canvasCommands = []
222		self._sizeCommands = []
223		self.setLock(lock)
224
225		### Create widges.
226		self.setRoot(Toplevel())
227		root = self.getRoot()
228		root.tk.call('tk', 'useinputmethods', 'False')
229		root.grid_rowconfigure(0, weight = 1)
230		root.grid_columnconfigure(0, weight = 1)
231		self.setFrame(Frame(root))
232		frame = self.getFrame()
233		frame.grid()
234		self.setCanvas(Canvas(frame))
235		canvas = self.getCanvas()
236		canvas.scrollX = Scrollbar(frame, orient = HORIZONTAL)
237		canvas.scrollY = Scrollbar(frame, orient = VERTICAL)
238		canvas.scrollX.grid(column = '0', row = '1', sticky= E + W)
239		canvas.scrollY.grid(column = '1', row = '0', sticky= N + S)
240		canvas.configure(xscrollcommand = self.xscroll)
241		canvas.configure(yscrollcommand = self.yscroll)
242		canvas.scrollX.configure(command = self.xview)
243		canvas.scrollY.configure(command = self.yview)
244		canvas.grid(column = '0', row = '0', sticky = N + E + S + W)
245
246		self._setFontCondition(threading.Condition())
247		textStyle = ITextStyle()
248		textStyle.setBold(False)
249		textStyle.setUnderlined(False)
250		self._fontMeasurement = self._createTkFont(textStyle)
251
252		self.setShow(True)
253		self.setTitle('')
254
255	def _sizeChanged(self, event):
256		self.getLock().acquire()
257		self._canvasCommands.append([self.canvas_sizeChanged, [event], {}])
258		self.getLock().release()
259
260	def canvas_sizeChanged(self, event):
261		root = self.getRoot()
262		frame = self.getFrame()
263		canvas = self.getCanvas()
264		if (root is None) or (frame is None) or (canvas is None):
265			return
266
267		frame.unbind('<Configure>')
268		canvas.configure(xscrollcommand = self.canvas_xscroll)
269		canvas.configure(yscrollcommand = self.canvas_yscroll)
270		canvas.scrollX.configure(command = self.canvas_xview)
271		canvas.scrollY.configure(command = self.canvas_yview)
272
273		pad = 5
274		padX = int(canvas.scrollX.cget('width')) + pad
275		padY = int(canvas.scrollY.cget('width')) + pad
276		x = root.winfo_width()
277		y = root.winfo_height()
278		canvas.configure(width = x - padX, height = y - padY)
279		root.update_idletasks()
280
281		canvas.configure(xscrollcommand = self.xscroll)
282		canvas.configure(yscrollcommand = self.yscroll)
283		canvas.scrollX.configure(command = self.xview)
284		canvas.scrollY.configure(command = self.yview)
285		frame.bind('<Configure>', self._sizeChanged)
286
287	def _setFontCondition(self, condition):
288		self._fontCondition = condition
289
290	def _getFontCondition(self):
291		return self._fontCondition
292
293	def getNCanvasCommands(self):
294		return len(self._canvasCommands)
295
296	def setRoot(self, root):
297		self._root = root
298
299	def getRoot(self):
300		return self._root
301
302	def setFrame(self, frame):
303		self._frame = frame
304
305	def getFrame(self):
306		return self._frame
307
308	def setCanvas(self, canvas):
309		self._canvas = canvas
310
311	def getCanvas(self):
312		return self._canvas
313
314	def setLock(self, lock):
315		self._lock = lock
316
317	def getLock(self):
318		return  self._lock
319
320	def xscroll(self, *args):
321		self.getLock().acquire()
322		self._canvasCommands.append([self.canvas_xscroll, args, {}])
323		self.getLock().release()
324
325	def yscroll(self, *args):
326		self.getLock().acquire()
327		self._canvasCommands.append([self.canvas_yscroll, args, {}])
328		self.getLock().release()
329
330	def xview(self, *args):
331		self.getLock().acquire()
332		self._canvasCommands.append([self.canvas_xview, args, {}])
333		self.getLock().release()
334
335	def yview(self, *args):
336		self.getLock().acquire()
337		self._canvasCommands.append([self.canvas_yview, args, {}])
338		self.getLock().release()
339
340	def canvas_xscroll(self, *args1):
341		canvas = self.getCanvas()
342		if canvas is not None:
343			canvas.scrollX.set(*args1)
344
345	def canvas_yscroll(self, *args1):
346		canvas = self.getCanvas()
347		if canvas is not None:
348			canvas.scrollY.set(*args1)
349
350	def canvas_xview(self, *args1):
351		canvas = self.getCanvas()
352		if canvas is not None:
353			canvas.xview(*args1)
354
355	def canvas_yview(self, *args1):
356		canvas = self.getCanvas()
357		if canvas is not None:
358			canvas.yview(*args1)
359
360	def canvas_title(self, title):
361		self.getFrame().master.title(title)
362		self._title = title
363
364	def canvas_show(self, boolean):
365		if boolean == True:
366			self.getRoot().deiconify()
367		else:
368			self.getRoot().withdraw()
369		self._show = boolean
370
371	def canvas_terminate(self):
372		self.getCanvas().destroy()
373		self.setCanvas(None)
374		self.getFrame().destroy()
375		self.setFrame(None)
376		self.getRoot().destroy()
377		self.setRoot(None)
378
379		self._fontMeasurement = None
380
381	def setTitle(self, title):
382		self.getLock().acquire()
383		self._canvasCommands.append([self.canvas_title, [title], {}])
384		self.getLock().release()
385
386	def getTitle(self):
387		return self._title
388
389	def setShow(self, boolean):
390		self.getLock().acquire()
391		self._canvasCommands.append([self.canvas_show, [boolean], {}])
392		self.getLock().release()
393
394	def getShow(self):
395		return self._show
396
397	def _createTkFont(self, textStyle):
398		fontFamily = textStyle.font()
399		fontSize = int(textStyle.fontSize())
400		if textStyle.isBold():
401			fontWeight = 'bold'
402		else:
403			fontWeight = 'normal'
404		if textStyle.isItalic():
405			fontSlant = 'italic'
406		else:
407			fontSlant = 'roman'
408		if textStyle.isUnderlined():
409			fontUnderline = 1
410		else:
411			fontUnderline = 0
412		return tkFont.Font(family=fontFamily, size=fontSize, weight=fontWeight, slant=fontSlant, underline=fontUnderline)
413
414	def _configureTkFont(self, font, textStyle):
415		fontFamily = textStyle.font()
416		fontSize = int(textStyle.fontSize())
417		if textStyle.isBold():
418			fontWeight = 'bold'
419		else:
420			fontWeight = 'normal'
421		if textStyle.isItalic():
422			fontSlant = 'italic'
423		else:
424			fontSlant = 'roman'
425		if textStyle.isUnderlined():
426			fontUnderline = 1
427		else:
428			fontUnderline = 0
429		font.configure(family=fontFamily, size=fontSize, weight=fontWeight, slant=fontSlant, underline=fontUnderline)
430		return font
431
432	def _getFontTuple(self, textStyle):
433		fontFamily = textStyle.font()
434		fontSize = str(int(textStyle.fontSize()))
435		options = ''
436		if textStyle.isBold():
437			options += 'bold'
438		else:
439			options += 'normal'
440		if textStyle.isItalic():
441			options += ' italic'
442		else:
443			options += ' roman'
444		if textStyle.isUnderlined():
445			options += ' underline'
446		else:
447			pass
448		return (fontFamily, fontSize, options)
449
450	def _getFontMeasurements(self, textDataList, bridge):
451		fontCondition = self._getFontCondition()
452		fontCondition.acquire()
453		self._canvasCommands.append([self.canvas_fontMeasurements, [textDataList, bridge], {}])
454		fontCondition.wait()
455		fontCondition.release()
456
457	def canvas_fontMeasurements(self, textDataList, bridge):
458		fontCondition = self._getFontCondition()
459		fontCondition.acquire()
460		result = []
461		fontMeasurement = self._fontMeasurement
462		for textStyle, text in textDataList:
463			fontMeasurement = self._configureTkFont(fontMeasurement, textStyle)
464			result.append([fontMeasurement.measure(text), fontMeasurement.metrics('linespace')])
465		bridge.append(result)
466		fontCondition.notifyAll()
467		fontCondition.release()
468
469	def update(self):
470		self.getLock().acquire()
471		for [method, args1, args2] in self._canvasCommands:
472			method(*args1, **args2)
473		else:
474			self._canvasCommands = []
475		self.getLock().release()
476
477class _Tree(_Base):
478	_folderIconString = 'R0lGODlhDgAPAIIAAA4ODkhz///U1ABV/46r/wAAAAAAAAAAACH5BAEAAAIALAAAAAAOAA8AAAhX\nAAUIHAgAwMCDBAEECFAQoYCCCyMyNChQocSLBiFelFgQAAGNHAEMKEigpMaCA1KSLGlSZEqVHll+\nfPlyJUuXNG2apKnyoUycPSvGxNkQYceRFB0KdRgQADs=\n'
479	_fileIconString = 'R0lGODlhCgAKAIIAACVX/7HH/9Tj/2uP/////wAAAAAAAAAAACH5BAEAAAQALAAAAAAKAAoAAAg0\nAAkIHEiQAICDCAkiRDhAgMCFBwcEcAgRgESKEC8azDhR4ICPIDsSEBCgpEmHAgWoXEkgIAA7\n'
480
481	def __init__(self, lock):
482		_Base.__init__(self, lock)
483		self.getCanvas().configure(bg='white', width=300)
484
485		self._folderImage = PhotoImage(data = self._folderIconString)
486		self._folderImageWidth = self._folderImage.width()
487		self._folderImageHeight = self._folderImage.height()
488		self._fileImage = PhotoImage(data = self._fileIconString)
489		self._fileImageWidth = self._fileImage.width()
490		self._fileImageHeight = self._fileImage.height()
491
492		textStyle = ITextStyle()
493		textStyle.setBold(False)
494		textStyle.setUnderlined(False)
495		self._fontNormal = self._createTkFont(textStyle)
496		textStyle.setBold(True)
497		textStyle.setUnderlined(True)
498		self._fontSelected = self._createTkFont(textStyle)
499
500		self.getFrame().bind('<Configure>', self._sizeChanged)
501
502	def terminate(self):
503		self.getLock().acquire()
504		self._canvasCommands.append([self.canvas_terminate, [], {}])
505		self.getLock().release()
506
507	def canvas_terminate(self):
508		getRoot()._removeTree(self)
509
510		_Base.canvas_terminate(self)
511
512		self._folderImage = None
513		self._fileImage = None
514		self._fontNormal = None
515		self._fontSelected = None
516
517	def redrawTree(self, block, itree):
518		if self.getLock().acquire(block):
519			canvasCommands = self._canvasCommands
520			command = [self.canvas_redrawTree, [itree], {}]
521			try:
522				while 1:
523					canvasCommands.remove(command)
524			except ValueError:
525				pass
526			canvasCommands.append(command)
527			self.getLock().release()
528
529	def canvas_redrawTree(self, itree):
530		canvas = self.getCanvas()
531		canvas.delete(['allItems'])
532		pwd = itree._getPwd()
533		self.redrawTreeWalker(itree, pwd, canvas, '/', 10, 10)
534		result = canvas.bbox('all')
535		if result != None:
536			cx1, cy1, cx2, cy2 = result
537			canvas.configure(scrollregion = (0, 0, cx2 + 10, cy2 + 10))
538
539	def redrawTreeWalker(self, itree, pwd, canvas, directoryPath, x, y):
540		spaceX = 16
541		spaceY = 4
542		stringSpaceX = 4
543		fileX = x + self._fileImageWidth + stringSpaceX
544		fontNormal = self._fontNormal
545		fileImage = self._fileImage
546		tags = ['allItems']
547		objects = itree._listObjects(directoryPath)
548		for object in objects:
549			if object._instance:
550				canvas.create_image(x, y, image = fileImage, anchor = W, tags = tags)
551				canvas.create_text(fileX, y, text = object.name(), font = fontNormal, anchor = W , tags = tags)
552				y += spaceY + self._fileImageHeight
553			else:
554				### Subdirectory.
555				canvas.create_image(x, y, image = self._folderImage, anchor = W, tags = tags)
556				if object == pwd:
557					canvas.create_text(x + self._folderImageWidth + stringSpaceX, y, text = object.name(), font = self._fontSelected, anchor = W , tags=tags)
558				else:
559					canvas.create_text(x + self._folderImageWidth + stringSpaceX, y, text = object.name(), font = fontNormal, anchor = W , tags=tags)
560				y += spaceY + self._folderImageHeight
561				x2, y = self.redrawTreeWalker(itree, pwd, canvas, '%s/%s' % (directoryPath, object.name()), x + spaceX, y)
562		return x, y
563
564class _Plotter(_Base):
565	def __init__(self, lock, viewWidth, viewHeight, width, height):
566		_Base.__init__(self, lock)
567		canvas = self.getCanvas()
568		canvas.configure(bg='white')
569		self.setImageIOCondition(threading.Condition())
570
571		self._legendsFont = self._createTkFont(ITextStyle())
572		self._statisticsFont = self._createTkFont(ITextStyle())
573		self._textsFont = self._createTkFont(ITextStyle())
574		self._canvasFont = self._createTkFont(ITextStyle())
575		self._canvasExponentBaseFont = self._createTkFont(ITextStyle())
576		self._canvasExponentIndexFont = self._createTkFont(ITextStyle())
577
578		self.setViewWidth(canvas.winfo_pixels(viewWidth))
579		self.setViewHeight(canvas.winfo_pixels(viewHeight))
580		self.setScrollRegion(0, 0, canvas.winfo_pixels(width), canvas.winfo_pixels(height))
581
582		self.getFrame().bind('<Configure>', self._sizeChanged)
583
584	def _requestRegion(self, serialNumber, allTags, x0, y0, x1, y1):
585		### Nothing to do for Tkinter GUI.
586		pass
587
588	def _convertToPixelX(self, length):
589		return self.getCanvas().winfo_pixels(length)
590
591	def _convertToPixelY(self, length):
592		return self.getCanvas().winfo_pixels(length)
593
594	def setImageIOCondition(self, condition):
595		self._imageIOCondition = condition
596
597	def getImageIOCondition(self):
598		return self._imageIOCondition
599
600	def setScrollRegion(self, *args):
601		self.getLock().acquire()
602		self._canvasCommands.append([self.canvas_scrollRegion, args, {}])
603		self.getLock().release()
604
605	def getScrollRegion(self):
606		return self._scrollRegion
607
608	def setViewWidth(self, viewWidth):
609		self.getLock().acquire()
610		self._canvasCommands.append([self.canvas_viewWidth, [viewWidth], {}])
611		self.getLock().release()
612
613	def getViewWidth(self):
614		return self._viewWidth
615
616	def setViewHeight(self, viewHeight):
617		self.getLock().acquire()
618		self._canvasCommands.append([self.canvas_viewHeight, [viewHeight], {}])
619		self.getLock().release()
620
621	def getViewHeight(self):
622		return self._viewHeight
623
624	def refresh(self):
625		pass
626
627	def delete(self, *args):
628		self.getLock().acquire()
629		self._canvasCommands.append([self.canvas_delete, args, {}])
630		self.getLock().release()
631
632	def create_styledText(self, *args1, **args2):
633		self.getLock().acquire()
634		self._canvasCommands.append([self.canvas_create_styledText, args1, args2])
635		self.getLock().release()
636
637	def create_styledExponent(self, *args1, **args2):
638		self.getLock().acquire()
639		self._canvasCommands.append([self.canvas_create_styledExponent, args1, args2])
640		self.getLock().release()
641
642	def create_styledOval(self, *args1, **args2):
643		self.getLock().acquire()
644		self._canvasCommands.append([self.canvas_create_styledOval, args1, args2])
645		self.getLock().release()
646
647	def create_styledRectangle(self, *args1, **args2):
648		self.getLock().acquire()
649		self._canvasCommands.append([self.canvas_create_styledRectangle, args1, args2])
650		self.getLock().release()
651
652	def create_styledLine(self, *args1, **args2):
653		self.getLock().acquire()
654		self._canvasCommands.append([self.canvas_create_styledLine, args1, args2])
655		self.getLock().release()
656
657	def create_styledPolygon(self, *args1, **args2):
658		self.getLock().acquire()
659		self._canvasCommands.append([self.canvas_create_styledPolygon, args1, args2])
660		self.getLock().release()
661
662	def create_styledMarker(self, *args1, **args2):
663		self.getLock().acquire()
664		self._canvasCommands.append([self.canvas_create_styledMarker, args1, args2])
665		self.getLock().release()
666
667	def create_styledTextsBox(self, *args1, **args2):
668		self.getLock().acquire()
669		self._canvasCommands.append([self.canvas_create_styledTextsBox, args1, args2])
670		self.getLock().release()
671
672	def create_styledLegendsBox(self, *args1, **args2):
673		self.getLock().acquire()
674		self._canvasCommands.append([self.canvas_create_styledLegendsBox, args1, args2])
675		self.getLock().release()
676
677	def create_styledStatisticsBox(self, *args1, **args2):
678		self.getLock().acquire()
679		self._canvasCommands.append([self.canvas_create_styledStatisticsBox, args1, args2])
680		self.getLock().release()
681
682	def setPostscript(self, fileName, landscape):
683		imageIOCondition = self.getImageIOCondition()
684		imageIOCondition.acquire()
685		self._canvasCommands.append([self.canvas_postscript, [fileName, landscape], {}])
686		imageIOCondition.wait()
687		imageIOCondition.release()
688
689	def setPostscriptStrings(self, landscape, bridge):
690		imageIOCondition = self.getImageIOCondition()
691		imageIOCondition.acquire()
692		self._canvasCommands.append([self.canvas_postscriptStrings, [landscape, bridge], {}])
693		imageIOCondition.wait()
694		imageIOCondition.release()
695
696	def terminate(self):
697		self.getLock().acquire()
698		self._canvasCommands.append([self.canvas_terminate, [], {}])
699		self.getLock().release()
700
701	def canvas_terminate(self):
702		getRoot()._removePlotter(self)
703
704		_Base.canvas_terminate(self)
705
706		self._legendsFont = None
707		self._statisticsFont = None
708		self._textsFont = None
709		self._canvasFont = None
710		self._canvasExponentBaseFont = None
711		self._canvasExponentIndexFont = None
712
713	def canvas_scrollRegion(self, x0, y0, x1, y1):
714		canvas = self.getCanvas()
715		cx0 = canvas.winfo_pixels(x0)
716		cy0 = canvas.winfo_pixels(y0)
717		cx1 = canvas.winfo_pixels(x1)
718		cy1 = canvas.winfo_pixels(y1)
719		self._scrollRegion = (cx0, cy0, cx1, cy1)
720		canvas.configure(scrollregion = (cx0, cy0, cx1, cy1))
721
722	def canvas_viewWidth(self, viewWidth):
723		canvas = self.getCanvas()
724		self._viewWidth = canvas.winfo_pixels(viewWidth)
725		screenWidth = canvas.winfo_screenwidth()
726		canvas.configure(width = min(self._viewWidth, screenWidth))
727
728	def canvas_viewHeight(self, viewHeight):
729		canvas = self.getCanvas()
730		self._viewHeight = canvas.winfo_pixels(viewHeight)
731		padY = 80
732		screenHeight = canvas.winfo_screenheight() - padY
733		canvas.configure(height = min(self._viewHeight, screenHeight))
734
735	def canvas_create_styledLegendsBox(self, infoStyle, region, layout, legends, tags):
736		self.canvas_delete(tags)
737		textStyle = infoStyle.textStyle()
738		fontData = self._configureTkFont(self._legendsFont, textStyle)
739		fontWidth = fontData.measure('W')
740		fontHeight = fontData.metrics('linespace')
741		fontHalf = fontData.metrics('ascent') / 2.0
742
743		longestDescription = 0
744		for [style, description] in legends:
745			longestDescription = max(longestDescription, fontData.measure(description))
746		longestStyle = fontWidth
747
748		xLower, xUpper = region._getAxisRangeX()
749		yLower, yUpper = region._getAxisRangeY()
750		regionLengthX = region._getRegionLengthX()
751		regionLengthY = region._getRegionLengthY()
752		tabX = max(5, int(0.014 * regionLengthX)) + 1
753		tabY = max(5, int(0.014 * regionLengthY)) + 1
754		spacerX = max(2, fontWidth / 2)
755		spacerY = max(2, fontHeight / 4)
756		boxOffsetX = self._convertToPixelX(layout._parameterData('legendsBoxOffsetX'))
757		boxOffsetY = self._convertToPixelY(layout._parameterData('legendsBoxOffsetY'))
758		boxAnchor = layout._parameterData('legendsBoxAnchor')
759		if boxAnchor == 'N':
760			boxX = (xLower + xUpper) / 2.0 - (longestStyle + spacerX + longestDescription) / 2.0 - tabX + boxOffsetX
761			boxY = yLower + boxOffsetY
762		elif boxAnchor == 'NE':
763			boxX = xUpper - longestStyle - spacerX - longestDescription - tabX * 2 + boxOffsetX
764			boxY = yLower + boxOffsetY
765		elif boxAnchor == 'E':
766			boxX = xUpper - longestStyle - spacerX - longestDescription - tabX * 2 + boxOffsetX
767			boxY = (yLower + yUpper) / 2.0 - (len(legends) * (fontHeight + spacerY) - spacerY) / 2.0 - tabY + boxOffsetY
768		elif boxAnchor == 'SE':
769			boxX = xUpper - longestStyle - spacerX - longestDescription - tabX * 2 + boxOffsetX
770			boxY = yUpper - (len(legends) * (fontHeight + spacerY) - spacerY) - tabY * 2 + boxOffsetY
771		elif boxAnchor == 'S':
772			boxX = (xLower + xUpper) / 2.0 - (longestStyle + spacerX + longestDescription) / 2.0 - tabX + boxOffsetX
773			boxY = yUpper - (len(legends) * (fontHeight + spacerY) - spacerY) - tabY * 2 + boxOffsetY
774		elif boxAnchor == 'SW':
775			boxX = xLower + boxOffsetX
776			boxY = yUpper - (len(legends) * (fontHeight + spacerY) - spacerY) - tabY * 2 + boxOffsetY
777		elif boxAnchor == 'W':
778			boxX = xLower + boxOffsetX
779			boxY = (yLower + yUpper) / 2.0 - (len(legends) * (fontHeight + spacerY) - spacerY) / 2.0 - tabY + boxOffsetY
780		elif boxAnchor == 'NW':
781			boxX = xLower + boxOffsetX
782			boxY = yLower + boxOffsetY
783		else:
784			raise RuntimeException()
785		styleX = boxX + tabX
786		descriptionX = styleX + longestStyle + spacerX
787		lineY = boxY + tabY
788
789		boxWidth = tabX * 2 + longestStyle + spacerX + longestDescription
790		boxHeight = len(legends) * (fontHeight + spacerY) - spacerY + tabY * 2
791		fillStyle = infoStyle._parameterData('fillStyle')
792		lineStyle = infoStyle._parameterData('lineStyle')
793		self.canvas_create_styledRectangle(lineStyle, fillStyle, tags, boxX, boxY, boxX + boxWidth, boxY + boxHeight)
794		for [style, description] in legends:
795			style = style._createCopy()
796			if style.__class__.__name__ == 'IFillStyle':
797				originalColor = lineStyle.color()
798				lineStyle.setColor(style.color())
799				self.canvas_create_styledRectangle(lineStyle, style, tags, styleX, lineY, styleX + fontWidth, lineY + fontHeight)
800				lineStyle.setColor(originalColor)
801			elif style.__class__.__name__ == 'ILineStyle':
802				self.canvas_create_styledLine(style, tags, styleX, lineY + fontHalf, styleX + fontWidth, lineY + fontHalf)
803			elif style.__class__.__name__ == 'IMarkerStyle':
804				originalSize = style._parameterData('size')
805				style.setParameter('size', fontWidth)
806				self.canvas_create_styledMarker(style, tags, styleX + fontWidth / 2.0, lineY + fontHalf)
807				style.setParameter('size', originalSize)
808			else:
809				raise RuntimeException()
810			self.canvas_create_styledText(textStyle, tags, descriptionX, lineY, description, NW)
811			lineY += fontHeight + spacerY
812
813	def canvas_create_styledStatisticsBox(self, infoStyle, region, layout, statisticsData, tags):
814		self.canvas_delete(tags)
815		textStyle = infoStyle.textStyle()
816		fontData = self._configureTkFont(self._statisticsFont, textStyle)
817		fontWidth = fontData.measure('W')
818		fontHeight = fontData.metrics('linespace')
819
820		longestName = 0
821		longestData = 0
822		for [name, data] in statisticsData:
823			longestName = max(longestName, fontData.measure(name))
824			longestData = max(longestData, fontData.measure(data))
825
826		xLower, xUpper = region._getAxisRangeX()
827		yLower, yUpper = region._getAxisRangeY()
828		regionLengthX = region._getRegionLengthX()
829		regionLengthY = region._getRegionLengthY()
830		tabX = max(5, int(0.014 * regionLengthX)) + 1
831		tabY = max(5, int(0.014 * regionLengthY)) + 1
832		spacerX = max(2, fontWidth / 2)
833		spacerY = max(2, fontHeight / 4)
834		boxOffsetX = self._convertToPixelX(layout._parameterData('statisticsBoxOffsetX'))
835		boxOffsetY = self._convertToPixelY(layout._parameterData('statisticsBoxOffsetY'))
836		boxAnchor = layout._parameterData('statisticsBoxAnchor')
837		if boxAnchor == 'N':
838			boxX = (xLower + xUpper) / 2.0 - (longestName + spacerX + longestData) / 2.0 - tabX + boxOffsetX
839			boxY = yLower + boxOffsetY
840		elif boxAnchor == 'NE':
841			boxX = xUpper - longestName - spacerX - longestData - tabX * 2 + boxOffsetX
842			boxY = yLower + boxOffsetY
843		elif boxAnchor == 'E':
844			boxX = xUpper - longestName - spacerX - longestData - tabX * 2 + boxOffsetX
845			boxY = (yLower + yUpper) / 2.0 - (len(statisticsData) * (fontHeight + spacerY) - spacerY) / 2.0 - tabY + boxOffsetY
846		elif boxAnchor == 'SE':
847			boxX = xUpper - longestName - spacerX - longestData - tabX * 2 + boxOffsetX
848			boxY = yUpper - (len(statisticsData) * (fontHeight + spacerY) - spacerY) - tabY * 2 + boxOffsetY
849		elif boxAnchor == 'S':
850			boxX = (xLower + xUpper) / 2.0 - (longestName + spacerX + longestData) / 2.0 - tabX + boxOffsetX
851			boxY = yUpper - (len(statisticsData) * (fontHeight + spacerY) - spacerY) - tabY * 2 + boxOffsetY
852		elif boxAnchor == 'SW':
853			boxX = xLower + boxOffsetX
854			boxY = yUpper - (len(statisticsData) * (fontHeight + spacerY) - spacerY) - tabY * 2 + boxOffsetY
855		elif boxAnchor == 'W':
856			boxX = xLower + boxOffsetX
857			boxY = (yLower + yUpper) / 2.0 - (len(statisticsData) * (fontHeight + spacerY) - spacerY) / 2.0 - tabY + boxOffsetY
858		elif boxAnchor == 'NW':
859			boxX = xLower + boxOffsetX
860			boxY = yLower + boxOffsetY
861		else:
862			raise RuntimeException()
863		nameX = boxX + tabX
864		dataX = nameX + longestName + spacerX
865		lineY = boxY + tabY
866
867		boxWidth = tabX * 2 + longestName + spacerX + longestData
868		boxHeight = len(statisticsData) * (fontHeight + spacerY) - spacerY + tabY * 2
869		fillStyle = infoStyle._parameterData('fillStyle')
870		lineStyle = infoStyle._parameterData('lineStyle')
871		self.canvas_create_styledRectangle(lineStyle, fillStyle, tags, boxX, boxY, boxX + boxWidth, boxY + boxHeight)
872		for [name, data] in statisticsData:
873			self.canvas_create_styledText(textStyle, tags, nameX, lineY, name, NW)
874			self.canvas_create_styledText(textStyle, tags, dataX, lineY, data, NW)
875			lineY += fontHeight + spacerY
876
877	def canvas_create_styledTextsBox(self, infoStyle, region, layout, textsData, tags):
878		self.canvas_delete(tags)
879		textStyle = infoStyle.textStyle()
880		fontData = self._configureTkFont(self._textsFont, textStyle)
881		fontWidth = fontData.measure('W')
882		fontHeight = fontData.metrics('linespace')
883
884		longestData = 0
885		for line in textsData:
886			longestData = max(longestData, fontData.measure(line))
887
888		xLower, xUpper = region._getAxisRangeX()
889		yLower, yUpper = region._getAxisRangeY()
890		regionLengthX = region._getRegionLengthX()
891		regionLengthY = region._getRegionLengthY()
892		tabX = max(5, int(0.014 * regionLengthX)) + 1
893		tabY = max(5, int(0.014 * regionLengthY)) + 1
894		spacerX = max(2, fontWidth / 2)
895		spacerY = max(2, fontHeight / 4)
896		boxOffsetX = self._convertToPixelX(layout._parameterData('textsBoxOffsetX'))
897		boxOffsetY = self._convertToPixelY(layout._parameterData('textsBoxOffsetY'))
898		boxAnchor = layout._parameterData('textsBoxAnchor')
899		if boxAnchor == 'N':
900			boxX = (xLower + xUpper) / 2.0 - longestData / 2.0 - tabX + boxOffsetX
901			boxY = yLower + boxOffsetY
902		elif boxAnchor == 'NE':
903			boxX = xUpper - longestData - tabX * 2 + boxOffsetX
904			boxY = yLower + boxOffsetY
905		elif boxAnchor == 'E':
906			boxX = xUpper - longestData - tabX * 2 + boxOffsetX
907			boxY = (yLower + yUpper) / 2.0 - (len(textsData) * (fontHeight + spacerY) - spacerY) / 2.0 - tabY + boxOffsetY
908		elif boxAnchor == 'SE':
909			boxX = xUpper - longestData - tabX * 2 + boxOffsetX
910			boxY = yUpper - (len(textsData) * (fontHeight + spacerY) - spacerY) - tabY * 2 + boxOffsetY
911		elif boxAnchor == 'S':
912			boxX = (xLower + xUpper) / 2.0 - longestData / 2.0 - tabX + boxOffsetX
913			boxY = yUpper - (len(textsData) * (fontHeight + spacerY) - spacerY) - tabY * 2 + boxOffsetY
914		elif boxAnchor == 'SW':
915			boxX = xLower + boxOffsetX
916			boxY = yUpper - (len(textsData) * (fontHeight + spacerY) - spacerY) - tabY * 2 + boxOffsetY
917		elif boxAnchor == 'W':
918			boxX = xLower + boxOffsetX
919			boxY = (yLower + yUpper) / 2.0 - (len(textsData) * (fontHeight + spacerY) - spacerY) / 2.0 - tabY + boxOffsetY
920		elif boxAnchor == 'NW':
921			boxX = xLower + boxOffsetX
922			boxY = yLower + boxOffsetY
923		else:
924			raise RuntimeException()
925		dataX = boxX + tabX
926		lineY = boxY + tabY
927
928		boxWidth = tabX * 2 + longestData
929		boxHeight = len(textsData) * (fontHeight + spacerY) - spacerY + tabY * 2
930		fillStyle = infoStyle._parameterData('fillStyle')
931		lineStyle = infoStyle._parameterData('lineStyle')
932		self.canvas_create_styledRectangle(lineStyle, fillStyle, tags, boxX, boxY, boxX + boxWidth, boxY + boxHeight)
933		for line in textsData:
934			self.canvas_create_styledText(textStyle, tags, dataX, lineY, line, NW)
935			lineY += fontHeight + spacerY
936
937	def canvas_postscript(self, fileName, landscape):
938		postscriptCondition = self.getImageIOCondition()
939		postscriptCondition.acquire()
940		x = self.getScrollRegion()[2]
941		y = self.getScrollRegion()[3]
942		self.getCanvas().postscript(file = fileName, width = x, height = y, rotate = landscape)
943		postscriptCondition.notifyAll()
944		postscriptCondition.release()
945
946	def canvas_postscriptStrings(self, landscape, bridge):
947		postscriptCondition = self.getImageIOCondition()
948		postscriptCondition.acquire()
949		x = self.getScrollRegion()[2]
950		y = self.getScrollRegion()[3]
951		bridge.append([self.getCanvas().postscript(pagewidth = x, pageheight = y, rotate = landscape)])
952		postscriptCondition.notifyAll()
953		postscriptCondition.release()
954
955	def canvas_create_styledOval(self, lineStyle, fillStyle, tags, x0, y0, x1, y1):
956		self.getCanvas().create_oval(x0, y0, x1, y1, fill=fillStyle.color(), outline = lineStyle.color(), width = lineStyle.thickness(), tags = tags)
957
958	def canvas_create_styledRectangle(self, lineStyle, fillStyle, tags, x0, y0, x1, y1):
959		lineType = lineStyle.lineType()
960		thickness = lineStyle.thickness()
961
962		if lineType == 'solid':
963			self.getCanvas().create_rectangle(x0, y0, x1, y1, fill = fillStyle.color(), outline = lineStyle.color(), width = thickness, tags = tags)
964		elif lineType == 'dot':
965			self.getCanvas().create_rectangle(x0, y0, x1, y1, fill = fillStyle.color(), outline = lineStyle.color(), width = thickness, dash = '.', tags = tags)
966		elif lineType == 'dash':
967			self.getCanvas().create_rectangle(x0, y0, x1, y1, fill = fillStyle.color(), outline = lineStyle.color(), width = thickness, dash = '-', tags = tags)
968		elif lineType == 'dash-dot':
969			self.getCanvas().create_rectangle(x0, y0, x1, y1, fill = fillStyle.color(), outline = lineStyle.color(), width = thickness, dash = '-.', tags = tags)
970		elif lineType == 'dash-dot-dot':
971			self.getCanvas().create_rectangle(x0, y0, x1, y1, fill = fillStyle.color(), outline = lineStyle.color(), width = thickness, dash = '-..', tags = tags)
972		else:
973			raise RuntimeException()
974
975	def canvas_create_styledLine(self, lineStyle, tags, *points):
976		lineType = lineStyle.lineType()
977		thickness = lineStyle.thickness()
978
979		if lineType == 'solid':
980			self.getCanvas().create_line(points, fill = lineStyle.color(), width = thickness, tags = tags)
981		elif lineType == 'dot':
982			self.getCanvas().create_line(points, fill = lineStyle.color(), width = thickness, dash = '.', tags = tags)
983		elif lineType == 'dash':
984			self.getCanvas().create_line(points, fill = lineStyle.color(), width = thickness, dash = '-', tags = tags)
985		elif lineType == 'dash-dot':
986			self.getCanvas().create_line(points, fill = lineStyle.color(), width = thickness, dash = '-.', tags = tags)
987		elif lineType == 'dash-dot-dot':
988			self.getCanvas().create_line(points, fill = lineStyle.color(), width = thickness, dash = '-..', tags = tags)
989		else:
990			raise RuntimeException()
991
992	def canvas_create_styledPolygon(self, lineStyle, fillStyle, tags, *points):
993		lineType = lineStyle.lineType()
994		thickness = lineStyle.thickness()
995
996		if lineType == 'solid':
997			self.getCanvas().create_polygon(points, fill = fillStyle.color(), outline = lineStyle.color(), width = thickness, tags = tags)
998		elif lineType == 'dot':
999			self.getCanvas().create_polygon(points, fill = fillStyle.color(), outline = lineStyle.color(), width = thickness, dash = '.', tags = tags)
1000		elif lineType == 'dash':
1001			self.getCanvas().create_polygon(points, fill = fillStyle.color(), outline = lineStyle.color(), width = thickness, dash = '-', tags = tags)
1002		elif lineType == 'dash-dot':
1003			self.getCanvas().create_polygon(points, fill = fillStyle.color(), outline = lineStyle.color(), width = thickness, dash = '-.', tags = tags)
1004		elif lineType == 'dash-dot-dot':
1005			self.getCanvas().create_polygon(points, fill = fillStyle.color(), outline = lineStyle.color(), width = thickness, dash = '-..', tags = tags)
1006		else:
1007			raise RuntimeException()
1008
1009	def canvas_create_styledMarker(self, markerStyle, tags, x, y):
1010		shape = markerStyle.shape()
1011		shapeSize = markerStyle._parameterData('size')
1012		shapeSizeCanvasX = self._convertToPixelX(shapeSize)
1013		shapeSizeCanvasY = self._convertToPixelY(shapeSize)
1014
1015		lineStyle = ILineStyle()
1016		lineStyle.setColor(markerStyle.color())
1017		fillStyle = IFillStyle()
1018		fillStyle.setColor('')
1019
1020		if shape == '':
1021			return
1022		elif shape == 'circle':
1023			x0 = x - shapeSizeCanvasX / 2.0
1024			y0 = y - shapeSizeCanvasY / 2.0
1025			x1 = x0 + shapeSizeCanvasX
1026			y1 = y0 + shapeSizeCanvasY
1027			self.canvas_create_styledOval(lineStyle, fillStyle, tags, x0, y0, x1, y1)
1028		elif shape == 'square':
1029			x0 = x - shapeSizeCanvasX / 2.0
1030			y0 = y - shapeSizeCanvasY / 2.0
1031			x1 = x0 + shapeSizeCanvasX
1032			y1 = y0 + shapeSizeCanvasY
1033			self.canvas_create_styledRectangle(lineStyle, fillStyle, tags, x0, y0, x1, y1)
1034		elif shape == 'diamond':
1035			x0 = x
1036			y0 = y - shapeSizeCanvasY / 2.0
1037			x1 = x - shapeSizeCanvasX / 2.0
1038			y1 = y
1039			x2 = x
1040			y2 = y0 + shapeSizeCanvasY
1041			x3 = x1 + shapeSizeCanvasX
1042			y3 = y
1043			self.canvas_create_styledLine(lineStyle, tags, x0, y0, x1, y1, x2, y2, x3, y3, x0, y0)
1044		elif shape == 'triangle':
1045			sqrt3 = math.sqrt(3)
1046			x0 = x
1047			y0 = y - shapeSizeCanvasY / sqrt3
1048			x1 = x - shapeSizeCanvasX / 2.0
1049			y1 = y + shapeSizeCanvasY / sqrt3 / 2.0
1050			x2 = x1 + shapeSizeCanvasX
1051			y2 = y1
1052			self.canvas_create_styledLine(lineStyle, tags, x0, y0, x1, y1, x2, y2, x0, y0)
1053		elif shape == 'cross':
1054			x0 = x - shapeSizeCanvasX / 2.0
1055			y0 = y - shapeSizeCanvasY / 2.0
1056			x1 = x0 + shapeSizeCanvasX
1057			y1 = y0 + shapeSizeCanvasY
1058			self.canvas_create_styledLine(lineStyle, tags, x0, y0, x1, y1)
1059			self.canvas_create_styledLine(lineStyle, tags, x0, y1, x1, y0)
1060
1061	def canvas_create_styledText(self, textStyle, tags, x, y, textData, anchor):
1062		self.getCanvas().create_text(x, y, text = textData, fill = textStyle.color(), font = self._getFontTuple(textStyle), anchor = anchor, tags = tags)
1063
1064	def canvas_delete(self, *args1):
1065		self.getCanvas().delete(*args1)
1066
1067	def canvas_create_styledExponent(self, textStyle, tags, x, y, a, b, anchor, fontRatio, overOffsetRatio):
1068		canvas = self.getCanvas()
1069		widthSpacer = 1
1070		indexTextStyle = textStyle._createCopy()
1071		indexTextStyle.setFontSize(textStyle.fontSize() * fontRatio)
1072		fontDataBase = self._configureTkFont(self._canvasExponentBaseFont, textStyle)
1073		fontDataIndex = self._configureTkFont(self._canvasExponentIndexFont, indexTextStyle)
1074		widthBase = fontDataBase.measure(a)
1075		widthIndex = fontDataIndex.measure(b)
1076		widthAll = widthBase + widthIndex + widthSpacer
1077		heightBase = fontDataBase.metrics('linespace')
1078		heightIndex = fontDataIndex.metrics('linespace')
1079		heightAll = heightBase + heightIndex * overOffsetRatio
1080		heightCap = heightAll - heightBase
1081		textColor = textStyle.color()
1082		if anchor == N:
1083			xBase = x - widthAll / 2
1084			yBase = y + heightCap
1085		elif anchor == NE:
1086			xBase = x - widthAll
1087			yBase = y + heightCap
1088		elif anchor == E:
1089			xBase = x - widthAll
1090			yBase = y + heightAll / 2 - heightBase
1091		elif anchor == SE:
1092			xBase = x - widthAll
1093			yBase = y - heightBase
1094		elif anchor == S:
1095			xBase = x - widthAll / 2
1096			yBase = y - heightBase
1097		elif anchor == SW:
1098			xBase = x
1099			yBase = y - heightBase
1100		elif anchor == W:
1101			xBase = x
1102			yBase = y + heightAll / 2 - heightBase
1103		elif anchor == NW:
1104			xBase = x
1105			yBase = y + heightCap
1106		else:
1107			raise RuntimeException()
1108		xIndex = xBase + widthBase + widthSpacer
1109		yIndex = yBase - heightCap
1110		self.canvas_create_styledText(textStyle, tags, xBase, yBase, a, NW)
1111		self.canvas_create_styledText(indexTextStyle, tags, xIndex, yIndex, b, NW)
1112