mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	
		
			
	
	
		
			401 lines
		
	
	
	
		
			8.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			401 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 |