# gcompris - anim
#
# Time-stamp: <2007-08-22 01:26:13 bruno>
#
# Copyright (C) 2003 Bruno Coudoin (redraw code), 2004 Yves Combe (anim code)
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see .
#
# Version 2 of anim
# Due to performance, the animation code as been rewriten
# For now, the animation is done keeping difference
# in parameters of graphicals object between shots?
# PythonTest Board module
import gobject
import gnomecanvas
import gcompris
import gcompris.utils
import gcompris.skin
import gcompris.bonus
import gcompris.sound
from gcompris import gcompris_gettext as _
import gtk
import gtk.gdk
import gtk.keysyms
import copy
import math
import time
import os
import sys
import tempfile
import cPickle as pickle
import base64
# Note that we only need one of these for any given version of the
# processing class.
#
python_xml = False
# python_xml = True
# try:
# from xml.dom.DOMImplementation import implementation
# import xml.sax.writer
# import xml.utils
# except:
# python_xml = False
# Commented out, until we have a clean support for a mainstream mozilla
#print _('You need the python xml module. Disabling SVG.')
fles=None
# When anim is passed the mode 'draw', animation is disabled.
#
#class Gcompris_anim:
class Gcompris_anim:
"""The cartoon activity"""
def __init__(self, gcomprisBoard):
self.gcomprisBoard = gcomprisBoard
self.timeout = 0
# There is two board in the same code
# here the diff in parameters
# The main list of items
# this parameter is used in svg save, to know where to get the list
self.itemlist = { 'draw' : 'framelist',
'anim': 'animlist'
}
if self.gcomprisBoard.mode == 'draw':
self.format_string = { 'gcompris' : 'GCompris draw 2 cPikle file',
'svg' : 'GCompris draw 2 svg file'
}
else:
self.format_string = { 'gcompris' : 'GCompris anim 2 cPikle file',
'svg' : 'GCompris anim 2 svg file'
}
if self.gcomprisBoard.mode == 'draw':
# DRAW
#
# draw is adapted to little kids : big anchors
self.DEFAULT_ANCHOR_SIZE = 12
# Step used in grid is wider
self.grid_step = 10
# draw specific UI
self.selector_section = "draw2"
else:
# Anim
#
# Normal anchors
self.DEFAULT_ANCHOR_SIZE = 8
# Step used in grid is wider
self.grid_step = 5
# anim specific UI
self.selector_section = "anim2"
# Initialisation. Should not change in draw.
self.running = False
# In draw objects are created without drag&drop
# Default size for rect, circle, line
self.draw_defaults_size = { 'RECT' : {'width' : 60 , 'height' : 40 },
'FILL_RECT' : {'width' : 60 , 'height' : 40 },
'CIRCLE' : {'width' : 60 , 'height' : 40 },
'FILL_CIRCLE' : {'width' : 60 , 'height' : 40 },
'LINE' : {'width' : 60 , 'height' : 40 }
}
# Cool !!!
self.empty="empty"
# global parameter to access object structures from global fonctions
global fles
fles=self
# File formats to save/restore
#
# svg has proprietary data to handle animation, base64 included images
# gcompris is cPickle python saved data
#
# svg in draw mode is normal svg file with base64 included images
global python_xml
if self.gcomprisBoard.mode == 'draw':
self.file_type = "image/gcompris+draw"
if python_xml:
self.file_type = self.file_type + " image/svg+xml"
else:
self.file_type = "image/gcompris+anim"
# if python_xml:
# self.file_type = self.file_type +" image/svg+xml+javascript"
# These are used to let us restart only after the bonux is displayed.
# When the bonus is displayed, it call us first with pause(1) and then with pause(0)
self.board_paused = 0
self.gamewon = 0
self.MAX_TEXT_CHAR = 50
# kind of beautiful blue
self.ANCHOR_COLOR = 0x36ede480
# anchortype
self.ANCHOR_NW = 1
self.ANCHOR_N = 2
self.ANCHOR_NE = 3
self.ANCHOR_E = 4
self.ANCHOR_W = 5
self.ANCHOR_SW = 6
self.ANCHOR_S = 7
self.ANCHOR_SE = 8
self.ANCHOR_T = 9
self.anchors = { 'LINE': [ self.ANCHOR_SW , self.ANCHOR_NE ],
'RECT': [ self.ANCHOR_N,
self.ANCHOR_NE,
self.ANCHOR_E,
self.ANCHOR_SE,
self.ANCHOR_S,
self.ANCHOR_SW,
self.ANCHOR_W,
self.ANCHOR_NW
],
'TEXT': [ self.ANCHOR_T ]
}
self.anchors ['FILL_RECT'] = self.anchors ['RECT']
self.anchors ['CIRCLE'] = self.anchors ['RECT']
self.anchors ['FILL_CIRCLE'] = self.anchors ['RECT']
self.anchors ['IMAGE'] = self.anchors ['RECT']
# gnomecanvas type corresponding
self.types = { 'RECT' : gnomecanvas.CanvasRect,
'FILL_RECT' : gnomecanvas.CanvasRect,
'CIRCLE' : gnomecanvas.CanvasEllipse,
'FILL_CIRCLE' : gnomecanvas.CanvasEllipse,
'TEXT' : gnomecanvas.CanvasText,
'IMAGE' : gnomecanvas.CanvasPixbuf,
'LINE' : gnomecanvas.CanvasLine
}
# mutable gnomecanvas attributs
self.attributs = { 'LINE' : [ "points",
"fill_color_rgba",
],
'RECT' : [ "x1",
"y1",
"x2",
"y2",
"outline_color_rgba",
],
'FILL_RECT' : [ "x1",
"y1",
"x2",
"y2",
"fill_color_rgba",
],
'CIRCLE' : [ "x1",
"y1",
"x2",
"y2",
"outline_color_rgba",
],
'FILL_CIRCLE' : [ "x1",
"y1",
"x2",
"y2",
"fill_color_rgba",
],
'TEXT' : [ "x",
"y",
"text",
"fill_color_rgba",
],
'IMAGE' : [ "x",
"y",
"width",
"height",
]
}
# non mutable gnomecanvas attributs
self.fixedattributs = { 'LINE' : { 'width-units': 8.0
},
'RECT' : { 'width-units': 4.0
},
'FILL_RECT' : { 'width-units': 1.0,
'outline_color_rgba': 0x000000FFL
},
'CIRCLE' : { 'width-units': 4.0 },
'FILL_CIRCLE' : { 'width-units': 1.0,
'outline_color_rgba': 0x000000FFL
},
'TEXT' : { 'font': gcompris.FONT_BOARD_BIG_BOLD,
'anchor' : gtk.ANCHOR_CENTER
},
'IMAGE' : { 'width_set': True,
'height_set': True
}
}
# events handled by each type
self.events = { 'LINE' : [ self.fillin_item_event,
self.move_item_event,
self.create_item_event,
self.del_item_event ] ,
'RECT' : [ self.fillout_item_event,
self.move_item_event,
self.create_item_event,
self.del_item_event ],
'TEXT' : [ self.fillin_item_event,
self.move_item_event,
self.create_item_event,
self.del_item_event ],
'IMAGE' : [ self.move_item_event,
self.create_item_event,
self.del_item_event ]
}
self.events ['FILL_RECT'] = self.events ['LINE']
self.events ['FILL_CIRCLE'] = self.events ['LINE']
self.events ['CIRCLE'] = self.events ['RECT']
# Part of UI : tools buttons
# TOOL SELECTION
self.tools = [
["SAVE", "draw/tool-save.png", "draw/tool-save.png", gcompris.CURSOR_SELECT],
["LOAD", "draw/tool-load.png", "draw/tool-load.png", gcompris.CURSOR_SELECT],
["MOVIE", "draw/tool-movie.png", "draw/tool-movie_on.png", gcompris.CURSOR_SELECT],
["PICTURE", "draw/tool-camera.png", "draw/tool-camera_on.png", gcompris.CURSOR_SELECT],
["RECT", "draw/tool-rectangle.png", "draw/tool-rectangle_on.png", gcompris.CURSOR_RECT],
["FILL_RECT", "draw/tool-filledrectangle.png", "draw/tool-filledrectangle_on.png", gcompris.CURSOR_FILLRECT],
["CIRCLE", "draw/tool-circle.png", "draw/tool-circle_on.png", gcompris.CURSOR_CIRCLE],
["FILL_CIRCLE", "draw/tool-filledcircle.png", "draw/tool-filledcircle_on.png", gcompris.CURSOR_FILLCIRCLE],
["LINE", "draw/tool-line.png", "draw/tool-line_on.png", gcompris.CURSOR_LINE],
["FILL", "draw/tool-fill.png", "draw/tool-fill_on.png", gcompris.CURSOR_FILL],
["DEL", "draw/tool-del.png", "draw/tool-del_on.png", gcompris.CURSOR_DEL],
["SELECT", "draw/tool-select.png", "draw/tool-select_on.png", gcompris.CURSOR_SELECT],
["RAISE", "draw/tool-up.png", "draw/tool-up_on.png", gcompris.CURSOR_DEFAULT],
["LOWER", "draw/tool-down.png", "draw/tool-down_on.png", gcompris.CURSOR_DEFAULT],
["CCW", "draw/tool-rotation-ccw.png", "draw/tool-rotation-ccw_on.png", gcompris.CURSOR_DEFAULT],
["CW", "draw/tool-rotation-cw.png", "draw/tool-rotation-cw_on.png", gcompris.CURSOR_DEFAULT],
["FLIP", "draw/tool-flip.png", "draw/tool-flip_on.png", gcompris.CURSOR_DEFAULT],
["TEXT", "draw/tool-text.png", "draw/tool-text_on.png", gcompris.CURSOR_LINE],
["IMAGE", "draw/tool-image.png", "draw/tool-image_on.png", gcompris.CURSOR_DEFAULT],
]
# keep the tool selected
self.current_tool=0
# Part of UI: colors buttons
# COLOR SELECTION
# RGBA unsigned long. A is always FF.
# keep in mind if you change that to change the svg export: it does not pass A.
self.colors = [ 0x000000FFL, 0x202020FFL, 0x404040FFL, 0x505050FFL,
0x815a38FFL, 0xb57c51FFL, 0xe5a370FFL, 0xfcc69cFFL,
0xb20c0cFFL, 0xea2c2cFFL, 0xf26363FFL, 0xf7a3a3FFL,
0xff6600FFL, 0xff8a3dFFL, 0xfcaf7bFFL, 0xf4c8abFFL,
0x9b8904FFL, 0xd3bc10FFL, 0xf4dd2cFFL, 0xfcee85FFL,
0x255b0cFFL, 0x38930eFFL, 0x56d11dFFL, 0x8fe268FFL,
0x142f9bFFL, 0x2d52e5FFL, 0x667eddFFL, 0xa6b4eaFFL,
0x328989FFL, 0x37b2b2FFL, 0x3ae0e0FFL, 0x96e0e0FFL,
0x831891FFL, 0xc741d8FFL, 0xde81eaFFL, 0xeecdf2FFL,
0x666666FFL, 0x838384FFL, 0xc4c4c4FFL, 0xffffffFFL
]
# keep the current color here
self.current_color = 0
# step of the grid used for positioning objects
# TODO : add a parameters to put step=5 in draw and step=1 in anim
self.current_step = 0
# selected object
self.selected = None
# Part of UI : drawing_area is the drawing zone
# when anim is played, it's masked and playing_area is displayed
#
# Drawing area is editing image area
# Palying area is playing map
self.drawing_area = [124.0, 20.0, gcompris.BOARD_WIDTH - 15, gcompris.BOARD_HEIGHT - 78]
self.playing_area = [124.0, 20.0, gcompris.BOARD_WIDTH - 15, gcompris.BOARD_HEIGHT - 78]
# Global used for the select event
#
# used to keep the distance between pointer and corner in moving objects
self.in_select_ofx = -1
self.in_select_ofy = -1
# The frame counter
# TODO : check if used
self.item_frame_counter = []
# Not used for the moment in anim2
# TODO : fix that
#self.current_image = 0
# Part of UI
# The root items
self.root_coloritem = []
self.root_toolitem = []
# Anim2 variables
# animlist is the full list of all items.
# each item is keeped with it's frame information
# - frames where it's modified
# - all modifications for each frame
#
# list of items in current frame
self.framelist = []
# list of items in the full animation
self.animlist = []
# rank of the current frame being processed
self.current_frame = 0
self.frames_total = self.current_frame
# list of z values in last shot
self.list_z_last_shot = []
# list of actual z values
self.list_z_actual = []
# used to handle draw creation of object
self.draw_created_object = False
def start(self):
self.last_commit = None
# GCompris initialisation
self.gcomprisBoard.level=1
self.gcomprisBoard.maxlevel=1
self.gcomprisBoard.sublevel=0
self.gcomprisBoard.number_of_sublevel=0
gcompris.bar_set(0)
gcompris.set_background(self.gcomprisBoard.canvas.root(),
gcompris.skin.image_to_skin("gcompris-bg.jpg"))
# Create our rootitem. We put each canvas item in it so at the end we
# only have to kill it. The canvas deletes all the items it contains automaticaly.
self.rootitem = self.gcomprisBoard.canvas.root().add(
gnomecanvas.CanvasGroup,
x=0.0,
y=0.0
)
# initialisation
self.draw_tools()
self.draw_animtools()
self.draw_colors()
self.draw_drawing_area(self.grid_step)
self.draw_playing_area()
self.pause(0)
global python_xml
if not python_xml:
#gcompris.utils.dialog(_('Python xml module not found. SVG is disabled. Install the python xml module to enable SVG Save/restore.'), None)
#print _('Python xml module not found. SVG is disabled. Install the python xml module to enable SVG Save/restore.')
pass
def end(self):
# stop the animation
if self.running:
self.playing_stop()
if self.timeout:
gobject.source_remove(self.timeout)
self.timeout = 0
# Remove the root item removes all the others inside it
gcompris.set_cursor(gcompris.CURSOR_DEFAULT);
self.rootitem.destroy()
def pause(self, pause):
#used to stop the event reception at the end?
self.board_paused = pause
return
def repeat(self):
print("Gcompris_anim repeat.")
def config(self):
print("Gcompris_anim config.")
def key_press(self, keyval, commit_str, preedit_str):
#
# I suppose codec is the stdin one.
#
codec = sys.stdin.encoding
# keyboard shortcuts
if (keyval == gtk.keysyms.F1):
gcompris.file_selector_save( self.gcomprisBoard, self.selector_section, self.file_type, general_save)
elif (keyval == gtk.keysyms.F2):
gcompris.file_selector_load( self.gcomprisBoard, self.selector_section, self.file_type, general_restore)
# Printing
# Bruno we need a print button !
#
# was in anim1, but not print an animation is not interesting.
elif (keyval == gtk.keysyms.F3):
pass
#if self.gcomprisBoard.mode == 'draw':
# We can keep in draw2, svg export will be pure svg.
#self.ps_print(self.get_drawing(self.current_image))
#else:
#print "Sorry i can't print an animation"
# AFAIR The keyboard part was written by bruno
elif ((keyval == gtk.keysyms.Shift_L) or
(keyval == gtk.keysyms.Shift_R) or
(keyval == gtk.keysyms.Control_L) or
(keyval == gtk.keysyms.Control_R) or
(keyval == gtk.keysyms.Caps_Lock) or
(keyval == gtk.keysyms.Shift_Lock) or
(keyval == gtk.keysyms.Meta_L) or
(keyval == gtk.keysyms.Meta_R) or
(keyval == gtk.keysyms.Alt_L) or
(keyval == gtk.keysyms.Alt_R) or
(keyval == gtk.keysyms.Super_L) or
(keyval == gtk.keysyms.Super_R) or
(keyval == gtk.keysyms.Hyper_L) or
(keyval == gtk.keysyms.Hyper_R) or
(keyval == gtk.keysyms.Mode_switch) or
(keyval == gtk.keysyms.dead_circumflex) or
(keyval == gtk.keysyms.Num_Lock)):
return False
if (self.selected == None):
return True
elif (gobject.type_name(self.selected.item_list[0])!="GnomeCanvasText"):
#print "Not Text object when got key !!!"
return True
textItem = self.selected.item_list[0]
if (self.last_commit == None):
oldtext = textItem.get_property('text').decode('UTF-8')
else:
oldtext = self.last_commit
if ((keyval == gtk.keysyms.BackSpace) or
(keyval == gtk.keysyms.Delete)):
if (len(oldtext) != 1):
newtext = oldtext[:-1]
else:
newtext = u'?'
self.last_commit = newtext
else:
if ((oldtext[:1] == u'?') and (len(oldtext)==1)):
oldtext = u' '
oldtext = oldtext.strip()
if (commit_str != None):
str = commit_str
self.last_commit = oldtext + str
if (preedit_str != None):
str = ''+ preedit_str +''
self.last_commit = oldtext
if (len(oldtext) < self.MAX_TEXT_CHAR):
newtext = oldtext + str
else:
newtext = oldtext
textItem.set(markup=newtext.encode('UTF-8'))
return True
# Display the tools
def draw_tools(self):
self.root_toolitem = self.rootitem.add(
gnomecanvas.CanvasGroup,
x=0.0,
y=0.0
)
self.root_toolitem.add(
gnomecanvas.CanvasPixbuf,
pixbuf = gcompris.utils.load_pixmap(gcompris.skin.image_to_skin("draw/tool-selector.png")),
x=5,
y=5.0,
width=107.0,
height=517.0,
width_set=True,
height_set=True
)
x1=11.0
x2=56.0
y=11.0
stepy=45
# Display the tools
for i in range(0,len(self.tools)):
# Exclude the anim specific buttons
if self.gcomprisBoard.mode == 'draw':
if self.tools[i][0]=="MOVIE" or self.tools[i][0]=="PICTURE":
continue
if(i%2):
theX = x2
else:
theX = x1
item = self.root_toolitem.add(
gnomecanvas.CanvasPixbuf,
pixbuf = gcompris.utils.load_pixmap(gcompris.skin.image_to_skin(self.tools[i][1])),
x=theX,
y=y
)
item.connect("event", self.tool_item_event, i)
if i%2:
y += stepy
if(self.tools[i][0]=="SELECT"):
self.select_tool = item
self.select_tool_number = i
# Always select the SELECT item by default
self.current_tool = i
self.old_tool_item = item
self.old_tool_item.set(pixbuf = gcompris.utils.load_pixmap(gcompris.skin.image_to_skin(self.tools[i][2])))
gcompris.set_cursor(self.tools[i][3]);
# Event when a tool is selected
# Perform instant action or swich the tool selection
def tool_item_event(self, item, event, tool):
if event.type == gtk.gdk.BUTTON_PRESS:
if event.button == 1:
gcompris.sound.play_ogg("sounds/bleep.wav")
# Some button have instant effects
if (self.tools[tool][0] == "SAVE"):
# self.Anim2Shot()
gcompris.file_selector_save( self.gcomprisBoard, self.selector_section, self.file_type, general_save)
return False
elif (self.tools[tool][0] == "LOAD"):
gcompris.file_selector_load( self.gcomprisBoard, self.selector_section, self.file_type, general_restore)
return False
elif (self.tools[tool][0] == "IMAGE"):
self.pos_x = gcompris.BOARD_WIDTH/2
self.pos_y = gcompris.BOARD_HEIGHT/2
gcompris.images_selector_start(self.gcomprisBoard,
"dataset",
image_selected);
return False
elif (self.tools[tool][0] == "PICTURE"):
self.Anim2Shot()
return False
elif (self.tools[tool][0] == "MOVIE"):
if self.frames_total == 0:
print 'Mmm... Need to make shots before run anim !!'
return False
if not self.running:
# unselect object if necessary
self.unselect()
self.playing_start()
return False
elif (self.tools[tool][0] != "SELECT") and (self.selected != None):
self.unselect()
#
# Normal case, tool button switch
# -------------------------------
# Deactivate old button
self.old_tool_item.set(pixbuf = gcompris.utils.load_pixmap(gcompris.skin.image_to_skin(self.tools[self.current_tool][1])))
# Activate new button
self.current_tool = tool
self.old_tool_item = item
self.old_tool_item.set(pixbuf = gcompris.utils.load_pixmap(gcompris.skin.image_to_skin(self.tools[self.current_tool][2])))
gcompris.set_cursor(self.tools[self.current_tool][3]);
# Display the color selector
def draw_colors(self):
pixmap = gcompris.utils.load_pixmap(gcompris.skin.image_to_skin("draw/color-selector.png"))
x = (self.drawing_area[2] - self.drawing_area[0]
- pixmap.get_width())/2 + self.drawing_area[0]
color_pixmap_height = pixmap.get_height()
y = gcompris.BOARD_HEIGHT - color_pixmap_height - 8
c = 0
self.root_coloritem = self.rootitem.add(
gnomecanvas.CanvasGroup,
x=0.0,
y=0.0
)
self.root_coloritem.add(
gnomecanvas.CanvasPixbuf,
pixbuf = pixmap,
x=x,
y=y,
)
for i in range(0,10):
x1=x+26+i*56
for j in range(0,4):
c = i*4 +j
item = self.root_coloritem.add(
gnomecanvas.CanvasRect,
x1=x1 + 26*(j%2),
y1=y+8 + (color_pixmap_height/2 -6)*(j/2),
x2=x1 + 24 + 26*(j%2),
y2=y + color_pixmap_height/2 + (color_pixmap_height/2 -6)*(j/2),
fill_color_rgba=self.colors[c],
outline_color_rgba=0x07A3E0FFL
)
item.connect("event", self.color_item_event, c)
if (c==0):
self.current_color = c
self.old_color_item = item
self.old_color_item.set(width_units = 4.0,
outline_color_rgba= 0x16EC3DFFL)
# Color event
def color_item_event(self, item, event, color):
if self.running:
return
if event.type == gtk.gdk.BUTTON_PRESS:
gcompris.sound.play_ogg("sounds/drip.wav")
if event.button == 1:
# Deactivate old button
self.old_color_item.set(width_units = 0.0,
outline_color_rgba= 0x144B9DFFL)
# Activate new button
self.current_color = color
self.old_color_item = item
self.old_color_item.set(width_units = 4.0,
outline_color_rgba= 0x16EC3DFFL)
# Display the drawing area
def draw_drawing_area(self,step):
x1=self.drawing_area[0]
y1=self.drawing_area[1]
x2=self.drawing_area[2]
y2=self.drawing_area[3]
item = self.rootitem.add (
gnomecanvas.CanvasRect,
x1=x1,
y1=y1,
x2=x2,
y2=y2,
fill_color_rgba=0xFFFFFFFFL,
width_units=2.0,
outline_color_rgba=0x111199FFL
)
item.connect("event", self.create_item_event)
# The CanvasGroup for the edit space.
self.root_drawingitem = self.rootitem.add(
gnomecanvas.CanvasGroup,
x=0.0,
y=0.0
)
self.draw_grid(x1,x2,y1,y2,step)
# Create the root_anim group which contains all the drawings.
# At root_anim root, there is a group for each drawings.
self.root_anim = self.rootitem.add(
gnomecanvas.CanvasGroup,
x=0.0,
y=0.0
)
gcompris.utils.item_absolute_move(self.root_anim,
int(self.playing_area[0]-self.drawing_area[0]),
int(self.playing_area[1]-self.drawing_area[1])
)
# Create a group for the first drawing
self.flash = self.rootitem.add (
gnomecanvas.CanvasPixbuf,
pixbuf = gcompris.utils.load_pixmap(gcompris.skin.image_to_skin("draw/camera.png")),
x=300,
y=200,
)
self.flash.hide()
# Display the drawing area
def draw_playing_area(self):
x1=self.playing_area[0]
y1=self.playing_area[1]
x2=self.playing_area[2]
y2=self.playing_area[3]
# The CanvasGroup for the playing area.
self.root_playingitem = self.rootitem.add(
gnomecanvas.CanvasGroup,
x=0.0,
y=0.0
)
self.root_playingitem.hide()
# intervall = 1000 / anim_speed
self.anim_speed=5
run = self.root_playingitem.add(
gnomecanvas.CanvasPixbuf,
pixbuf = gcompris.utils.load_pixmap(gcompris.skin.image_to_skin("draw/down.png")),
x = 15,
y = 410,
width = 20,
height = 20,
width_set = 1,
height_set = 1
)
run.connect("event", self.speed_event,False)
self.speed_item = self.root_playingitem.add(
gnomecanvas.CanvasText,
text=self.anim_speed,
font = gcompris.skin.get_font("gcompris/board/medium"),
x=52,
y=420,
anchor=gtk.ANCHOR_CENTER,
)
run = self.root_playingitem.add(
gnomecanvas.CanvasPixbuf,
pixbuf = gcompris.utils.load_pixmap(gcompris.skin.image_to_skin("draw/up.png")),
x = 70,
y = 410,
width = 20,
height = 20,
width_set = 1,
height_set = 1
)
run.connect("event", self.speed_event,True)
# And finaly a STOP icon
run = self.root_playingitem.add(
gnomecanvas.CanvasPixbuf,
pixbuf = gcompris.utils.load_pixmap(gcompris.skin.image_to_skin("boardicons/draw.svg")),
x = 16,
y = 110,
)
run.connect("event", self.stop_event,True)
def stop_event(self, item, event, up):
if event.type == gtk.gdk.BUTTON_PRESS:
gcompris.sound.play_ogg("sounds/bleep.wav")
self.playing_stop()
def playing_stop(self):
self.running=False
gobject.source_remove(self.timeout)
self.run_anim2()
def speed_event(self, item, event, up):
if event.type == gtk.gdk.BUTTON_PRESS:
gcompris.sound.play_ogg("sounds/bleep.wav")
if up:
if self.anim_speed==25:
return
else:
self.anim_speed=self.anim_speed+1
else:
if self.anim_speed==1:
return
else:
self.anim_speed=self.anim_speed-1
gobject.source_remove(self.timeout)
self.timeout=gobject.timeout_add(1000/self.anim_speed, self.run_anim2)
self.speed_item.set(text=self.anim_speed)
# Draw the grid
#
def draw_grid(self, x1, x2, y1, y2, step):
self.current_step = step
color = 0x1D0DFFFFL
self.grid = self.rootitem.add (
gnomecanvas.CanvasGroup,
x=0.0,
y=0.0
)
self.grid.hide()
for i in range(int(x1), int(x2), step):
item = self.grid.add (
gnomecanvas.CanvasLine,
points=(i , y1, i , y2),
fill_color_rgba=color,
width_units=1.0,
)
# Clicking on lines let you create object
item.connect("event", self.create_item_event)
for i in range(int(y1), int(y2), step):
item = self.grid.add (
gnomecanvas.CanvasLine,
points=(x1, i, x2 , i),
fill_color_rgba=color,
width_units=1.0,
)
item.connect("event", self.create_item_event)
# Given x,y return a new x,y snapped to the grid
def snap_to_grid(self, x, y):
result = []
tmp = round(((x+(self.current_step)) -
self.drawing_area[0])/self.current_step) - 1
result.append(float(self.drawing_area[0] + tmp*self.current_step))
tmp = round(((y+(self.current_step)) -
self.drawing_area[1])/self.current_step) - 1
result.append(float(self.drawing_area[1] + tmp*self.current_step))
return result
# Event when a click on any item. Perform the move
def move_item_event(self, item, event):
if self.tools[self.current_tool][0] == "CCW":
if ((event.type == gtk.gdk.BUTTON_PRESS) and
(event.button == 1) and
(gobject.type_name(item)!="GnomeCanvasText")):
# this one seems broken
#gcompris.utils.item_rotate_relative(item.get_property("parent"),-10)
self.rotate_relative(item,-10)
return True
else:
return False
if self.tools[self.current_tool][0] == "CW":
if ((event.type == gtk.gdk.BUTTON_PRESS) and
(event.button == 1) and
(gobject.type_name(item)!="GnomeCanvasText")):
self.rotate_relative(item,10)
return True
else:
return False
if self.tools[self.current_tool][0] == "FLIP":
if ((event.type == gtk.gdk.BUTTON_PRESS) and
(event.button == 1) and
(gobject.type_name(item)!="GnomeCanvasText")):
self.item_flip(item);
return True
else:
return False
if self.tools[self.current_tool][0] == "RAISE":
if event.type == gtk.gdk.BUTTON_PRESS and event.button == 1:
item.get_property("parent").raise_(1)
self.z_raise(item.get_data("AnimItem"))
return True
else:
return False
if self.tools[self.current_tool][0] == "LOWER":
if event.type == gtk.gdk.BUTTON_PRESS and event.button == 1:
item.get_property("parent").lower(1)
self.z_lower(item.get_data("AnimItem"))
return True
else:
return False
if self.tools[self.current_tool][0] != "SELECT":
return False
if event.type == gtk.gdk.BUTTON_PRESS and event.button == 1:
if event.button == 1:
gcompris.sound.play_ogg("sounds/bleep.wav")
self.unselect()
#
# MOUSE DRAG STOP
# ---------------
if event.type == gtk.gdk.BUTTON_RELEASE:
if event.button == 1:
if self.draw_created_object:
self.draw_created_object = False
return True
# activate the anchors
self.selected=item.get_property("parent")
self.selected.item_list[1].show()
# Reset the in_select_ofx ofset
self.in_select_ofx = -1
self.in_select_ofy = -1
return True
if event.state & gtk.gdk.BUTTON1_MASK:
wx=event.x
wy=event.y
#pass in item relative coordinate
(x, y)= item.w2i( wx, wy)
bounds = item.get_bounds()
#bounds = self.get_bounds(item)
# Save the ofset between the mouse pointer and the upper left corner of the object
if(self.in_select_ofx == -1):
self.in_select_ofx = x-bounds[0]
self.in_select_ofy = y-bounds[1]
x -= self.in_select_ofx
y -= self.in_select_ofy
x,y = self.snap_to_grid(x,y)
# Check drawing boundaries
#needs to be corrected with item relative coordinate
# FIXME
# if(x(self.drawing_area[2]-(bounds[2]-bounds[0]))):
# x=self.drawing_area[2]-(bounds[2]-bounds[0])
# We need to realign x cause the bounds values are not precise enough
# x,n = self.snap_to_grid(x,y)
# if(y(self.drawing_area[3]-(bounds[3]-bounds[1]))):
# y=self.drawing_area[3]-(bounds[3]-bounds[1])
# We need to realign y cause the bounds values are not precise enough
# n,y = self.snap_to_grid(x,y)
# Now perform the object move
#gcompris.utils.item_absolute_move(item.get_property("parent"), x, y)
# pass it in item coordinate:
#(idx, idy) = item.w2i( x-bounds[0], y-bounds[1] )
(idx, idy) = ( x-bounds[0], y-bounds[1] )
self.object_move(
item.get_property("parent"),
idx,
idy
)
return True
return False
# Event when a click on an item happen on fill in type object
def fillin_item_event(self, item, event):
if event.type == gtk.gdk.BUTTON_PRESS:
if event.button == 1:
gcompris.sound.play_ogg("sounds/paint1.wav")
if self.tools[self.current_tool][0] == "FILL":
item.set(fill_color_rgba=self.colors[self.current_color])
return True
return False
# Event when a click on an item happen on border fill type object
def fillout_item_event(self, item, event):
if event.type == gtk.gdk.BUTTON_PRESS:
if event.button == 1:
gcompris.sound.play_ogg("sounds/paint1.wav")
if self.tools[self.current_tool][0] == "FILL":
item.set(outline_color_rgba=self.colors[self.current_color])
return True
return False
# Del an item and internal struct cleanup
def del_item(self, item):
item.get_property("parent").destroy()
self.del_AnimItem(item.get_data("AnimItem"))
# Event when a click on an item happen
def del_item_event(self, item, event):
if event.type == gtk.gdk.BUTTON_PRESS:
if event.button == 1:
if self.tools[self.current_tool][0] == "DEL":
gcompris.sound.play_ogg("sounds/eraser1.wav",
"sounds/eraser2.wav")
self.del_item(item);
return True
return False
# Event when an event on the drawing area happen
def create_item_event(self, item, event):
if(event.type == gtk.gdk.BUTTON_PRESS and self.running==True):
self.playing_stop()
return False
# Right button is a shortcup to Shot
if (self.gcomprisBoard.mode != 'draw' and
event.type == gtk.gdk.BUTTON_PRESS and
event.button == 3):
self.Anim2Shot()
return False
if (not (self.tools[self.current_tool][0] == "RECT" or
self.tools[self.current_tool][0] == "CIRCLE" or
self.tools[self.current_tool][0] == "FILL_RECT" or
self.tools[self.current_tool][0] == "FILL_CIRCLE" or
self.tools[self.current_tool][0] == "IMAGE" or
self.tools[self.current_tool][0] == "TEXT" or
self.tools[self.current_tool][0] == "LINE")):
return False
if event.type == gtk.gdk.BUTTON_PRESS:
if event.button == 1:
gcompris.sound.play_ogg("sounds/bleep.wav")
self.newitem = None
#print "----------------------------------------"
#print "Current image = " + str(self.current_frame)
#self.dump_group(self.root_anim)
self.newitemgroup = self.root_anim.add(
gnomecanvas.CanvasGroup,
x=0.0,
y=0.0
)
if (self.tools[self.current_tool][0] == "DEL" or
self.tools[self.current_tool][0] == "SELECT" or
self.tools[self.current_tool][0] == "FILL"):
# This event is treated in del_item_event to avoid
# operating on background item and grid
return False
elif self.tools[self.current_tool][0] == "LINE":
x,y = self.snap_to_grid(event.x,event.y)
self.pos_x = x
self.pos_y = y
tuple_points = (x , y, self.pos_x, self.pos_y)
if self.gcomprisBoard.mode == 'draw':
dist = {'x' : 'width', 'y' : 'height'}
points = {}
for c in ['x', 'y']:
points[c + '1'] = eval(c) - self.draw_defaults_size['LINE'][dist[c]]/2
points[c + '2'] = eval(c) + self.draw_defaults_size['LINE'][dist[c]]/2
tuple_points = ( points['x1'], points['y1'], points['x2'], points['y2'])
# ItemGroup:
# AnchorsGroup
# ANCHOR_SE
# .....
# Item
self.newitem = self.newitemgroup.add(
gnomecanvas.CanvasLine,
points=tuple_points,
fill_color_rgba=self.colors[self.current_color],
width_units=8.0
)
elif self.tools[self.current_tool][0] == "RECT":
x,y = self.snap_to_grid(event.x,event.y)
self.pos_x = x
self.pos_y = y
points = {}
for c in ['x' , 'y']:
points[c + '1'] = eval(c)
points[c + '2'] = eval( 'self.pos_' + c )
if self.gcomprisBoard.mode == 'draw':
dist = {'x' : 'width', 'y' : 'height'}
points = {}
for c in ['x', 'y']:
points[c + '1'] = eval(c) - self.draw_defaults_size['LINE'][dist[c]]/2
points[c + '2'] = eval(c) + self.draw_defaults_size['LINE'][dist[c]]/2
self.newitem = self.newitemgroup.add(
gnomecanvas.CanvasRect,
x1=points['x1'],
y1=points['y1'],
x2=points['x2'],
y2=points['y2'],
outline_color_rgba=self.colors[self.current_color],
width_units=4.0
)
# self.newitem.set_data('empty',True)
gcompris.utils.canvas_set_property(self.newitem, "empty", "True")
elif self.tools[self.current_tool][0] == "FILL_RECT":
x,y = self.snap_to_grid(event.x,event.y)
self.pos_x = x
self.pos_y = y
points = {}
for c in ['x' , 'y']:
points[c + '1'] = eval(c)
points[c + '2'] = eval( 'self.pos_' + c )
if self.gcomprisBoard.mode == 'draw':
dist = {'x' : 'width', 'y' : 'height'}
points = {}
for c in ['x', 'y']:
points[c + '1'] = eval(c) - self.draw_defaults_size['LINE'][dist[c]]/2
points[c + '2'] = eval(c) + self.draw_defaults_size['LINE'][dist[c]]/2
self.newitem = self.newitemgroup.add(
gnomecanvas.CanvasRect,
x1=points['x1'],
y1=points['y1'],
x2=points['x2'],
y2=points['y2'],
fill_color=self.colors[self.current_color],
fill_color_rgba=self.colors[self.current_color],
outline_color_rgba=0x000000FFL,
width_units=1.0
)
elif self.tools[self.current_tool][0] == "CIRCLE":
x,y = self.snap_to_grid(event.x,event.y)
self.pos_x = x
self.pos_y = y
points = {}
for c in ['x' , 'y']:
points[c + '1'] = eval(c)
points[c + '2'] = eval( 'self.pos_' + c )
if self.gcomprisBoard.mode == 'draw':
dist = {'x' : 'width', 'y' : 'height'}
points = {}
for c in ['x', 'y']:
points[c + '1'] = eval(c) - self.draw_defaults_size['LINE'][dist[c]]/2
points[c + '2'] = eval(c) + self.draw_defaults_size['LINE'][dist[c]]/2
self.newitem = self.newitemgroup.add(
gnomecanvas.CanvasEllipse,
x1=points['x1'],
y1=points['y1'],
x2=points['x2'],
y2=points['y2'],
outline_color_rgba=self.colors[self.current_color],
width_units=5.0
)
# self.newitem.set_data('empty',True)
gcompris.utils.canvas_set_property(self.newitem, "empty", "True")
elif self.tools[self.current_tool][0] == "FILL_CIRCLE":
x,y = self.snap_to_grid(event.x,event.y)
self.pos_x = x
self.pos_y = y
points = {}
for c in ['x' , 'y']:
points[c + '1'] = eval(c)
points[c + '2'] = eval( 'self.pos_' + c )
if self.gcomprisBoard.mode == 'draw':
dist = {'x' : 'width', 'y' : 'height'}
points = {}
for c in ['x', 'y']:
points[c + '1'] = eval(c) - self.draw_defaults_size['LINE'][dist[c]]/2
points[c + '2'] = eval(c) + self.draw_defaults_size['LINE'][dist[c]]/2
self.newitem = self.newitemgroup.add(
gnomecanvas.CanvasEllipse,
x1=points['x1'],
y1=points['y1'],
x2=points['x2'],
y2=points['y2'],
fill_color_rgba=self.colors[self.current_color],
outline_color_rgba=0x000000FFL,
width_units=1.0
)
elif self.tools[self.current_tool][0] == "TEXT":
x,y = self.snap_to_grid(event.x,event.y)
self.pos_x = x
self.pos_y = y
self.newitem = self.newitemgroup.add(
gnomecanvas.CanvasText,
x=self.pos_x,
y=self.pos_y,
fill_color_rgba=self.colors[self.current_color],
font=gcompris.FONT_BOARD_BIG_BOLD,
text=u'?',
anchor=gtk.ANCHOR_CENTER
)
if self.newitem != 0:
self.anchorize(self.newitemgroup)
anAnimItem = self.AnimItem()
anAnimItem.z = self.new_z()
anAnimItem.canvas_item = self.newitem
anAnimItem.type = self.tools[self.current_tool][0]
anAnimItem.canvas_item.set_data("AnimItem", anAnimItem)
self.framelist.append(anAnimItem)
self.list_z_actual.append(anAnimItem.z)
self.draw_created_object = True
if self.tools[self.current_tool][0] == "TEXT":
(x1, x2, y1, y2) = self.get_bounds(self.newitem)
self.object_set_size_and_pos(self.newitemgroup, x1, x2, y1, y2)
self.select_item(self.newitemgroup)
self.newitem = None
self.newitemgroup = None
elif self.gcomprisBoard.mode == 'draw':
# needed because used to set the anchors.
# The item has already the right size
self.object_set_size_and_pos(self.newitemgroup,
x1=points['x1'],
y1=points['y1'],
x2=points['x2'],
y2=points['y2']
)
self.select_item(self.newitemgroup)
# in draw creation is finished. Object is selected.
self.newitem = None
self.newitemgroup = None
return True
#
# MOTION EVENT
# ------------
if event.type == gtk.gdk.MOTION_NOTIFY:
# That's used only in itel creation.
# In draw mode, item creation does not use drag&drop
if self.gcomprisBoard.mode == 'draw':
return False
if ((self.tools[self.current_tool][0] == "IMAGE") or
(self.tools[self.current_tool][0] == "TEXT")):
return False
if event.state & gtk.gdk.BUTTON1_MASK:
if (self.tools[self.current_tool][0] == "RAISE" or
self.tools[self.current_tool][0] == "LOWER"):
return False
x=event.x
y=event.y
x,y = self.snap_to_grid(event.x,event.y)
# Check drawing boundaries
if(event.xself.drawing_area[2]):
x=self.drawing_area[2]
if(event.yself.drawing_area[3]):
y=self.drawing_area[3]
# if self.tools[self.current_tool][0] == "LINE":
# self.newitem.set( points=( self.pos_x, self.pos_y, x, y) )
# elif (self.tools[self.current_tool][0] == "RECT" or
# self.tools[self.current_tool][0] == "FILL_RECT" or
# self.tools[self.current_tool][0] == "CIRCLE" or
# self.tools[self.current_tool][0] == "FILL_CIRCLE"):
# self.newitem.set(
# x2=x,
# y2=y)
if self.tools[self.current_tool][0] == "LINE":
points= self.newitem.get_property("points")
x1=points[0]
y1=points[1]
else:
x1=self.newitem.get_property("x1")
y1=self.newitem.get_property("y1")
self.object_set_size_and_pos(self.newitemgroup,
x1=x1,
y1=y1,
x2=x,
y2=y
)
#
# MOUSE DRAG STOP
# ---------------
if event.type == gtk.gdk.BUTTON_RELEASE:
# That's used only in item creation.
# In draw mode, item creation does not use drag&drop
if self.draw_created_object:
self.draw_created_object = False
return True
if ((self.tools[self.current_tool][0] == "IMAGE") or
(self.tools[self.current_tool][0] == "TEXT")):
return False
if event.button == 1:
if (self.tools[self.current_tool][0] == "RAISE" or
self.tools[self.current_tool][0] == "LOWER"):
return False
# We have to remove empty created items (the kid did not drag enough)
if self.tools[self.current_tool][0] == "LINE":
# need to delete empty line. self.newitem est l'objet courant
pass
elif (self.tools[self.current_tool][0] == "RECT" or
self.tools[self.current_tool][0] == "FILL_RECT" or
self.tools[self.current_tool][0] == "CIRCLE" or
self.tools[self.current_tool][0] == "FILL_CIRCLE"):
# Oups, empty rect
#self.del_item(self.newitem)
pass
# print self.tools[self.current_tool][0]
# print self.newitem.get_bounds()
# print self.newitemgroup.get_bounds()
return True
return False
def snapshot_event(self, item, event):
if event.type == gtk.gdk.BUTTON_PRESS:
self.Anim2Shot()
def run_flash(self):
self.flash.hide()
return False
def playing_start(self):
if not self.running:
self.running=True
self.root_coloritem.hide()
self.root_toolitem.hide()
self.root_playingitem.show()
self.Anim2Run()
def playing_event(self, item, event, state):
if event.type == gtk.gdk.BUTTON_PRESS:
if state:
self.playing_start()
else:
self.playing_stop()
# Display the animation tools
def draw_animtools(self):
# Desactived for the moment
x_left = 8
y_top = 472
minibutton_width = 32
minibutton_height = 20
if self.gcomprisBoard.mode == 'draw':
return
# Draw the background area
self.rootitem.add(
gnomecanvas.CanvasPixbuf,
pixbuf = gcompris.utils.load_pixmap(gcompris.skin.image_to_skin("draw/counter.png")),
x=x_left - -11,
y=y_top - 2,
width=70.0,
height=34.0,
width_set=True,
height_set=True
)
# First
#item = self.rootitem.add(
# gnomecanvas.CanvasPixbuf,
# pixbuf = gcompris.utils.load_pixmap(gcompris.skin.image_to_skin("anim/minibutton.png")),
# x = x_left,
# y = y_top,
# )
#item.connect("event", self.image_select_event, "first")
#item = self.rootitem.add(
# gnomecanvas.CanvasText,
# text = "<<",
# x = x_left + 14,
# y = y_top + 7,
# )
#item.connect("event", self.image_select_event, "first")
# Image Number
self.item_frame_counter = self.rootitem.add(
gnomecanvas.CanvasText,
text = self.current_frame + 1,
x = x_left + minibutton_width + 14,
y = y_top + 15,
font = gcompris.skin.get_font("gcompris/board/medium"))
# Last
#item = self.rootitem.add(
# gnomecanvas.CanvasPixbuf,
# pixbuf = gcompris.utils.load_pixmap(gcompris.skin.image_to_skin("anim/minibutton.png")),
# x = x_left + 2*minibutton_width,
# y = y_top,
# )
#item.connect("event", self.image_select_event, "last")
#item = self.rootitem.add(
# gnomecanvas.CanvasText,
# text = ">>",
# x = x_left + 2*minibutton_width + 14,
# y = y_top + 7,
# )
#item.connect("event", self.image_select_event, "last")
# Next line
#y_top += minibutton_height
# Previous
#item = self.rootitem.add(
# gnomecanvas.CanvasPixbuf,
# pixbuf = gcompris.utils.load_pixmap(gcompris.skin.image_to_skin("anim/minibutton.png")),
# x = x_left,
# y = y_top,
# )
#item.connect("event", self.image_select_event, "previous")
##item = self.rootitem.add(
# gnomecanvas.CanvasText,
# text = "<",
# x = x_left + 14,
# y = y_top + 7,
# )
#item.connect("event", self.image_select_event, "previous")
# Next
#item = self.rootitem.add(
# gnomecanvas.CanvasPixbuf,
# pixbuf = gcompris.utils.load_pixmap(gcompris.skin.image_to_skin("anim/minibutton.png")),
# x = x_left + 2*minibutton_width,
# y = y_top,
# )
#item.connect("event", self.image_select_event, "next")
#item = self.rootitem.add(
# gnomecanvas.CanvasText,
# text = ">",
# x = x_left + 2*minibutton_width + 14,
# y = y_top + 7,
# )
#item.connect("event", self.image_select_event, "next")
# Last button line
#y_top += minibutton_height
def object_move(self,object,dx,dy):
# Unfortunately object.move is broken for 'TEXT' group.
if gobject.type_name(object.item_list[0])=="GnomeCanvasText":
(x1,y1,x2,y2) = object.get_bounds()
(idx, idy) = object.w2i( dx, dy )
self.object_set_size_and_pos(object, x1+idx, y1+idy, x2+idx, y2+idy)
else:
object.move(dx, dy)
def object_set_size_and_pos(self, object, x1, y1, x2, y2):
if gobject.type_name(object.item_list[0])=="GnomeCanvasLine":
object.item_list[0].set(
points=(x1,y1,x2,y2)
)
elif gobject.type_name(object.item_list[0])=="GnomeCanvasPixbuf":
object.item_list[0].set(
x=x1,
y=y1,
width=x2-x1,
height=y2-y1
)
elif gobject.type_name(object.item_list[0])=="GnomeCanvasText":
object.item_list[0].set(
x=(x1+x2)/2,
y=(y1+y2)/2
)
else:
object.item_list[0].set(
x1=x1,
x2=x2,
y1=y1,
y2=y2
)
for anchor in object.item_list[1].item_list:
anchor_type = anchor.get_data('anchor_type')
if anchor_type == self.ANCHOR_N:
anchor.set(
x1= (x1 + x2 - self.DEFAULT_ANCHOR_SIZE)/2,
x2= (x1 + x2 + self.DEFAULT_ANCHOR_SIZE)/2,
y1= y2,
y2= y2 + self.DEFAULT_ANCHOR_SIZE
)
elif anchor_type == self.ANCHOR_T:
anchor.set(
x1= (x1 + x2 - self.DEFAULT_ANCHOR_SIZE*3)/2,
x2= (x1 + x2 + self.DEFAULT_ANCHOR_SIZE*3)/2,
y1= y2,
y2= y2 + self.DEFAULT_ANCHOR_SIZE
)
elif anchor_type == self.ANCHOR_NE:
anchor.set(
x1= x2,
x2= x2 + self.DEFAULT_ANCHOR_SIZE,
y1= y2,
y2= y2 + self.DEFAULT_ANCHOR_SIZE
)
elif anchor_type == self.ANCHOR_E:
anchor.set(
x1= x2,
x2= x2 + self.DEFAULT_ANCHOR_SIZE,
y1= (y1 + y2 - self.DEFAULT_ANCHOR_SIZE)/2,
y2= (y1 + y2 + self.DEFAULT_ANCHOR_SIZE)/2
)
elif anchor_type == self.ANCHOR_SE:
anchor.set(
x1= x2,
x2= x2 + self.DEFAULT_ANCHOR_SIZE,
y1= y1,
y2= y1 - self.DEFAULT_ANCHOR_SIZE
)
elif anchor_type == self.ANCHOR_S:
anchor.set(
x1= (x1 + x2 - self.DEFAULT_ANCHOR_SIZE)/2,
x2= (x1 + x2 + self.DEFAULT_ANCHOR_SIZE)/2,
y1= y1,
y2= y1 - self.DEFAULT_ANCHOR_SIZE
)
elif anchor_type == self.ANCHOR_SW:
anchor.set(
x1= x1,
x2= x1 - self.DEFAULT_ANCHOR_SIZE,
y1= y1,
y2= y1 - self.DEFAULT_ANCHOR_SIZE
)
elif anchor_type == self.ANCHOR_W:
anchor.set(
x1= x1,
x2= x1 - self.DEFAULT_ANCHOR_SIZE,
y1= (y1 + y2 - self.DEFAULT_ANCHOR_SIZE)/2,
y2= (y1 + y2 + self.DEFAULT_ANCHOR_SIZE)/2,
)
elif anchor_type == self.ANCHOR_NW:
anchor.set(
x1= x1,
x2= x1 - self.DEFAULT_ANCHOR_SIZE,
y1= y2,
y2= y2 + self.DEFAULT_ANCHOR_SIZE
)
def resize_item_event(self, item, event, anchor_type):
if self.running:
return
# Right button is a shortcup to Shot
if event.type == gtk.gdk.BUTTON_PRESS and event.button == 3:
self.Anim2Shot()
return False
if event.state & gtk.gdk.BUTTON1_MASK:
# warning: anchor is in a group of anchors, which is in the object group
parent=item.get_property("parent").get_property("parent")
real_item=parent.item_list[0]
wx=event.x
wy=event.y
#passing x, y to item relative coordinate
(x,y)= item.w2i(wx,wy)
if gobject.type_name(real_item)=="GnomeCanvasLine":
points= real_item.get_property("points")
x1=points[0]
y1=points[1]
x2=points[2]
y2=points[3]
elif gobject.type_name(real_item)=="GnomeCanvasPixbuf":
x1=real_item.get_property("x")
y1=real_item.get_property("y")
x2=x1+real_item.get_property("width")
y2=y1+real_item.get_property("height")
elif gobject.type_name(real_item)=="GnomeCanvasText":
y1=y
y2=y+real_item.get_property("text_height")
pass
else:
x1=real_item.get_property("x1")
y1=real_item.get_property("y1")
x2=real_item.get_property("x2")
y2=real_item.get_property("y2")
if (anchor_type == self.ANCHOR_N):
self.object_set_size_and_pos(parent,
x1=x1,
y1=y1,
x2=x2,
y2=y
)
elif (anchor_type == self.ANCHOR_T):
self.object_set_size_and_pos(parent,
x1=x,
y1=y1,
x2=x,
y2=y2
)
elif (anchor_type == self.ANCHOR_NE):
self.object_set_size_and_pos(parent,
x1=x1,
y1=y1,
x2=x,
y2=y
)
elif (anchor_type == self.ANCHOR_E):
self.object_set_size_and_pos(parent,
x1=x1,
y1=y1,
x2=x,
y2=y2
)
elif (anchor_type == self.ANCHOR_SE):
self.object_set_size_and_pos(parent,
x1=x1,
y1=y,
x2=x,
y2=y2
)
elif (anchor_type == self.ANCHOR_S):
self.object_set_size_and_pos(parent,
x1=x1,
y1=y,
x2=x2,
y2=y2
)
elif (anchor_type == self.ANCHOR_SW):
self.object_set_size_and_pos(parent,
x1=x,
y1=y,
x2=x2,
y2=y2
)
elif (anchor_type == self.ANCHOR_W):
self.object_set_size_and_pos(parent,
x1=x,
y1=y1,
x2=x2,
y2=y2
)
elif (anchor_type == self.ANCHOR_NW):
self.object_set_size_and_pos(parent,
x1=x,
y1=y1,
x2=x2,
y2=y
)
def get_bounds(self, item):
if gobject.type_name(item)=="GnomeCanvasLine":
(x1,y1,x2,y2)=item.get_property("points")
elif gobject.type_name(item)=="GnomeCanvasPixbuf":
x1=item.get_property("x")
y1=item.get_property("y")
x2=item.get_property("x")+item.get_property("width")
y2=item.get_property("y")+item.get_property("height")
elif gobject.type_name(item)=="GnomeCanvasText":
x=item.get_property("x")
y=item.get_property("y")
width=item.get_property("text_width")
height=item.get_property("text_height")
x1=x-width/2
y1=y-height/2
x2=x1+width
y2=y1+height
else:
x1=item.get_property("x1")
y1=item.get_property("y1")
x2=item.get_property("x2")
y2=item.get_property("y2")
return (min(x1,x2),min(y1,y2),max(x1,x2),max(y1,y2))
def item_type(self, item):
item_type = ''
if gobject.type_name(item)=="GnomeCanvasGroup":
item_type='GROUP'
elif gobject.type_name(item)=="GnomeCanvasLine":
item_type='LINE'
elif gobject.type_name(item)=="GnomeCanvasPixbuf":
item_type='IMAGE'
elif gobject.type_name(item)=="GnomeCanvasRect":
try:
# Can't do it here because it needs to be C compatible for the svgexport
empty = gcompris.utils.canvas_get_property(item, "empty")
#empty = item.get_data('empty')
if empty == None:
empty = Fale
else:
empty = True
# empty is passed from C, not python object
# if we get it that means is True
except:
empty = False
if empty:
item_type='RECT'
else:
item_type='FILL_RECT'
elif gobject.type_name(item)=="GnomeCanvasEllipse":
try:
#empty = item.get_data('empty')
# Can't do it here because it needs to be C compatible for the svgexport
empty = gcompris.utils.canvas_get_property(item, "empty")
if empty == None:
empty = Fale
else:
empty = True
# empty is passed from C, not python object
# if we get it that means is True
except:
empty = False
if empty:
item_type='CIRCLE'
else:
item_type='FILL_CIRCLE'
elif gobject.type_name(item)=="GnomeCanvasText":
item_type='TEXT'
return item_type
#
# Call anchorize recursively on each item of the group
#
def recursive_anchorize(self, root_item):
for item in root_item.item_list:
if gobject.type_name(item)=="GnomeCanvasGroup":
self.recursive_anchorize(item)
else:
self.anchorize(item.get_property("parent"))
#
# Add the anchors and callbacks on an item
#
def anchorize(self, group):
# group contains normal items.
item = group.item_list[0]
item_type = self.item_type(item)
if item_type == "GROUP" or not item_type:
return
for event in self.events[item_type]:
item.connect("event", event)
anchorgroup=group.add(
gnomecanvas.CanvasGroup,
x=0,
y=0
)
anchorgroup.set_data('anchors',True)
anchorgroup.hide()
for anchor_type in self.anchors[item_type]:
anchor=anchorgroup.add(
gnomecanvas.CanvasRect,
fill_color_rgba=self.ANCHOR_COLOR,
outline_color_rgba=0x000000FFL,
width_pixels=1,
)
anchor.set_data('anchor_type', anchor_type)
anchor.connect("event", self.resize_item_event,anchor_type)
def select_item(self, group):
if (self.selected != None):
self.unselect()
# Deactivate old button
self.old_tool_item.set(pixbuf = gcompris.utils.load_pixmap(gcompris.skin.image_to_skin(self.tools[self.current_tool][1])))
# Activate new button
self.current_tool = self.select_tool_number
self.old_tool_item = self.select_tool
self.old_tool_item.set(pixbuf = gcompris.utils.load_pixmap(gcompris.skin.image_to_skin(self.tools[self.current_tool][2])))
gcompris.set_cursor(self.tools[self.current_tool][3]);
self.selected = group
self.selected.item_list[1].show()
def rotate_relative(self, item, angle):
bounds = item.get_bounds()
# print "Item bounds : ", bounds
#bds = item.get_property("parent").get_bounds()
# print "Item parent bounds : ", bounds
(cx, cy) = ( (bounds[2]+bounds[0])/2 , (bounds[3]+bounds[1])/2)
t = math.radians(angle)
# This matrix rotate around ( cx, cy )
# This is the result of the product:
# T_{-c} Rot (t) T_c
# 1 0 cx cos(t) -sin(t) 0 1 0 -cx
# 0 1 cy by sin(t) cos(t) 0 by 0 1 -cy
# 0 0 1 0 0 1 0 0 1
mat = ( math.cos(t),
math.sin(t),
-math.sin(t),
math.cos(t),
(1-math.cos(t))*cx + math.sin(t)*cy,
-math.sin(t)*cx + (1 - math.cos(t))*cy)
item.get_property("parent").affine_relative(mat)
return
def item_flip(self, item):
bounds = self.get_bounds(item)
(cx, cy) = ( (bounds[2]+bounds[0])/2 , (bounds[3]+bounds[1])/2)
mat = ( -1, 0, 0, 1, 2*cx, 0)
item.get_property("parent").affine_relative(mat)
###########################################
# Anim 2 specific
###########################################
class AnimItem:
def __init__(self):
self.z = None
self.frames_info = {}
self.canvas_item = None
self.z_previous = None
def new_z(self):
if self.list_z_actual != []:
return int(self.list_z_actual[-1] + 1 )
else:
return 1
def del_AnimItem(self, AnimItem):
# AnimItem is really deleted only on shot.
self.list_z_actual.remove(AnimItem.z)
AnimItem.z = None
#AnimItem.frames_info[self.current_frame]['deleted']=True
def z_raise(self, anAnimItem):
index = self.list_z_actual.index(anAnimItem.z)
if index < len(self.list_z_actual) -1 :
if index < len(self.list_z_actual) - 2 :
anAnimItem.z = (self.list_z_actual[index + 1] + self.list_z_actual[index + 2])/2.0
else:
anAnimItem.z = self.list_z_actual[-1] + 1
self.list_z_actual.pop(index)
self.list_z_actual.insert(index+1, anAnimItem.z)
def z_lower(self, anAnimItem):
index = self.list_z_actual.index(anAnimItem.z)
if index > 0:
if index > 1:
anAnimItem.z = (self.list_z_actual[index - 1] + self.list_z_actual[index - 2])/2.0
else:
anAnimItem.z = self.list_z_actual[0] /2.0
self.list_z_actual.pop(index)
self.list_z_actual.insert(index-1, anAnimItem.z)
# Version 2: compare attributs and put those with difference in frames_info
#
# self.attributs is list of specific attributs usable for animation
# There is matrice (rotation, flip) and z position to check too
def get_animitem_properties(self, anAnimItem):
properties = {'matrice' : anAnimItem.canvas_item.i2c_affine((0,0,0,0,0,0)) }
for property_name in self.attributs[anAnimItem.type]:
properties [property_name] = anAnimItem.canvas_item.get_property(property_name)
if property_name == 'text':
properties [property_name] = properties [property_name].decode('UTF-8')
return properties
def z_reinit(self):
for anAnimItem in self.framelist:
anAnimItem.z = self.list_z_actual.index(anAnimItem.z)+1
anAnimItem.z_previous = anAnimItem.z
self.list_z_last_shot= range(1, len(self.list_z_actual) + 1)
self.list_z_actual=self.list_z_last_shot[:]
def z_delete_on_shot(self, anAnimItem):
if anAnimItem.z_previous != None:
self.list_z_last_shot.remove(anAnimItem.z_previous)
def get_modified_parameters(self, animItem):
modified= {}
dict_properties = self.get_animitem_properties(animItem)
frames = animItem.frames_info.keys()
if frames != []:
frames.sort()
frames.reverse()
for property in dict_properties.keys():
for frame in frames:
# print animItem.type, property, frame, animItem.frames_info[frame]
if animItem.frames_info[frame].has_key(property):
if not animItem.frames_info[frame][property]==dict_properties[property]:
modified[property]=dict_properties[property]
break
else:
modified = dict_properties
modified.update(self.fixedattributs[animItem.type])
if animItem.type == 'IMAGE':
modified['image_name']= animItem.image_name
modified['create']=True
self.animlist.append(animItem)
if animItem.z != animItem.z_previous:
if animItem.z_previous != None:
self.list_z_last_shot.remove(animItem.z_previous)
modified['z'] = self.z_find_index(animItem)
self.list_z_last_shot.insert( modified['z'], animItem.z)
return modified
def Anim2Shot(self):
if self.gcomprisBoard.mode == 'draw':
return
self.flash.show()
for anAnimItem in self.framelist[:]:
if anAnimItem.z == None:
# deleted
self.z_delete_on_shot(anAnimItem)
modified = { 'delete': True }
self.framelist.remove(anAnimItem)
if self.animlist.count(anAnimItem) == 0:
# deleted without being in any shot
continue
else:
#
modified = self.get_modified_parameters(anAnimItem)
if len(modified) != 0:
anAnimItem.frames_info[self.current_frame] = modified
#
self.current_frame = self.current_frame + 1
self.frames_total = self.current_frame
self.z_reinit()
self.item_frame_counter.set(text=self.current_frame + 1)
# print self.current_frame + 1
self.timeout = gobject.timeout_add(500, self.run_flash)
def z_find_index(self, anAnimItem):
def f(x): return x < anAnimItem.z
return len(filter(f, self.list_z_last_shot))
# self.z_reinit()
# def anim2Run(self):
def apply_frame(self, frame):
for item in self.playlist:
if not item.frames_info.has_key(frame):
continue
modif = item.frames_info[frame].copy()
if modif.has_key('delete'):
item.canvas_item.destroy()
continue
if modif.has_key('create'):
del modif['create']
z = modif['z']
del modif['z']
matrice = modif['matrice']
del modif['matrice']
if item.type == 'IMAGE':
image = modif['image_name']
del modif['image_name']
pixmap = gcompris.utils.load_pixmap(image)
modif['pixbuf']= pixmap
item.canvas_item = self.playing.add(self.types[item.type], **modif)
delta = len(self.playing.item_list) - z -1
if delta != 0:
item.canvas_item.lower(delta)
item.canvas_item.affine_absolute(matrice)
continue
else:
if modif.has_key('z'):
z = modif['z']
del modif['z']
index = self.playing.item_list.index(item.canvas_item)
if index > z:
item.canvas_item.lower(index - z)
else:
item.canvas_item.raise_(z - index)
if modif.has_key('matrice'):
matrice = modif['matrice']
del modif['matrice']
item.canvas_item.affine_absolute(matrice)
if len(modif) != 0:
item.canvas_item.set(**modif)
def run_anim2(self):
if self.running:
if self.current_frame==0:
self.playing.destroy()
self.playing = self.rootitem.add(
gnomecanvas.CanvasGroup,
x=0.0,
y=0.0
)
self.apply_frame((self.current_frame)%(self.frames_total))
self.current_frame=(self.current_frame+1)%(self.frames_total)
self.item_frame_counter.set(text=self.current_frame + 1)
else:
self.playing.destroy()
self.current_frame = self.frames_total
self.item_frame_counter.set(text=self.current_frame + 1)
self.root_anim.show()
self.root_coloritem.show()
self.root_toolitem.show()
self.root_playingitem.hide()
gcompris.bar_hide(False)
return self.running
def Anim2Run(self):
gcompris.bar_hide(True)
if self.frames_total==0:
#print "Mmm... Need to make shots before run anim !!"
self.running=False
return
# Hide the current drawing
self.root_anim.hide()
self.playing = self.root_anim.add(
gnomecanvas.CanvasGroup,
x=0.0,
y=0.0
)
self.playlist = []
for aItem in self.animlist:
playItem = self.AnimItem()
playItem.frames_info = aItem.frames_info.copy()
playItem.type = aItem.type
self.playlist.append(playItem)
# Show the first drawing
self.apply_frame(0)
self.current_frame = 0
self.timeout=gobject.timeout_add(1000/self.anim_speed, self.run_anim2)
def unselect(self):
if not self.selected:
return
if ((gobject.type_name(self.selected.item_list[0])=="GnomeCanvasText")
and
(self.last_commit != None)):
#suppress preedit
self.selected.item_list[0].set(markup=self.last_commit)
self.last_commit = None
gcompris.im_reset()
self.selected.item_list[1].hide()
self.selected = None
###############################################
#
# GLOBAL functions
#
###############################################
def general_save(filename, filetype):
global fles
fles.z_reinit()
#print "general_save : ", filename, " type ",filetype
if filetype == None:
filetype = filename.split('.')[-1]
if (filetype in ['image/svg+xml+javascript','image/svg+xml']):
anim2_to_svg(filename)
return
if (filetype in ['image/gcompris+anim','image/gcompris+draw']):
anim2_to_file(filename)
return
#print "Error File selector return unknown filetype :",'|' + filetype + '|', "!!!"
def general_restore(filename, filetype):
#print "general_restore : ", filename, " type ",filetype
if filetype == None:
filetype = filename.split('.')[-1]
# Determine the file format by reading the first line
file = open(filename, 'r')
line = file.read(24)
file.close();
filetype = ""
if(line == "UGCompris draw 2 cPikle"
or line == "UGCompris anim 2 cPikle"):
filetype = 'image/gcompris+anim'
elif(line == " item.z:
item.canvas_item.get_property("parent").lower(index - item.z)
else:
item.canvas_item.get_property("parent").raise_(item.z - index)
if modif.has_key('matrice'):
matrice = modif['matrice']
del modif['matrice']
item.canvas_item.get_property("parent").affine_absolute(matrice)
if len(modif) != 0:
# Bourrin: je supprime les ancres et je les remets apres les modifs
# Pas envie de me faire ch*** a retraiter les resize et les move
#item.canvas_item.get_property("parent").item_list[1].destroy()
item.canvas_item.set(**modif)
#fles.anchorize(item.canvas_item.get_property("parent"))
return True
##############################################
#
# SVG anim 2 export
#
##############################################
def anim2_to_svg(filename):
processor_class = DOMProcess
outfp = open(filename,'w')
processor = processor_class(outfp)
processor.run()
outfp.close()
class BaseProcess:
"""Base class for the conversion processors. Each concrete subclass
must provide the following methods:
initOutput()
Initialize the output stream and any internal data structures
that the conversion process needs.
addRecord(lname, fname, type)
Add one record to the output stream (or the internal structures)
where lname is the last name, fname is the first name, and type
is either 'manager' or 'employee'.
finishOutput()
Finish all output generation. If all work has been on internal
data structures, this is where they should be converted to text
and written out.
"""
def __init__(self, outfp):
"""Store the input and output streams for later use."""
self.types = { 'RECT' : 'rect',
'FILL_RECT' : 'rect',
'CIRCLE' : 'ellipse',
'FILL_CIRCLE' : 'ellipse',
'TEXT' : 'text',
'IMAGE' : 'use',
'LINE' : 'line'
}
global fles
self.outfp = outfp
self.images_list = {}
self.frames_total = fles.frames_total
# save the list into
self.list_to = []
# get the list
self.list_from = []
if (fles.gcomprisBoard.mode == 'draw'):
# in draw we need to get the list in z order, because of svg.
def get_item_at(z):
for item in eval('fles.' + fles.itemlist[fles.gcomprisBoard.mode]):
if item.z == z: return item
for z in fles.list_z_actual:
self.list_from.append(get_item_at(z))
# now each item needs to get it's frames_info updated
for anAnimItem in self.list_from[:]:
modified = fles.get_modified_parameters(anAnimItem)
if len(modified) != 0:
anAnimItem.frames_info[fles.current_frame] = modified
else:
self.list_from = fles.animlist
for item in self.list_from:
frames_info_copied = {}
for t, d in item.frames_info.iteritems():
frames_info_copied[t] = d.copy();
Sitem = [ item.type, frames_info_copied]
list_frames = Sitem[1].keys()
list_frames.sort()
# if ((Sitem[0] == 'TEXT') and (Sitem[1][list_frames[0]].has_key('anchor'))):
# Sitem[1][list_frames[0]]['text-anchor']='middle'
# del Sitem[1][list_frames[0]]['anchor']
self.list_to.append(Sitem)
def get_last_rectel_bounds(self, item, frame_no):
listkeys = item[1].keys()
listkeys.sort()
def f(x): return x < frame_no
#print "rectel last", item, frame_no, filter(f,listkeys)
for frame in filter(f,listkeys):
if item[1][frame].has_key('x1'):
x1 = item[1][frame]['x1']
if item[1][frame].has_key('x2'):
x2 = item[1][frame]['x2']
if item[1][frame].has_key('y1'):
y1 = item[1][frame]['y1']
if item[1][frame].has_key('y2'):
y2 = item[1][frame]['y2']
return (x1,y1,x2,y2)
def get_last_line_points(self, item, frame_no):
listkeys = item[1].keys()
listkeys.sort()
def f(x): return x < frame_no
for frame in filter(f,listkeys):
if item[1][frame].has_key('points'):
points = item[1][frame]['points']
return points
def rgb_write(self, rgba):
red = int ( ( rgba >> 24 ) & 255 )
green = int ( ( rgba >> 16 ) & 255 )
blue = int ( ( rgba >> 8 ) & 255 )
return 'rgb(' + str(red) +',' + str(green) + ',' + str(blue) + ')'
def run(self):
"""Perform the complete conversion process.
This method is responsible for parsing the input and calling the
subclass-provided methods in the right order.
"""
self.initOutput()
global fles
for item in self.list_to:
self.element = self.document.createElement(self.types[item[0]])
self.svg.appendChild(self.element)
listkeys = item[1].keys()
listkeys.sort()
for frame_no in listkeys:
# if draw there is only one key.
# in this case parameters are put in self.element
# and not in self.frame
if fles.gcomprisBoard.mode == 'draw':
self.frame = self.element
else:
self.frame = self.document.createElement("gcompris:frame")
self.frame.setAttribute('time',str(frame_no))
self.element.appendChild(self.frame)
for attr in item[1][frame_no].keys():
if (self.types[item[0]] == 'rect'):
if (item[0] == 'RECT') and item[1][frame_no].has_key('create'):
self.frame.setAttribute('fill', 'none')
if (attr == 'x2'):
if item[1][frame_no].has_key('x1'):
self.frame.setAttribute('width', str(item[1][frame_no]['x2']-item[1][frame_no]['x1']))
else:
points = self.get_last_rectel_bounds(item, frame_no)
self.frame.setAttribute('width', str(item[1][frame_no]['x2']- points[0]))
continue
if (attr == 'y2'):
if item[1][frame_no].has_key('y1'):
self.frame.setAttribute('height', str(item[1][frame_no]['y2']-item[1][frame_no]['y1']))
else:
points = self.get_last_rectel_bounds(item, frame_no)
self.frame.setAttribute('height', str(item[1][frame_no]['y2']- points[1]))
continue
if (attr == 'x1'):
self.frame.setAttribute('x', str(item[1][frame_no]['x1']))
if not item[1][frame_no].has_key('x2'):
points = self.get_last_rectel_bounds(item, frame_no)
self.frame.setAttribute('width', str( - item[1][frame_no]['x1'] + points[2]))
continue
if (attr == 'y1'):
self.frame.setAttribute('y', str(item[1][frame_no]['y1']))
if not item[1][frame_no].has_key('y2'):
points = self.get_last_rectel_bounds(item, frame_no)
self.frame.setAttribute('width', str( - item[1][frame_no]['y1']+ points[3]))
continue
if (attr == 'fill_color_rgba'):
self.frame.setAttribute(
'fill',
self.rgb_write(item[1][frame_no]['fill_color_rgba']))
continue
if (attr == 'outline_color_rgba'):
self.frame.setAttribute(
'stroke',
self.rgb_write(item[1][frame_no]['outline_color_rgba']))
continue
if (attr == 'width-units'):
self.frame.setAttribute(
'stroke-width',
str(item[1][frame_no]['width-units']))
continue
if (self.types[item[0]] == 'ellipse'):
if (attr == 'width-units'):
self.frame.setAttribute(
'stroke-width',
str(item[1][frame_no]['width-units']))
continue
if (attr == 'outline_color_rgba'):
self.frame.setAttribute(
'stroke',
self.rgb_write(item[1][frame_no]['outline_color_rgba']))
continue
if (item[0] == 'CIRCLE') and item[1][frame_no].has_key('create'):
self.frame.setAttribute('fill', 'none')
if (attr == 'fill_color_rgba'):
self.frame.setAttribute(
'fill',
self.rgb_write(item[1][frame_no]['fill_color_rgba']))
continue
if (attr == 'x2'):
if item[1][frame_no].has_key('x1'):
cx = (item[1][frame_no]['x2']+item[1][frame_no]['x1'])/2
else:
points = self.get_last_rectel_bounds(item, frame_no)
cx = (item[1][frame_no]['x2']+ points[0])/2
rx = item[1][frame_no]['x2']-cx
self.frame.setAttribute('cx',str(cx))
self.frame.setAttribute('rx',str(rx))
continue
if (attr == 'x1'):
if item[1][frame_no].has_key('x2'):
continue
else:
points = self.get_last_rectel_bounds(item, frame_no)
cx = (item[1][frame_no]['x1']+ points[2])/2
rx = cx - item[1][frame_no]['x1']
self.frame.setAttribute('cx',str(cx))
self.frame.setAttribute('rx',str(rx))
continue
if (attr == 'y2'):
if item[1][frame_no].has_key('y1'):
cy = (item[1][frame_no]['y2']+item[1][frame_no]['y1'])/2
else:
points = self.get_last_rectel_bounds(item, frame_no)
cy = (item[1][frame_no]['y2']+ points[1])/2
ry = item[1][frame_no]['y2']-cy
self.frame.setAttribute('cy',str(cy))
self.frame.setAttribute('ry',str(ry))
continue
if (attr == 'y1'):
if item[1][frame_no].has_key('y2'):
continue
else:
points = self.get_last_rectel_bounds(item, frame_no)
cy = (item[1][frame_no]['y1']+ points[3])/2
ry = cy - item[1][frame_no]['y1']
self.frame.setAttribute('cy',str(cy))
self.frame.setAttribute('ry',str(ry))
continue
if (self.types[item[0]] == 'line'):
if (attr == 'fill_color_rgba'):
self.frame.setAttribute(
'stroke',
self.rgb_write(item[1][frame_no]['fill_color_rgba']))
continue
if (attr == 'width-units'):
self.frame.setAttribute(
'stroke-width',
str(item[1][frame_no]['width-units']))
continue
if (attr == 'points'):
if item[1][frame_no].has_key('create'):
self.frame.setAttribute('x1', str(item[1][frame_no]['points'][0]))
self.frame.setAttribute('y1', str(item[1][frame_no]['points'][1]))
self.frame.setAttribute('x2', str(item[1][frame_no]['points'][2]))
self.frame.setAttribute('y2', str(item[1][frame_no]['points'][3]))
else:
last_points = self.get_last_line_points(item, frame_no)
points = item[1][frame_no]['points']
if points[0] != last_points[0]:
self.frame.setAttribute('x1', str(points[0]))
if points[1] != last_points[1]:
self.frame.setAttribute('y1', str(points[1]))
if points[2] != last_points[2]:
self.frame.setAttribute('x2', str(points[2]))
if points[3] != last_points[3]:
self.frame.setAttribute('y2',str( points[3]))
continue
if (self.types[item[0]] == 'text'):
if (attr == 'fill_color_rgba'):
self.frame.setAttribute(
'fill',
self.rgb_write(item[1][frame_no]['fill_color_rgba']))
continue
if (attr == 'anchor'):
self.frame.setAttribute(
'text-anchor',
'middle')
continue
# if (attr == 'text'):
# self.frame.appendChild(self.document.createTextNode(item[1][frame_no]['text'].encode('UTF-8')))
# continue
if ( attr == 'font' ):
font = item[1][frame_no]['font']
list = font.split()
self.frame.setAttribute(
'font-size',list[-1] + 'pt')
self.frame.setAttribute(
'font-family',list[0] + ' ' + list[1])
if (item[0] == 'IMAGE'):
if (attr == 'image_name'):
image_name=item[1][frame_no]['image_name']
list_image_name = image_name.split('/')
if self.images_list.has_key(image_name):
self.element.setAttribute(
'xlink:href',self.images_list[image_name])
else:
self.symbol = self.document.createElement('symbol')
self.defel.appendChild(self.symbol)
self.image = self.document.createElement('image')
self.symbol.appendChild(self.image)
self.symbol.setAttribute(
'id', 'image' + str(len(self.images_list)))
self.element.setAttribute(
'xlink:href', '#image' + str(len(self.images_list)))
self.images_list[image_name]= 'image' + str(len(self.images_list))
# Base64 included image, to get all in one file
#
# that's dirty, but i want something simple for kids
#
# anyway image can be used multiple time,
# it will be included only once
#
# Maybe put file and image in same directory ?
#
imagefile = open(gcompris.DATA_DIR + '/' + image_name)
base64string = base64.encodestring(imagefile.read())
self.image.setAttribute(
'xlink:href','data:image/png;base64,' + base64string)
# get real size of the image.
pixmap = gcompris.utils.load_pixmap(image_name)
width = pixmap.get_width()
height = pixmap.get_height()
# Pass the with image included.
self.image.setAttribute(
'x','0')
self.image.setAttribute(
'y','0')
self.image.setAttribute(
'width', str(width))
self.image.setAttribute(
'height',str(height))
self.symbol.setAttribute(
'viewBox','0 0 '+ str(width) + ' ' + str(height))
self.symbol.setAttribute(
'preserveAspectRatio','none')
self.gcompris_name = self.document.createElement('gcompris:image_name')
# Pass the image_name info in private child
self.image.appendChild(self.gcompris_name)
self.gcompris_name.setAttribute('value',image_name)
continue
if ((attr == 'height_set') or (attr == 'width_set')):
continue
if (attr == 'matrice'):
self.frame.setAttribute(
'transform',
'matrix' + str(item[1][frame_no]['matrice']))
continue
if fles.gcomprisBoard.mode == 'draw':
if (attr != 'create'):
self.frame.setAttribute(attr,str(item[1][frame_no][attr]))
else:
self.frame.setAttribute(attr,str(item[1][frame_no][attr]))
self.finishOutput()
class DOMProcess(BaseProcess):
"""Concrete conversion process which uses a DOM structure as an
internal data structure.
Content is added to the DOM tree for each input record, and the
entire tree is serialized and written to the output stream in the
finishOutput() method.
"""
def initOutput(self):
global fles
# Create a new document with no namespace uri, qualified name,
# or document type
self.document = implementation.createDocument(None,None,None)
self.svg = self.document.createElement("svg")
self.svg.setAttribute("id","svgroot")
self.svg.setAttribute("width","800")
self.svg.setAttribute("height","550")
self.svg.setAttribute("version","1.1")
self.svg.setAttribute("xmlns","http://www.w3.org/2000/svg")
self.svg.setAttribute("xmlns:xlink","http://www.w3.org/1999/xlink")
self.svg.setAttribute("xmlns:html","http://www.w3.org/1999/xhtml")
self.svg.setAttribute("xmlns:gcompris","http://www.ofset.org/gcompris")
self.svg.setAttribute("onload","init();")
self.document.appendChild(self.svg)
self.metadata = self.document.createElement("metadata")
self.svg.appendChild(self.metadata)
self.gc_desc = self.document.createElement("gcompris:description")
self.metadata.appendChild(self.gc_desc)
self.gc_desc.setAttribute('value',fles.format_string['svg'])
if fles.gcomprisBoard.mode != 'draw':
self.script = self.document.createElement("script")
self.svg.appendChild(self.script)
self.gcompris_frames_total = self.document.createElement("gcompris:frames_total")
self.svg.appendChild(self.gcompris_frames_total)
self.gcompris_frames_total.setAttribute("value",str(self.frames_total))
scriptfile = open(gcompris.DATA_DIR + "/anim/animation.js")
t = self.document.createCDATASection(scriptfile.read())
self.script.appendChild(t)
self.defel = self.document.createElement("defs")
self.svg.appendChild(self.defel)
if fles.gcomprisBoard.mode != 'draw':
# html buttons included
self.foreign = self.document.createElement("foreignObject")
self.svg.appendChild(self.foreign)
self.foreign.setAttribute("x","300")
self.foreign.setAttribute("y","520")
self.foreign.setAttribute("width","800")
self.foreign.setAttribute("height","30")
self.foreign.setAttribute("requiredExtensions","http://www.mozilla.org/SVGExtensions/EmbeddedXHTML")
self.button1 = self.document.createElement("html:button")
self.foreign.appendChild(self.button1)
self.button1.setAttribute("onclick", "start_animation();")
self.button1text = self.document.createTextNode(u'>'.encode('UTF-8'))
self.button1.appendChild(self.button1text)
self.button2 = self.document.createElement("html:button")
self.foreign.appendChild(self.button2)
self.button2.setAttribute("onclick", "speed_down();")
self.button2text = self.document.createTextNode(u'<<'.encode('UTF-8'))
self.button2.appendChild(self.button2text)
self.speedtext = self.document.createElement("html:input")
self.foreign.appendChild(self.speedtext)
self.speedtext.setAttribute("id","speed_text")
self.speedtext.setAttribute("type","TEXT")
self.speedtext.setAttribute("size","6")
self.speedtext.setAttribute("maxlength","6")
self.speedtext.setAttribute("value","4 fps")
self.ratetext = self.document.createElement("html:input")
self.foreign.appendChild(self.ratetext)
self.ratetext.setAttribute("id","rate_text")
self.ratetext.setAttribute("type","TEXT")
self.ratetext.setAttribute("size","6")
self.ratetext.setAttribute("maxlength","6")
self.ratetext.setAttribute("value","")
self.button3 = self.document.createElement("html:button")
self.foreign.appendChild(self.button3)
self.button3.setAttribute("onclick", "speed_up();")
self.button3text = self.document.createTextNode(u'>>'.encode('UTF-8'))
self.button3.appendChild(self.button3text)
self.button4 = self.document.createElement("html:button")
self.foreign.appendChild(self.button4)
self.button4.setAttribute("onclick", "stop_animation();")
self.button4text = self.document.createTextNode(u'||'.encode('UTF-8'))
self.button4.appendChild(self.button4text)
def finishOutput(self):
# t = self.document.createTextNode("\n")
# self.svg.appendChild(t)
# XXX toxml not supported by 4DOM
# self.outfp.write(self.document.toxml())
xml.dom.ext.PrettyPrint(self.document, self.outfp)
self.outfp.write("\n")
# now each item needs to get it's frames_info cleared
global fles
if fles.gcomprisBoard.mode == 'draw':
for anAnimItem in self.list_from[:]:
del anAnimItem.frames_info[fles.current_frame]
##############################################
#
# SVG anim 2 import
#
##############################################
#try:
# import xml.parsers.expat
#except ImportError:
# import pyexpat
#from xml.parsers import expat
def svg_to_anim2(filename):
"""Process command line parameters and run the conversion."""
infp = open(filename)
global fles
fles.filename = filename
out = Outputter()
parser = expat.ParserCreate()
HANDLER_NAMES = [
'StartElementHandler', 'EndElementHandler',
'CharacterDataHandler', 'ProcessingInstructionHandler',
'UnparsedEntityDeclHandler', 'NotationDeclHandler',
'StartNamespaceDeclHandler', 'EndNamespaceDeclHandler',
'CommentHandler', 'StartCdataSectionHandler',
'EndCdataSectionHandler',
'DefaultHandler', 'DefaultHandlerExpand',
#'NotStandaloneHandler',
'ExternalEntityRefHandler', 'SkippedEntityHandler',
]
parser.returns_unicode = 1
for name in HANDLER_NAMES:
setattr(parser, name, getattr(out, name))
try:
parser.ParseFile(infp)
except expat.error:
print '** Error', parser.ErrorCode, expat.ErrorString(parser.ErrorCode)
print '** Line', parser.ErrorLineNumber
print '** Column', parser.ErrorColumnNumber
print '** Byte', parser.ErrorByteIndex
infp.close()
return
class Outputter:
global fles
def __init__(self):
self.fixedattributs = fles.fixedattributs
# used to check the element coming is the right one
self.wait_element_list = ['svg']
# keep where we are in the tree
self.in_element = []
# elements constituting the draws.
self.svg_element = ['use', 'rect', 'ellipse', 'line', 'text']
# dict with id : image_name pairs
self.images = {}
# Format of output in the gcompris anim2 pickle format,
# close to the anim2 internal format
self.picklelist = []
# Item we are looking in. In fact we keep here the item we actually read the frames information.
self.item_getting = None
# id of image we are looking in
self.image_getting = None
# used to skip elements we are not interested in (foreignObject, script)
self.wait_end_of = None
def StartElementHandler(self, name, attrs):
global fles
def get_attrs(attrs):
global fles
def rgb(r,g,b):
return (r<<24L) + (g<<16) + (b<<8) + 255
def matrix(a, b, c, d, e, f):
return (a , b, c, d, e, f)
frame_info = {}
keys = attrs.keys()
for k in keys:
if (k == 'create'):
if (self.item_getting[0] == 'IMAGE'):
frame_info['image_name'] = self.image_getting
if ('fill' in keys):
if (attrs['fill']=='none'):
if (self.item_getting[0] == 'FILL_RECT'):
self.item_getting[0] = 'RECT'
if (self.item_getting[0] == 'FILL_CIRCLE'):
self.item_getting[0] = 'CIRCLE'
frame_info.update(self.fixedattributs[self.item_getting[0]])
if (k == 'transform'):
frame_info['matrice'] = eval(attrs[k])
continue
if (k == 'stroke'):
# used in CIRCLE LINE and RECT
if (self.item_getting[0] in ['CIRCLE','RECT','LINE','FILL_RECT','FILL_CIRCLE']):
# CIRCLE RECT -> outline_color_rgba
# LINE -> fill_color_rgba
if (self.item_getting[0] == 'LINE'):
frame_info['fill_color_rgba'] = eval(attrs[k])
else:
frame_info['outline_color_rgba'] = eval(attrs[k])
continue
if (k == 'fill'):
#used in FILL_CIRCLE and FILL_RECT
if (self.item_getting[0] in ['FILL_CIRCLE','FILL_RECT','TEXT']):
frame_info['fill_color_rgba'] = eval(attrs[k])
continue
if (k in ['stroke-width', 'font-size', 'font-family', 'font', 'text-anchor']):
continue
if (k in ['x1', 'y1', 'x2', 'y2','x','y','width','height', 'cx', 'cy', 'rx', 'ry']):
self.points[k] = eval(attrs[k])
continue
if (k == 'text'):
frame_info['text']=attrs[k]
continue
if (k == 'xlink:href'):
# in draw, this is in attrs becaus the frame is directly in element.
frame_info['image_name'] = self.image_getting
continue
if (not (k in ['x1', 'y1', 'x2', 'y2','x','y','width','height', 'cx', 'cy', 'rx', 'ry'])):
#print u'Attribut non trait\xe9 :', self.item_getting[0], " ", k, "=", attrs[k]
frame_info[k] = eval(attrs[k])
if (self.points != {}):
if (self.item_getting[0] == 'LINE'):
for coord in ['x1', 'y1', 'x2', 'y2']:
if (not self.points.has_key(coord)):
self.points[coord] = self.last_points[coord]
frame_info['points'] = ( self.points['x1'],
self.points['y1'],
self.points['x2'],
self.points['y2'])
self.last_points.update(self.points)
self.points = {}
if (self.item_getting[0] == 'IMAGE'):
for j in self.points.keys():
frame_info[j] = self.points[j]
self.points = {}
if (self.item_getting[0] in ['RECT', 'FILL_RECT']):
dist = { 'x' : 'width', 'y': 'height'}
for c in ['x', 'y']:
if (self.points.has_key(c)):
b1 = self.points[c]
if (self.points.has_key(dist[c])):
# x and w changed
b2 = b1 + self.points[dist[c]]
else:
# x changed but not w
b2 = b1 + self.last_points[c + '2'] - self.last_points[c + 1]
else:
b1 = self.last_points[c + '1']
if (self.points.has_key(dist[c])):
# x not changed but w
b2 = b1 + self.points[dist[c]]
else:
# x and w not changed. normally never here
b2 = self.last_points[c + '2']
if (b1 != self.last_points[c+'1']):
frame_info[c+'1'] = b1
self.last_points[c+'1'] = b1
if (b2 != self.last_points[c+'2']):
frame_info[c+'2'] = b2
self.last_points[c+'2'] = b2
if (self.item_getting[0] in ['CIRCLE', 'FILL_CIRCLE']):
dist = { 'x' : 'rx', 'y': 'ry'}
for c in ['x', 'y']:
if (self.points.has_key('c' + c)):
if (self.points.has_key(dist[c])):
# c and r change
b1 = self.points['c' + c] - self.points[dist[c]]
b2 = self.points['c' + c] + self.points[dist[c]]
else:
# c changed but not r
b1 = self.points['c' + c] - (self.last_points[c +'2'] - self.last_points[c +'1'])/2
b2 = self.points['c' + c] + (self.last_points[c +'2'] - self.last_points[c +'1'])/2
else:
if (self.points.has_key(dist[c])):
# c not changed , r changed
b1 = (self.last_points[c + '1'] + self.last_points[c + '2'])/2 - self.points[dist[c]]
b2 = b1 + 2 * self.points[dist[c]]
else:
# c and r not changed
b1 = self.last_points[c + '1']
b2 = self.last_points[c + '2']
if (b1 != self.last_points[c+'1']):
frame_info[c+'1'] = b1
self.last_points[c+'1'] = b1
if (b2 != self.last_points[c+'2']):
frame_info[c+'2'] = b2
self.last_points[c+'2'] = b2
if (self.item_getting[0] in ['TEXT']):
for c in ['x', 'y']:
if (self.points[c] != self.last_points[c+'1']):
frame_info[c] = self.points[c]
self.last_points[c+'1'] = self.points[c]
return frame_info
if self.wait_end_of != None:
# ignore all childs of that element .
return
if not (name in self.wait_element_list):
#print "Error : wait ", self.wait_element_list, " get ", name
return
self.in_element.append(name)
if (name == 'svg'):
if (fles.gcomprisBoard.mode == 'draw'):
self.wait_element_list = [ 'defs', 'metadata' ]
else:
self.wait_element_list = [ 'script', 'metadata' ]
return
if (name == 'metadata'):
self.wait_element_list = ['gcompris:description']
return
if (name == 'gcompris:description'):
desc = attrs['value']
return
if (name == 'script'):
self.wait_end_of = name
return
if (name == 'foreignObject'):
self.wait_end_of = name
return
if (name == 'gcompris:frames_total'):
fles.frames_total = eval(attrs['value'])
return
if (name == 'defs'):
self.wait_element_list = ['symbol']
return
if (name == 'symbol'):
# just get the id.
self.wait_element_list = ['image']
self.image_getting = attrs['id']
if (name == 'image'):
#the only interresting thing is the name in gcompris tree of this image. This the child element value attribut.
self.wait_element_list = ['gcompris:image_name']
return
if (name == 'gcompris:image_name'):
#the only interresting thing is the name in gcompris tree of this image. This the child element value attribut.
image_id = attrs['value']
self.images['#' + self.image_getting] = image_id
return
if (name in self.svg_element):
self.wait_element_list = ['gcompris:frame']
# used to check modification in x, y, w, h positions
self.points = {}
self.last_points = { 'x1' : None,
'y1' : None,
'x2' : None,
'y2' : None
}
if (name == 'use'):
self.item_getting = ['IMAGE',{}]
# We will put image_name when we meet 'create' attr, in frame_info spec. For that we need to keep the name of that image.
self.image_getting = self.images[attrs['xlink:href']]
if (name == 'text'):
self.item_getting = ['TEXT',{}]
if (name == 'line'):
self.item_getting = ['LINE',{}]
if (name == 'rect'):
# Warning ! Will be changed in RECT
# if fill='none' found with create attr.
self.item_getting = ['FILL_RECT',{}]
if (name == 'ellipse'):
# Warning ! Will be changed in CIRCLE
# if fill='none' found with create attr.
self.item_getting = ['FILL_CIRCLE',{}]
if (fles.gcomprisBoard.mode == 'draw'):
self.item_getting[1][0] = get_attrs(attrs)
if (name == 'gcompris:frame'):
self.item_getting[1][eval(attrs['time'])] = {}
frame_info = self.item_getting[1][eval(attrs['time'])]
del attrs['time']
frame_info.update(get_attrs(attrs))
def EndElementHandler(self, name):
if (self.wait_end_of != None):
if (name == self.wait_end_of):
self.wait_end_of = None
else: return
if (name != self.in_element[-1]):
# Let this print it can handle error
print "Error close ", name, " but ", self.in_element[-1], " waited."
return
self.in_element.pop()
if (name == 'svg'):
list_restore(self.picklelist)
return
if (name == 'metadata'):
if (fles.gcomprisBoard.mode == 'draw'):
self.wait_element_list = [ 'defs' ]
else:
self.wait_element_list = [ 'script' ]
return
if (name == 'script'):
self.wait_element_list = [ 'gcompris:frames_total' ]
return
if (name == 'gcompris:frames_total'):
self.wait_element_list = ['defs']
return
if (name == 'symbol'):
self.wait_element_list = ['symbol']
return
if (name == 'defs'):
if (fles.gcomprisBoard.mode == 'draw'):
self.wait_element_list = self.svg_element
else:
self.wait_element_list = ['foreignObject']
return
if (name == 'foreignObject'):
self.wait_element_list = self.svg_element
return
if (name in self.svg_element):
self.wait_element_list = self.svg_element
self.picklelist.append([self.item_getting[0],self.item_getting[1].copy()])
self.item_getting = None
return
def CharacterDataHandler(self, data):
pass
def ProcessingInstructionHandler(self, target, data):
pass
def StartNamespaceDeclHandler(self, prefix, uri):
pass
def EndNamespaceDeclHandler(self, prefix):
pass
def StartCdataSectionHandler(self):
pass
def EndCdataSectionHandler(self):
pass
def CommentHandler(self, text):
pass
def NotationDeclHandler(self, *args):
pass
def UnparsedEntityDeclHandler(self, *args):
pass
def NotStandaloneHandler(self, userData):
return 1
def ExternalEntityRefHandler(self, *args):
return 1
def SkippedEntityHandler(self, *args):
pass
def DefaultHandler(self, userData):
pass
def DefaultHandlerExpand(self, userData):
pass
def image_selected(image):
#fles is used because self is not passed through callback
global fles
pixmap = gcompris.utils.load_pixmap(image)
fles.newitem = None
fles.newitemgroup = fles.root_anim.add(
gnomecanvas.CanvasGroup,
x=0.0,
y=0.0
)
x= fles.pos_x
y= fles.pos_y
width = pixmap.get_width()
height = pixmap.get_height()
fles.newitem = fles.newitemgroup.add(
gnomecanvas.CanvasPixbuf,
pixbuf = pixmap,
x=x,
y=y,
width=width,
height=height,
width_set = True,
height_set = True
)
# Tell svg_save the filename
# Write "filename=image" in the property of newitem
# Can't do it here because in C python string are unreadable
# gcompris.utils.canvas_set_property(fles.newitem, "filename", image)
anAnimItem = fles.AnimItem()
anAnimItem.z = fles.new_z()
anAnimItem.canvas_item = fles.newitem
anAnimItem.canvas_item.set_data("AnimItem", anAnimItem)
anAnimItem.type = 'IMAGE'
anAnimItem.image_name = image
fles.framelist.append(anAnimItem)
fles.list_z_actual.append(anAnimItem.z)
fles.anchorize(fles.newitemgroup)
fles.object_set_size_and_pos(fles.newitemgroup, x, y, x+width, y+height)
fles.select_item(fles.newitemgroup)
fles.newitem = None
fles.newitemgroup = None