2 # flp - Module to load fl forms from fd files
4 # Jack Jansen, December 1991
6 from warnings
import warnpy3k
7 warnpy3k("the flp module has been removed in Python 3.0", stacklevel
=2)
14 SPLITLINE
= '--------------------'
15 FORMLINE
= '=============== FORM ==============='
16 ENDLINE
= '=============================='
18 class error(Exception):
21 ##################################################################
22 # Part 1 - The parsing routines #
23 ##################################################################
26 # Externally visible function. Load form.
28 def parse_form(filename
, formname
):
29 forms
= checkcache(filename
)
31 forms
= parse_forms(filename
)
32 if forms
.has_key(formname
):
33 return forms
[formname
]
35 raise error
, 'No such form in fd file'
38 # Externally visible function. Load all forms.
40 def parse_forms(filename
):
41 forms
= checkcache(filename
)
42 if forms
is not None: return forms
43 fp
= _open_formfile(filename
)
44 nforms
= _parse_fd_header(fp
)
46 for i
in range(nforms
):
47 form
= _parse_fd_form(fp
, None)
48 forms
[form
[0].Name
] = form
49 writecache(filename
, forms
)
53 # Internal: see if a cached version of the file exists
56 _internal_cache
= {} # Used by frozen scripts only
57 def checkcache(filename
):
58 if _internal_cache
.has_key(filename
):
59 altforms
= _internal_cache
[filename
]
60 return _unpack_cache(altforms
)
62 fp
, filename
= _open_formfile2(filename
)
64 cachename
= filename
+ 'c'
66 fp
= open(cachename
, 'r')
68 #print 'flp: no cache file', cachename
71 if fp
.read(4) != MAGIC
:
72 print 'flp: bad magic word in cache file', cachename
74 cache_mtime
= rdlong(fp
)
75 file_mtime
= getmtime(filename
)
76 if cache_mtime
!= file_mtime
:
77 #print 'flp: outdated cache file', cachename
79 #print 'flp: valid cache file', cachename
80 altforms
= marshal
.load(fp
)
81 return _unpack_cache(altforms
)
85 def _unpack_cache(altforms
):
87 for name
in altforms
.keys():
88 altobj
, altlist
= altforms
[name
]
92 for altobj
in altlist
:
96 forms
[name
] = obj
, list
101 if len(s
) != 4: return None
102 a
, b
, c
, d
= s
[0], s
[1], s
[2], s
[3]
103 return ord(a
)<<24 |
ord(b
)<<16 |
ord(c
)<<8 |
ord(d
)
106 a
, b
, c
, d
= (x
>>24)&0xff, (x
>>16)&0xff, (x
>>8)&0xff, x
&0xff
107 fp
.write(chr(a
) + chr(b
) + chr(c
) + chr(d
))
109 def getmtime(filename
):
111 from stat
import ST_MTIME
113 return os
.stat(filename
)[ST_MTIME
]
118 # Internal: write cached version of the form (parsing is too slow!)
120 def writecache(filename
, forms
):
122 fp
, filename
= _open_formfile2(filename
)
124 cachename
= filename
+ 'c'
126 fp
= open(cachename
, 'w')
128 print 'flp: can\'t create cache file', cachename
130 fp
.write('\0\0\0\0') # Seek back and write MAGIC when done
131 wrlong(fp
, getmtime(filename
))
132 altforms
= _pack_cache(forms
)
133 marshal
.dump(altforms
, fp
)
137 #print 'flp: wrote cache file', cachename
140 # External: print some statements that set up the internal cache.
141 # This is for use with the "freeze" script. You should call
142 # flp.freeze(filename) for all forms used by the script, and collect
143 # the output on a file in a module file named "frozenforms.py". Then
144 # in the main program of the script import frozenforms.
145 # (Don't forget to take this out when using the unfrozen version of
148 def freeze(filename
):
149 forms
= parse_forms(filename
)
150 altforms
= _pack_cache(forms
)
152 print 'flp._internal_cache[', repr(filename
), '] =', altforms
155 # Internal: create the data structure to be placed in the cache
157 def _pack_cache(forms
):
159 for name
in forms
.keys():
160 obj
, list = forms
[name
]
161 altobj
= obj
.__dict
__
163 for obj
in list: altlist
.append(obj
.__dict
__)
164 altforms
[name
] = altobj
, altlist
168 # Internal: Locate form file (using PYTHONPATH) and open file
170 def _open_formfile(filename
):
171 return _open_formfile2(filename
)[0]
173 def _open_formfile2(filename
):
174 if filename
[-3:] != '.fd':
175 filename
= filename
+ '.fd'
176 if filename
[0] == '/':
178 fp
= open(filename
,'r')
183 pn
= os
.path
.join(pc
, filename
)
191 raise error
, 'Cannot find forms file ' + filename
195 # Internal: parse the fd file header, return number of forms
197 def _parse_fd_header(file):
198 # First read the magic header line
199 datum
= _parse_1_line(file)
200 if datum
!= ('Magic', 12321):
201 raise error
, 'Not a forms definition file'
202 # Now skip until we know number of forms
204 datum
= _parse_1_line(file)
205 if type(datum
) == type(()) and datum
[0] == 'Numberofforms':
209 # Internal: parse fd form, or skip if name doesn't match.
210 # the special value None means 'always parse it'.
212 def _parse_fd_form(file, name
):
213 datum
= _parse_1_line(file)
214 if datum
!= FORMLINE
:
215 raise error
, 'Missing === FORM === line'
216 form
= _parse_object(file)
217 if form
.Name
== name
or name
is None:
219 for j
in range(form
.Numberofobjects
):
220 obj
= _parse_object(file)
224 for j
in range(form
.Numberofobjects
):
229 # Internal class: a convenient place to store object info fields
232 def add(self
, name
, value
):
233 self
.__dict
__[name
] = value
234 def make(self
, dict):
235 for name
in dict.keys():
236 self
.add(name
, dict[name
])
239 # Internal parsing routines.
241 def _parse_string(str):
243 s
= '\'' + str + '\''
253 def _parse_numlist(str):
257 nlist
.append(_parse_num(i
))
260 # This dictionary maps item names to parsing routines.
261 # If no routine is given '_parse_num' is default.
263 'Name': _parse_string
, \
264 'Box': _parse_numlist
, \
265 'Colors': _parse_numlist
, \
266 'Label': _parse_string
, \
267 'Name': _parse_string
, \
268 'Callback': _parse_string
, \
269 'Argument': _parse_string
}
271 # This function parses a line, and returns either
272 # a string or a tuple (name,value)
275 prog
= re
.compile('^([^:]*): *(.*)')
277 def _parse_line(line
):
278 match
= prog
.match(line
)
281 name
, value
= match
.group(1, 2)
283 name
= ''.join(name
.split())
285 name
= name
.capitalize()
287 pf
= _parse_func
[name
]
294 line
= file.readline()
299 def _parse_1_line(file):
300 line
= _readline(file)
302 line
= _readline(file)
303 return _parse_line(line
)
305 def _skip_object(file):
307 while not line
in (SPLITLINE
, FORMLINE
, ENDLINE
):
309 line
= _readline(file)
313 def _parse_object(file):
317 datum
= _parse_1_line(file)
318 if datum
in (SPLITLINE
, FORMLINE
, ENDLINE
):
319 if datum
== FORMLINE
:
322 if type(datum
) is not type(()) or len(datum
) != 2:
323 raise error
, 'Parse error, illegal line in object: '+datum
324 obj
.add(datum
[0], datum
[1])
326 #################################################################
327 # Part 2 - High-level object/form creation routines #
328 #################################################################
331 # External - Create a form an link to an instance variable.
333 def create_full_form(inst
, (fdata
, odatalist
)):
334 form
= create_form(fdata
)
335 exec 'inst.'+fdata
.Name
+' = form\n'
336 for odata
in odatalist
:
337 create_object_instance(inst
, form
, odata
)
340 # External - Merge a form into an existing form in an instance
343 def merge_full_form(inst
, form
, (fdata
, odatalist
)):
344 exec 'inst.'+fdata
.Name
+' = form\n'
345 if odatalist
[0].Class
!= FL
.BOX
:
346 raise error
, 'merge_full_form() expects FL.BOX as first obj'
347 for odata
in odatalist
[1:]:
348 create_object_instance(inst
, form
, odata
)
351 #################################################################
352 # Part 3 - Low-level object/form creation routines #
353 #################################################################
356 # External Create_form - Create form from parameters
358 def create_form(fdata
):
360 return fl
.make_form(FL
.NO_BOX
, fdata
.Width
, fdata
.Height
)
363 # External create_object - Create an object. Make sure there are
364 # no callbacks. Returns the object created.
366 def create_object(form
, odata
):
367 obj
= _create_object(form
, odata
)
369 raise error
, 'Creating free object with callback'
372 # External create_object_instance - Create object in an instance.
374 def create_object_instance(inst
, form
, odata
):
375 obj
= _create_object(form
, odata
)
377 cbfunc
= eval('inst.'+odata
.Callback
)
378 obj
.set_call_back(cbfunc
, odata
.Argument
)
380 exec 'inst.' + odata
.Name
+ ' = obj\n'
382 # Internal _create_object: Create the object and fill options
384 def _create_object(form
, odata
):
385 crfunc
= _select_crfunc(form
, odata
.Class
)
386 obj
= crfunc(odata
.Type
, odata
.Box
[0], odata
.Box
[1], odata
.Box
[2], \
387 odata
.Box
[3], odata
.Label
)
388 if not odata
.Class
in (FL
.BEGIN_GROUP
, FL
.END_GROUP
):
389 obj
.boxtype
= odata
.Boxtype
390 obj
.col1
= odata
.Colors
[0]
391 obj
.col2
= odata
.Colors
[1]
392 obj
.align
= odata
.Alignment
393 obj
.lstyle
= odata
.Style
394 obj
.lsize
= odata
.Size
395 obj
.lcol
= odata
.Lcol
398 # Internal crfunc: helper function that returns correct create function
400 def _select_crfunc(fm
, cl
):
401 if cl
== FL
.BEGIN_GROUP
: return fm
.bgn_group
402 elif cl
== FL
.END_GROUP
: return fm
.end_group
403 elif cl
== FL
.BITMAP
: return fm
.add_bitmap
404 elif cl
== FL
.BOX
: return fm
.add_box
405 elif cl
== FL
.BROWSER
: return fm
.add_browser
406 elif cl
== FL
.BUTTON
: return fm
.add_button
407 elif cl
== FL
.CHART
: return fm
.add_chart
408 elif cl
== FL
.CHOICE
: return fm
.add_choice
409 elif cl
== FL
.CLOCK
: return fm
.add_clock
410 elif cl
== FL
.COUNTER
: return fm
.add_counter
411 elif cl
== FL
.DIAL
: return fm
.add_dial
412 elif cl
== FL
.FREE
: return fm
.add_free
413 elif cl
== FL
.INPUT
: return fm
.add_input
414 elif cl
== FL
.LIGHTBUTTON
: return fm
.add_lightbutton
415 elif cl
== FL
.MENU
: return fm
.add_menu
416 elif cl
== FL
.POSITIONER
: return fm
.add_positioner
417 elif cl
== FL
.ROUNDBUTTON
: return fm
.add_roundbutton
418 elif cl
== FL
.SLIDER
: return fm
.add_slider
419 elif cl
== FL
.VALSLIDER
: return fm
.add_valslider
420 elif cl
== FL
.TEXT
: return fm
.add_text
421 elif cl
== FL
.TIMER
: return fm
.add_timer
423 raise error
, 'Unknown object type: %r' % (cl
,)
429 if len(sys
.argv
) == 2:
430 forms
= parse_forms(sys
.argv
[1])
432 print 'parse time:', 0.001*(t1
-t0
), 'sec.'
437 elif len(sys
.argv
) == 3:
438 form
= parse_form(sys
.argv
[1], sys
.argv
[2])
440 print 'parse time:', round(t1
-t0
, 3), 'sec.'
443 print 'Usage: test fdfile [form]'
445 def _printform(form
):
448 print 'Form ', f
.Name
, ', size: ', f
.Width
, f
.Height
, ' Nobj ', f
.Numberofobjects
450 print ' Obj ', i
.Name
, ' type ', i
.Class
, i
.Type
451 print ' Box ', i
.Box
, ' btype ', i
.Boxtype
452 print ' Label ', i
.Label
, ' size/style/col/align ', i
.Size
,i
.Style
, i
.Lcol
, i
.Alignment
453 print ' cols ', i
.Colors
454 print ' cback ', i
.Callback
, i
.Argument