Skip to content

Commit f6c7f6b

Browse files
committed
visual-lambda: predecessors
1 parent 4b9f636 commit f6c7f6b

7 files changed

Lines changed: 202 additions & 86 deletions

File tree

config.cfg

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,18 @@ eatingsec=2.0
88
bold_lambda=1
99

1010
# Main window size
11-
windowsize=800x600
12-
#windowsize=1280x960
11+
#windowsize=800x600
12+
windowsize=1280x960
1313

1414
# Menu font size
15-
fontsize=11
15+
#fontsize=11
1616
#fontsize=15
17+
fontsize=13
1718

1819
# Library file
1920
library=library.txt
2021

2122
# Default Workspace
22-
workspace=library_demo.xml
23+
#workspace=library_demo.xml
24+
#workspace=clear.xml
25+
workspace=predecessors.xml

lambdaparser.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ class Parser:
2929

3030
def __init__( self ):
3131

32-
self.lib = Library() # Create Library
33-
self.lib.init( self ) # parser.lib reference must exist before initialization of Library
32+
self.lib = Library( self ) # Create Library
33+
self.lib.init() # parser.lib reference must exist before initialization of Library
3434

3535

3636
def parse( self, str ):
@@ -81,11 +81,10 @@ def getExpression( self, struct, vars, func=None ):
8181
expr = Variable( vars[ varname ] )
8282

8383
else:
84-
try:
85-
expr = self.lib[ varname ] # Try to search in Library
86-
except:
84+
expr = self.lib.find_item( varname )
85+
if not expr:
8786
expr = Variable()
88-
print("Warning: Free Variable '%s': %s" % (varname, expr))
87+
print("Warning: Free Variable '%s'" % varname)
8988

9089

9190
elif LET == vartype: # Variable of Let-Expression
@@ -166,10 +165,10 @@ def poplevel( type ):
166165
elif 'let' == t:
167166
level = addlevel( LET, level )
168167

169-
var = tokens.next()
168+
var = next(tokens)
170169
level.append( ( var, LET ) )
171170

172-
be = tokens.next()
171+
be = next(tokens)
173172
if not( '=' == be or 'be' == be ):
174173
debug('parse', "Error: 'let %s' without '=' (got %s)" % (var, be) )
175174

library.py

Lines changed: 51 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
1+
r"""
2+
The Parser owns (and initializes) the Library object.
3+
"""
24

35
from debug import *
46

@@ -9,86 +11,81 @@
911
import config
1012

1113

14+
def strip( expr ):
15+
return expr.strip(' \t\n\r')
1216

13-
class Library:
14-
15-
def __init__( self ):
16-
17-
self.dict = {}
18-
19-
self.numbers = True # Simulate numbers in library
20-
21-
22-
23-
def __setitem__( self, key, value ):
24-
self.dict[ key ] = isinstance( value, let.Expression ) \
25-
and value \
26-
or self.parser.parse( value )
2717

28-
def __getitem__( self, key ):
18+
class Library:
2919

30-
if key in self.dict:
31-
#return copy.deepcopy( self.dict[ key ] )
32-
debug( 4, 'library. asked', key, self.dict[ key ] )
33-
return self.dict[ key ].copy( ({},{}) )
20+
def __init__( self, parser ):
21+
self.parser = parser
3422

35-
elif self.numbers and key.isdigit():
36-
return self.number( int( key ) )
23+
self.globalItems = {} # loaded from (e.g.) "library.txt" always available
24+
self.localItems = {} # loaded from workspace; reset on workspace reload
3725

26+
self.generateNumbers = True # Generate numbers by demand
27+
28+
29+
def add_item( self, key, value, isGlobal = True ):
30+
if not isinstance( value, let.Expression ):
31+
value = self.parser.parse( value )
32+
if isGlobal:
33+
self.globalItems[ key ] = value
3834
else:
39-
raise KeyError(key)
35+
self.localItems[ key ] = value
4036

41-
42-
def __iter__( self ):
43-
return self.dict.__iter__()
4437

38+
def reset_local_items( self ):
39+
self.localItems = {}
4540

41+
42+
def add_line( self, line, isGlobal = True ):
43+
line = strip(line)
44+
if not line or line[0] == '#': return False
45+
if '=' not in line: return False
46+
key, value = tuple(map( strip, line.split('=', 1) ))
47+
self.add_item( key, value, isGlobal )
4648

47-
def init( self, parser ):
48-
49-
self.parser = parser
50-
51-
def getDefs( lines, spaces ):
52-
53-
def strip( s ):
54-
return s.strip( spaces )
55-
56-
while lines:
57-
line = strip( lines.pop(0) )
58-
59-
while lines and lines[0] and lines[0][0] in spaces:
60-
next = strip( lines.pop(0) )
61-
if next: line += ' ' + next
62-
63-
if line and not '#'==line[0]:
64-
yield list(map( strip, line.split('=',1) ))
65-
6649

67-
50+
def init( self ):
6851
# Read library from txt
69-
txt = config.get( 'library', 'library.txt' )
52+
libraryFile = config.get( 'library', 'library.txt' )
7053
try:
71-
f = open( txt )
54+
f = open( libraryFile, 'r' )
7255
except IOError:
73-
print("Warning: no library found", txt)
56+
print("Warning: can't open library file", libraryFile)
57+
return
7458
else:
7559
lines = f.readlines()
7660
f.close()
7761

78-
for d in getDefs( lines, ' \t\n\r' ):
79-
self[ d[0] ] = d[1] # Add synonym to Library
62+
for line in lines:
63+
self.add_line( line, isGlobal = True )
8064

81-
8265

83-
def number( self, n ):
66+
def find_item( self, key ):
67+
value = self.localItems.get( key ) or \
68+
self.globalItems.get( key )
69+
if value:
70+
debug( 4, 'library. asked', key, value )
71+
return value.copy( ({},{}) )
72+
73+
elif self.generateNumbers and key.isdigit():
74+
return self.generate_number( int( key ) )
75+
76+
else:
77+
return None
78+
79+
80+
def generate_number( self, n ):
8481
"Generates Number Expression"
8582

8683
lf = let.Abstraction( expr= None )
8784
lx = let.Abstraction( expr= None )
8885

8986
x = let.Variable( lx )
9087

91-
for _ in range( n ):
88+
for _ in range( n ):
9289
f = let.Variable( lf )
9390
x = let.Application( func= f, arg= x )
9491

main.py

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
from window import Window
2424

2525
import let
26-
import lambdaparser
2726
import refnames
2827

2928
from figure import Ring,Bubble,Group,Figure
@@ -140,8 +139,13 @@ def __init__( self, caption ):
140139
windowSize = tuple(map(int, config.get( 'windowsize', '600x450' ).split("x")))
141140

142141
Window.__init__( self, caption, windowSize )
142+
143+
if not config.IS_WEB_PLATFORM:
144+
favicon = pygame.image.load('favicon.png')
145+
pygame.display.set_icon(favicon)
146+
143147

144-
self.items = []
148+
self.items = [] # FieldItem-s
145149

146150

147151
# Load default workspace
@@ -155,7 +159,6 @@ def __init__( self, caption ):
155159
self.expandMatrix = TransformMatrix()
156160
self.expandMatrix.setExpand( Figure.expandCoef )
157161

158-
self.viewMatrix = None
159162
self.viewMatrix = self.defaultView( self.size, 35 )
160163
self.viewMovePos = None # Start position of dragging the View
161164
self.viewMatrixSaved = None #!!! temporal ?
@@ -811,7 +814,15 @@ def handleEvent( self, event ):
811814
for procMod,proc in procs:
812815
if procMod == eventMods or procMod & eventMods:
813816
proc()
817+
818+
819+
elif VIDEORESIZE == event.type:
820+
# mainly handled in Window class; here we additionally centrize the view
821+
if self.size != event.size:
822+
shift = (Vector2(event.size) - Vector2(self.size)) / 2
823+
self.moveView( shift.x, shift.y )
814824

825+
815826
# User events
816827

817828
if ENDURINGEVENT == event.type:
@@ -1007,16 +1018,20 @@ def onClearWorkspace( self, _ ):
10071018
self.invalidate()
10081019

10091020
def onSaveWorkspaceName( self, workspaceName ):
1021+
if not workspaceName: return
10101022
xmlData = saving.save( self, pretty = True )
10111023
if xmlData:
10121024
key = "workspace_%s" % workspaceName
10131025
localstorage.save_value(key, xmlData)
10141026

10151027
def onLoadWorkspaceName( self, workspaceName ):
1028+
if not workspaceName: return
10161029
key = "workspace_%s" % workspaceName
10171030
xmlData = localstorage.load_value(key)
10181031
if xmlData and saving.load( self, xmlData ):
10191032
self.invalidate()
1033+
elif saving.load_from_file( self, workspaceName + ".xml" ): # allow loading included workspaces
1034+
self.invalidate()
10201035

10211036

10221037
if config.ALLOW_FILE_WRITING:

saving.py

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
from debug import *
66

7+
from lambdaparser import parser
78
from figure import Figure
89
from fielditem import TextItem
910

@@ -56,25 +57,35 @@ def load( manipulator, xmlData ):
5657
print("Error. Can't parse workspace xml")
5758
return False
5859

60+
# Reset library local defines
61+
parser.lib.reset_local_items()
62+
63+
# Load items
5964
manipulator.items = []
6065
lastOrigin = Vector((0, 0))
6166
for item in dom.getElementsByTagName('item'):
6267

68+
# Define
69+
if item.hasAttribute('define'):
70+
parser.lib.add_line( item.getAttribute('define'), isGlobal = False )
71+
continue
72+
73+
# Figure or Text item
6374
i = None
6475
if item.hasAttribute('figure'):
6576
i = Figure( item.getAttribute('figure') )
6677
elif item.hasAttribute('text'):
6778
i = TextItem( item.getAttribute('text') )
68-
69-
pos = item.getAttribute('pos').split(',')
70-
pos = tuple(map( float, pos ))
71-
pos = lastOrigin + Vector(pos)
72-
i.position.setTranspose( pos[0],pos[1], 1 )
73-
i.refreshTransform()
74-
manipulator.items.append( i )
75-
76-
if item.hasAttribute('origin'):
77-
lastOrigin = pos
79+
if i:
80+
pos = item.getAttribute('pos').split(',')
81+
pos = tuple(map( float, pos ))
82+
pos = lastOrigin + Vector(pos)
83+
i.position.setTranspose( pos[0],pos[1], 1 )
84+
i.refreshTransform()
85+
manipulator.items.append( i )
86+
87+
if item.hasAttribute('origin'):
88+
lastOrigin = pos
7889

7990
dom.unlink()
8091

window.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,12 @@ class Window:
1414
def __init__( self, caption, size ):
1515

1616
pygame.init()
17-
self.size = size # tuple, size of window in pixels
18-
pygame.display.set_mode( self.size, pygame.RESIZABLE )
19-
self.window = pygame.display.get_surface() # main surface
17+
18+
self.size = None # tuple, size of window in pixels
19+
self.window = None # main surface
20+
self.surface = None # Draw to other Surface, not self.window !!! used?
21+
22+
self.createWindow( size )
2023

2124
self.caption = caption
2225
pygame.display.set_caption( caption )
@@ -27,8 +30,6 @@ def __init__( self, caption, size ):
2730
self.font = pygame.font.SysFont( 'lucidaconsole', fontsize )
2831
self.fontAntialias = config.IS_WEB_PLATFORM #!!! fixing pygbag
2932

30-
self.surface = None # Draw to other Surface, not self.window
31-
3233
# Invalidation
3334
self.paintEvent = pygame.event.Event( events.ONPAINTEVENT )
3435
self.paintEventSent = False
@@ -39,6 +40,11 @@ def __del__( self ):
3940
pygame.quit()
4041

4142

43+
def createWindow( self, size ):
44+
self.size = size
45+
pygame.display.set_mode( self.size, pygame.RESIZABLE )
46+
self.window = pygame.display.get_surface()
47+
4248

4349
def getSurface( self ):
4450
return self.surface or self.window
@@ -109,8 +115,7 @@ def handleEvent( self, event ):
109115
"Process standart events"
110116
if pygame.VIDEORESIZE == event.type:
111117
if self.size != event.size:
112-
self.size = event.size
113-
self.window = pygame.display.set_mode( self.size, pygame.RESIZABLE )
118+
self.createWindow( event.size )
114119
self.invalidate()
115120

116121
elif events.ONPAINTEVENT == event.type:

0 commit comments

Comments
 (0)