A4

Merge lp:~gaspa/a4/presentation-objects into lp:a4

Proposed by Andrea Gasparini
Status: Merged
Merged at revision: 106
Proposed branch: lp:~gaspa/a4/presentation-objects
Merge into: lp:a4
Prerequisite: lp:~gaspa/a4/neweditor
Diff against target: 672 lines (+400/-84)
7 files modified
a4lib/app.py (+34/-4)
a4lib/editor.py (+58/-48)
a4lib/presentation.py (+10/-32)
a4lib/presentation_objects.py (+139/-0)
a4lib/region.py (+22/-0)
data/window_main.glade (+59/-0)
tests/objects/polaroid.svg (+78/-0)
To merge this branch: bzr merge lp:~gaspa/a4/presentation-objects
Reviewer Review Type Date Requested Status
Andrea Gasparini Pending
Review via email: mp+41838@code.launchpad.net

Description of the change

Refactoring code for a better and simpler use of object in the editor.

it should add some base objects and a test object (PolaroidObject).

To post a comment you must log in.
Revision history for this message
Andrea Colangelo (warp10) wrote :

List of bugs:
1- all rectangles are always drawn from the presentation upper edge.
2- all rectangles have a lower border way bigger than other ones
3- very small rectangles are badly drawn
4- rectangles have weird starting points (I mean: there is a weird correlation between the point you begin to draw and the place the rectangle is actually drawn)
5- when a selection is drawn downside up, the rectangle is drawn outside of the presentation, starting from the upper edge. Further, the black part of the rectangle is bigger than the white part

lp:~gaspa/a4/presentation-objects updated
91. By Andrea Gasparini

added test svg for "polaroid" object

92. By Andrea Gasparini

refactoring of objects and editor modes

93. By Andrea Gasparini

started on menus

94. By Andrea Gasparini

merged from trunk a couple of fixes

95. By Andrea Gasparini

select button,working on getting the right position of shapes

96. By Andrea Gasparini

drawing rectangles in right position,even when region is rotated (but still no rotated rect)

97. By Andrea Gasparini

rotated shapes work(!!)

98. By Andrea Gasparini

little cleaning

99. By Andrea Gasparini

reenable button for "polaroid" object

100. By Andrea Gasparini

polaroid objects working

101. By Andrea Gasparini

polaroid object has now proportional border

102. By Andrea Gasparini

text in polaroid start working

103. By Andrea Gasparini

undo saved test image

104. By Andrea Gasparini

added images, near to work

105. By Andrea Gasparini

image objects work

106. By Andrea Gasparini

little cleaning

Revision history for this message
Andrea Gasparini (gaspa) wrote :

now bugs should be fixed.

Re-writing down what this branch aims to do: implement a (still stub) system to handle graphics objects, both simple as rects/circles and more complex as the image or "polaroid" object.

What comes toghether with these changes:
 * a method in region.py that helps calculate point coordinates between screen coords and svg coords.
 * I added a sample of the polaroid object, perhaps we could keep them in that directory (I'd like to have more 'complex objects' than simple ones, that can be drawn simply by a normal svg editor)
 * there is a couple of unused button in the editor toolbar (things like 'frames','notes') that could be drop... perhaps :p

If someone can do a little test if everything seems to work, I'd merge this to trunk in the next days.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'a4lib/app.py'
--- a4lib/app.py 2010-12-01 23:24:34 +0000
+++ a4lib/app.py 2010-12-22 22:58:09 +0000
@@ -66,10 +66,10 @@
66 # Try to open a file.66 # Try to open a file.
67 if is_edited:67 if is_edited:
68 self.player = Editor(file_name, self.drawing_area,68 self.player = Editor(file_name, self.drawing_area,
69 self.builder.get_object('iconview1'),force_loading)69 self.builder.get_object('iconview1'), force_loading)
70 else:70 else:
71 self.player = GtkCairoPlayer(file_name, self.drawing_area,71 self.player = GtkCairoPlayer(file_name, self.drawing_area,
72 force_loading)72 force_loading)
73 except PresentationError as error:73 except PresentationError as error:
74 # The file doesn't exist, or is not an SVG file. Show an error74 # The file doesn't exist, or is not an SVG file. Show an error
75 # dialog and don't do anything else.75 # dialog and don't do anything else.
@@ -241,11 +241,34 @@
241 widget.set_active(False)241 widget.set_active(False)
242 self.builder.get_object('drawing_toolbar').set_visible(False)242 self.builder.get_object('drawing_toolbar').set_visible(False)
243243
244 def _ask_image_dialog(self):
245 dialog = gtk.FileChooserDialog(
246 None, None, gtk.FILE_CHOOSER_ACTION_OPEN, (
247 gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
248 gtk.STOCK_SAVE, gtk.RESPONSE_OK))
249 dialog.set_default_response(gtk.RESPONSE_OK)
250 # If an another file has been opened, use its location as starting
251 # folder for the dialog.
252 if self.last_path is not None:
253 dialog.set_current_folder(path)
254
255 # Show the dialog, back up the relevant properties and destroy it.
256 response = dialog.run()
257 file_name = dialog.get_filename()
258 dialog.destroy()
259 # Save in the specified location
260 if response == gtk.RESPONSE_OK and self.player:
261 return file_name
262 return ""
263
244 def on_toggle_tool(self, widget):264 def on_toggle_tool(self, widget):
245 if not isinstance(self.player, Editor):265 if not isinstance(self.player, Editor):
246 return266 return
247 toggle_modes = {'PathToolbutton': 'path',267 toggle_modes = {'SelectToolbutton': 'select',
268 'PathToolbutton': 'path',
248 'ShapesToolbutton': 'rect',269 'ShapesToolbutton': 'rect',
270 'ImageToolbutton': 'image',
271 'PolaroidToolbutton': 'polaroid',
249 'TextToolbutton': 'text'}272 'TextToolbutton': 'text'}
250273
251 widget_name = gtk.Buildable.get_name(widget)274 widget_name = gtk.Buildable.get_name(widget)
@@ -257,7 +280,14 @@
257 obj = self.builder.get_object(i)280 obj = self.builder.get_object(i)
258 if obj.get_active():281 if obj.get_active():
259 obj.set_active(False)282 obj.set_active(False)
260 self.player.set_editor_mode(toggle_modes[widget_name])283 object_name = toggle_modes[widget_name]
284 if object_name in ['path', 'select']:
285 self.player.set_editor_mode(object_name)
286 else:
287 self.player.set_editor_mode('objects')
288 self.player.set_next_new_object(toggle_modes[widget_name])
289 if toggle_modes[widget_name] == 'image':
290 self.player.set_target_image(self._ask_image_dialog())
261 if not any(self.builder.get_object(i).get_active() for i in toggle_modes.keys()):291 if not any(self.builder.get_object(i).get_active() for i in toggle_modes.keys()):
262 self.player.set_editor_mode()292 self.player.set_editor_mode()
263 self.drawing_area.queue_draw()293 self.drawing_area.queue_draw()
264294
=== modified file 'a4lib/editor.py'
--- a4lib/editor.py 2010-12-01 23:24:34 +0000
+++ a4lib/editor.py 2010-12-22 22:58:09 +0000
@@ -9,6 +9,14 @@
9from a4lib.player import GtkCairoPlayer9from a4lib.player import GtkCairoPlayer
10from a4lib.region import Region10from a4lib.region import Region
1111
12from presentation_objects import RectObject, TextObject, PolaroidObject, ImageObject
13
14
15def object_class_from_name(name):
16 obj_dict = {'rect': RectObject, 'text': TextObject,
17 'image': ImageObject, 'polaroid': PolaroidObject}
18 return obj_dict[name]
19
1220
13class Editor(GtkCairoPlayer):21class Editor(GtkCairoPlayer):
1422
@@ -25,15 +33,18 @@
25 self.treeview.set_item_width(120)33 self.treeview.set_item_width(120)
26 self.treeview.set_size_request(130, -1)34 self.treeview.set_size_request(130, -1)
2735
28 ## used to keep status of each tool.36 ## used to keep status of mouse actions:
37 ## value currently used: [None,'start','moving']
29 self.action_status = None38 self.action_status = None
30 ## tells if we should draw the rect of the path.39 ## tells if we should draw the rect of the path.
31 self.show_path = None40 self.show_path = None
32 ## tell the tool we're using and how we should behave.41 ## tell the tool we're using and how we should behave.
33 self.editor_modes = ['select', 'path', 'rect', 'text']42 self.editor_modes = ['select', 'path', 'objects']
34 self.editor_mode = 'select'43 self.editor_mode = 'select'
44 self.new_object_name = None
35 ## the selected object id:45 ## the selected object id:
36 self.current_object = None46 self.current_object = None
47 self.target_filename = None
3748
38 for i in xrange(0, len(self.presentation.path)):49 for i in xrange(0, len(self.presentation.path)):
39 region = self.presentation.get_path_region(i)50 region = self.presentation.get_path_region(i)
@@ -42,64 +53,72 @@
42 def set_show_path(self, flag=True):53 def set_show_path(self, flag=True):
43 self.show_path = flag54 self.show_path = flag
4455
56 # objects mode: rect/polaroid
57 def set_next_new_object(self, obj_name):
58 self.new_object_name = obj_name
59
60 # select/objects
45 def set_editor_mode(self, status='select'):61 def set_editor_mode(self, status='select'):
46 if status in self.editor_modes:62 if status in self.editor_modes:
47 self.editor_mode = status63 self.editor_mode = status
4864
65 def set_target_image(self, file_name):
66 self.target_filename = file_name
67
49 def on_area_button_press_event(self, widget, event):68 def on_area_button_press_event(self, widget, event):
69 event_point = (event.x, event.y)
70 winsize = self.area.window.get_size()
71 cr = self.current_region
72 point = cr.get_point_from_window_coordinates(winsize, event_point)
73
74 self.selection_start_position = (event.x, event.y)
75 self.action_status = 'start'
50 if self.editor_mode == 'select':76 if self.editor_mode == 'select':
51 pass # presentation.select(something)77 pass # presentation.select(something)
52 elif self.editor_mode == 'rect':78 elif self.editor_mode == 'objects':
53 props = {'x': event.x, 'y': event.y}79 cls = object_class_from_name(self.new_object_name)
54 myid = self.presentation.draw_rect(0, 0, props)80 self.current_object = cls(x=point[0], y=point[1],
55 self.current_object = myid81 rotate=self.current_region.rotate)
56 self.action_status = "selection"82 if self.new_object_name == 'image':
57 self.selection_start_position = (event.x, event.y)83 self.current_object.set_image(self.target_filename)
58 elif self.editor_mode == 'text':84 self.presentation.add_object(self.current_object)
59 props = {'x': event.x, 'y': event.y}
60 myid = self.presentation.draw_text("", props)
61 self.current_object = myid
62 self.action_status = "selection"
63 self.selection_start_position = (event.x, event.y)
64 elif self.editor_mode == 'path' and event.state & gtk.gdk.CONTROL_MASK:
65 self.action_status = "selection"
66 self.selection_start_position = (event.x, event.y)
67 else:85 else:
68 GtkCairoPlayer.on_area_button_press_event(self, widget, event)86 GtkCairoPlayer.on_area_button_press_event(self, widget, event)
6987
70 def on_area_button_release_event(self, widget, event):88 def on_area_button_release_event(self, widget, event):
71 GtkCairoPlayer.on_area_button_release_event(self, widget, event)89 GtkCairoPlayer.on_area_button_release_event(self, widget, event)
72 if self.editor_mode == 'path' and self.action_status is not None:90 if self.editor_mode == 'path' and event.state & gtk.gdk.CONTROL_MASK:
73 rect = (self.selection_start_position, self.mouse_position)91 rect = (self.selection_start_position, self.mouse_position)
74 self.add_treeview_icon(rect)92 self.add_treeview_icon(rect)
75 if self.editor_mode == 'rect' and self.action_status is not None:93 elif self.editor_mode == 'objects':
76 self.current_object = None94 pass
77 if self.editor_mode != 'text':95 self.action_status = None
78 self.action_status = None
7996
80 def on_area_motion_notify_event(self, widget, event):97 def on_area_motion_notify_event(self, widget, event):
81 if self.action_status is None:98 if self.action_status is None:
82 GtkCairoPlayer.on_area_motion_notify_event(self, widget, event)99 GtkCairoPlayer.on_area_motion_notify_event(self, widget, event)
83 elif self.editor_mode == 'path':100 else:
84 self.mouse_position = (event.x, event.y)101 if self.editor_mode == 'path':
85 self.area.queue_draw()102 if event.state & gtk.gdk.CONTROL_MASK:
86 elif self.editor_mode == 'rect' and self.action_status is not None:103 self.mouse_position = (event.x, event.y)
87 if self.current_object:104 self.area.queue_draw()
88 ## x/y is ignored105 elif self.editor_mode == 'objects' and self.action_status:
89 props = {'id': self.current_object}106 if self.current_object:
90 w = event.x - self.selection_start_position[0]107 winsize = self.area.window.get_size()
91 h = event.y - self.selection_start_position[1]108 cr = self.current_region
92 myid = self.presentation.draw_rect(w, h, props)109 scale = self.current_region.get_window_scale_factor(winsize)
93 self.mouse_position = (event.x, event.y)110 w = (event.x - self.selection_start_position[0]) / scale
94 self.area.queue_draw()111 h = (event.y - self.selection_start_position[1]) / scale
112 self.current_object.set_size(w, h)
113 self.mouse_position = (event.x, event.y)
114 self.area.queue_draw()
115 self.action_status = 'moving'
95116
96 def on_area_key_press(self, widget, event):117 def on_area_key_press(self, widget, event):
97 if self.editor_mode == 'text' and self.action_status:118 if self.current_object:
98 if True: # premo tutto tranne esc:119 if True: # premo tutto tranne esc:
99 props = {'id': self.current_object}
100 key = gtk.gdk.keyval_name(event.keyval)120 key = gtk.gdk.keyval_name(event.keyval)
101 text = self.presentation.get_text(self.current_object) + key121 self.current_object.character_pressed(key)
102 self.presentation.draw_text(text, props)
103 self.area.queue_draw()122 self.area.queue_draw()
104 elif False: # premo esc123 elif False: # premo esc
105 self.action_status = None124 self.action_status = None
@@ -109,14 +128,10 @@
109 context.save()128 context.save()
110 if not region:129 if not region:
111 context.set_matrix(cairo.Matrix(1, 0, 0, 1, 0, 0))130 context.set_matrix(cairo.Matrix(1, 0, 0, 1, 0, 0))
112 #a = context.set_matrix( 1,0,0,1,0,0 )
113 #matrix = array([[a[0], a[2], a[4]], [a[1], a[3], a[5]], [0, 0, 1]])
114 x0 = self.selection_start_position[0]131 x0 = self.selection_start_position[0]
115 y0 = self.selection_start_position[1]132 y0 = self.selection_start_position[1]
116 x1 = self.mouse_position[0]133 x1 = self.mouse_position[0]
117 y1 = self.mouse_position[1]134 y1 = self.mouse_position[1]
118 #x0, y0, nulla = dot(inv(matrix), [x0, y0, 1])
119 #x1, y1, nulla = dot(inv(matrix), [x1, y1, 1])
120 else:135 else:
121 context.translate(region.xc, region.yc)136 context.translate(region.xc, region.yc)
122 context.rotate(region.rotate)137 context.rotate(region.rotate)
@@ -149,9 +164,8 @@
149 for i in xrange(0, len(self.presentation.path)):164 for i in xrange(0, len(self.presentation.path)):
150 region = self.presentation.get_path_region(i)165 region = self.presentation.get_path_region(i)
151 self.draw_selection_box(context, region)166 self.draw_selection_box(context, region)
152 if self.editor_mode == 'path' and self.action_status == "selection":167 if self.editor_mode == 'path' and self.action_status:
153 self.draw_selection_box(context)168 self.draw_selection_box(context)
154 #self.rotate_icon.render(context, self.area.window.get_size() )
155169
156 def add_treeview_icon(self, rect=None):170 def add_treeview_icon(self, rect=None):
157 ## * trasforma rect in Regione171 ## * trasforma rect in Regione
@@ -174,10 +188,6 @@
174 (rect2[1][0] - rect2[0][0]),188 (rect2[1][0] - rect2[0][0]),
175 (rect2[1][1] - rect2[0][1]),189 (rect2[1][1] - rect2[0][1]),
176 self.current_region.rotate)190 self.current_region.rotate)
177 #print "Finestra", self.area.window.get_size()
178 #print "Current", self.current_region
179 #print "Aggiungo", region
180 #print
181 ## * metti la regione in lista191 ## * metti la regione in lista
182 self.presentation.path.append(region)192 self.presentation.path.append(region)
183 ## * usa la regione per la pixbuf.193 ## * usa la regione per la pixbuf.
184194
=== modified file 'a4lib/presentation.py'
--- a4lib/presentation.py 2010-12-01 23:24:34 +0000
+++ a4lib/presentation.py 2010-12-22 22:58:09 +0000
@@ -20,6 +20,7 @@
20a4nsmap = {'a4': A4HTMLNS}20a4nsmap = {'a4': A4HTMLNS}
21nsmap = {21nsmap = {
22 'a4': A4HTMLNS,22 'a4': A4HTMLNS,
23 'xlink': 'http://www.w3.org/1999/xlink',
23 'svg': 'http://www.w3.org/2000/svg'}24 'svg': 'http://www.w3.org/2000/svg'}
2425
25available_version = '0.1'26available_version = '0.1'
@@ -269,7 +270,8 @@
269 Presentation.__init__(self, file_name, force_loading)270 Presentation.__init__(self, file_name, force_loading)
270 # main_g is the main <g> tag. it will be used mainly to add othe271 # main_g is the main <g> tag. it will be used mainly to add othe
271 # tag painted with A4272 # tag painted with A4
272 self.main_g = self.svgtree.xpath('/svg:svg/svg:g', namespaces=nsmap)[0]273 #self.main_g = self.svgtree.xpath('/svg:svg/svg:g', namespaces=nsmap)[0]
274 self.main_g = self.svgtree.xpath('/svg:svg', namespaces=nsmap)[0]
273 self.render_cairo = self._render_cairo275 self.render_cairo = self._render_cairo
274276
275 def _render_cairo(self, context):277 def _render_cairo(self, context):
@@ -277,39 +279,15 @@
277 svg_handler = rsvg.Handle(data=tempdata)279 svg_handler = rsvg.Handle(data=tempdata)
278 svg_handler.render_cairo(context)280 svg_handler.render_cairo(context)
279281
280 def _generate_new_id(self):282 def add_object(self, presentation_object):
281 import random283 self.main_g.append(presentation_object.element)
282 return str(random.random()).split('.')[1]
283284
284 def _init_tag(self, tagname, piuprops={}):285 def search_id(self, object_id):
285 ## if piuprops contains an id already present modify inplace the rect.286 target = self.svgtree.xpath(
286 if 'id' in piuprops:
287 target = self.svgtree.xpath(
288 "//*[@id='{0}']".format(piuprops['id']), namespaces=nsmap)[0]287 "//*[@id='{0}']".format(piuprops['id']), namespaces=nsmap)[0]
289 else:288 if target:
290 target = etree.SubElement(self.main_g, 'rect')289 return target
291 if 'x' not in piuprops or 'y' not in piuprops:290 return False
292 return False
293 target.attrib['id'] = self._generate_new_id()
294 for k in piuprops.keys():
295 target.attrib[k] = str(piuprops[k])
296 return target
297
298 def draw_rect(self, width, height, piuprops={}):
299 target_rect = self._init_tag('rect', piuprops)
300 target_rect.attrib['width'] = str(width)
301 target_rect.attrib['height'] = str(height)
302 return target_rect.attrib['id']
303
304 def get_text(self, textid):
305 target_text = self.svgtree.xpath(
306 "//*[@id='{0}']".format(textid), namespaces=nsmap)[0]
307 return target_text.text
308
309 def draw_text(self, text="", piuprops={}):
310 target_text = self._init_tag('text', piuprops)
311 target_text.text = text
312 return target_text.attrib['id']
313291
314292
315class PathElement(object):293class PathElement(object):
316294
=== added file 'a4lib/presentation_objects.py'
--- a4lib/presentation_objects.py 1970-01-01 00:00:00 +0000
+++ a4lib/presentation_objects.py 2010-12-22 22:58:09 +0000
@@ -0,0 +1,139 @@
1# Copyright 2010 A4 Developers. This software is licensed under the
2# GNU General Public License version 3 (see the file COPYING).
3
4import random
5import math
6from lxml import etree
7
8import presentation
9
10
11class PresentationObject(object):
12 def __init__(self, tag_name, x=0, y=0, rotate=0.0):
13 self.element = etree.Element(tag_name, nsmap=presentation.nsmap)
14 self.element.attrib['id'] = self._generate_new_id()
15 self.move(x, y)
16 self.rotate(rotate)
17
18 def _generate_new_id(self, length=10):
19 seed = "abcdef0123456789"
20 return ''.join(random.choice(seed) for i in xrange(length))
21
22 def append_attributes(self, attribs):
23 for key in attribs:
24 self.element.attrib[key] = str(piuprops[key])
25
26 @property
27 def get_id(self):
28 return self.element.attrib['id']
29
30 def move(self, x, y):
31 self.element.attrib['x'] = str(x)
32 self.element.attrib['y'] = str(y)
33
34 def rotate(self, rotate):
35 # need to calculate the transform matrix to rotate the object around his (x,y),
36 # otherwise it will rotate around (0,0)
37 xc = float(self.element.attrib['x'])
38 yc = float(self.element.attrib['y'])
39 xc1 = math.cos(-rotate) * xc - math.sin(-rotate) * yc
40 yc1 = math.sin(-rotate) * xc + math.cos(-rotate) * yc
41 self.element.attrib['transform'] = ("rotate(%s)" % str(math.degrees(rotate))) + \
42 (" translate(%s,%s)" % (xc1 - xc, yc1 - yc))
43
44 def set_size(self, width, height):
45 self.element.attrib['width'] = str(width)
46 self.element.attrib['height'] = str(height)
47
48 ## Methods that could be implemented in subclasses.
49 ## Implementing a stub here so subclasses doesn't have to reimplement.
50 def start_move(self):
51 pass
52 def end_move(self):
53 pass
54 def character_pressed(self, char):
55 pass
56 def clicked_on_(self, x, y):
57 pass
58
59
60class RectObject(PresentationObject):
61 def __init__(self, x=0, y=0, rotate=0.0):
62 PresentationObject.__init__(self, 'rect', x, y, rotate)
63
64
65class TextObject(PresentationObject):
66 def __init__(self, x=0, y=0, rotate=0.0, text=""):
67 PresentationObject.__init__(self, 'text', x, y, rotate)
68 self.element.text = text
69
70 def character_pressed(self, char):
71 self.element.text += char
72
73 def get_text(self):
74 return self.element.text
75
76 def set_text(self, text):
77 self.element.text = text
78
79 text = property(get_text, set_text)
80
81
82class PolaroidObject(PresentationObject):
83 def __init__(self, x=0, y=0, rotate=0.0, text=""):
84 PresentationObject.__init__(self, 'g', x, y, rotate)
85
86 self.xratio = 0.95
87 self.yratio = 0.80
88
89 self.rect1 = etree.Element('rect')
90 self.rect1.attrib['id'] = self._generate_new_id()
91 self.rect1.attrib['style'] = "fill:#fbfae1;fill-opacity:1;stroke:#000000;stroke-opacity:1"
92 self.rect1.attrib['x'] = str(x)
93 self.rect1.attrib['y'] = str(y)
94
95 self.rect2 = etree.Element('rect')
96 self.rect2.attrib['id'] = self._generate_new_id()
97 self.rect2.attrib['style'] = "fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
98 self.rect2.attrib['x'] = str(x)
99 self.rect2.attrib['y'] = str(y)
100
101 self.textelement = etree.Element('text')
102 self.textelement.attrib['id'] = self._generate_new_id()
103 self.textelement.text = ""
104
105 self.element.append(self.rect1)
106 self.element.append(self.rect2)
107 self.element.append(self.textelement)
108
109 def set_size(self, width, height):
110 self.rect1.attrib['width'] = str(width)
111 self.rect1.attrib['height'] = str(height)
112
113 self.rect2.attrib['width'] = str(width * self.xratio)
114 self.rect2.attrib['height'] = str(height * self.yratio)
115
116 top = (width - width * self.xratio) / 2
117
118 self.rect2.attrib['x'] = str(float(self.rect1.attrib['x']) + top)
119 self.rect2.attrib['y'] = str(float(self.rect1.attrib['y']) + top)
120
121 self.textelement.attrib['x'] = str(float(self.rect1.attrib['x']) +
122 width / 2)
123 self.textelement.attrib['y'] = str(float(self.rect1.attrib['y']) +
124 height - (height - (height * self.yratio + top)) / 2)
125
126 def get_size(self):
127 return (self.rect1.attrib['width'], self.rect1.attrib['height'])
128
129 def character_pressed(self, char):
130 self.textelement.text += char
131
132
133class ImageObject(PresentationObject):
134 def __init__(self, x=0, y=0, rotate=0.0):
135 PresentationObject.__init__(self, 'image', x, y, rotate)
136
137 def set_image(self, target):
138 href_attr = '{%s}href' % "http://www.w3.org/1999/xlink"
139 self.element.attrib[href_attr] = "file://" + target
0140
=== modified file 'a4lib/region.py'
--- a4lib/region.py 2010-08-11 16:33:02 +0000
+++ a4lib/region.py 2010-12-22 22:58:09 +0000
@@ -83,6 +83,28 @@
83 else:83 else:
84 return ((scale_x - scale_y) * self.width, 0)84 return ((scale_x - scale_y) * self.width, 0)
8585
86 def get_point_from_window_coordinates(self, window_size, window_point):
87 scale = self.get_window_scale_factor(window_size)
88 translate = self.get_window_fit_vector(window_size)
89
90 x = window_point[0]
91 y = window_point[1]
92
93 x -= translate[0] / 2.0
94 y -= translate[1] / 2.0
95
96 x = x / scale
97 y = y / scale
98
99 x -= self.width / 2
100 y -= self.height / 2
101 x1 = math.cos(self.rotate) * x - math.sin(self.rotate) * y
102 y1 = math.sin(self.rotate) * x + math.cos(self.rotate) * y
103 x1 += self.xc
104 y1 += self.yc
105
106 return (x1, y1)
107
86 def render(self, context, svg_image, window_size):108 def render(self, context, svg_image, window_size):
87 """Render the region of interest to the given Cairo context."""109 """Render the region of interest to the given Cairo context."""
88 scale = self.get_window_scale_factor(window_size)110 scale = self.get_window_scale_factor(window_size)
89111
=== modified file 'data/window_main.glade'
--- data/window_main.glade 2010-11-20 12:46:38 +0000
+++ data/window_main.glade 2010-12-22 22:58:09 +0000
@@ -304,6 +304,7 @@
304 <property name="label" translatable="yes">Selector</property>304 <property name="label" translatable="yes">Selector</property>
305 <property name="use_underline">True</property>305 <property name="use_underline">True</property>
306 <property name="active">True</property>306 <property name="active">True</property>
307 <signal name="toggled" handler="on_toggle_tool"/>
307 </object>308 </object>
308 <packing>309 <packing>
309 <property name="expand">False</property>310 <property name="expand">False</property>
@@ -337,11 +338,38 @@
337 </packing>338 </packing>
338 </child>339 </child>
339 <child>340 <child>
341 <object class="GtkToggleToolButton" id="ImageToolbutton">
342 <property name="visible">True</property>
343 <property name="is_important">True</property>
344 <property name="label" translatable="yes">Image</property>
345 <property name="use_underline">True</property>
346 <signal name="toggled" handler="on_toggle_tool"/>
347 </object>
348 <packing>
349 <property name="expand">False</property>
350 <property name="homogeneous">True</property>
351 </packing>
352 </child>
353 <child>
354 <object class="GtkToggleToolButton" id="PolaroidToolbutton">
355 <property name="visible">True</property>
356 <property name="is_important">True</property>
357 <property name="label" translatable="yes">Polaroid</property>
358 <property name="use_underline">True</property>
359 <signal name="toggled" handler="on_toggle_tool"/>
360 </object>
361 <packing>
362 <property name="expand">False</property>
363 <property name="homogeneous">True</property>
364 </packing>
365 </child>
366 <child>
340 <object class="GtkMenuToolButton" id="toolbutton4">367 <object class="GtkMenuToolButton" id="toolbutton4">
341 <property name="visible">True</property>368 <property name="visible">True</property>
342 <property name="is_important">True</property>369 <property name="is_important">True</property>
343 <property name="label" translatable="yes">Frames</property>370 <property name="label" translatable="yes">Frames</property>
344 <property name="use_underline">True</property>371 <property name="use_underline">True</property>
372 <property name="menu">FramesMenu</property>
345 </object>373 </object>
346 <packing>374 <packing>
347 <property name="expand">False</property>375 <property name="expand">False</property>
@@ -452,5 +480,36 @@
452 <object class="GtkAction" id="action1"/>480 <object class="GtkAction" id="action1"/>
453 <object class="GtkMenu" id="ShapesMenu">481 <object class="GtkMenu" id="ShapesMenu">
454 <property name="visible">True</property>482 <property name="visible">True</property>
483 <child>
484 <object class="GtkMenuItem" id="rect_item">
485 <property name="visible">True</property>
486 <property name="label" translatable="yes">Rect</property>
487 <property name="use_underline">True</property>
488 </object>
489 </child>
490 <child>
491 <object class="GtkMenuItem" id="polaroid_item">
492 <property name="visible">True</property>
493 <property name="label" translatable="yes">Polaroid</property>
494 <property name="use_underline">True</property>
495 </object>
496 </child>
497 </object>
498 <object class="GtkMenu" id="FramesMenu">
499 <property name="visible">True</property>
500 <child>
501 <object class="GtkMenuItem" id="normal_frame">
502 <property name="visible">True</property>
503 <property name="label" translatable="yes">Normal frame</property>
504 <property name="use_underline">True</property>
505 </object>
506 </child>
507 <child>
508 <object class="GtkMenuItem" id="hidden_frame">
509 <property name="visible">True</property>
510 <property name="label" translatable="yes">Hidden Frame</property>
511 <property name="use_underline">True</property>
512 </object>
513 </child>
455 </object>514 </object>
456</interface>515</interface>
457516
=== added directory 'tests/objects'
=== added file 'tests/objects/polaroid.svg'
--- tests/objects/polaroid.svg 1970-01-01 00:00:00 +0000
+++ tests/objects/polaroid.svg 2010-12-22 22:58:09 +0000
@@ -0,0 +1,78 @@
1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2<!-- Created with Inkscape (http://www.inkscape.org/) -->
3
4<svg
5 xmlns:dc="http://purl.org/dc/elements/1.1/"
6 xmlns:cc="http://creativecommons.org/ns#"
7 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
8 xmlns:svg="http://www.w3.org/2000/svg"
9 xmlns="http://www.w3.org/2000/svg"
10 xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
11 xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
12 width="744.09448819"
13 height="1052.3622047"
14 id="svg2"
15 version="1.1"
16 inkscape:version="0.48.0 r9654"
17 sodipodi:docname="polaroid.svg">
18 <defs
19 id="defs4" />
20 <sodipodi:namedview
21 id="base"
22 pagecolor="#ffffff"
23 bordercolor="#666666"
24 borderopacity="1.0"
25 inkscape:pageopacity="0.0"
26 inkscape:pageshadow="2"
27 inkscape:zoom="1.4"
28 inkscape:cx="305.17697"
29 inkscape:cy="860.0891"
30 inkscape:document-units="px"
31 inkscape:current-layer="layer1"
32 showgrid="false"
33 inkscape:window-width="1440"
34 inkscape:window-height="827"
35 inkscape:window-x="0"
36 inkscape:window-y="24"
37 inkscape:window-maximized="1" />
38 <metadata
39 id="metadata7">
40 <rdf:RDF>
41 <cc:Work
42 rdf:about="">
43 <dc:format>image/svg+xml</dc:format>
44 <dc:type
45 rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
46 <dc:title></dc:title>
47 </cc:Work>
48 </rdf:RDF>
49 </metadata>
50 <g id="layer1">
51 <rect
52 style="fill:#fbfae1;fill-opacity:1;stroke:#000000;stroke-opacity:1"
53 id="rect2985"
54 width="327.14285"
55 height="220.71428"
56 x="82.85714"
57 y="20.933611" />
58 <rect
59 style="fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
60 id="rect3755"
61 width="314.28571"
62 height="186.42857"
63 x="89.285713"
64 y="26.647896" />
65 <text
66 xml:space="preserve"
67 style="font-size:12px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans"
68 x="245"
69 y="227.36218"
70 id="text3757"
71 sodipodi:linespacing="125%"><tspan
72 sodipodi:role="line"
73 id="tspan3759"
74 x="245"
75 y="227.36218"
76 style="font-family:Times New Roman;-inkscape-font-specification:Times New Roman">polaroid-text</tspan></text>
77 </g>
78</svg>

Subscribers

People subscribed via source and target branches