1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 """Defines a layout implementation that mimics html absolute positioning."""
17
18 import re
19
20 from muntjac.ui.abstract_layout import AbstractLayout
21 from muntjac.terminal.gwt.client.event_id import EventId
22 from muntjac.terminal.sizeable import ISizeable
23
24 from muntjac.event.layout_events import \
25 LayoutClickEvent, ILayoutClickListener, ILayoutClickNotifier
26
27 from muntjac.util import OrderedSet
28
29
31 """AbsoluteLayout is a layout implementation that mimics html
32 absolute positioning.
33 """
34
35 CLIENT_WIDGET = None
36
37 _CLICK_EVENT = EventId.LAYOUT_CLICK
38
50
51
53 """Gets an iterator for going through all components enclosed
54 in the absolute layout.
55 """
56 return iter(self._components)
57
58
60 """Gets the number of contained components. Consistent with
61 the iterator returned by L{getComponentIterator}.
62
63 @return: the number of contained components
64 """
65 return len(self._components)
66
67
69 """Replaces one component with another one. The new component
70 inherits the old components position.
71 """
72 position = self.getPosition(oldComponent)
73 self.removeComponent(oldComponent)
74 self.addComponent(newComponent)
75 self._componentToCoordinates[newComponent] = position
76
77
79 """Adds a component to the layout. The component can be positioned
80 by providing a string formatted in CSS-format.
81
82 For example the string "top:10px;left:10px" will position the
83 component 10 pixels from the left and 10 pixels from the top. The
84 identifiers: "top","left","right" and "bottom" can be used to
85 specify the position.
86
87 @param c:
88 The component to add to the layout
89 @param cssPosition:
90 The css position string
91 """
92
93
94
95 if cssPosition is not None:
96 position = ComponentPosition(self)
97 position.setCSSString(cssPosition)
98 self._componentToCoordinates[c] = position
99
100 self._components.add(c)
101 try:
102 super(AbsoluteLayout, self).addComponent(c)
103 self.requestRepaint()
104 except ValueError, e:
105 self._components.remove(c)
106 if cssPosition is not None:
107
108 del self._componentToCoordinates[c]
109 raise e
110
111
119
120
122 """Gets the position of a component in the layout. Returns C{None}
123 if component is not attached to the layout.
124
125 @param component:
126 The component which position is needed
127 @return: An instance of ComponentPosition containing the position
128 of the component, or null if the component is not enclosed
129 in the layout.
130 """
131 if component.getParent() != self:
132 return None
133 elif component in self._componentToCoordinates:
134 return self._componentToCoordinates.get(component)
135 else:
136 coords = ComponentPosition(self)
137 self._componentToCoordinates[component] = coords
138 return coords
139
140
141 - def paintContent(self, target):
142 super(AbsoluteLayout, self).paintContent(target)
143 for component in self._components:
144 target.startTag('cc')
145 css = self.getPosition(component).getCSSString()
146 target.addAttribute('css', css)
147 component.paint(target)
148 target.endTag('cc')
149
150
158
159
160 - def addCallback(self, callback, eventType=None, *args):
169
170
178
179
189
190
192 """The CompontPosition class represents a components position within
193 the absolute layout. It contains the attributes for left, right, top
194 and bottom and the units used to specify them.
195 """
196
198 self._zIndex = -1
199 self._topValue = None
200 self._rightValue = None
201 self._bottomValue = None
202 self._leftValue = None
203
204 self._topUnits = 0
205 self._rightUnits = 0
206 self._bottomUnits = 0
207 self._leftUnits = 0
208
209 self._layout = layout
210
211
213 """Sets the position attributes using CSS syntax. Attributes not
214 included in the string are reset to their unset states.
215
216 C{setCSSString("top:10px;left:20%;z-index:16;")}
217 """
218 self._topValue = self._bottomValue = None
219 self._rightValue = self._leftValue = None
220 self._topUnits = self._bottomUnits = 0
221 self._rightUnits = self._leftUnits = 0
222 self._zIndex = -1
223
224 if css is None:
225 return
226
227 cssProperties = css.split(';')
228 for i in range(len(cssProperties)):
229 keyValuePair = cssProperties[i].split(':')
230 key = keyValuePair[0].strip()
231 if key == '':
232 continue
233
234 if key == 'z-index':
235 self._zIndex = int( keyValuePair[1].strip() )
236 else:
237 if len(keyValuePair) > 1:
238 value = keyValuePair[1].strip()
239 else:
240 value = ''
241
242 unit = re.sub('[0-9\\.\\-]+', '', value)
243 if not (unit == ''):
244 value = value[:value.find(unit)].strip()
245
246 v = float(value)
247 unitInt = self.parseCssUnit(unit)
248
249 if key == 'top':
250 self._topValue = v
251 self._topUnits = unitInt
252
253 elif key == 'right':
254 self._rightValue = v
255 self._rightUnits = unitInt
256
257 elif key == 'bottom':
258 self._bottomValue = v
259 self._bottomUnits = unitInt
260
261 elif key == 'left':
262 self._leftValue = v
263 self._leftUnits = unitInt
264
265 self._layout.requestRepaint()
266
267
269 """Parses a string and checks if a unit is found. If a unit
270 is not found from the string the unit pixels is used.
271
272 @param string:
273 The string to parse the unit from
274 @return: The found unit
275 """
276 for i in range(len(ISizeable.UNIT_SYMBOLS)):
277 if ISizeable.UNIT_SYMBOLS[i] == string:
278 return i
279 return 0
280
281
283 """Converts the internal values into a valid CSS string.
284
285 @return: A valid CSS string
286 """
287 s = ''
288 if self._topValue is not None:
289 symbol = ISizeable.UNIT_SYMBOLS[self._topUnits]
290 s += 'top:' + str(self._topValue) + symbol + ';'
291
292 if self._rightValue is not None:
293 symbol = ISizeable.UNIT_SYMBOLS[self._rightUnits]
294 s += 'right:' + str(self._rightValue) + symbol + ';'
295
296 if self._bottomValue is not None:
297 symbol = ISizeable.UNIT_SYMBOLS[self._bottomUnits]
298 s += 'bottom:' + str(self._bottomValue) + symbol + ';'
299
300 if self._leftValue is not None:
301 symbol = ISizeable.UNIT_SYMBOLS[self._leftUnits]
302 s += 'left:' + str(self._leftValue) + symbol + ';'
303
304 if self._zIndex >= 0:
305 s += 'z-index:' + str(self._zIndex) + ';'
306
307 return s
308
309
310 - def setTop(self, topValue, topUnits):
311 """Sets the 'top' attribute; distance from the top of the
312 component to the top edge of the layout.
313
314 @param topValue:
315 The value of the 'top' attribute
316 @param topUnits:
317 The unit of the 'top' attribute. See UNIT_SYMBOLS
318 for a description of the available units.
319 """
320 self._topValue = topValue
321 self._topUnits = topUnits
322 self._layout.requestRepaint()
323
324
325 - def setRight(self, rightValue, rightUnits):
326 """Sets the 'right' attribute; distance from the right of the
327 component to the right edge of the layout.
328
329 @param rightValue:
330 The value of the 'right' attribute
331 @param rightUnits:
332 The unit of the 'right' attribute. See UNIT_SYMBOLS
333 for a description of the available units.
334 """
335 self._rightValue = rightValue
336 self._rightUnits = rightUnits
337 self._layout.requestRepaint()
338
339
340 - def setBottom(self, bottomValue, bottomUnits):
341 """Sets the 'bottom' attribute; distance from the bottom of the
342 component to the bottom edge of the layout.
343
344 @param bottomValue:
345 The value of the 'bottom' attribute
346 @param bottomUnits:
347 The unit of the 'bottom' attribute. See UNIT_SYMBOLS
348 for a description of the available units.
349 """
350 self._bottomValue = bottomValue
351 self._bottomUnits = bottomUnits
352 self._layout.requestRepaint()
353
354
355 - def setLeft(self, leftValue, leftUnits):
356 """Sets the 'left' attribute; distance from the left of the
357 component to the left edge of the layout.
358
359 @param leftValue:
360 The value of the 'left' attribute
361 @param leftUnits:
362 The unit of the 'left' attribute. See UNIT_SYMBOLS
363 for a description of the available units.
364 """
365 self._leftValue = leftValue
366 self._leftUnits = leftUnits
367 self._layout.requestRepaint()
368
369
371 """Sets the 'z-index' attribute; the visual stacking order
372
373 @param zIndex:
374 The z-index for the component.
375 """
376 self._zIndex = zIndex
377 self._layout.requestRepaint()
378
379
381 """Sets the value of the 'top' attribute; distance from the top
382 of the component to the top edge of the layout.
383
384 @param topValue:
385 The value of the 'left' attribute
386 """
387 self._topValue = topValue
388 self._layout.requestRepaint()
389
390
392 """Gets the 'top' attributes value in current units.
393
394 @see: L{getTopUnits}
395 @return: The value of the 'top' attribute, null if not set
396 """
397 return self._topValue
398
399
401 """Gets the 'right' attributes value in current units.
402
403 @return: The value of the 'right' attribute, null if not set
404 @see: L{getRightUnits}
405 """
406 return self._rightValue
407
408
410 """Sets the 'right' attribute value (distance from the right
411 of the component to the right edge of the layout). Currently
412 active units are maintained.
413
414 @param rightValue:
415 The value of the 'right' attribute
416 @see: L{setRightUnits}
417 """
418 self._rightValue = rightValue
419 self._layout.requestRepaint()
420
421
423 """Gets the 'bottom' attributes value using current units.
424
425 @return: The value of the 'bottom' attribute, null if not set
426 @see: L{getBottomUnits}
427 """
428 return self._bottomValue
429
430
432 """Sets the 'bottom' attribute value (distance from the bottom
433 of the component to the bottom edge of the layout). Currently
434 active units are maintained.
435
436 @param bottomValue:
437 The value of the 'bottom' attribute
438 @see: L{setBottomUnits}
439 """
440 self._bottomValue = bottomValue
441 self._layout.requestRepaint()
442
443
445 """Gets the 'left' attributes value using current units.
446
447 @return: The value of the 'left' attribute, null if not set
448 @see: L{getLeftUnits}
449 """
450 return self._leftValue
451
452
454 """Sets the 'left' attribute value (distance from the left of
455 the component to the left edge of the layout). Currently active
456 units are maintained.
457
458 @param leftValue:
459 The value of the 'left' CSS-attribute
460 @see: L{setLeftUnits}
461 """
462 self._leftValue = leftValue
463 self._layout.requestRepaint()
464
465
467 """Gets the unit for the 'top' attribute
468
469 @return: See L{ISizeable} UNIT_SYMBOLS for a description of
470 the available units.
471 """
472 return self._topUnits
473
474
476 """Sets the unit for the 'top' attribute
477
478 @param topUnits:
479 See L{ISizeable} UNIT_SYMBOLS for a description
480 of the available units.
481 """
482 self._topUnits = topUnits
483 self._layout.requestRepaint()
484
485
487 """Gets the unit for the 'right' attribute
488
489 @return: See L{ISizeable} UNIT_SYMBOLS for a description of
490 the available units.
491 """
492 return self._rightUnits
493
494
496 """Sets the unit for the 'right' attribute
497
498 @param rightUnits:
499 See L{ISizeable} UNIT_SYMBOLS for a description
500 of the available units.
501 """
502 self._rightUnits = rightUnits
503 self._layout.requestRepaint()
504
505
507 """Gets the unit for the 'bottom' attribute
508
509 @return: See L{ISizeable} UNIT_SYMBOLS for a description of
510 the available units.
511 """
512 return self._bottomUnits
513
514
516 """Sets the unit for the 'bottom' attribute
517
518 @param bottomUnits:
519 See L{ISizeable} UNIT_SYMBOLS for a description
520 of the available units.
521 """
522 self._bottomUnits = bottomUnits
523 self._layout.requestRepaint()
524
525
527 """Gets the unit for the 'left' attribute
528
529 @return: See L{ISizeable} UNIT_SYMBOLS for a description
530 of the available units.
531 """
532 return self._leftUnits
533
534
536 """Sets the unit for the 'left' attribute
537
538 @param leftUnits:
539 See L{ISizeable} UNIT_SYMBOLS for a description
540 of the available units.
541 """
542 self._leftUnits = leftUnits
543 self._layout.requestRepaint()
544
545
547 """Gets the 'z-index' attribute.
548
549 @return: the zIndex The z-index attribute
550 """
551 return self._zIndex
552
553
556