2 # flp - Module to load fl forms from fd files
4 # Jack Jansen, December 1991
11 SPLITLINE
= '--------------------'
12 FORMLINE
= '=============== FORM ==============='
13 ENDLINE
= '=============================='
17 ##################################################################
18 # Part 1 - The parsing routines #
19 ##################################################################
22 # Externally visible function. Load form.
24 def parse_form(filename
, formname
):
25 forms
= checkcache(filename
)
27 if forms
.has_key(formname
):
28 return forms
[formname
]
31 fp
= _open_formfile(filename
)
32 nforms
= _parse_fd_header(fp
)
33 for i
in range(nforms
):
34 form
= _parse_fd_form(fp
, formname
)
38 raise error
, 'No such form in fd file'
39 forms
[formname
] = form
40 writecache(filename
, forms
)
44 # Externally visible function. Load all forms.
46 def parse_forms(filename
):
47 forms
= checkcache(filename
)
48 if forms
!= None: return forms
49 fp
= _open_formfile(filename
)
50 nforms
= _parse_fd_header(fp
)
52 for i
in range(nforms
):
53 form
= _parse_fd_form(fp
, None)
54 forms
[form
[0].Name
] = form
55 writecache(filename
, forms
)
59 # Internal: see if a cached version of the file exists
62 _internal_cache
= {} # Used by frozen scripts only
63 def checkcache(filename
):
64 if _internal_cache
.has_key(filename
):
65 altforms
= _internal_cache
[filename
]
66 return _unpack_cache(altforms
)
68 fp
, filename
= _open_formfile2(filename
)
70 cachename
= filename
+ 'c'
72 fp
= open(cachename
, 'r')
74 #print 'flp: no cache file', cachename
77 if fp
.read(4) != MAGIC
:
78 print 'flp: bad magic word in cache file', cachename
80 cache_mtime
= rdlong(fp
)
81 file_mtime
= getmtime(filename
)
82 if cache_mtime
!= file_mtime
:
83 #print 'flp: outdated cache file', cachename
85 #print 'flp: valid cache file', cachename
86 altforms
= marshal
.load(fp
)
87 return _unpack_cache(altforms
)
91 def _unpack_cache(altforms
):
93 for name
in altforms
.keys():
94 altobj
, altlist
= altforms
[name
]
98 for altobj
in altlist
:
102 forms
[name
] = obj
, list
107 if len(s
) != 4: return None
108 a
, b
, c
, d
= s
[0], s
[1], s
[2], s
[3]
109 return ord(a
)<<24 |
ord(b
)<<16 |
ord(c
)<<8 |
ord(d
)
112 a
, b
, c
, d
= (x
>>24)&0xff, (x
>>16)&0xff, (x
>>8)&0xff, x
&0xff
113 fp
.write(chr(a
) + chr(b
) + chr(c
) + chr(d
))
115 def getmtime(filename
):
117 from stat
import ST_MTIME
119 return os
.stat(filename
)[ST_MTIME
]
124 # Internal: write cached version of the form (parsing is too slow!)
126 def writecache(filename
, forms
):
128 fp
, filename
= _open_formfile2(filename
)
130 cachename
= filename
+ 'c'
132 fp
= open(cachename
, 'w')
134 print 'flp: can\'t create cache file', cachename
136 fp
.write('\0\0\0\0') # Seek back and write MAGIC when done
137 wrlong(fp
, getmtime(filename
))
138 altforms
= _pack_cache(forms
)
139 marshal
.dump(altforms
, fp
)
143 #print 'flp: wrote cache file', cachename
146 # External: print some statements that set up the internal cache.
147 # This is for use with the "freeze" script. You should call
148 # flp.freeze(filename) for all forms used by the script, and collect
149 # the output on a file in a module file named "frozenforms.py". Then
150 # in the main program of the script import frozenforms.
151 # (Don't forget to take this out when using the unfrozen version of
154 def freeze(filename
):
155 forms
= parse_forms(filename
)
156 altforms
= _pack_cache(forms
)
158 print 'flp._internal_cache[', `filename`
, '] =', altforms
161 # Internal: create the data structure to be placed in the cache
163 def _pack_cache(forms
):
165 for name
in forms
.keys():
166 obj
, list = forms
[name
]
167 altobj
= obj
.__dict
__
169 for obj
in list: altlist
.append(obj
.__dict
__)
170 altforms
[name
] = altobj
, altlist
174 # Internal: Locate form file (using PYTHONPATH) and open file
176 def _open_formfile(filename
):
177 return _open_formfile2(filename
)[0]
179 def _open_formfile2(filename
):
180 if filename
[-3:] <> '.fd':
181 filename
= filename
+ '.fd'
182 if filename
[0] == '/':
184 fp
= open(filename
,'r')
189 pn
= os
.path
.join(pc
, filename
)
197 raise error
, 'Cannot find forms file ' + filename
201 # Internal: parse the fd file header, return number of forms
203 def _parse_fd_header(file):
204 # First read the magic header line
205 datum
= _parse_1_line(file)
206 if datum
<> ('Magic', 12321):
207 raise error
, 'Not a forms definition file'
208 # Now skip until we know number of forms
210 datum
= _parse_1_line(file)
211 if type(datum
) == type(()) and datum
[0] == 'Numberofforms':
215 # Internal: parse fd form, or skip if name doesn't match.
216 # the special value None means 'allways parse it'.
218 def _parse_fd_form(file, name
):
219 datum
= _parse_1_line(file)
220 if datum
<> FORMLINE
:
221 raise error
, 'Missing === FORM === line'
222 form
= _parse_object(file)
223 if form
.Name
== name
or name
== None:
225 for j
in range(form
.Numberofobjects
):
226 obj
= _parse_object(file)
230 for j
in range(form
.Numberofobjects
):
235 # Internal class: a convient place to store object info fields
238 def add(self
, name
, value
):
239 self
.__dict
__[name
] = value
240 def make(self
, dict):
241 for name
in dict.keys():
242 self
.add(name
, dict[name
])
245 # Internal parsing routines.
247 def _parse_string(str):
249 s
= '\'' + str + '\''
259 def _parse_numlist(str):
260 slist
= string
.split(str)
263 nlist
.append(_parse_num(i
))
266 # This dictionary maps item names to parsing routines.
267 # If no routine is given '_parse_num' is default.
269 'Name': _parse_string
, \
270 'Box': _parse_numlist
, \
271 'Colors': _parse_numlist
, \
272 'Label': _parse_string
, \
273 'Name': _parse_string
, \
274 'Callback': _parse_string
, \
275 'Argument': _parse_string
}
277 # This function parses a line, and returns either
278 # a string or a tuple (name,value)
281 prog
= regex
.compile('^\([^:]*\): *\(.*\)')
283 def _parse_line(line
):
284 if prog
.match(line
) < 0:
287 name
= line
[:a
[1][1]]
289 name
= string
.joinfields(string
.split(name
),'')
290 name
= string
.lower(name
)
291 name
= string
.upper(name
[0]) + name
[1:]
292 value
= line
[a
[2][0]:]
294 pf
= _parse_func
[name
]
301 line
= file.readline()
306 def _parse_1_line(file):
307 line
= _readline(file)
309 line
= _readline(file)
310 return _parse_line(line
)
312 def _skip_object(file):
314 while not line
in (SPLITLINE
, FORMLINE
, ENDLINE
):
316 line
= _readline(file)
320 def _parse_object(file):
324 datum
= _parse_1_line(file)
325 if datum
in (SPLITLINE
, FORMLINE
, ENDLINE
):
326 if datum
== FORMLINE
:
329 if type(datum
) <> type(()) or len(datum
) <> 2:
330 raise error
, 'Parse error, illegal line in object: '+datum
331 obj
.add(datum
[0], datum
[1])
333 #################################################################
334 # Part 2 - High-level object/form creation routines #
335 #################################################################
338 # External - Create a form an link to an instance variable.
340 def create_full_form(inst
, (fdata
, odatalist
)):
341 form
= create_form(fdata
)
342 exec('inst.'+fdata
.Name
+' = form\n')
343 for odata
in odatalist
:
344 create_object_instance(inst
, form
, odata
)
347 # External - Merge a form into an existing form in an instance
350 def merge_full_form(inst
, form
, (fdata
, odatalist
)):
351 exec('inst.'+fdata
.Name
+' = form\n')
352 if odatalist
[0].Class
<> FL
.BOX
:
353 raise error
, 'merge_full_form() expects FL.BOX as first obj'
354 for odata
in odatalist
[1:]:
355 create_object_instance(inst
, form
, odata
)
358 #################################################################
359 # Part 3 - Low-level object/form creation routines #
360 #################################################################
363 # External Create_form - Create form from parameters
365 def create_form(fdata
):
367 return fl
.make_form(FL
.NO_BOX
, fdata
.Width
, fdata
.Height
)
370 # External create_object - Create an object. Make sure there are
371 # no callbacks. Returns the object created.
373 def create_object(form
, odata
):
374 obj
= _create_object(form
, odata
)
376 raise error
, 'Creating free object with callback'
379 # External create_object_instance - Create object in an instance.
381 def create_object_instance(inst
, form
, odata
):
382 obj
= _create_object(form
, odata
)
384 cbfunc
= eval('inst.'+odata
.Callback
)
385 obj
.set_call_back(cbfunc
, odata
.Argument
)
387 exec('inst.' + odata
.Name
+ ' = obj\n')
389 # Internal _create_object: Create the object and fill options
391 def _create_object(form
, odata
):
392 crfunc
= _select_crfunc(form
, odata
.Class
)
393 obj
= crfunc(odata
.Type
, odata
.Box
[0], odata
.Box
[1], odata
.Box
[2], \
394 odata
.Box
[3], odata
.Label
)
395 if not odata
.Class
in (FL
.BEGIN_GROUP
, FL
.END_GROUP
):
396 obj
.boxtype
= odata
.Boxtype
397 obj
.col1
= odata
.Colors
[0]
398 obj
.col2
= odata
.Colors
[1]
399 obj
.align
= odata
.Alignment
400 obj
.lstyle
= odata
.Style
401 obj
.lsize
= odata
.Size
402 obj
.lcol
= odata
.Lcol
405 # Internal crfunc: helper function that returns correct create function
407 def _select_crfunc(fm
, cl
):
408 if cl
== FL
.BEGIN_GROUP
: return fm
.bgn_group
409 elif cl
== FL
.END_GROUP
: return fm
.end_group
410 elif cl
== FL
.BITMAP
: return fm
.add_bitmap
411 elif cl
== FL
.BOX
: return fm
.add_box
412 elif cl
== FL
.BROWSER
: return fm
.add_browser
413 elif cl
== FL
.BUTTON
: return fm
.add_button
414 elif cl
== FL
.CHART
: return fm
.add_chart
415 elif cl
== FL
.CHOICE
: return fm
.add_choice
416 elif cl
== FL
.CLOCK
: return fm
.add_clock
417 elif cl
== FL
.COUNTER
: return fm
.add_counter
418 elif cl
== FL
.DIAL
: return fm
.add_dial
419 elif cl
== FL
.FREE
: return fm
.add_free
420 elif cl
== FL
.INPUT
: return fm
.add_input
421 elif cl
== FL
.LIGHTBUTTON
: return fm
.add_lightbutton
422 elif cl
== FL
.MENU
: return fm
.add_menu
423 elif cl
== FL
.POSITIONER
: return fm
.add_positioner
424 elif cl
== FL
.ROUNDBUTTON
: return fm
.add_roundbutton
425 elif cl
== FL
.SLIDER
: return fm
.add_slider
426 elif cl
== FL
.VALSLIDER
: return fm
.add_valslider
427 elif cl
== FL
.TEXT
: return fm
.add_text
428 elif cl
== FL
.TIMER
: return fm
.add_timer
430 raise error
, 'Unknown object type: ' + `cl`
436 if len(sys
.argv
) == 2:
437 forms
= parse_forms(sys
.argv
[1])
439 print 'parse time:', 0.001*(t1
-t0
), 'sec.'
444 elif len(sys
.argv
) == 3:
445 form
= parse_form(sys
.argv
[1], sys
.argv
[2])
447 print 'parse time:', round(t1
-t0
, 3), 'sec.'
450 print 'Usage: test fdfile [form]'
452 def _printform(form
):
455 print 'Form ', f
.Name
, ', size: ', f
.Width
, f
.Height
, ' Nobj ', f
.Numberofobjects
457 print ' Obj ', i
.Name
, ' type ', i
.Class
, i
.Type
458 print ' Box ', i
.Box
, ' btype ', i
.Boxtype
459 print ' Label ', i
.Label
, ' size/style/col/align ', i
.Size
,i
.Style
, i
.Lcol
, i
.Alignment
460 print ' cols ', i
.Colors
461 print ' cback ', i
.Callback
, i
.Argument
464 # py-indent-offset: 4