mirror of
				https://github.com/python/cpython.git
				synced 2025-10-30 05:01:30 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			400 lines
		
	
	
	
		
			8.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			400 lines
		
	
	
	
		
			8.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| # GL STDWIN
 | |
| #
 | |
| # See stdwingl for a convenient hack to use this instead of built-in stdwin
 | |
| # without modifying your application, except for one line in the main file.
 | |
| #
 | |
| # Intrinsic differences with built-in stdwin (hard or impossible to fix):
 | |
| # - Need to call w.close() to close a window !!!
 | |
| # - Need to call m.close() to remove a menu !!!
 | |
| # - Doesn't enforce the existence of at most one drawing object
 | |
| # - No textedit package
 | |
| # - No X11 selections
 | |
| #
 | |
| # Not yet implemented:
 | |
| # - shade drawing
 | |
| # - elliptical arc drawing (need to play with transformation)
 | |
| # - more than one mouse button
 | |
| # - scroll bars (need to redo viewport handling to get this)
 | |
| # - partial redraws
 | |
| # - dialog boxes
 | |
| # - timer events
 | |
| # - cursors
 | |
| #
 | |
| # Extra features:
 | |
| # - color (for now, you need to know the colormap index)
 | |
| 
 | |
| 
 | |
| import gl
 | |
| import fm
 | |
| from GL import *
 | |
| from DEVICE import *
 | |
| from stdwinevents import *
 | |
| 
 | |
| 
 | |
| # Customizable constants
 | |
| #
 | |
| DEF_FONT = 'Times-Roman'		# Default font
 | |
| DEF_SIZE = 12				# Default font size (points)
 | |
| MASK = 20				# Viewport minus scrmask
 | |
| 
 | |
| 
 | |
| # A structure to hold global variables
 | |
| #
 | |
| class Struct: pass
 | |
| G = Struct()
 | |
| #
 | |
| G.queue = []				# Pending STDWIN events
 | |
| G.drawqueue = []			# Windows that need WE_REDRAW
 | |
| G.windowmap = {}			# Map window id to window object
 | |
| G.windowmap['0'] = None			# For convenience
 | |
| G.focus = None				# Input focus
 | |
| G.fg = BLACK				# Foreground color
 | |
| G.bg = WHITE				# Background color
 | |
| G.def_size = 0, 0			# Default window size
 | |
| G.def_pos = 0, 0			# Default window position
 | |
| #
 | |
| G.size = DEF_SIZE
 | |
| G.font = fm.findfont(DEF_FONT).scalefont(G.size)
 | |
| 
 | |
| 
 | |
| # Initialize GL
 | |
| #
 | |
| gl.foreground()
 | |
| gl.noport()
 | |
| dummygid = gl.winopen('')
 | |
| 
 | |
| # Ask for all sorts of events
 | |
| #
 | |
| # Both REDRAW (= resize and/or redraw!) and INPUTCHANGE are implicitly queued
 | |
| #qdevice(REDRAW)
 | |
| #qdevice(INPUTCHANGE)
 | |
| #
 | |
| # Keyboard
 | |
| gl.qdevice(KEYBD)
 | |
| gl.qdevice(LEFTARROWKEY)
 | |
| gl.qdevice(RIGHTARROWKEY)
 | |
| gl.qdevice(UPARROWKEY)
 | |
| gl.qdevice(DOWNARROWKEY)
 | |
| gl.qdevice(LEFTALTKEY)
 | |
| gl.qdevice(RIGHTALTKEY)
 | |
| #
 | |
| # Mouse
 | |
| gl.qdevice(LEFTMOUSE)
 | |
| #gl.qdevice(MIDDLEMOUSE)
 | |
| gl.qdevice(RIGHTMOUSE)			# Menu button
 | |
| # NB MOUSEX, MOUSEY events are queued on button down
 | |
| #
 | |
| # Window close requests
 | |
| gl.qdevice(WINQUIT)
 | |
| gl.qdevice(WINSHUT)
 | |
| #
 | |
| # These aren't needed
 | |
| #gl.qdevice(TIMER0)
 | |
| #gl.qdevice(WINFREEZE)
 | |
| #gl.qdevice(WINTHAW)
 | |
| #gl.qdevice(REDRAWICONIC)
 | |
| 
 | |
| 
 | |
| # STDWIN: create a new window
 | |
| #
 | |
| def open(title):
 | |
| 	h, v = G.def_pos
 | |
| 	width, height = G.def_size
 | |
| 	if h > 0 or v > 0:
 | |
| 		# Choose arbitrary defaults
 | |
| 		if h < 0: h = 10
 | |
| 		if v < 0: v = 30
 | |
| 		if width <= 0: width = 400
 | |
| 		if height <= 0: height = 300
 | |
| 		gl.prefposition(h, h+width, 1024-v, 1024-v-height)
 | |
| 	elif width > 0 or height > 0:
 | |
| 		if width <= 0: width = 400
 | |
| 		if height <= 0: height = 300
 | |
| 		gl.prefsize(width, height)
 | |
| 	from glstdwwin import WindowObject
 | |
| 	win = WindowObject()._init(title)
 | |
| 	G.windowmap[`win._gid`] = win
 | |
| 	return win
 | |
| 
 | |
| 
 | |
| # STDWIN: set default initial window position (0 means use default)
 | |
| #
 | |
| def setdefwinpos(h, v):
 | |
| 	G.def_pos = h, v
 | |
| 
 | |
| 
 | |
| # STDWIN: set default window size (0 means use default)
 | |
| #
 | |
| def setdefwinsize(width, height):
 | |
| 	G.def_size = width, height
 | |
| 
 | |
| 
 | |
| # STDWIN: beep or ring the bell
 | |
| #
 | |
| def fleep():
 | |
| 	gl.ringbell()
 | |
| 
 | |
| 
 | |
| # STDWIN: set default foreground color
 | |
| #
 | |
| def setfgcolor(color):
 | |
| 	G.fg = color
 | |
| 
 | |
| 
 | |
| # STDWIN: set default background color
 | |
| #
 | |
| def setbgcolor(color):
 | |
| 	G.bg = color
 | |
| 
 | |
| 
 | |
| # STDWIN: get default foreground color
 | |
| #
 | |
| def getfgcolor():
 | |
| 	return G.fgcolor
 | |
| 
 | |
| 
 | |
| # STDWIN: get default background color
 | |
| #
 | |
| def getbgcolor():
 | |
| 	return G.bgcolor
 | |
| 
 | |
| 
 | |
| # Table mapping characters to key codes
 | |
| #
 | |
| key2code = key = {}
 | |
| key['A'] = AKEY
 | |
| key['B'] = BKEY
 | |
| key['C'] = CKEY
 | |
| key['D'] = DKEY
 | |
| key['E'] = EKEY
 | |
| key['F'] = FKEY
 | |
| key['G'] = GKEY
 | |
| key['H'] = HKEY
 | |
| key['I'] = IKEY
 | |
| key['J'] = JKEY
 | |
| key['K'] = KKEY
 | |
| key['L'] = LKEY
 | |
| key['M'] = MKEY
 | |
| key['N'] = NKEY
 | |
| key['O'] = OKEY
 | |
| key['P'] = PKEY
 | |
| key['Q'] = QKEY
 | |
| key['R'] = RKEY
 | |
| key['S'] = SKEY
 | |
| key['T'] = TKEY
 | |
| key['U'] = UKEY
 | |
| key['V'] = VKEY
 | |
| key['W'] = WKEY
 | |
| key['X'] = XKEY
 | |
| key['Y'] = YKEY
 | |
| key['Z'] = ZKEY
 | |
| key['0'] = ZEROKEY
 | |
| key['1'] = ONEKEY
 | |
| key['2'] = TWOKEY
 | |
| key['3'] = THREEKEY
 | |
| key['4'] = FOURKEY
 | |
| key['5'] = FIVEKEY
 | |
| key['6'] = SIXKEY
 | |
| key['7'] = SEVENKEY
 | |
| key['8'] = EIGHTKEY
 | |
| key['9'] = NINEKEY
 | |
| del key
 | |
| #
 | |
| code2key = {}
 | |
| codelist = []
 | |
| for key in key2code.keys():
 | |
| 	code = key2code[key]
 | |
| 	code2key[`code`] = key
 | |
| 	codelist.append(code)
 | |
| del key
 | |
| 
 | |
| 
 | |
| # STDWIN: wait for the next event
 | |
| #
 | |
| commands = {}
 | |
| commands['\r'] = WC_RETURN
 | |
| commands['\b'] = WC_BACKSPACE
 | |
| commands['\t'] = WC_TAB
 | |
| #
 | |
| def getevent():
 | |
|   while 1:
 | |
| 	#
 | |
| 	# Get next event from the processed queue, if any
 | |
| 	#
 | |
| 	if G.queue:
 | |
| 		event = G.queue[0]
 | |
| 		del G.queue[0]
 | |
| 		#print 'getevent from queue -->', event
 | |
| 		return event
 | |
| 	#
 | |
| 	# Get next event from the draw queue, if any,
 | |
| 	# but only if there is nothing in the system queue.
 | |
| 	#
 | |
| 	if G.drawqueue and not gl.qtest():
 | |
| 		win = G.drawqueue[0]
 | |
| 		del G.drawqueue[0]
 | |
| 		gl.winset(win._gid)
 | |
| 		gl.color(win._bg)
 | |
| 		gl.clear()
 | |
| 		event = WE_DRAW, win, win._area
 | |
| 		#print 'getevent from drawqueue -->', event
 | |
| 		return event
 | |
| 	#
 | |
| 	# Get next event from system queue, blocking if necessary
 | |
| 	# until one is available.
 | |
| 	# Some cases immediately return the event, others do nothing
 | |
| 	# or append one or more events to the processed queue.
 | |
| 	#
 | |
| 	dev, val = gl.qread()
 | |
| 	#
 | |
| 	if dev == REDRAW:
 | |
| 		win = G.windowmap[`val`]
 | |
| 		old_area = win._area
 | |
| 		win._fixviewport()
 | |
| 		win._needredraw()
 | |
| 		if old_area <> win._area:
 | |
| 			#print 'getevent --> WE_SIZE'
 | |
| 			return WE_SIZE, win, None
 | |
| 	elif dev == KEYBD:
 | |
| 		if val == 3:
 | |
| 			raise KeyboardInterrupt # Control-C in window
 | |
| 		character = chr(val)
 | |
| 		if commands.has_key(character):
 | |
| 			return WE_COMMAND, G.focus, commands[character]
 | |
| 		return WE_CHAR, G.focus, character
 | |
| 	elif dev == LEFTARROWKEY:
 | |
| 		if val:
 | |
| 			return WE_COMMAND, G.focus, WC_LEFT
 | |
| 	elif dev == RIGHTARROWKEY:
 | |
| 		if val:
 | |
| 			return WE_COMMAND, G.focus, WC_RIGHT
 | |
| 	elif dev == UPARROWKEY:
 | |
| 		if val:
 | |
| 			return WE_COMMAND, G.focus, WC_UP
 | |
| 	elif dev == DOWNARROWKEY:
 | |
| 		if val:
 | |
| 			return WE_COMMAND, G.focus, WC_DOWN
 | |
| 	elif dev in (LEFTALTKEY, RIGHTALTKEY):
 | |
| 		if val:
 | |
| 			for code in codelist:
 | |
| 				gl.qdevice(code)
 | |
| 		else:
 | |
| 			for code in codelist:
 | |
| 				gl.unqdevice(code)
 | |
| 	elif dev in codelist:
 | |
| 		if val:
 | |
| 			event = G.focus._doshortcut(code2key[`dev`])
 | |
| 			if event:
 | |
| 				return event
 | |
| 	elif dev == LEFTMOUSE:
 | |
| 		G.mousex = gl.getvaluator(MOUSEX)
 | |
| 		G.mousey = gl.getvaluator(MOUSEY)
 | |
| 		if val:
 | |
| 			type = WE_MOUSE_DOWN
 | |
| 			gl.qdevice(MOUSEX)
 | |
| 			gl.qdevice(MOUSEY)
 | |
| 		else:
 | |
| 			type = WE_MOUSE_UP
 | |
| 			gl.unqdevice(MOUSEX)
 | |
| 			gl.unqdevice(MOUSEY)
 | |
| 		return _mouseevent(type)
 | |
| 	elif dev == MOUSEX:
 | |
| 		G.mousex = val
 | |
| 		return _mouseevent(WE_MOUSE_MOVE)
 | |
| 	elif dev == MOUSEY:
 | |
| 		G.mousey = val
 | |
| 		return _mouseevent(WE_MOUSE_MOVE)
 | |
| 	elif dev == RIGHTMOUSE:		# Menu button press/release
 | |
| 		if val:			# Press
 | |
| 			event = G.focus._domenu()
 | |
| 			if event:
 | |
| 				return event
 | |
| 	elif dev == INPUTCHANGE:
 | |
| 		if G.focus:
 | |
| 			G.queue.append(WE_DEACTIVATE, G.focus, None)
 | |
| 		G.focus = G.windowmap[`val`]
 | |
| 		if G.focus:
 | |
| 			G.queue.append(WE_ACTIVATE, G.focus, None)
 | |
| 	elif dev in (WINSHUT, WINQUIT):
 | |
| 		return WE_CLOSE, G.windowmap[`val`], None
 | |
| 	else:
 | |
| 		print '*** qread() --> dev:', dev, 'val:', val
 | |
| 
 | |
| # Helper routine to construct a mouse (up, move or down) event
 | |
| #
 | |
| def _mouseevent(type):
 | |
| 	gl.winset(G.focus._gid)
 | |
| 	orgx, orgy = gl.getorigin()
 | |
| 	sizex, sizey = gl.getsize()
 | |
| 	x = G.mousex - orgx
 | |
| 	y = G.mousey - orgy
 | |
| 	return type, G.focus, ((x, sizey-y), 1, 0, 0)
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| # STDWIN: text measuring functions
 | |
| 
 | |
| def baseline():
 | |
| 	(printermatched, fixed_width, xorig, yorig, xsize, ysize, \
 | |
| 		height, nglyphs) = G.font.getfontinfo()
 | |
| 	return height - yorig
 | |
| 
 | |
| def lineheight():
 | |
| 	(printermatched, fixed_width, xorig, yorig, xsize, ysize, \
 | |
| 			height, nglyphs) = G.font.getfontinfo()
 | |
| 	return height
 | |
| 
 | |
| def textbreak(string, width):
 | |
| 	# XXX Slooooow!
 | |
| 	n = len(string)
 | |
| 	nwidth = textwidth(string[:n])
 | |
| 	while nwidth > width:
 | |
| 		n = n-1
 | |
| 		nwidth = textwidth(string[:n])
 | |
| 	return n
 | |
| 
 | |
| def textwidth(string):
 | |
| 	return G.font.getstrwidth(string)
 | |
| 
 | |
| 
 | |
| # STDWIN: set default font and size
 | |
| 
 | |
| def setfont(fontname):
 | |
| 	G.font = fm.findfont(fontname).scalefont(G.size)
 | |
| 
 | |
| def setsize(size):
 | |
| 	ratio = float(size) / float(G.size)
 | |
| 	G.size = size
 | |
| 	G.font = G.font.scalefont(ratio)
 | |
| 
 | |
| 
 | |
| # Utility functions
 | |
| 
 | |
| # Exclusive-or of two BYTES
 | |
| #
 | |
| def xor(x, y):
 | |
| 	a = bits(x)
 | |
| 	b = bits(y)
 | |
| 	c = [0, 0, 0, 0, 0, 0, 0, 0]
 | |
| 	for i in range(8):
 | |
| 		c[i] = (a[i] + b[i]) % 2
 | |
| 	return stib(c)
 | |
| 
 | |
| # Return the bits of a byte as a list of 8 integers
 | |
| #
 | |
| def bits(x):
 | |
| 	b = [0, 0, 0, 0, 0, 0, 0, 0]
 | |
| 	for i in range(8):
 | |
| 		x, b[i] = divmod(x, 2)
 | |
| 	return b
 | |
| 
 | |
| # Convert a list of 8 integers (0|1) to a byte
 | |
| #
 | |
| def stib(b):
 | |
| 	x = 0
 | |
| 	shift = 1
 | |
| 	for i in range(8):
 | |
| 		x = x + b[i]*shift
 | |
| 		shift = shift*2
 | |
| 	return x
 | 
