sugar-flipsticks-activity-1.orig/0000755000175000017500000000000010715422424015724 5ustar janijanisugar-flipsticks-activity-1.orig/flipsticks.activity/0000755000175000017500000000000010715422424021732 5ustar janijanisugar-flipsticks-activity-1.orig/flipsticks.activity/NEWS0000644000175000017500000000004310715416404022427 0ustar janijani1 * Initial version (ed@whsd.net) sugar-flipsticks-activity-1.orig/flipsticks.activity/icons/0000755000175000017500000000000010715422424023045 5ustar janijanisugar-flipsticks-activity-1.orig/flipsticks.activity/icons/big_pause.png0000644000175000017500000000326010715416404025513 0ustar janijaniPNG  IHDR"*UbKGD pHYs   vpAg"*0 IDATh{lUww}!@1 HT&$&A>R%@$Ī H((DMP|$-!KRvgǽw In{;w\X20`n)/t٬|Qr%e4Y@@#0OG[;6lM`cE,r DY[u`N5DTXSxq m\nX*lfLS {_? X`{ VK-ڧNg]nEd*0ggozT~LWv/-b$33s|m&M@<&2O\&|$imLjda t XjZ8,<%a C- a5ԩ4, ,sxNd,]ÀC,;|T;7TT@lI5ΥOS<gG"`Hnv3la1JBJO%PQ.3= KJpk@ (!Mgl}c L)i܍V Ǻ5^rm|*<>/]|{pb0_״j*`zf ;_8s)@.#;ދZa_\Qq9ʧ3͕K9By+^޸M82&Z^]˙kB`<&-0"!*\qfnrnahEd;&Rbu Me15CF4KWb͢& \vik";ù=/3kJMY%qne:]4DϮ?z/*M[i9b0+T 4@s6X0( 0Q7Mܶo),5ɀp @p/Wb7Fwԡ-p( F(}̑,I༊b޳F}ބy>vh\ 3h5Xi~a+^]uys;797a&%Ho4tʢҢh60tKʏ*]S&B@Q+w;VtS!%ҼBjgV=rB/T3I*ML^yiꟘ7o'¨ol2VtIME 73ϟ`tEXtCommentCreated with The GIMPd%nIDATH-[o]{5ql4B rmT腊"U/} ?OZTQZBB&)r!8ZΔ0ИCuFAsP*%`1T)  b1 %qXT=A=V K^P@{j_Ö1v5;}pɅYM^4=G2Hb AJb,$Me(ACK(<>bfUTD<)Ro[ũy|6y ġMXA:lx6NhY}O-qc?{B:AqZbЂ#Sa|pkגK[KP+h !P  Z /<N(3T?۟edžtR%k^h}C I&S51hS6=m]4|ؔe㙼5sS,ɊXC4Bڭ9N?:ݭJZf&j#"uŠC,>ȮG"EAN$ $&d  ,+&4 fgH"l ) :CəK(-Xv3^~}™Syjk12==MF\-ei)gnnսZC#kufbXz6 0\_M^#0[\},ˠQ0T;cZRI{_5ls5bp}5F'X?E^bc-o͕34&=}Вf[ gfhF ABTz{GG7- 1ql`8z,^#g/F1gNƑwpo¥$.a{=MG_LH)\axg8Zz JfX\fr%OX/ñÜFXWdU*EI<XMf&(.PQZ yQZSὧx{3>wOHRK(Z(Yak$b0y.@kW|^s_懇8{//Ww`'nc$>dn޿K"LɹiGE,OmUAqIe|y?~zn݀ j/w|Zq<1X4ޮ앉`aM6. Ֆ*g3== NpYoҌ; ,MVО@o[EO_3ҷ}We ϡSn&UOmzNIqΑgs,gPqiB=z( k$/tt248 {qQ-aMTnܹ{Z+ۆ7Wlzg!m(虹kWHTeU;Hs'Q>4u U} at;I\ܝ 4`!f%LM9]=tډ!,qb,kVPU,35`02>Jv2><~(<7h@b:WVyx޶:1D`7DZgh:E@Pļ.Qp5/w}jJBs7qW\%cGٶQ6U- ˃>aaq j| H2a@Th*j=w{ Yԕf  GX$}y&T$b;bH%:Cz[s FDŨRi 3'y8IꑖRCF#JRbhb$i[6ahUWw23ŕ׸:5HGY*  P@beD"FA"JFȩ>'BZb )  PPzE"(PY, pBc{ )X$W1D?!?kn6mIENDB`sugar-flipsticks-activity-1.orig/flipsticks.activity/icons/big_left_arrow.png0000644000175000017500000000333110715416404026541 0ustar janijaniPNG  IHDR"*UbKGD pHYsiTS vpAg"*02IDAThݚgl[eGb'vcg:q# KeJ ؈-ZF *J, )F:)]д+D+ s?|\}|l:HmTjW5b|vX>f³e()6|'6FbI` ҿg1Cr6"`%M W =vqC"yr\Se!P!BˮQL2lzAzAT771Xa֡o|Pe':y5%4m.l+F ģacO㑮2=K!uGEwNF`Azh(SGcMVerpߔ:%i+./[^ɛޖ%9,#-K9.fV|[ `=l>wџlCIYb1 c6q,;eՔy4/o#e9v8GpRuT:N;y{5}bȝ8dw9b@f7Gl敬(BrR+2t-T"T&c24~!ۧaqضOT!χM d` %#S5_tpr&zTXtCommentxs.JM,IMQ(,PHUp R#epIENDB`sugar-flipsticks-activity-1.orig/flipsticks.activity/icons/pink_arrow.png0000644000175000017500000000055110715416404025730 0ustar janijaniPNG  IHDR" _<gAMAOX2tEXtSoftwareAdobe ImageReadyqe<IDATxb03a"K2y@:(Hu1q o8PG$x9{?a`Ħp 5y@)z i ^ Tp{ e$qZv f#+8hk|2Ѕ. o"A 6h|-HĆ24;@I1A P6QP@@Cc&9! @ >K!0f6MxIENDB`sugar-flipsticks-activity-1.orig/flipsticks.activity/icons/big_right_arrow.png0000644000175000017500000000341210715416404026724 0ustar janijaniPNG  IHDR"*UbKGD pHYsiTS vpAg"*0cIDAThݚylTUߴ@Y@(aJPqwшq+\FEAM-QcbF[k7-mL[Z;]vvf:5R igϗtλνs%//ھ=iaa[ l2e:cܛEt~V 4h'?Wf>1{+ΈvGʈj:ļwGE;9+EO8Y }j:3AHVt8cqR b !kHh?BASĴ!kHb"OwbbIbx?B0v "qD1A1PwX+/+bM_3 H) iG~1XLzYL{Mib1bO"& hgv,Z ncXq=P-RG܋ťKD7JSGtĀ /.ÖTI?f"Aǘ Nf][nS'"eF@H38ی1A<3pNmbϢtʔp#D1bLQboybאiQz,lRYo vA 1ѶIÜ/qtAK?` v]bj̲Ws)2)PթA9q5a#ڟc1kX2R}g{aABwaVq/sEX4W,ڷNB{][`ꝄtoжQ,xne)QzEGH|?{X2K5k,~֧IJeHjBˠiO!ZCĮZ}/$;a#- !HyC$H&"ÍZ\ *B<# !`#en9bE!-r+uff-upT+xc:LAyݼ.I}ܩshI*5-01/.crڟpj6]kq3#qXgcs<Db }&zTXtCommentxs.JM,IMQ(,PHUp R#epIENDB`sugar-flipsticks-activity-1.orig/flipsticks.activity/icons/old_pause.png0000644000175000017500000000033710715416404025532 0ustar janijaniPNG  IHDR&N:bKGD pHYs  tIME tEXtCommentCreated with The GIMPd%nCIDAT(c<4`֐e>0&2.qig#ʈM;m#c&OM`mIENDB`sugar-flipsticks-activity-1.orig/flipsticks.activity/icons/pause.png0000644000175000017500000000037410715416404024675 0ustar janijaniPNG  IHDRbKGD pHYs  tIME 9 tEXtCommentCreated with The GIMPd%n`IDAT8c`V8tI 2000032j] c:#5\BȐ8$B 0`;Tq5O!Lv5m_gIENDB`sugar-flipsticks-activity-1.orig/flipsticks.activity/icons/yellow_arrow.png0000644000175000017500000000056710715416404026311 0ustar janijaniPNG  IHDR bKGD pHYs  tIME %qVIDATxڱ P, BJ8h 1e'\)NQ͵LKuGxfD'sV ,AxLxLx_G+V!I&i&i&i&i'O,Exˀ՟9+Tk-e'f7b]%n냗$a`*mz|xx ^I$^W/p+ \J.x%;`S.1t`{ .7ƗIENDB`sugar-flipsticks-activity-1.orig/flipsticks.activity/icons/reset.png0000644000175000017500000000277610715416404024712 0ustar janijaniPNG  IHDR%bKGD pHYsnu>tIME 6tEXtCommentCreated with The GIMPd%nbIDATHmMg9U3e`Ikb"iCB4Mjb1.tSƥq ]XMWՠP-E[;Rv)Hý}Vf<_+03ps FX}D 9gDx|0+2J?d:BP闈U@ $Ł2B vd'aS_?_-U%gAIDHv$;da<e):Q80p)%::Pڌ@1**<[ّ ,G#"be̼'O0g?9XqʓbBE\0l~z9Ž۷)ΝdQQLY)qB͏^^8|w시>D)ӗ rƇ@޻g'bϮXwi ?s  4m˘C<ϨqQujz/S`m ¦ {9aF8+pUpz /]XX3S 8tIME+;otEXtCommentCreated with The GIMPd%nIDAT8˥O+QUy-ވ)RVFHba!3YȊHB Oyyf[{9㨲aW w X7%`ht uD!q[q|Bzu M\ F?IG` ShtR'}@u/L9gAa9k8Lr#N^ƅm=j t9SBJ>KA L'\(FVCinrpg"4B=,IENDB`sugar-flipsticks-activity-1.orig/flipsticks.activity/icons/sound_icon.png0000644000175000017500000000623310715416404025720 0ustar janijaniPNG  IHDR<<:rbKGD pHYsnu>tIME.W:tEXtCommentCreated with The GIMPd%n IDATh{Uu?9{y\DDDQ,0"N|1$VBŰ^X褥#$DaJ8[}9ofy[{}ZL>g*ĢV0(#m`(Q\h$ ٗfXF0"*0Vb$.6#`Z]F.IS~k{pyx>:I$5`|7vIwX+5o|d@E/ 橯 ĹYfݨkwG&}/6TU+=bMMC0B(=WI].H 2t'=쒤?j-*zYfZ;Zg1$@U\{ckz1mv'i~yjhر+..;P /SzS% 0^(= +uo`TDA{w|F53B򝁿a΢pXztLj[B.T%D|V$lR‚ ;mv߹tLj'r~|`\.ym Ynj:Ƶp[T5A6آؓM X9o8LK Y6y,zG7rnVaN{,9}M_w?>  pT)ucP$"DjToɕo&{tmr̬In+@LN˹X ''6Ɔ,e۳kXplrM !kE ŚoFܱLRG!^@cS.%oJ >VE-S%ªE|r/BD&0QNQ*(:SQީnTXZ bbbHWbN$V<qm b<+BT6Hjl DDX d% ZEB>vsSkQm4E{-XPKoRkk3|]}@cK#nVt+%5"ܢd{F@$yI#!F`j,=(_Bk{3{^ gٓN.j|xѸH|e EiDUFjUqy|u!Oö544Qא)T}amq QusT]P5Z"#BO!PI6K833]m: @Sk# 9oTamixk8kb2UȃhזÚ\3'"LZ%`>V[{{]z^޾$RC kMMG_x9?f//m(DDU`Ccq>xnd3Y{=wpz,cƭ>lyjM* S[E^b3r++}6;xTJg}:̚5+OocǶna\yнD޵K~F~"69EO/:D? ^7!*|Hǰy5uxȈ#`5YV)J5#qydB'E4B 4u\6oSPYsϼĺ5Uxud0 *ׅ?5=?Կ-.~7ΟܳP;SfRlÁOZXmBhi}Ã|1bkZ4vX4Y֍;\ۚՓCz׻6ܱA[=%a.YFVݺ.@J啇aZuډ> (~qʵ}.F'_@Giҥ@? ע)lI؜Y E׋2eWeȡ3%#NJ$qw߰:Xީ㴴h`NU:þOKmjBhƻ6:TJ}yk6xZZ:UՓ3kycH/`/zcF_k+ٯ_hLංIENDB`sugar-flipsticks-activity-1.orig/flipsticks.activity/icons/up_arrow.png0000644000175000017500000000062510715416404025415 0ustar janijaniPNG  IHDR2bKGD pHYsnu>tIME*$IptEXtCommentCreated with The GIMPd%nIDAT8˥O+DQϙƟI‚dDHdk1a‚$VJHy ފ7({fwu==s~'|ߔ0w| zy [XB+PT^z7U!;o*)eýJs7c[*N .tIME7HntEXtCommentCreated with The GIMPd%n IDATxy$Y;Dy3^kYԍK2BHBlF<2Hcccc[Xf`MfԲ^k{DުBXyYr"ꕢ@oCDPJy߉h&1H@Tց"4*[oͷ~|_C#ys~E"` ‰$(A9,BS JEi0[zY;oo?W~(eRicn.6pwZqo}@zͲ$k߯"8wD:8yՅ JRSm?X=˟O^rhRҌ SaSP;`;X"Z04EVRW^\1F*,:ШС,AF``Ch(f?k ?ز?ܺ@?v!9l fl4®X6\rNFׅֈ{~R;/Iz"$^YZwF@ٔqcu{UR\"pd~FzAZ:.p$Fѩkď ߊ{oSU_)"}iXkW(ڡN)ø`?&soAžgq84]nqA>#!_Pdr5C,3HI|clf\.!F(ieBA80X-̵sy8h7;sĥQ3 䆍Tw\>OK*&;>nTS&`%cZ:[񑯟+Z !.Jpgu$dG'xoew!0ZĊ8qX%W*X1p QMGFT+]QlY:xf.^Ҫ?FwOЙ@gFX49H~P\Yش\gtv$ob󏽇{-pi!$VXoWt4T JDmS<;4N. & N̞'&eQ(H!]p,^Qi1]fdڟxY/-^pdi^lև-隀z?G=(O QmhMwue81PK?KQ>/zog/-bil  >-l.bŪיIzjN9F%;s d{NJYn 0i. 6v&8.{^ Ntx^/P9v1?I#,axP۱Yա3jtzR,`p>6U=O !dU g"i:4br G1]/΂|/UR -KT`Nx_}MƢ.43Lv}kwt}sq(e8ğlܜfQV'o>QK"jv6.F鞈m K/1㈕0L6@(' @l׋_3`{gRj G9VLi oYC`Y#j Flsxam(f8Q)pRM<޼ȧ# _s<yrsUZlbW{B CcĢTRFq%WW!F( P2DܶĖVѨl+L /w#q Zk53.[+} wq+ ^uN]Y!yZoh}mK ͑Wxf22kz/];xƓ#|ReSw6]nbR*J@6Z{A$Qui$Efn]83? . ٘I p}9|‘h P쪷鶘,}ơm٬C~:n bL.kEZ¸RoI#"T]8Y.浯P0ϳ,O"RĠ5ڌu}0;[u\_⑜`y",:uYV'={/!t"Z-/EgJ@׆Xmߨ=[(' y^?=CyOW;y\ih&EgMz&J~LG+^SIiE?zV(E)8^;{Oh:y"u(NԞ!t';Z+^*\qhPhxQ;>}غ]x|4Agu*k-X罒*5(T̙Rl CShGFS[YX]2?|m|,^^yf_?NMӜy1} F^b'icT`#ve:Be<[%.o/[q6 Jd":$rGdž8- EK7b,s^`m GrhJy}89FSI|VOw\1>`!ZMQ"v<[)B}]yVr} {>Gd(] l.,O=O~y>Z.R}+MD6㝘k8 *,.xِeaQW)q|g=Mƺ~p<#{1oD([/[?^}Tkfص\'w]LA4W1| M h?mc_x3ʳ6(A'}] Kiicqlr@uĈUB\IBʏqw{/?xQWR GQ ?t5fǑŕ#ʋP3H^U9I J|0xv.t6[|/˺Cl̞%i @ChFksϳL/t>/y?~Q42G'OdS5Q:4?p,6"Dl!S"g/?s`?e ]`{E.WGt~g\SQ>{Q9{1<03}sS/ 1BE@4@mXw!T!* AˠuJy9/Hf9,ۘ0NYt /0ϲ }.x#% +<26A7w=>8(OL-<0;˽ ( "8S,#q%'qk8$W/;wJX05(Gg%>t04_2?IB!7I6*A9oހ [O+*tfj"I8Q+[;Vj[-EJмfj/ƫ4`w(KG%X9E vezkX4%(J4huX:ֱ[&l1)ߘ1oD-o`2SݑB|i0 GgH+q&WEqga4ϭ 9rVtf/3uuq{Rps,gzŗ,sO/`XCb J>nRz )t+É*:=jL(f f}_E;Rt{!XU0B1Vs[2s\,ٽB0N3܉̿QSaIJ+sPC++ 9,SIq wQL%o3YNwg+,H/X CG0%Lv@ /8W*23G(KiQapܶ.]81Pud5꾆_T(@>3:R1Z[bONLpS}S= ֎Xp4Y蔢} F:<̧xxr2k$e5ᮕ2Nh@4$C %|yx9O=ZLJjtH/?gJPNVbӋxD &ǾNiVhPb%fnEo{?Lȴ隸idr '?Aqle|CYdK|QxoRRy @=, q+ '73$4ˢ$_14V`dSrO̞`i{fcff;,868g:g* p`i JyRFWVLZhw܃Fh:QrX&p K4}Y4H̱Av7((Z˞24(~f.@1z(kĭ5j|GFEΠTShX/j %/Rmp|+jbя%zSg+.򠢴ukiOMF+OU82xhN2(%zNikwM]DXdxVi+N+xxrfq0pFM\gwAk~ֽC-]NfLو@$/an|P[/R_v TtK7J Jɧ2(y}n+'*iٹmK||K"B?+A !g N[Z-n[fGM%;?Zasce ޯηR Xjw"=%E:<,+ O 4ƭ)oW-! IDAT[ \esI%d:4t~w]_ c!^5=z,P(Pp }:R*) .DZ8XƬXjr~Y+TW (Y8. zz~_4 \ңýosk>`A8&*[d&Giɕ |vDeq{^-GɌW(P B+$Ӟ_byzkY>?;z>vla%{},WWyn-#Hv+&4tj62|-M)t|_[ĭ)]$:j! ".$8H !\K1|{~yV}XF?| {JWA$ƳaR.rOKšM"6N exphi%MnI <:2/e]MrK; KhXD)w/, ōɆUßi*tPd>1&njմJ[RTDK4QMbشʷ@`J*jK돊,f3~B#BZ9"6\bij=BTo&Aby<[ƻ>P͈tQX5mRFȞzzݭ Y\&B+_a|AĀvaBf439Mk{g)9O>B2T(ח)d*dƆ- To7ŝcPmȆ"wnkQ,γpix;e`ɟ?sdK cLBa:t+%+(2XQbAg\G+n8hxƁ&"j&A1EmUS'6g,OG"u3O^' Ð0h&-ʱ'Z@A[^ F`$Dʫ:3c[@,Y^i4 w--ܰzY}ۇMy5Bv% sH4hI?| BRhV%\8_gT _o2LTdJZF|=9ktŇʂK5݊Fi-jt"NznWHddV= }uƲsgMipP J5so7ț4sGj n( SXBÒcC o&B VrrlL 6“@usܶ=[K|~dEsEM2{eO\6b%hbO1I$Ԅ.&##1Xа ѝ\9;}o|pe൯y=Ӽ-o(ֆ΄ _ϒ4TYƩ.jǢ|;IfbTP֖Q<>8^ҿ}c:|y_V!uݡVJgj%B a6c6̀<4w-,۫94;%=`U,O T/eWV3 ,@\YnuzMћ/dKx Tme˯(CSۚRlW+Uŋ'J[##{Vmi0LףU)qz5C]LaYDK/tV3G |6vgJI+QjmW_bȈicקɒ3:WiJGaTZ~YJįrfFln6>,SON{M95&GMOnj&uO R7&8zJjW"ٶONlBĈ35;(&FAj2r}$NӪ KW}xr-yP:TKgKZ$9=qj&䅢i&>pPi>ߓX+ 'QqLP:1ѾnL&"6 6u 8^,"I[c{W}w3ͩJM†f3 Ny wuTߢ·A =gY3a3:v_ JF,螸`ܶ"BDcMTDG,*E&+1<=:O<2[4'R eƷ S.h VH"mc2$͠&OԏD-S$]"F6gY46um"4)ɒ6@^#V1꘶ 99Pi:|VcK̈́ŭ#ڒG%}G:}_|0 FЅTOUV*ʡf2_rĭ%=]DCCicV[[>R8F.$&dmg!xZ$ݍo Nϕוz^%Nש+[,JZp\b)P}LMiA#xnxҥjZH_rNrRJꂆ;8S&U]ºΟSof%rTٹ;ъjqXH{繈pwX+ n}ASrjXudR/5pz֔&:G$mڪoUʫ$A)!N9V!Qfْ6NV`BTf.<+bȑYJZ(_m$q z]?α|?Y~;g?üevE䱳{9bf.r9vuWh{Qوi47TlBHfcMX/J苭mzաNvVϊk\ŧiU!Vi/h\o2iĐqij'VE-P!NA K+_$ƹƟA 4rjj~(ǵ\ wsڬSc0>IHh&"GF~;/t!"BUT(#NI5ɥSa.] Ru6}t(S;XWPw>ʋxv&y]hT4OWPBM^#~n5u&׹*NA5H{-%zWo! Wz6ڍyd:_0iM"Socmt J6ARA+cUO4)d~o XDqel%a>;{ٻy[\EG&:@ɾ%ڭ ?cyȦ%\<ϦaoE3jZ"IEsf+͌yas zN15W +dԗ:_b 4(# ^lpΕz7 4 YJ&˛\NtpZ/&6;9yvZ)](0$:`"Kp<~PlrZbyo6^kË"w;KܻHn i~2~jjΧ|vl/ Sp eO E~Uݳf2a1Uӓo1llF+cΞ偅uI) 2+t€Zӳlg~b""VBFQg. onv5٦ ֨E]^33˞z (͚]m(ۄ6,V).JܹpEJp`i ab~1NmivNԪ39^c8م]:1Y?z[ݞ/8_*;3hF .GݪQ3*+,gB7MN"@ j.V;ND +U]Bސ@i{u9P!X_=<4k,A* SQ1vk p >rЅ(k|%z·eiY?vy|/W;]*[xue[h,Lpy~.:L`Ǐ7}ç?Ǽ$&\b`JZ!* T( |g@3Ba1vJDmK^esh;Cܙ%|@`T3A/{Lz]n6fs5K4y,8w-VZHgKOJ9!_/ٱYG)amvcǘeF EE']Xk}m'ϼ%Zm:{.aj|#geÐ$8I_8ϜۑK#s#xdtr'e>[`&-e\*{SSu3gwJϡa*WaHgɱ(:k?x CRJ^1;xwD =?}+M~ؓ\ȹ^o:XON$#]{7L]R1*mZsuf19;Kb.]"DΊof^߲лJS)}#݊Z ׻!ZzKµ%J)/L |s-[|Siw&;vԆצLWC⬈I Qu(^R xRg )qyPz7Jb@b>e;_!w&9'DX~y-<]d5\սtZsuNp\oyP}{Y_զ.#.rGyTZ(LtZi0a#?I6NT}Fה,c؟#tZi kJ_޻º\5ouP &_8%\y/b'-zi㞹ƹtmiyh86WM{4tDy0S_@'5I~!NY !J aDv$"4 0e߷Ү3'.m{J!Q(dCoGuMB/ sWWH ʴyJ[Gy`+9)~}9rq V%viW,g|lDڴջRWɅ8eX̳Mhp6zw]lhC[?YZdzwOobɑ*J!'6aTD('ysm 6*|L?ٴ1u/u0Ώk|G=':Tbs /ՠ8\S2bԡa(֎/q;x$Gv01)ף|jJΖ|M૓ [mܓ5+R^dyI_`cv\'j|jbLG9]H{%(HlnmI@=ofs{CUϞZilM:ʭ Q|;"t<x hBeЁ;'WD~sg_ d&af39L_{ ɮ<9˽UUf{F7 4)R\d9$ْ5Ќ,)b&ccOL1?&(ƎЈTx$sNN;e6IyU$ac'v8  iLS.΂&4|P ׍9H`E :BDJa-F>;:â͝ Mۖ}.|A"o2cvg(6}zSL}4Wf׸Wa-S#D'Iml*uGyriW6&"P3@1ry9jL UBpQthoXjr}ݢt "JAh\1ɢ S'U7ӊb1MV./S,-7'EJ02зTzںFV  t2 }+(m8h)(WZah2B IDATˊlڽj+1]6{X/Tse I}W>d,v]mtO=`ru/reBu;' f8cPmg& &XO2q\f; LP݀9u #fѹP ?X)BAh'\PZw3Q8ŌйXҐlv`|/QԄ(ڲh5ʮ 16 SH%Nԡhk)&.fz0G>=ô-b/`W75ǕKkZ0ﶃ\}iqFMZ&)׭9KC(CVy{3Z[$ xI':sYXc}3%wROaRSj~z͋+GCc4E؞<:rD&sԗfW/OWjJhi(2p~5&膢mɻs<υ>n)=tY .ƕA>8[:e^F;0E|";i+t,aɜbbjfyX$#E`s$;Ov n$JefDoe *svKTE5D`Tp&g_Kycp{F. |Al=sc-p#V6T#+fTHJkPd/u K6^-7Rw L[2g謅Rx'dL̞1}i^[J,p&q&hw1-l"%XФdۊߚBF8ap9E娓{#Amh^/<ˇ?yzu3?- ÷OR'JH:U O_yf>vB+/\מb"*i-l2sa>+3kEዊp!g냮U QAžQ`3aw;7n7 ϺY` )m_un ^h" AHp͕6 *v SwrKT82m?םya mKxEpa GTǺaq\¶W>/'g',PgB/e߾|Ga!wtԎN0CQ0tG4"Z hѪpr=6/>1]$ IMb S(dJ>\Q3T/γ"A`qe:/h^v?1z 4;9LZ$=}FGȈ|⧦1r}[1 [p{~@z3=dY͗z ¦ԙP[ ;oeW5a˾}kXJlڵ-"Nv/.$% ^p1axbr^򇧙_1.|_$ Ǩ~רE9G$G).n3N,PrsZcUCmDA$r*a\t>eęs \8G.JHd6I[FK3XaTKC- m\92Au- 6|CG&kb8WXDꫜfʐoJB7o9 :ϸ]XJbS|VdrA#aNϷQl%u u:d ^$b l>lpB&v 肚t移[D~dHRpS3?ϮP~_aeyζzL?Nktj1EΩ{78{Cc$<:,cgsCѢ.JXtaE:} K4 3xd/D?d].1QHSK3kI)im,E]P>exDZCî#e'JLdhV[[' ??Aky9ЉØ.>ʽGYD7ڡĉ\(7mJ9 6# X 6l()Nns$6;>xp;3 z#!sPȆ6/HF2HxttDy_8yؐt~ nNAp2d"N (<Xg yLebW|珸P'Ev(fDG#y~*&yC[uBymĺ4?KJYJ zNRϼu-^} zqÌ/|}臨\.zh;(I6݄єsaXy_Ia DL!%r+עB{4HC1o %aH$ D9s%^,"~\eFɠ Q (M'P;R rE; Q`/Y c+_~Y'NYK1/SVkeallcwK~{`9Jm86uu8DH6;Ht@ R&j=7&YZZ̫p: nX{ kKU05cA)1i(^^8ޕzs/G1!_ZA5 wvԟe>uix" 󟺓! }x;s3Wh>>M%Sr@Kd;#tk ~,R^yivfo|=џw^e佇{xf3?`y{m)c)1³RI/uX%!o(B@F)3# jD"Wqv Պ1x!Z8xEi fLYPm *ReqMIG+=YcС>( !oS Ƴflۅ]xT~.Q0AfH֛7*ߛ.i]}m^PjݷyΟ!hyJуkXaHWkUzWy4{s0\&C9Ë_{׮-1w>*9 "q#ElQQQHKII:Gp{޿S_7]zWiHV̍Op#gzv(^Z<IyWt BAN"B ,UMեzkHp? ]r&/ǡ 1>I|>HkY^؃w( Q!aWxΠZ̏x4`FȊmx~yҚo^/ gxvkf,ashH!)F6'% V(Rq(j"B'RL1yOZfu~k$Y^Jhoeg7f$;ksT)/(CȨA&vmTӧyX;Nuxܠ{khlGuѣ ]EǛ>0DP{Bg5GZBS{v28lEM6PV^-к4f[0›2:}+'/eA&Hi=5Mw)|b=$S$|tZ'*@/3_Ƌ͊KƾF*Lf̥a2>]w0H14DZ ^RDzN`09̝9_ g}v GbɷR:_@0qgLdC[˫|Dexf(>(qpYZYZQ!7!Qf?l$yN9W qaEQ#(]txdK{h] >rɛP:UHG~/,&ԟ$u+ q0/Ol"s`0Jǖ:yOs0 NGЙd@4G/cq a7^"k RٶҡG4yhzӻ@!܍l;~ 'sn\1:mv/Om6(ZAEj9%R`gͷH?\n%rHeXY嵗S<Gyۗ&W ll ][{U%E.YKMg;nϲ4%ìgXDbʑ%StP"(l.aԖ6+1>4^ﰴiH֚8G󭽒q;|p2\ obbG NBkYKVҔtBb=^0i W!*d8c;PFg/8+4)_%DQ0rwNl'")(?[ʠ_NuP"baB %ʻ{8wf[|"ɵ`=]WxvmTY7oQ\ }#C9f+%LX(;ma"K!RD988w'uKjֲ??CKg<;VˮB2v&mp\)AD ?:E-6=ef?uB(RL E7*+5M2\V:3~V܅sgG^$7A+,BA߁M0#K=^EJX>_&?A~j'$ ֿ>Ip|oc`V(h(\ ?ۘvoL+{loMq by?p 4?7ۋp&x`笠qLV䦫#)Ѯ*ɵrp;@\G%,>{U1haJ|g;:?ykkU^cy#^YwW1^#eLV7Vq2}_<>kq>dhv`2{v+2t~&>tô,m+&nW)Sve@Dȥ y8PQwuQuk_-*r#-#IIC!<o K5D귦;ƫYZ3.k#?^9DP}f;c8(< T_fn mgh(NĦémHSovOWQ81R(o½ ʏ*0B@F^lQ]dQѽo6ȳQMN [2fXԤarT19ɧ 6^?3Oƿ.;Fh.i\D:/RomH/{^ګmϜ ڡ$«`+ISxcf(*HX =)jTlmava?Z;mTH]*K(v A -TvuR՘gqO 5)_'x;@Bd։y\j[AoxRt;#6p:_·xIMGgvȫĕ# ɣ ml>eaښffs.SWVsC?or' /~go̥gȦ稊<ÿ CYH4mLBd\{v}dz !AN\/b3w>2C߃+  `ȏUqr2؃P EiRaa-B"@vF;~4>jIVPVz_!}*&l1Xh ?1GpPP{yē݅!3Cnv~#^@6OcJ^wRL蛪brroNVPaV(縤nG׻qej[^2_el w9El칯- )BT4W$FXqԘ})#8a}>OigXR.YmV_3qMBm4~_ax1r'R/ ^~E;#tބ>藎 l1yGl|G(͙ڲa G\VEqxʛ)۸XE GHbL![MO׍x X sl^BńCj1@>rҵud[j TOz6*d ۺ{/ 2\/oQ..]R@kG ucsqaSSIu?{P DzZܾ/=YvYowVt 7e#Da&yCs"(T0l\39lB7tb7:orv= QEFi |J9^#;j#yBZw¡5Sn QqH'&YlGwJ>5|jbNLJxң5[A;D!q0Lg@q:HjBD#j/QH:Etǧw-^G7q jgH %Ck(PuRKe"eTh" `w~ڱ0*$!X"ok<'>q裏~dY_eud\Vz"gP-Eu=#,iˑV ûR*rJN2Pfp/VіUK+u :- += ϝ+Hk :s[ 򝒁K&#O/ZT֠u`d9w>]zsްkm \"Tzk >GyރpI:Abp~ Y-ڙf\l`<(pl#F;K[쌊ؙ+*ER$]yΆYr e`@vIQ'" TG<{WD@'vd-?H4gSaԹa9!bIN$nYyc%=-hn̬OrLϱ2騗,ƽ,o}Wi9opY32RZʲWEarp|AeїwL\E64eC(-9c5v!O! DŽE+F˷^ضW͎a|fIsY:֫l簈Jkҝx,{{\!HK{?-L^I73&!$pz*[iI*vA^$04%9v|7PެHFd +eIBR&l`arOK`?x$3ow+/p\Gwhk͔Tz,m <gUB?-F =NHӆPиrK C|/TF޻,|L*!h$Zm#F:)_9~'0Iuì!Ť kDZlp}*Fb:ǦGd<}*9"7j)J tG!)38pOqamkq "A[3)AQPD~Ūp;,)JqJ-GgF<(`d?^eɵ VLTiqyIrf6<8H¸=!\4AqБA8rWnmF+l45H)ޟX?n!(ܢn*(7Img R baJhЖ4DgJe(HI:mFijH8#f%w rnbiHBI(cQ8K. "#>SmÖv늾 G2lKPwwuמ/"]tjwyP/<0#]UPkO6<&jh1.ªM3D!ߣ^)P zJp}[wOV2\rv`"Hx"2b!%6;5N>IKh[A^ =GS^<j-BEdyGxHNE`}GHJp)z*\8Hق9,\dctb!D+z`UB)hCVz԰fϲIym X(r*G Hq^_ewْ8g{n[cOБZK/$iz j*R2@VH:QY<;wW-tP5%JxM6TI >hɬƃUZGIt @kMb\鯎=,B8b)* v%ܶQ "mƝb ֆ<wk.ylpn tW[֩8 g4@% =C%D>F3Mh֡TD UXZt:)cjKjӒ(4 !#d$DhT"|gXZKE4XA!N@\dwHC*8$©Է>o!å{d'l^eԾw'&^_GU,$>8f'ƊHrak yevZrI-ZQHvmI1R-EXRws/mp2]бGj'D.ˁHaC[S[wvwgVkCQ)xg%][ѶRZ*6*5A\{t4$cjohzpu>bH~&+X{C!'&[`y]D·. EAt()B":X蘘W. Fm Y_!-V1xw'S v`BpGX\F[BHxtgl6>vm9m4 l= 1ͭ0ݲjB%:P|@n5)؂Ñ)$d|uQIENDB`sugar-flipsticks-activity-1.orig/flipsticks.activity/icons/camera.png0000644000175000017500000000500510715416404025004 0ustar janijaniPNG  IHDR)ҦPbKGD pHYsnu>tIME 65?tEXtCommentCreated with The GIMPd%n iIDATXímfEy53e]AV(]64,AY B6%MiZ?CӄET_,i B oRYh wyv>k?d2sN&ssp+ 95X,Z+uP"t6gPUTP@ )fsD aFmӎMlFP(aVRh,#1ED,&0VHe jJRJ2'#sLQn1k@+V)fL?iNgd\k92 1C'>NG Z9H/4[l99.!t!EU1lenlscVdqvrz ܷl7dkb8Ϩ%zzlT1kylb),%r꠪(9Rca%Լ?&F#ؑ#_qS^nin 0sVEsdTѓ!PXKdkцV kcs&M-e˄}*+`U UVyߧngygˤbe<2f dTNibì)X,l,1 3rm4"Lq}14Ԥʰ[Q|bXkqT9x J0##K [WnG*U 6XNhO~*fܦ1auΖ |/#qF% FoSuE+!QD6k~ƛyk<}c7/ N;#y}I>a#y <(b  -sTjj\A2O(@񱀱yl~w{yy̶6 [ncGxu87ZK 1J6(s/M/59ѶgUh'S '&p;7yqGX AB1J1:n[!'(pd =,,9\)MSԦA,E /! |ZO01SՖ3KE`DA) 4(V (S[sΙg 5Dø━ S.<E.Gm,2XO1RH\t(@.U©i!,w_H1B9|! $Jm]_wd˄ͬ;7>ؽv&_o~,Gナ3ic!BQIF~,p0Ja3XebjiLN1R,`%7;^9#} ~+{Wطo` R}+W aVOwad%FRޯӈ[!wcO:ߡJ/tx}O{5\qN~} _sx߂:˃O=??x?FPc9SrB֖+D0cU h3X'T"jDZǴvxC_㩃;{ce;銫ib ;̳=O[cZD7.n|"Rc`Ǝ4XĠf!zC<7;)#X-)P$g tTb暩4MsΫid2QQUK+GHsFD0AKUAnӏr AW_ ` , 鈵Ɔ^8LX"V{B bJPUDh+i1cc?QK!-ҡs㹅-| !آV pHYs  tIME3% !ktEXtComment̖IDAThAIEsؠ{E 8 6,ZT#x=~X! H;DТ)ꨪU0i$QwyvG~Pr}V>fo"ETR\ JU\UtMѲJ٪. V( k`5fJsue "q{MUIJ"Kـ$*(XADSY8?ϿIqO= . 5*7>&r%H o:JrEb~.<8!kُޠETHn[D]UQni274DWr9>DI͑U⮸%QJN'gf/ovbzejR\cbܶ9"-GR'H፴Ac>8 ۴6x 7pI!%8}c{][TW0HSfNDV=0^5Xs8#-AW)^$IWE,d<*V[.SP*qQ[>8Ώ|iMWUQ a*4WVD*[0rD)DeTňI*2yon:?94YT**'ْuJ\6's:jNHV3 i|2⟄oYFݢX"iCƩizUN"me3!VF$ueќhSwmٞwN2=V uQ_tQ*Y%䊻sʪfoZ)e TyuZ:3y]#i҈ԐtK# uIxХck䤅,m")"f74CD."~WI%M[]N_4NV?jMԂiҽЃ*u+rȞlk-QǍPG-ޜ/c:,uZ -gX+9$]7kR:*- Fkrk+4IjIAbQu 6ϕnl2G#Фܛp!.|MÊb6n7]xNܒV| ڑ"sneNphfRݪB DنeHtIME+>tEXtCommentCreated with The GIMPd%n IDAT8˥1(Ea9]a0dHJ6$& .ZȢL6Aդ R,$X9yƷ]'GJhJ`0jQHֱ~ *9} ‵x-j'm%'c/jIENDB`sugar-flipsticks-activity-1.orig/flipsticks.activity/icons/right_arrow.png0000644000175000017500000000065010715416404026104 0ustar janijaniPNG  IHDRbKGD pHYsnu>tIME+&\tEXtCommentCreated with The GIMPd%n IDAT8˥Կ/QOa!n.`61J LO0Kb",6`(!;4Y>mcchT7Fo't@$s̠?h;E=1lXEDE苁$*G'JGĢгQ *""SB-q,cxMo};o\fZA~pezm#lf%b YU~.c3PIIENDB`sugar-flipsticks-activity-1.orig/flipsticks.activity/lp-en/0000755000175000017500000000000010715422424022745 5ustar janijanisugar-flipsticks-activity-1.orig/flipsticks.activity/lp-en/Lesson_Plan_1.txt0000644000175000017500000000706410715416404026153 0ustar janijaniLesson Plan 1: Exploring Flipsticks From the Home screen of your XO, click on the Flipsticks icon to open it. You can also open Flipsticks from the MaMaMedia Creative Center activity. POSE YOUR STICK FIGURE BY CLICKING DIRECTLY ON HIM The first thing you will notice is a stick figure in the 'stage' area. - Put him in different poses by clicking and dragging on the red dots on his body - Use the yellow dot to rotate him. - Use the green dot to move him to a different place on the screen POSE YOUR STICK FIGURE USING THE BODY PARTS LIST - Look at the text list of body parts on the right side of the screen. - Click on a part, such as "Head" or "Upper Left Arm" and look at the numbers for "Angle" and "Size" that appear at the top of the list. - Click on the "Angle" number then type in a new number on your keyboard to move that part on your stick figure - Click on the "Size" number then type in a new number on you keyboard to make the part bigger or smaller. - Press the "enter" key on your keyboard to save your new number. - Notice how your stick figure has changed. SAVE YOUR POSES AS KEYFRAMES - When you like the way your stick figure looks, save it as a "keyframe" - The keyframes are the five circles under the Stage window. - Click on a keyframe circle to choose it -- it will turn pink so you know it is ready. Then click on the Camera button (at the bottom of the screen) to save you pose into this keyframe. - Move the stick figure into a new pose, then save it by clicking on another keyframe circle and then clicking the Camera button. - Fill up all five keyframes with different poses. WATCH YOUR ANIMATION! - To play your animationl, press the Play (right arrow) button at the right end of the keyframes line. Your figure will move through the poses you created. - Notice how the computer adds extra poses in between you keyframes, so your animation plays smoothly. - Press on the Play button again if you would like to stop - Press the Play Backwards (left arrow) button to play it backwards - Press the Play Backwards button again if you would like to stop. EDIT YOUR ANIMATION REORDER THE POSES: You can change the order of you keyframes by clicking on each circle and dragging it to the left or right. Press Play to see how the figure moves when the frames are in a different order. ADJUST THE SPEED: There is a Speed control "slider" bar underneath the keyframes. Make your animation move faster or slower by clicking on the little circle on the Speed bar and dragging it left (to go slower) or right (to go faster). RESET THE STICK FIGURE: If you want to start a new post from the original standing position, click the butotn with the man on it. CLEAR FRAMES: If you want to clear out the keyframes and start fresh, click the button that looks like a circle with a line through it. SAVE AND SHARE YOUR ANIMATION Take time to explore and make many different movements with your figure. When you are done, click on the Journal icon (open book at the top of your screen) to keep a copy of your animation in the Journal. Share the animation you made with your friends and classmates by selecting the "Share with: My Neighborhood" option in the top bar of your screen. Use the "Export Frame One" button to turn your first pose into a picture that you can use in other programs, like Paint or Jigshaw Puzzle. After looking at one another's Flipsticks animations, discuss what was difficult and what was easy about making them. What would you like to program your Flipsticks figure to do next? sugar-flipsticks-activity-1.orig/flipsticks.activity/lp-en/Lesson_Plan_2.txt0000644000175000017500000000525210715416404026151 0ustar janijaniLesson Plan 2: Introducing Geometry Geometry is the study of curves, angles, and shapes. Teachers or students who are familiar with geometry can lead new learners in the following exercise. EXPLORE BASICS ABOUT ANGLES AND STRAIGHT LINES Ask the learners: What do you know about geometry? Then explain that you will be exploring some basics about angles and straight lines. - Using a chalk board or paper, draw a circle and explain that a perfect circle is 360 degrees around. - Draw a straight horizontal line through the circle and explain that the line is a 180 degree angle. - Draw a staight vertical line through the middle of the circle; ask learners what they notice about the shape it created by crossing the straight horizontal line. - Point out how cutting the circle into four quarters forms 90 degree angles. Explain that a 90 degree angle is called a right angle - Draw a diagonal line that cuts one of the four quarters of the circle in half again. Explain that an angle half the size of the 90 degree angle is a 45 degree angle. - Discuss with the class why mathematicians measure angles and what migth be the importance of doing this NOW USE FLIPSTICKS TO EXPLORE ANGLES FURTHER From the Home screen of your XO, lick on the Flipsticks icon to open it. You can also open Flipsticks from the MaMaMedia Creative Center activity. Go the the Body Parts list and click on the "Upper Right Arm" then move your cursor where it says "Angle" and type in a 0. Press "enter" on the keyboard. Click on the "Lower Right Arm" and type in 0. Press "enter" on the keyboard. Now you should have a straight line. This should be the figure's first movement. Click on the first keyframe circle and then the camera button to save this pose. Click on the second keyframe circle, then go back to the Body Parts list. Click on the "Lower Right Arm" and type in 45. Press "enter" on the keyboard. Click on the camera button to save this pose. Click on the the third keyframe circle, then go back to the Body Parts list. Click on the "Lower Right Arm" and then type in 270. Press "enter" on the keyboard. Click on the camera button to save this pose. Click on the fifth keyframe circle, then go back to the Body Parts list. Click on the "Lower Right Arm" and type in 360. Press "enter" on the keyboard. Click on the camera button to save this pose. Press the play button and discuss what you notice about the movements this figure is making. What size angles are made? What is the final shape that has been made? How many 90 degree anbles are there? How many 45 degree angles are there? Have on student record this discussion on the XO laptop in the WRITE program. sugar-flipsticks-activity-1.orig/flipsticks.activity/lp-en/Lesson_Plan_3.txt0000644000175000017500000000241210715416404026145 0ustar janijaniLesson Plan 3: Progressive Story Telling A progressive story is when one person starts a story idea an everyone else in the group adds a part of the story to it until the story is complete. To start this Flipsticks story, the teacher or a student should create a Flipsticks animation on the XO computer. Together the class is going to write a story based on this animation. Sit in a circle on the floor and watch the starter animation as a group. The person who created the animation should tell the first part of the story, and explain who and where the character is. The next student should share what would happen next in the story. Just choose one simple action. This story should be based on the picture and should follow what came begore. The next student should add do the story and so on. Each idea should build off of the next. The story needs to build up to a problem, a climax, and finally a solution. One student should record this story on their XO laptop. Now each person should work on a Flipsticks animation for their part of the story. When everyone is done, have the group sit together again. The person who wrote the story down for the group will read it out loud. As their part comes up in the story, each person will show their animation to the group. sugar-flipsticks-activity-1.orig/flipsticks.activity/lp-en/An_Overview.txt0000644000175000017500000000216310715416404025735 0ustar janijaniFlipsticks: Lesson Plans Overview Flipsticks is a "keyframe animation" tool that lets you pose and program a stick figure to rotate, twist, turn, tumble, and dane. It provides a fun context for learners (and beginning XO users) to explore basic functions of the XO laptop and to learn how to articulate many creative ideas. You can save your Flipsticks animations to the Journal and share them with friends using the mesh network. You can export the first pose as a picture, then use it in other creative projects. Flipsticks can be integrated into many school subject areas such as creative writing, art, drama, geometry and computer programming. Students can make Flipsticks figures that relate to a subject the class is studying, and share them with peers. It helps you develop spatial and analytical thinking skills and to express ideas that you might not have words for yet. Skills: Learn how to use specific programs of the XO Laptop. Learn some basic geometric ideas. Learn to translate ideas into artistic images. Learn about the climax of a story. Learn how to tell a story. Practice working in groups and with a partner. sugar-flipsticks-activity-1.orig/flipsticks.activity/flipsticks.py0000644000175000017500000020057210715416404024466 0ustar janijani#!/usr/bin/env python # 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 2 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, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # ### flipsticks ### ### author: Ed Stoner (ed@whsd.net) ### (c) 2007 World Wide Workshop Foundation import time import pygtk pygtk.require('2.0') import gtk import gobject import os import math import textwrap import pickle SERVICE = 'org.freedesktop.Telepathy.Tube.Connect' IFACE = SERVICE PATH = '/org/freedesktop/Telepathy/Tube/Connect' GRAY = "#B7B7B7" # gray PINK = "#FF0099" # pink YELLOW = "#FFFF00" # yellow WHITE = "#FFFFFF" BLACK = "#000000" BACKGROUND = "#66CC00" # light green BUTTON_FOREGROUND = "#CCFB99" # very light green BUTTON_BACKGROUND = "#027F01" # dark green COLOR_FG_BUTTONS = ( (gtk.STATE_NORMAL,"#CCFF99"), (gtk.STATE_ACTIVE,"#CCFF99"), (gtk.STATE_PRELIGHT,"#CCFF99"), (gtk.STATE_SELECTED,"#CCFF99"), (gtk.STATE_INSENSITIVE,"#CCFF99"), ) # very light green COLOR_BG_BUTTONS = ( (gtk.STATE_NORMAL,"#027F01"), (gtk.STATE_ACTIVE,"#CCFF99"), (gtk.STATE_PRELIGHT,"#016D01"), (gtk.STATE_SELECTED,"#CCFF99"), (gtk.STATE_INSENSITIVE,"#027F01"), ) OLD_COLOR_BG_BUTTONS = ( (gtk.STATE_NORMAL,"#027F01"), (gtk.STATE_ACTIVE,"#014D01"), (gtk.STATE_PRELIGHT,"#016D01"), (gtk.STATE_SELECTED,"#027F01"), (gtk.STATE_INSENSITIVE,"#027F01"), ) SPANISH = u'Espa\xf1ol' LANG = {'English':{'size':'Size', 'angle':'Angle', 'lessonplan':'Lesson Plans', 'lpdir':'lp-en', 'export':'Export Frame One', 'HEAD':'Head', 'NECK':'Neck', 'RIGHT SHOULDER':'Right Shoulder', 'UPPER RIGHT ARM':'Upper Right Arm', 'LOWER RIGHT ARM':'Lower Right Arm', 'RIGHT HAND':'Right Hand', 'LEFT SHOULDER':'Left Shoulder', 'UPPER LEFT ARM':'Upper Left Arm', 'LOWER LEFT ARM':'Lower Left Arm', 'LEFT HAND':'Left Hand', 'TORSO':'Torso', 'RIGHT HIP':'Right Hip', 'UPPER RIGHT LEG':'Upper Right Leg', 'LOWER RIGHT LEG':'Lower Right Leg', 'RIGHT FOOT':'Right Foot', 'LEFT HIP':'Left Hip', 'UPPER LEFT LEG':'Upper Left Leg', 'LOWER LEFT LEG':'Lower Left Leg', 'LEFT FOOT':'Left Foot'}, SPANISH:{'size':u'Tama\xf1o', 'angle':u'\xe1ngulo', 'lessonplan':u'Planes de la lecci\xf3n', 'lpdir':'lp-en', 'export':'Un marco de la exportacion', 'HEAD':'Cabeza', 'NECK':'Cuello', 'RIGHT SHOULDER':'Hombro derecho', 'UPPER RIGHT ARM':'Brazo derecho superior', 'LOWER RIGHT ARM':'Bajar el brazo derecho', 'RIGHT HAND':'Mano derecha', 'LEFT SHOULDER':'Hombro izquierdo', 'UPPER LEFT ARM':'Brazo izquierdo superior', 'LOWER LEFT ARM':u'Un brazo izquierdo m\xe1s bajo', 'LEFT HAND':'Mano izquierda', 'TORSO':'Torso', 'RIGHT HIP':'Cadera derecha', 'UPPER RIGHT LEG':'Pierna derecha superior', 'LOWER RIGHT LEG':'Bajar la pierna derecha', 'RIGHT FOOT':'Pie derecho', 'LEFT HIP':'Cadera izquierda', 'UPPER LEFT LEG':'Pierna izquierda superior', 'LOWER LEFT LEG':u'Una pierna izquierda m\xe1s baja', 'LEFT FOOT':'Pie izquierdo'}} DRAWWIDTH = 750 DRAWHEIGHT = 500 FPWIDTH = 150 FPHEIGHT = 100 #DRAWHEIGHT = 300 for my laptop KEYFRAMEWIDTH = 675 KEYFRAMEHEIGHT = 80 KEYFRAMES = [50,190,337,487,625] TOTALFRAMES = 30 STICKS = {'HEAD':(0,15), 'NECK':(90,15), 'RIGHT SHOULDER':(185,25), 'UPPER RIGHT ARM':(60,35), 'LOWER RIGHT ARM':(35,35), 'LEFT SHOULDER':(355,25), 'UPPER LEFT ARM':(300,35), 'LOWER LEFT ARM':(325,35), 'TORSO':(270,60), 'RIGHT HIP':(80,20), 'UPPER RIGHT LEG':(300,50), 'LOWER RIGHT LEG':(340,40), 'RIGHT FOOT':(85,15), 'LEFT HIP':(280,20), 'UPPER LEFT LEG':(65,50), 'LOWER LEFT LEG':(15,40), 'LEFT FOOT':(275,15)} PARTS = {'RIGHT HAND':14, 'LEFT HAND':14} STICKLIST = ['NECK','HEAD','RIGHT SHOULDER','UPPER RIGHT ARM','LOWER RIGHT ARM', 'LEFT SHOULDER','UPPER LEFT ARM','LOWER LEFT ARM','TORSO', 'RIGHT HIP','UPPER RIGHT LEG','LOWER RIGHT LEG','RIGHT FOOT', 'LEFT HIP','UPPER LEFT LEG','LOWER LEFT LEG','LEFT FOOT'] LABELLIST = ['HEAD','NECK','RIGHT SHOULDER','UPPER RIGHT ARM','LOWER RIGHT ARM', 'RIGHT HAND','LEFT SHOULDER','UPPER LEFT ARM','LOWER LEFT ARM','LEFT HAND', 'TORSO','RIGHT HIP','UPPER RIGHT LEG','LOWER RIGHT LEG','RIGHT FOOT', 'LEFT HIP','UPPER LEFT LEG','LOWER LEFT LEG','LEFT FOOT'] # The joint is the circle at the end of the stick JOINTS = {'HEAD':'head', 'NECK':'neck', 'RIGHT SHOULDER':'rightshoulder', 'UPPER RIGHT ARM':'rightelbow', 'LOWER RIGHT ARM':'righthand', 'LEFT SHOULDER':'leftshoulder', 'UPPER LEFT ARM':'leftelbow', 'LOWER LEFT ARM':'lefthand', 'TORSO':'groin', 'RIGHT HIP':'righthip', 'UPPER RIGHT LEG':'rightknee', 'LOWER RIGHT LEG':'rightheel', 'RIGHT FOOT':'righttoe', 'LEFT HIP':'lefthip', 'UPPER LEFT LEG':'leftknee', 'LOWER LEFT LEG':'leftheel', 'LEFT FOOT':'lefttoe'} JOINTTOSTICK = {} for jname in JOINTS: JOINTTOSTICK[JOINTS[jname]] = jname PARTS = {'HEAD':40, 'RIGHT HAND':14, 'LEFT HAND':14} TESTSTICKS = {'RIGHT SHOULDER':(37,20), 'UPPER RIGHT ARM':(6,15), 'LOWER RIGHT ARM':(10,15)} def getwrappedfile(filepath,linelength): text = [] f = file(filepath) for line in f: if line == '\n': text.append(line) else: for wline in textwrap.wrap(line.strip()): text.append('%s\n' % wline) return ''.join(text) def capwords(s): x = s.split() n = [] for word in x: n.append(word.capitalize()) return ' '.join(n) def prepare_btn(btn, w=-1, h=-1): for state, color in COLOR_BG_BUTTONS: btn.modify_bg(state, gtk.gdk.color_parse(color)) c = btn.get_child() if c is not None: for state, color in COLOR_FG_BUTTONS: c.modify_fg(state, gtk.gdk.color_parse(color)) else: for state, color in COLOR_FG_BUTTONS: btn.modify_fg(state, gtk.gdk.color_parse(color)) if w>0 or h>0: btn.set_size_request(w, h) return btn def inarea(x,y,awidth,aheight): if x+5 > awidth: return False if y+5 > aheight: return False if y < 5: return False if x < 5: return False return True def interpolate(x,x0,y0,x1,y1): if x1-x0 == 0: return y0 m = float(y1-y0)/float(x1-x0) y = y0 + ((x-x0)*m) return y def getpoints(x,y,angle,len): nx = int(round(x + (len * math.cos(math.radians(angle))))) ny = int(round(y - (len * math.sin(math.radians(angle))))) return (nx,ny) def scalesticks(stickdict,i): for key in stickdict: (angle,len) = stickdict[key] newlen = int(len * i) stickdict[key] = (angle,newlen) class flipsticks: def delete_event(self, widget, event, data=None): return False def destroy(self, widget, data=None): gtk.main_quit() def expose_event(self, widget, event): x , y, width, height = event.area widget.window.draw_drawable(widget.get_style().fg_gc[gtk.STATE_NORMAL], self.pixmap, x, y, x, y, width, height) return False def kf_expose_event(self, widget, event): x , y, width, height = event.area widget.window.draw_drawable(widget.get_style().fg_gc[gtk.STATE_NORMAL], self.kfpixmap, x, y, x, y, width, height) return False def fp_expose_event(self, widget, event): x , y, width, height = event.area widget.window.draw_drawable(widget.get_style().fg_gc[gtk.STATE_NORMAL], self.fppixmap, x, y, x, y, width, height) return False def configure_event(self, widget, event): x, y, width, height = self.mfdraw.get_allocation() self.pixmap = gtk.gdk.Pixmap(self.mfdraw.window, width, height) self.drawmainframe() return True def kf_configure_event(self, widget, event): self.drawkeyframe() return True def fp_configure_event(self, widget, event): self.drawfp() return True def motion_notify_event(self, widget, event): if event.is_hint: x, y, state = event.window.get_pointer() else: x = event.x y = event.y state = event.state if state & gtk.gdk.BUTTON1_MASK and self.pixmap != None: if self.jointpressed: if inarea(x,y,DRAWWIDTH,DRAWHEIGHT): #self.joints[self.jointpressed] = (x,y) # old hack way # first find the parents x,y (px,py) = self.getparentjoint(self.jointpressed,self.joints, self.middle) if x-px == 0: #computeangle = 0 b = 1 else: b = float(px-x) a = float(y-py) computeangle = int(math.degrees(math.atan(a/b))) stickname = JOINTTOSTICK[self.jointpressed] # add sum of parent angles to new angle parents = self.getparentsticks(stickname) panglesum = 0 for parentname in parents: (pangle,plen) = self.sticks[parentname] panglesum += pangle (angle, len) = self.sticks[stickname] #print 'X:%s,Y:%s,PX:%s,PY:%s,ANGLE:%s,NEWANGLE:%s' % (x,y,px,py,angle,newangle) newangle = computeangle-panglesum if (x < px) or (b == 1): newangle = newangle + 180 if newangle < 0: newangle = 360 + newangle self.sticks[stickname] = (newangle,len) self.setjoints() # this is overkill self.drawmainframe() self.updateentrybox() elif self.middlepressed: if inarea(x,y,DRAWWIDTH,DRAWHEIGHT): xdiff = x-self.middle[0] ydiff = y-self.middle[1] self.shiftjoints(xdiff,ydiff) self.middle = (x,y) self.drawmainframe() elif self.rotatepressed: if inarea(x,y,DRAWWIDTH,DRAWHEIGHT): (px,py) = self.middle if x-px == 0: #computeangle = 0 b = 1 else: b = float(px-x) a = float(y-py) computeangle = int(math.degrees(math.atan(a/b))) stickname = 'TORSO' (angle, len) = self.sticks[stickname] newangle = computeangle if (x < px) or (b == 1): newangle = newangle + 180 if newangle < 0: newangle = 360 + newangle anglediff = newangle-angle self.sticks[stickname] = (newangle,len) # now rotate the other sticks off of the middle for stickname in ['NECK','RIGHT SHOULDER','LEFT SHOULDER']: (sangle,slen) = self.sticks[stickname] newsangle = sangle+anglediff if newsangle < 0: newsangle = 360 + newsangle if newsangle > 360: newsangle = newsangle - 360 self.sticks[stickname] = (newsangle,slen) self.setjoints() self.drawmainframe() self.updateentrybox() return True def kf_motion_notify_event(self, widget, event): if event.is_hint: x, y, state = event.window.get_pointer() else: x = event.x y = event.y state = event.state if state & gtk.gdk.BUTTON1_MASK and self.pixmap != None: if self.kfpressed >= 0: if inarea(x,y,KEYFRAMEWIDTH,KEYFRAMEHEIGHT): xdiff = x-self.keyframes[self.kfpressed] self.shiftjoints(xdiff,0,self.kfsjoints[self.kfpressed]) self.keyframes[self.kfpressed] = x self.drawkeyframe() return True def button_press_event(self, widget, event): if event.button == 1 and self.pixmap != None: joint = self.injoint(event.x, event.y) if joint: self.jointpressed = joint self.drawmainframe() elif self.inmiddle(event.x, event.y): self.middlepressed = True self.drawmainframe() elif self.inrotate(event.x, event.y): self.rotatepressed = True self.drawmainframe() return True def syncmaintokf(self): # set the main window to the keyframe if self.kfsticks[self.kfselected]: self.sticks = self.kfsticks[self.kfselected].copy() self.parts = self.kfparts[self.kfselected].copy() self.middle = self.kfmiddles[self.kfselected] self.setjoints() self.drawmainframe() def kf_button_press_event(self, widget, event): if event.button == 1 and self.pixmap != None: kfnum = self.inkeyframe(event.x, event.y) if kfnum >= 0: self.kfpressed = kfnum self.kfselected = kfnum self.drawkeyframe() self.syncmaintokf() self.updateentrybox() return True def button_release_event(self, widget, event): self.jointpressed = None self.middlepressed = False self.rotatepressed = False self.drawmainframe() return True def kf_button_release_event(self, widget, event): self.kfpressed = -1 self.drawkeyframe() return True def setplayspeed(self,adj): #self.waittime = int((6-adj.value)*150) self.waittime = int((6-adj.value)*75) if self.playing: gobject.source_remove(self.playing) self.playing = gobject.timeout_add(self.waittime, self.playframe) def playframe(self): if not self.playing: return False else: if self.playframenum == -1: return True joints = self.frames[self.playframenum] parts = self.fparts[self.playframenum] # draw on the main drawing area area = self.toplevel.window drawgc = area.new_gc() drawgc.line_width = 3 cm = drawgc.get_colormap() white = cm.alloc_color('white') black = cm.alloc_color('black') drawgc.fill = gtk.gdk.SOLID x, y, width, height = self.mfdraw.get_allocation() #self.pixmap = gtk.gdk.Pixmap(self.mfdraw.window, width, height) # clear area drawgc.set_foreground(white) self.pixmap.draw_rectangle(drawgc,True,0,0,width,height) drawgc.set_foreground(black) #hsize = self.sticks['HEAD'][1] # really half of head size hsize = self.fhsize[self.playframenum] middle = self.fmiddles[self.playframenum] rhsize = parts['RIGHT HAND'] lhsize = parts['LEFT HAND'] self.drawstickman(drawgc,self.pixmap,middle,joints,hsize,rhsize,lhsize) # draw circle for middle #green = cm.alloc_color('green') #drawgc.set_foreground(green) #x,y = middle #self.pixmap.draw_arc(drawgc,True,x-5,y-5,10,10,0,360*64) self.mfdraw.queue_draw() fsecs = self.frames.keys() fsecs.sort() if self.playingbackwards: # decrement playframenum if self.playframenum == fsecs[0]: self.playframenum = fsecs[-1] else: i = fsecs.index(self.playframenum) self.playframenum = fsecs[i-1] else: # increment playframenum if self.playframenum == fsecs[-1]: self.playframenum = fsecs[0] else: i = fsecs.index(self.playframenum) self.playframenum = fsecs[i+1] if self.playing: return True else: return False def enterangle_callback(self, widget, entry): stickname = self.stickselected if stickname in self.sticks: newangle = int(entry.get_text()) (angle, len) = self.sticks[stickname] self.sticks[stickname] = (newangle,len) else: # part not stick self.angleentry.set_text('-') self.setjoints() self.drawmainframe() def updateentrybox(self): if self.stickselected in self.sticks: (angle, len) = self.sticks[self.stickselected] self.angleentry.set_text(str(angle)) else: # part not stick len = self.parts[self.stickselected] self.sizeentry.set_text(str(len)) def enterlen_callback(self, widget, entry): stickname = self.stickselected newlen = int(entry.get_text()) if stickname in self.sticks: if stickname == 'HEAD': newlen = int(newlen/2.0) (angle, len) = self.sticks[stickname] self.sticks[stickname] = (angle,newlen) else: # part not stick self.parts[stickname] = newlen self.setjoints() self.drawmainframe() def reset(self, widget, data=None): xmiddle = int(DRAWWIDTH/2.0) ymiddle = int(DRAWHEIGHT/2.0) self.middle = (xmiddle,ymiddle) self.sticks = STICKS.copy() self.parts = PARTS.copy() self.selectstickebox() self.setjoints() self.drawmainframe() def setframe(self, widget, data=None): self.kfmiddles[self.kfselected] = self.middle self.kfparts[self.kfselected] = self.parts.copy() self.kfsticks[self.kfselected] = self.sticks.copy() self.kfssticks[self.kfselected] = self.sticks.copy() scalesticks(self.kfssticks[self.kfselected],.2) self.kfjoints[self.kfselected] = self.joints.copy() self.kfsjoints[self.kfselected] = self.initjoints() #x, y, width, height = self.kfdraw.get_allocation() #y = int(height/2.0) #y = int(KEYFRAMEHEIGHT/2.0)-5 y = int(KEYFRAMEHEIGHT/2.0) x = self.keyframes[self.kfselected] kfmiddle = (x,y) self.setjoints(self.kfsjoints[self.kfselected],self.kfssticks[self.kfselected],kfmiddle) self.drawkeyframe() def clearframe(self, widget, data=None): self.kfsticks[self.kfselected] = None self.kfssticks[self.kfselected] = None self.kfjoints[self.kfselected] = None self.kfsjoints[self.kfselected] = None self.kfparts[self.kfselected] = None self.drawkeyframe() def intjoints(self,sjoints,ejoints,count,numpoints): # numpoints: number of points between start and end # count: point were getting now ijoints = {} for jname in sjoints: (x0,y0) = sjoints[jname] (x1,y1) = ejoints[jname] #print 'x0:%s,y0:%s' % (x0,y0) #print 'x1:%s,y1:%s' % (x1,y1) x = x0 + (count * ((x1-x0)/float(numpoints))) y = interpolate(x,x0,y0,x1,y1) ijoints[jname] = (int(x),int(y)) return ijoints def intparts(self,sparts,eparts,count,numpoints): iparts = {} for pname in sparts: x0 = sparts[pname] x1 = eparts[pname] if x0 == x1: iparts[pname] = x0 continue x = x0 + (count * ((x1-x0)/float(numpoints))) iparts[pname] = int(x) return iparts def inthsize(self,shsize,ehsize,count,numpoints): x0 = shsize x1 = ehsize if x0 == x1: return x0 x = x0 + (count * ((x1-x0)/float(numpoints))) return int(x) def intmiddle(self,smiddle,emiddle,count,numpoints): (x0,y0) = smiddle (x1,y1) = emiddle x = x0 + (count * ((x1-x0)/float(numpoints))) y = interpolate(x,x0,y0,x1,y1) return (int(x),int(y)) def makeframes(self): endsecs = KEYFRAMEWIDTH fint = int(endsecs/float(TOTALFRAMES)) # frame interval self.frames = {} self.fparts = {} self.fmiddles = {} self.fhsize = {} kf = {} # point to keyframes by x-middle (which represents a time, like seconds) for i in range(len(self.keyframes)): secs = self.keyframes[i] #kf[secs] = i # use self.kfjoints[kf[secs]] and self.kfparts[kf[secs]] if self.kfjoints[i]: self.frames[secs] = self.kfjoints[i].copy() self.fparts[secs] = self.kfparts[i].copy() self.fmiddles[secs] = self.kfmiddles[i] #print '%s:KFMIDDLE:%s = (%s,%s)' % (i,secs,self.fmiddles[secs][0],self.fmiddles[secs][1]) self.fhsize[secs] = self.kfsticks[i]['HEAD'][1] fsecs = self.frames.keys() fsecs.sort() if not fsecs: return # ADD frame at 0 self.frames[0] = self.frames[fsecs[0]].copy() self.fparts[0] = self.fparts[fsecs[0]].copy() self.fmiddles[0] = self.fmiddles[fsecs[0]] self.fhsize[0] = self.fhsize[fsecs[0]] # ADD frame at end self.frames[endsecs] = self.frames[fsecs[-1]].copy() self.fparts[endsecs] = self.fparts[fsecs[-1]].copy() self.fmiddles[endsecs] = self.fmiddles[fsecs[-1]] self.fhsize[endsecs] = self.fhsize[fsecs[-1]] # now fill in frames between fsecs = self.frames.keys() fsecs.sort() for i in range(len(fsecs)): if i == len(fsecs)-1: continue # nothing after end startsecs = fsecs[i] endsecs = fsecs[i+1] numframes = int((endsecs-startsecs)/float(fint))-1 #print 'NUMFRAMES(%s):%s' % (i,numframes) for j in range(numframes-1): # MAYBE SHOULD BE numframes secs = startsecs + ((j+1)*fint) self.frames[secs] = self.intjoints(self.frames[startsecs],self.frames[endsecs], j+1,numframes) self.fparts[secs] = self.intparts(self.fparts[startsecs],self.fparts[endsecs], j+1,numframes) self.fmiddles[secs] = self.intmiddle(self.fmiddles[startsecs],self.fmiddles[endsecs], j+1,numframes) self.fhsize[secs] = self.inthsize(self.fhsize[startsecs],self.fhsize[endsecs], j+1,numframes) #print '%s,%s(%s secs):(%s,%s) START(%s,%s) - END(%s,%s) startsecs:%s endsecs:%s numframes:%s' % (i,j,secs,self.fmiddles[secs][0],self.fmiddles[secs][1],self.fmiddles[startsecs][0],self.fmiddles[startsecs][1],self.fmiddles[endsecs][0],self.fmiddles[endsecs][1],startsecs,endsecs,numframes) #print self.frames.keys() def shiftjoints(self,xdiff,ydiff,joints=None): if not joints: joints = self.joints for jname in joints: #if isinstance(self.joints[jname],tuple): (jx,jy) = joints[jname] njx = jx + xdiff njy = jy + ydiff joints[jname] = (njx,njy) def initjoints(self): joints = {} for stickname in JOINTS: jname = JOINTS[stickname] joints[jname] = (0,0) return joints def getparentsticks(self, stickname): if stickname in ['RIGHT SHOULDER','LEFT SHOULDER','NECK','TORSO']: return [] if stickname in ['HEAD']: return ['NECK'] if stickname == 'UPPER RIGHT ARM': return ['RIGHT SHOULDER'] if stickname == 'LOWER RIGHT ARM': return ['UPPER RIGHT ARM','RIGHT SHOULDER'] if stickname == 'UPPER LEFT ARM': return ['LEFT SHOULDER'] if stickname == 'LOWER LEFT ARM': return ['UPPER LEFT ARM','LEFT SHOULDER'] if stickname == 'RIGHT HIP': return ['TORSO'] if stickname == 'UPPER RIGHT LEG': return ['RIGHT HIP','TORSO'] if stickname == 'LOWER RIGHT LEG': return ['UPPER RIGHT LEG','RIGHT HIP','TORSO'] if stickname == 'RIGHT FOOT': return ['LOWER RIGHT LEG','UPPER RIGHT LEG','RIGHT HIP','TORSO'] if stickname == 'LEFT HIP': return ['TORSO'] if stickname == 'UPPER LEFT LEG': return ['LEFT HIP','TORSO'] if stickname == 'LOWER LEFT LEG': return ['UPPER LEFT LEG','LEFT HIP','TORSO'] if stickname == 'LEFT FOOT': return ['LOWER LEFT LEG','UPPER LEFT LEG','LEFT HIP','TORSO'] def getparentjoint(self,jname,joints,middle): if jname in ['rightshoulder','leftshoulder','groin','neck']: return middle parentjoints = {'rightelbow':'rightshoulder', 'righthand':'rightelbow', 'leftelbow':'leftshoulder', 'lefthand':'leftelbow', 'righthip':'groin', 'rightknee':'righthip', 'rightheel':'rightknee', 'righttoe':'rightheel', 'lefthip':'groin', 'leftknee':'lefthip', 'leftheel':'leftknee', 'lefttoe':'leftheel', 'head':'neck'} return joints[parentjoints[jname]] def setjoints(self,joints=None,sticks=None,middle=None): if not joints: joints = self.joints if not sticks: sticks = self.sticks if not middle: middle = self.middle # have to traverse in order because # parent joints must be set right for stickname in self.sticklist: (angle,len) = sticks[stickname] jname = JOINTS[stickname] (x,y) = self.getparentjoint(jname,joints,middle) parents = self.getparentsticks(stickname) panglesum = 0 for parentname in parents: (pangle,plen) = sticks[parentname] panglesum += pangle (nx,ny) = getpoints(x,y,angle+panglesum,len) joints[jname] = (nx,ny) def drawmainframe(self): area = self.toplevel.window drawgc = area.new_gc() drawgc.line_width = 3 cm = drawgc.get_colormap() red = cm.alloc_color('red') yellow = cm.alloc_color('yellow') white = cm.alloc_color('white') black = cm.alloc_color('black') blue = cm.alloc_color('blue') green = cm.alloc_color('green') drawgc.fill = gtk.gdk.SOLID x, y, width, height = self.mfdraw.get_allocation() #self.pixmap = gtk.gdk.Pixmap(self.mfdraw.window, width, height) # clear area drawgc.set_foreground(white) self.pixmap.draw_rectangle(drawgc,True,0,0,width,height) drawgc.set_foreground(black) hsize = self.sticks['HEAD'][1] # really half of head size rhsize = self.parts['RIGHT HAND'] lhsize = self.parts['LEFT HAND'] self.drawstickman(drawgc,self.pixmap,self.middle,self.joints,hsize,rhsize,lhsize) # draw circle for middle drawgc.set_foreground(green) if self.middlepressed: drawgc.set_foreground(blue) x,y = self.middle self.pixmap.draw_arc(drawgc,True,x-5,y-5,10,10,0,360*64) # draw circle for rotate (should be halfway between middle and groin (rx,ry) = self.getrotatepoint() drawgc.set_foreground(yellow) if self.rotatepressed: drawgc.set_foreground(blue) self.pixmap.draw_arc(drawgc,True,rx-5,ry-5,10,10,0,360*64) # draw circles for joints drawgc.set_foreground(black) for jname in self.joints: if jname == 'head': continue x,y = self.joints[jname] if self.jointpressed == jname: drawgc.set_foreground(blue) self.pixmap.draw_arc(drawgc,True,x-5,y-5,10,10,0,360*64) drawgc.set_foreground(black) else: drawgc.set_foreground(red) self.pixmap.draw_arc(drawgc,True,x-5,y-5,10,10,0,360*64) drawgc.set_foreground(black) self.mfdraw.queue_draw() def drawstickman(self,drawgc,pixmap,middle,joints,hsize,rhsize,lhsize): leftarm = [middle, joints['leftshoulder'],joints['leftelbow'],joints['lefthand']] rightarm = [middle, joints['rightshoulder'],joints['rightelbow'],joints['righthand']] torso = [joints['neck'],middle,joints['groin']] leftleg = [joints['groin'],joints['lefthip'],joints['leftknee'], joints['leftheel'],joints['lefttoe']] rightleg = [joints['groin'],joints['righthip'],joints['rightknee'], joints['rightheel'],joints['righttoe']] # draw lines pixmap.draw_lines(drawgc, leftarm) pixmap.draw_lines(drawgc, rightarm) pixmap.draw_lines(drawgc, torso) pixmap.draw_lines(drawgc, leftleg) pixmap.draw_lines(drawgc, rightleg) # draw head x,y = joints['head'] pixmap.draw_arc(drawgc,True,x-hsize,y-hsize,hsize*2,hsize*2,0,360*64) # draw circles for hands x,y = joints['righthand'] pixmap.draw_arc(drawgc,True,x-int(rhsize/2.0),y-int(rhsize/2.0),rhsize,rhsize,0,360*64) x,y = joints['lefthand'] pixmap.draw_arc(drawgc,True,x-int(lhsize/2.0),y-int(lhsize/2.0),lhsize,lhsize,0,360*64) def drawkeyframe(self): area = self.toplevel.window drawgc = area.new_gc() drawgc.line_width = 2 cm = drawgc.get_colormap() red = cm.alloc_color('red') white = cm.alloc_color('white') black = cm.alloc_color('black') blue = cm.alloc_color('blue') green = cm.alloc_color('green') pink = cm.alloc_color(PINK) bgcolor = cm.alloc_color(BACKGROUND) darkgreen = cm.alloc_color(BUTTON_BACKGROUND) drawgc.fill = gtk.gdk.SOLID x, y, width, height = self.kfdraw.get_allocation() self.kfpixmap = gtk.gdk.Pixmap(self.kfdraw.window, width, height) # clear area drawgc.set_foreground(bgcolor) self.kfpixmap.draw_rectangle(drawgc,True,0,0,width,height) # draw line in middle drawgc.set_foreground(darkgreen) self.kfpixmap.draw_rectangle(drawgc,True,10,int(height/2.0)-5,width-20,10) x = 10 y = int(height/2.0) self.kfpixmap.draw_arc(drawgc,True,x-5,y-5,10,10,0,360*64) x = width-10 self.kfpixmap.draw_arc(drawgc,True,x-5,y-5,10,10,0,360*64) # draw the keyframe circles for i in range(len(self.keyframes)): # first the outer circle x = self.keyframes[i] if i == self.kfselected: drawgc.set_foreground(pink) else: drawgc.set_foreground(darkgreen) self.kfpixmap.draw_arc(drawgc,True,x-40,y-40,80,80,0,360*64) # then the inner circle drawgc.set_foreground(white) self.kfpixmap.draw_arc(drawgc,True,x-35,y-35,70,70,0,360*64) if self.kfssticks[i]: # draw a man in the circle drawgc.set_foreground(black) hsize = self.kfssticks[i]['HEAD'][1] rhsize = int(self.kfparts[i]['RIGHT HAND']*0.2) lhsize = int(self.kfparts[i]['LEFT HAND']*0.2) self.drawstickman(drawgc,self.kfpixmap,(x,y),self.kfsjoints[i],hsize,rhsize,lhsize) #self.kfpixmap.draw_arc(drawgc,True,x-5,y-5,10,10,0,360*64) self.kfdraw.queue_draw() def drawfp(self): area = self.toplevel.window drawgc = area.new_gc() drawgc.line_width = 1 cm = drawgc.get_colormap() red = cm.alloc_color('red') white = cm.alloc_color('white') black = cm.alloc_color('black') blue = cm.alloc_color('blue') green = cm.alloc_color('green') pink = cm.alloc_color(PINK) bgcolor = cm.alloc_color(BACKGROUND) darkgreen = cm.alloc_color(BUTTON_BACKGROUND) drawgc.fill = gtk.gdk.SOLID x, y, width, height = self.fpdraw.get_allocation() self.fppixmap = gtk.gdk.Pixmap(self.fpdraw.window, width, height) # clear area drawgc.set_foreground(white) self.fppixmap.draw_rectangle(drawgc,True,0,0,width,height) self.fpdraw.queue_draw() def inkeyframe(self, x, y): for i in range(len(self.keyframes)): kx = self.keyframes[i] if (abs(kx-x) <= 20): return i return -1 def injoint(self, x, y): for jname in self.joints: jx, jy = self.joints[jname] if (abs(jx-x) <= 5) and (abs(jy-y) <= 5): return jname def inmiddle(self, x, y): mx, my = self.middle if (abs(mx-x) <= 5) and (abs(my-y) <= 5): return True def inrotate(self, x, y): rx, ry = self.getrotatepoint() if (abs(rx-x) <= 5) and (abs(ry-y) <= 5): return True def getrotatepoint(self): (angle,len) = self.sticks['TORSO'] x,y = self.middle (rx,ry) = getpoints(x,y,angle,int(len/2.0)) return (rx,ry) def selectstick(self, widget, event, data=None): if data: if self.stickselected: ebox = self.stickbuttons[self.stickselected] ebox.modify_bg(gtk.STATE_NORMAL,gtk.gdk.color_parse(BUTTON_BACKGROUND)) label = ebox.get_child() label.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(BUTTON_FOREGROUND)) self.stickselected = data self.selectstickebox() def selectstickebox(self): ebox = self.stickbuttons[self.stickselected] ebox.modify_bg(gtk.STATE_NORMAL,gtk.gdk.color_parse(BUTTON_FOREGROUND)) label = ebox.get_child() label.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(BUTTON_BACKGROUND)) if self.stickselected in self.sticks: if self.stickselected == 'HEAD': self.sizeentry.set_text(str(self.sticks[self.stickselected][1]*2)) else: self.sizeentry.set_text(str(self.sticks[self.stickselected][1])) self.angleentry.set_text(str(self.sticks[self.stickselected][0])) else: # its a part not a stick self.angleentry.set_text('-') self.sizeentry.set_text(str(self.parts[self.stickselected])) def showlessonplans(self, widget, data=None): dia = gtk.Dialog(title='Lesson Plans', parent=None, flags=0, buttons=None) dia.set_default_size(500,500) dia.show() #dia.vbox.pack_start(scrolled_window, True, True, 0) notebook = gtk.Notebook() # uncomment below to highlight tabs notebook.modify_bg(gtk.STATE_NORMAL,gtk.gdk.color_parse(WHITE)) notebook.set_tab_pos(gtk.POS_TOP) #notebook.set_default_size(400,400) notebook.show() lessonplans = {} lpdir = os.path.join(self.mdirpath,LANG[self.language]['lpdir']) lpentries = os.listdir(lpdir) for entry in lpentries: fpath = os.path.join(lpdir,entry) lessonplans[entry] = getwrappedfile(fpath,95) lpkeys = lessonplans.keys() lpkeys.sort() for lpkey in lpkeys: lpname = lpkey.replace('_',' ').replace('0','')[:-4] label = gtk.Label(lessonplans[lpkey]) #if self.insugar: # label.modify_fg(gtk.STATE_NORMAL,gtk.gdk.color_parse(WHITE)) eb = gtk.EventBox() eb.modify_bg(gtk.STATE_NORMAL,gtk.gdk.color_parse(WHITE)) #label.set_line_wrap(True) label.show() eb.add(label) eb.show() #tlabel = gtk.Label('Lesson Plan %s' % str(i+1)) tlabel = gtk.Label(lpname) tlabel.show() scrolled_window = gtk.ScrolledWindow() scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS) scrolled_window.show() scrolled_window.add_with_viewport(eb) notebook.append_page(scrolled_window, tlabel) #dia.action_area.pack_start(notebook, True, True, 0) dia.vbox.pack_start(notebook, True, True, 0) result = dia.run() dia.destroy() def loadfile(self, widget, data=None): pass def savefile(self, widget, data=None): pass def exportanim(self, widget, data=None): if self.insugar: self.exporttojournal() else: self.exportfile() def exportfile(self): self.makeframes() fsecs = self.frames.keys() tmpdir = '/tmp' pngpaths = [] for i in fsecs: joints = self.frames[i] parts = self.fparts[i] # draw on the main drawing area area = self.toplevel.window drawgc = area.new_gc() drawgc.line_width = 3 cm = drawgc.get_colormap() white = cm.alloc_color('white') black = cm.alloc_color('black') drawgc.fill = gtk.gdk.SOLID x, y, width, height = self.mfdraw.get_allocation() pixmap = gtk.gdk.Pixmap(self.mfdraw.window, width, height) # clear area drawgc.set_foreground(white) pixmap.draw_rectangle(drawgc,True,0,0,width,height) drawgc.set_foreground(black) #hsize = self.sticks['HEAD'][1] # really half of head size hsize = self.fhsize[i] middle = self.fmiddles[i] rhsize = parts['RIGHT HAND'] lhsize = parts['LEFT HAND'] self.drawstickman(drawgc,pixmap,middle,joints,hsize,rhsize,lhsize) pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False, 8, width, height) gtk.gdk.Pixbuf.get_from_drawable(pixbuf,pixmap,pixmap.get_colormap(),0,0,0,0,width,height) filename = 'fp%03d.png' % i filepath = os.path.join(tmpdir,filename) pixbuf.save(filepath,'png') pngpaths.append(filepath) # now convert all of the pngs to gif and then make a gif animation convertpath = 'convert' tmpdir = '/tmp' entires = os.listdir(tmpdir) gifpaths = [] for pngfilepath in pngpaths: giffilepath = pngfilepath[:-4]+'.gif' gifpaths.append(giffilepath) os.system('%s %s %s' % (convertpath,pngfilepath,giffilepath)) #os.remove(pngfilepath) agifpath = os.path.join(self.mdirpath,'animatefp.gif') os.system('%s -delay 20 -loop 0 %s/fp*.gif %s' % (convertpath,tmpdir,agifpath)) for giffilepath in gifpaths: os.remove(giffilepath) def exporttojournal(self): self.makeframes() fsecs = self.frames.keys() tmpdir = '/tmp' pngpaths = [] firstpixindex = fsecs[0] for i in [fsecs[0]]: joints = self.frames[i] parts = self.fparts[i] # draw on the main drawing area area = self.toplevel.window drawgc = area.new_gc() drawgc.line_width = 3 cm = drawgc.get_colormap() white = cm.alloc_color('white') black = cm.alloc_color('black') drawgc.fill = gtk.gdk.SOLID x, y, width, height = self.mfdraw.get_allocation() pixmap = gtk.gdk.Pixmap(self.mfdraw.window, width, height) # clear area drawgc.set_foreground(white) pixmap.draw_rectangle(drawgc,True,0,0,width,height) drawgc.set_foreground(black) #hsize = self.sticks['HEAD'][1] # really half of head size hsize = self.fhsize[i] middle = self.fmiddles[i] rhsize = parts['RIGHT HAND'] lhsize = parts['LEFT HAND'] self.drawstickman(drawgc,pixmap,middle,joints,hsize,rhsize,lhsize) pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False, 8, width, height) if i == firstpixindex: firstpixbuf = pixbuf gtk.gdk.Pixbuf.get_from_drawable(pixbuf,pixmap,pixmap.get_colormap(),0,0,0,0,width,height) filename = 'fp%03d.png' % i filepath = os.path.join(tmpdir,filename) pixbuf.save(filepath,'png') pngpaths.append(filepath) from sugar.datastore import datastore mediaObject = datastore.create() mediaObject.metadata['title'] = 'FlipSticks PNG' thumbData = self._get_base64_pixbuf_data(firstpixbuf) mediaObject.metadata['preview'] = thumbData #medaiObject.metadata['icon-color'] = '' mediaObject.metadata['mime_type'] = 'image/png' mediaObject.file_path = pngpaths[0] datastore.write(mediaObject) def _get_base64_pixbuf_data(self, pixbuf): data = [""] pixbuf.save_to_callback(self._save_data_to_buffer_cb, "png", {}, data) import base64 return base64.b64encode(str(data[0])) def _save_data_to_buffer_cb(self, buf, data): data[0] += buf return True def playbackwards(self, widget, data=None): if self.playing: playimg = gtk.Image() playimg.set_from_file(os.path.join(self.iconsdir,'big_left_arrow.png')) playimg.show() widget.set_image(playimg) self.playing = False # set the main window to the keyframe if self.kfsticks[self.kfselected]: self.sticks = self.kfsticks[self.kfselected].copy() self.parts = self.kfparts[self.kfselected].copy() self.middle = self.kfmiddles[self.kfselected] self.setjoints() self.drawmainframe() self.updateentrybox() else: stopimg = gtk.Image() stopimg.set_from_file(os.path.join(self.iconsdir,'big_pause.png')) stopimg.show() widget.set_image(stopimg) self.makeframes() fsecs = self.frames.keys() fsecs.sort() if fsecs: self.playframenum = fsecs[-1] else: self.playframenum = -1 self.playingbackwards = True self.playing = gobject.timeout_add(self.waittime, self.playframe) def playforwards(self, widget, data=None): if self.playing: playimg = gtk.Image() playimg.set_from_file(os.path.join(self.iconsdir,'big_right_arrow.png')) playimg.show() widget.set_image(playimg) self.playing = False # set the main window to the keyframe if self.kfsticks[self.kfselected]: self.sticks = self.kfsticks[self.kfselected].copy() self.parts = self.kfparts[self.kfselected].copy() self.middle = self.kfmiddles[self.kfselected] self.setjoints() self.drawmainframe() self.updateentrybox() else: stopimg = gtk.Image() stopimg.set_from_file(os.path.join(self.iconsdir,'big_pause.png')) stopimg.show() widget.set_image(stopimg) self.makeframes() #mkeys = self.fmiddles.keys() #mkeys.sort() #for mkey in mkeys: # print '%s:(%s,%s)' % (mkey,self.fmiddles[mkey][0],self.fmiddles[mkey][1]) fsecs = self.frames.keys() fsecs.sort() if fsecs: self.playframenum = fsecs[0] else: self.playframenum = -1 self.playingbackwards = False self.playing = gobject.timeout_add(self.waittime, self.playframe) def changed_cb(self, combobox): model = combobox.get_model() index = combobox.get_active() if index: lang = model[index][0] if lang == 'Espa\xc3\xb1ol': lang = SPANISH if lang in LANG: self.lessonplans.set_label(LANG[lang]['lessonplan']) self.anglelabel.set_label(LANG[lang]['angle']+':') self.sizelabel.set_label(LANG[lang]['size']+':') self.export.set_label(LANG[lang]['export']) for stickpartname in self.labellist: label = self.sticklabels[stickpartname] label.set_label(LANG[lang][stickpartname]) prepare_btn(self.lessonplans) prepare_btn(self.export) return def setlastlanguage(self, widget, data=None): li = LANGLIST.index(self.language) if li == 0: self.language = LANGLIST[len(LANGLIST)-1] else: self.language = LANGLIST[li-1] self.changebuttonlang() def setnextlanguage(self, widget, data=None): li = LANGLIST.index(self.language) if li == (len(LANGLIST)-1): self.language = LANGLIST[0] else: self.language = LANGLIST[li+1] self.changebuttonlang() def getdefaultlang(self): return 'English' def getsdata(self): self.makeframes() sdd = {} # save data dictionary sdd['kfmiddles'] = self.kfmiddles sdd['kfparts'] = self.kfparts sdd['kfsticks'] = self.kfsticks sdd['kfssticks'] = self.kfssticks sdd['kfjoints'] = self.kfjoints sdd['kfsjoints'] = self.kfsjoints sdd['keyframes'] = self.keyframes sdd['kfselected'] = self.kfselected return pickle.dumps(sdd) def restore(self, sdata): sdd = pickle.loads(sdata) self.kfmiddles = sdd['kfmiddles'] self.kfparts = sdd['kfparts'] self.kfsticks = sdd['kfsticks'] self.kfssticks = sdd['kfssticks'] self.kfjoints = sdd['kfjoints'] self.kfsjoints = sdd['kfsjoints'] self.keyframes = sdd['keyframes'] self.kfselected = sdd['kfselected'] self.drawkeyframe() self.syncmaintokf() self.updateentrybox() def __init__(self, toplevel_window, mdirpath): self.insugar = False self.playing = False self.playingbackwards = False self.waittime = 3*150 self.keyframe = 0 self.toplevel = toplevel_window self.mdirpath = mdirpath xmiddle = int(DRAWWIDTH/2.0) ymiddle = int(DRAWHEIGHT/2.0) self.middle = (xmiddle,ymiddle) self.sticks = STICKS.copy() self.parts = PARTS.copy() self.sticklist = STICKLIST self.labellist = LABELLIST self.stickselected = 'RIGHT SHOULDER' self.laststickselected = None self.keyframes = KEYFRAMES self.kfsticks = [None,None,None,None,None] self.kfssticks = [None,None,None,None,None] self.kfjoints = [None,None,None,None,None] self.kfsjoints = [None,None,None,None,None] self.kfmiddles = [None,None,None,None,None] self.kfparts = [None,None,None,None,None] self.kfselected = 0 self.joints = self.initjoints() self.setjoints() self.jointpressed = None self.kfpressed = -1 self.middlepressed = False self.rotatepressed = False self.iconsdir = os.path.join(self.mdirpath,'icons') self.language = self.getdefaultlang() self.mpbox = gtk.VBox() self.main = gtk.EventBox() self.main.show() self.main.modify_bg(gtk.STATE_NORMAL,gtk.gdk.color_parse(YELLOW)) self.mainbox = gtk.EventBox() self.mainbox.modify_bg(gtk.STATE_NORMAL,gtk.gdk.color_parse(BACKGROUND)) self.mainbox.set_border_width(5) self.mainbox.show() self.main.add(self.mainbox) self.mpbox.show() self.hbox = gtk.HBox() self.hbox.show() self.vbox = gtk.VBox() self.vbox.show() self.hbox.pack_start(self.vbox,False,False,0) self.mainbox.add(self.mpbox) self.mpbox.pack_start(self.hbox,True,True,0) self.logobox = gtk.HBox(False,0) self.logobox.show() self.logo = gtk.Image() self.logo.show() self.logo.set_from_file(os.path.join(self.iconsdir,'logo.png')) self.logobox.pack_start(self.logo,False,False,0) self.lessonplans = gtk.Button('Lesson Plans') self.lessonplans.connect('clicked',self.showlessonplans, None) prepare_btn(self.lessonplans) self.lessonplans.show() self.lpvbox = gtk.VBox() self.lpvbox.show() self.lpvbox.pack_start(self.lessonplans,True,False,0) self.lpoframe = gtk.EventBox() self.lpoframe.modify_bg(gtk.STATE_NORMAL,gtk.gdk.color_parse(YELLOW)) self.lpoframe.show() self.lpframe = gtk.EventBox() self.lpframe.modify_bg(gtk.STATE_NORMAL,gtk.gdk.color_parse(BACKGROUND)) self.lpframe.show() self.lpalign = gtk.Alignment(1.0,1.0,1.0,1.0) self.lpalign.add(self.lpframe) self.lpalign.set_padding(0,5,5,0) self.lpalign.show() self.lpoframe.add(self.lpalign) self.lphbox = gtk.HBox() self.lphbox.show() self.lphbox.pack_start(self.lpvbox,True,False,0) self.lpframe.add(self.lphbox) self.logobox.pack_start(self.lpoframe,True,True,0) #vvvvv LANGUAGE BUTTONS vvvvv #self.lastlang = gtk.Button() #self.lastlang.connect('clicked', self.setlastlanguage, None) #llla = gtk.Image() #llla.set_from_file(os.path.join(self.iconsdir,'left_arrow.png')) #llla.show() #self.lastlang.add(llla) #prepare_btn(self.lastlang) #self.lastlang.show() #self.llvbox = gtk.VBox() #self.llvbox.show() #self.llvbox.pack_start(self.lastlang,True,False,0) #self.lang = gtk.Button(self.language) #prepare_btn(self.lang) #self.lang.show() #self.nextlang = gtk.Button() #self.nextlang.connect('clicked', self.setnextlanguage, None) #nlra = gtk.Image() #nlra.set_from_file(os.path.join(self.iconsdir,'right_arrow.png')) #nlra.show() #self.nextlang.add(nlra) #prepare_btn(self.nextlang) #self.nextlang.show() #self.nlvbox = gtk.VBox() #self.nlvbox.show() #self.nlvbox.pack_start(self.nextlang,True,False,0) #self.langvbox = gtk.VBox() #self.langvbox.show() #self.langvbox.pack_start(self.lang,True,False,0) #^^^^^ LANGUAGE BUTTONS ^^^^^ #vvvvv LANGUAGE DROPDOWN vvvvv self.langdd = gtk.combo_box_new_text() self.langdd.append_text('Language') self.langdd.append_text('English') self.langdd.append_text(SPANISH) self.langdd.connect('changed', self.changed_cb) self.langdd.set_active(0) self.langdd.show() self.langddvbox = gtk.VBox() self.langddvbox.show() self.langddvbox.pack_start(self.langdd,True,False,0) #^^^^^ LANGUAGE DROPDOWN ^^^^^ self.langoframe = gtk.EventBox() self.langoframe.modify_bg(gtk.STATE_NORMAL,gtk.gdk.color_parse(YELLOW)) self.langoframe.show() self.langframe = gtk.EventBox() self.langframe.modify_bg(gtk.STATE_NORMAL,gtk.gdk.color_parse(BACKGROUND)) self.langframe.show() self.langalign = gtk.Alignment(1.0,1.0,1.0,1.0) self.langalign.add(self.langframe) self.langalign.set_padding(0,5,5,5) self.langalign.show() self.langoframe.add(self.langalign) self.langhbox = gtk.HBox() self.langhbox.show() #self.langhbox.pack_start(self.llvbox,True,False,0) #self.langhbox.pack_start(self.langvbox,True,False,0) #self.langhbox.pack_start(self.nlvbox,True,False,0) self.langhbox.pack_start(self.langddvbox,True,False,0) self.langframe.add(self.langhbox) self.logobox.pack_start(self.langoframe,True,True,0) self.vbox.pack_start(self.logobox,False,False,0) #self.drawhbox = gtk.HBox() #self.drawhbox.show() self.mfdraw = gtk.DrawingArea() self.mfdraw.set_size_request(DRAWWIDTH,DRAWHEIGHT) self.mfdraw.show() self.mfdraw.connect('expose_event', self.expose_event) self.mfdraw.connect('configure_event', self.configure_event) self.mfdraw.connect('motion_notify_event', self.motion_notify_event) self.mfdraw.connect('button_press_event', self.button_press_event) self.mfdraw.connect('button_release_event', self.button_release_event) self.mfdraw.set_events(gtk.gdk.EXPOSURE_MASK | gtk.gdk.LEAVE_NOTIFY_MASK | gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.BUTTON_RELEASE_MASK | gtk.gdk.POINTER_MOTION_MASK | gtk.gdk.POINTER_MOTION_HINT_MASK) self.drawborder = gtk.EventBox() self.drawborder.modify_bg(gtk.STATE_NORMAL,gtk.gdk.color_parse(PINK)) self.drawborder.set_border_width(10) self.drawborder.show() self.drawframe = gtk.EventBox() self.drawframe.modify_bg(gtk.STATE_NORMAL,gtk.gdk.color_parse(BACKGROUND)) self.drawframe.set_border_width(5) self.drawframe.show() self.drawborder.add(self.drawframe) self.drawframe.add(self.mfdraw) #self.drawhbox.pack_start(self.drawborder, False, False, 10) #self.vbox.pack_start(self.drawhbox,False,False,0) self.vbox.pack_start(self.drawborder,False,False,0) self.keyframehbox = gtk.HBox() self.keyframehbox.show() self.playback = gtk.Button() self.playback.connect('clicked', self.playbackwards, None) playbackla = gtk.Image() playbackla.set_from_file(os.path.join(self.iconsdir,'big_left_arrow.png')) playbackla.show() self.playback.add(playbackla) prepare_btn(self.playback) self.playback.show() self.playbackvbox = gtk.VBox() self.playbackvbox.show() self.playbackvbox.pack_start(self.playback,True,False,0) self.keyframehbox.pack_start(self.playbackvbox,True,False,0) # vvvvvvvvvvKEYFRAME DRAWING AREA HEREvvvvvvvvvvvv self.kfdraw = gtk.DrawingArea() self.kfdraw.set_size_request(KEYFRAMEWIDTH,KEYFRAMEHEIGHT) self.kfdraw.show() self.kfdraw.connect('expose_event', self.kf_expose_event) self.kfdraw.connect('configure_event', self.kf_configure_event) self.kfdraw.connect('motion_notify_event', self.kf_motion_notify_event) self.kfdraw.connect('button_press_event', self.kf_button_press_event) self.kfdraw.connect('button_release_event', self.kf_button_release_event) self.kfdraw.set_events(gtk.gdk.EXPOSURE_MASK | gtk.gdk.LEAVE_NOTIFY_MASK | gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.BUTTON_RELEASE_MASK | gtk.gdk.POINTER_MOTION_MASK | gtk.gdk.POINTER_MOTION_HINT_MASK) #self.drawborder = gtk.EventBox() #self.drawborder.modify_bg(gtk.STATE_NORMAL,gtk.gdk.color_parse(PINK)) #self.drawborder.show() #self.drawframe = gtk.EventBox() #self.drawframe.modify_bg(gtk.STATE_NORMAL,gtk.gdk.color_parse(BACKGROUND)) #self.drawframe.set_border_width(5) #self.drawframe.show() #self.drawborder.add(self.drawframe) #self.drawframe.add(self.mfdraw) self.keyframehbox.pack_start(self.kfdraw,False,False,0) # ^^^^^^^^^^KEYFRAME DRAWING AREA HERE^^^^^^^^^^^^ self.playforward = gtk.Button() self.playforward.connect('clicked', self.playforwards, None) playforwardla = gtk.Image() playforwardla.set_from_file(os.path.join(self.iconsdir,'big_right_arrow.png')) playforwardla.show() self.playforward.add(playforwardla) prepare_btn(self.playforward) self.playforward.show() self.playforwardvbox = gtk.VBox() self.playforwardvbox.show() self.playforwardvbox.pack_start(self.playforward,True,False,0) self.keyframehbox.pack_start(self.playforwardvbox,True,False,0) self.vbox.pack_start(self.keyframehbox,False,False,10) self.bottomcontrolshbox = gtk.HBox() self.bottomcontrolshbox.show() self.resetbutton = gtk.Button() resetimg = gtk.Image() resetimg.set_from_file(os.path.join(self.iconsdir,'reset.png')) resetimg.show() self.resetbutton.add(resetimg) self.resetbutton.connect('clicked', self.reset, None) prepare_btn(self.resetbutton) self.resetbutton.show() self.bottomcontrolshbox.pack_start(self.resetbutton, True, False, 0) self.setframebutton = gtk.Button() cameraimg = gtk.Image() cameraimg.set_from_file(os.path.join(self.iconsdir,'camera.png')) cameraimg.show() self.setframebutton.add(cameraimg) self.setframebutton.connect('clicked', self.setframe, None) prepare_btn(self.setframebutton) self.setframebutton.show() self.bottomcontrolshbox.pack_start(self.setframebutton, True, False, 0) self.clearframebutton = gtk.Button() clearimg = gtk.Image() clearimg.set_from_file(os.path.join(self.iconsdir,'clear.png')) clearimg.show() self.clearframebutton.add(clearimg) self.clearframebutton.connect('clicked', self.clearframe, None) prepare_btn(self.clearframebutton) self.clearframebutton.show() self.bottomcontrolshbox.pack_start(self.clearframebutton, True, False, 0) adj = gtk.Adjustment(2.5,1,5,.5,1) adj.connect('value_changed',self.setplayspeed) self.playspeed = gtk.HScale(adj) self.playspeed.set_draw_value(False) for state, color in COLOR_BG_BUTTONS: self.playspeed.modify_bg(state, gtk.gdk.color_parse(color)) self.playspeed.show() self.bottomcontrolshbox.pack_start(self.playspeed, True, True, 5) self.vbox.pack_start(self.bottomcontrolshbox,False,False,10) # NOW THE RIGHT SIDE self.rightvbox = gtk.VBox() self.rightvbox.show() # vvvvv FILE PICKER THING vvvvv #self.filechooserhbox = gtk.HBox() #self.filechooserhbox.show() #self.lastfile = gtk.Button() #lfla = gtk.Image() #lfla.set_from_file(os.path.join(self.iconsdir,'left_arrow.png')) #lfla.show() #self.lastfile.add(lfla) #prepare_btn(self.lastfile) #self.lastfile.show() #self.lfvbox = gtk.VBox() #self.lfvbox.show() #self.lfvbox.pack_start(self.lastfile,True,False,0) #self.filechooserhbox.pack_start(self.lfvbox,True,False,5) ## vvvvv FILE PICKER DRAWING AREA vvvvv #self.fpdraw = gtk.DrawingArea() #self.fpdraw.set_size_request(FPWIDTH,FPHEIGHT) #self.fpdraw.show() #self.fpdraw.connect('expose_event', self.fp_expose_event) #self.fpdraw.connect('configure_event', self.fp_configure_event) #self.fpdrawborder = gtk.EventBox() #self.fpdrawborder.modify_bg(gtk.STATE_NORMAL,gtk.gdk.color_parse(PINK)) #self.fpdrawborder.show() #self.fpdrawframe = gtk.EventBox() #self.fpdrawframe.modify_bg(gtk.STATE_NORMAL,gtk.gdk.color_parse(BACKGROUND)) #self.fpdrawframe.set_border_width(5) #self.fpdrawframe.show() #self.fpdrawborder.add(self.fpdrawframe) #self.fpdrawframe.add(self.fpdraw) #self.filechooserhbox.pack_start(self.fpdrawborder,False,False,0) ## ^^^^^ FILE PICKER DRAWING AREA ^^^^^ #self.nextfile = gtk.Button() #nfla = gtk.Image() #nfla.set_from_file(os.path.join(self.iconsdir,'right_arrow.png')) #nfla.show() #self.nextfile.add(nfla) #prepare_btn(self.nextfile) #self.nextfile.show() #self.nfvbox = gtk.VBox() #self.nfvbox.show() #self.nfvbox.pack_start(self.nextfile,True,False,0) #self.filechooserhbox.pack_start(self.nfvbox,True,False,5) #self.rightvbox.pack_start(self.filechooserhbox,False,False,5) # ADD FILENAME LABEL HERE # ^^^^^ FILE PICKER THING ^^^^^ # START OF STICK CONTROLS self.stickcontrols = gtk.VBox() self.stickcontrols.show() self.stickcontrolsborder = gtk.EventBox() self.stickcontrolsborder.modify_bg(gtk.STATE_NORMAL,gtk.gdk.color_parse(PINK)) self.stickcontrolsborder.set_border_width(5) self.stickcontrolsborder.show() self.stickcontrolsframe = gtk.EventBox() self.stickcontrolsframe.modify_bg(gtk.STATE_NORMAL,gtk.gdk.color_parse(BUTTON_BACKGROUND)) self.stickcontrolsframe.set_border_width(5) self.stickcontrolsframe.show() self.stickcontrolsborder.add(self.stickcontrolsframe) self.stickcontrolsframe.add(self.stickcontrols) self.anglesizehbox = gtk.HBox() self.anglesizehbox.show() #label = gtk.Label('Angle:') self.anglelabel = gtk.Label(LANG[self.language]['angle']+':') self.anglelabel.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(BUTTON_BACKGROUND)) self.anglelabel.show() self.anglesizehbox.pack_start(self.anglelabel,False,False,5) self.angleentry = gtk.Entry() self.angleentry.set_max_length(3) self.angleentry.set_width_chars(3) self.angleentry.connect('activate', self.enterangle_callback, self.angleentry) self.angleentry.show() self.anglesizehbox.pack_start(self.angleentry,False,False,0) #label = gtk.Label('Size:') self.sizelabel = gtk.Label(LANG[self.language]['size']+':') self.sizelabel.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(BUTTON_BACKGROUND)) self.sizelabel.show() self.anglesizehbox.pack_start(self.sizelabel,False,False,5) self.sizeentry = gtk.Entry() self.sizeentry.set_max_length(3) self.sizeentry.set_width_chars(3) self.sizeentry.connect('activate', self.enterlen_callback, self.sizeentry) self.sizeentry.show() self.anglesizehbox.pack_start(self.sizeentry,False,False,0) self.asbox = gtk.EventBox() self.asbox.modify_bg(gtk.STATE_NORMAL,gtk.gdk.color_parse(BUTTON_FOREGROUND)) self.asbox.show() self.asbox.add(self.anglesizehbox) self.stickcontrols.pack_start(self.asbox,False,False,0) self.stickbuttons = {} self.sticklabels = {} for stickpartname in self.labellist: #label = gtk.Label(capwords(stickpartname)) label = gtk.Label(LANG[self.language][stickpartname]) label.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse(BUTTON_FOREGROUND)) label.show() self.sticklabels[stickpartname] = label ebox = gtk.EventBox() ebox.modify_bg(gtk.STATE_NORMAL,gtk.gdk.color_parse(BUTTON_BACKGROUND)) ebox.show() ebox.set_events(gtk.gdk.BUTTON_PRESS_MASK) ebox.connect('button_press_event',self.selectstick,stickpartname) ebox.add(label) self.stickbuttons[stickpartname] = ebox self.stickcontrols.pack_start(ebox,False,False,0) # highlight the currently selected stick and update the entry boxes self.selectstickebox() # END OF STICK CONTROLS stickalign = gtk.Alignment(1.0,1.0,1.0,1.0) stickalign.add(self.stickcontrolsborder) stickalign.set_padding(80,5,5,5) # top,bottom,left,right stickalign.show() self.rightvbox.pack_start(stickalign,False,False, 0) #self.rightvbox.pack_start(self.stickcontrolsborder,False,False, 0) #self.filesave = gtk.Button() #self.filesave.set_label('SAVE') #prepare_btn(self.filesave) #self.filesave.connect('clicked',self.savefile,None) #self.filesave.show() #self.fshbox = gtk.HBox() #self.fshbox.show() #self.fshbox.pack_start(self.filesave,True,False,0) #self.rightvbox.pack_start(self.fshbox,True,False,0) self.export = gtk.Button() #self.export.set_label('EXPORT') self.export.set_label(LANG[self.language]['export']) prepare_btn(self.export) self.export.connect('clicked',self.exportanim,None) self.export.show() self.exporthbox = gtk.HBox() self.exporthbox.show() self.exporthbox.pack_start(self.export,True,False,0) self.rightvbox.pack_start(self.exporthbox,True,False,0) self.hbox.pack_start(self.rightvbox,False,False,0) try: from sugar.activity import activity from sugar.presence import presenceservice from sugar.presence.tubeconn import TubeConnection import telepathy import telepathy.client from dbus import Interface from dbus.service import method, signal from dbus.gobject_service import ExportedGObject class flipsticksActivity(activity.Activity): def __init__(self, handle): activity.Activity.__init__(self,handle) self.connect("destroy",self.destroy_cb) bundle_path = activity.get_bundle_path() os.chdir(bundle_path) self.set_title('FlipSticks') toolbox = activity.ActivityToolbox(self) self.set_toolbox(toolbox) toolbox.show() if hasattr(self, '_jobject'): self._jobject.metadata['title'] = 'FlipSticks' title_widget = toolbox._activity_toolbar.title title_widget.set_size_request(title_widget.get_layout().get_pixel_size()[0] + 20, -1) self.app = flipsticks(self, bundle_path) self.app.insugar = True outerframe = gtk.EventBox() outerframe.modify_bg(gtk.STATE_NORMAL,gtk.gdk.color_parse(BUTTON_BACKGROUND)) outerframe.show() innerframe = gtk.EventBox() innerframe.show() ifalign = gtk.Alignment(1.0,1.0,1.0,1.0) ifalign.add(innerframe) ifalign.set_padding(20,20,50,50) # top,bottom,left,right ifalign.show() #innerframe.set_border_width(150) outerframe.add(ifalign) innerframe.add(self.app.main) self.set_canvas(outerframe) # mesh stuff self.pservice = presenceservice.get_instance() owner = self.pservice.get_owner() self.owner = owner try: name, path = self.pservice.get_preferred_connection() self.tp_conn_name = name self.tp_conn_path = path self.conn = telepathy.client.Connection(name, path) except TypeError: pass self.initiating = None #sharing stuff self.game = None self.connect('shared', self._shared_cb) if self._shared_activity: # we are joining the activity self.connect('joined', self._joined_cb) if self.get_shared(): # oh, OK, we've already joined self._joined_cb() else: # we are creating the activity pass def destroy_cb(self, data=None): return True def read_file(self, filepath): f = file(filepath) sdata = f.read() f.close() self.app.restore(sdata) def write_file(self, filepath): sdata = self.app.getsdata() f = open(filepath,'w') f.write(sdata) f.close() def _shared_cb(self,activity): self.initiating = True self._setup() id = self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].OfferDBusTube( SERVICE, {}) #self.app.export.set_label('Shared Me') def _joined_cb(self,activity): if self.game is not None: return if not self._shared_activity: return #for buddy in self._shared_activity.get_joined_buddies(): # self.buddies_panel.add_watcher(buddy) #logger.debug('Joined an existing Connect game') #self.app.export.set_label('Joined You') self.initiating = False self._setup() #logger.debug('This is not my activity: waiting for a tube...') self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].ListTubes( reply_handler=self._list_tubes_reply_cb, error_handler=self._list_tubes_error_cb) def _setup(self): if self._shared_activity is None: return bus_name, conn_path, channel_paths = self._shared_activity.get_channels() # Work out what our room is called and whether we have Tubes already room = None tubes_chan = None text_chan = None for channel_path in channel_paths: channel = telepathy.client.Channel(bus_name, channel_path) htype, handle = channel.GetHandle() if htype == telepathy.HANDLE_TYPE_ROOM: #logger.debug('Found our room: it has handle#%d "%s"', # handle, self.conn.InspectHandles(htype, [handle])[0]) room = handle ctype = channel.GetChannelType() if ctype == telepathy.CHANNEL_TYPE_TUBES: #logger.debug('Found our Tubes channel at %s', channel_path) tubes_chan = channel elif ctype == telepathy.CHANNEL_TYPE_TEXT: #logger.debug('Found our Text channel at %s', channel_path) text_chan = channel if room is None: #logger.error("Presence service didn't create a room") return if text_chan is None: #logger.error("Presence service didn't create a text channel") return # Make sure we have a Tubes channel - PS doesn't yet provide one if tubes_chan is None: #logger.debug("Didn't find our Tubes channel, requesting one...") tubes_chan = self.conn.request_channel(telepathy.CHANNEL_TYPE_TUBES, telepathy.HANDLE_TYPE_ROOM, room, True) self.tubes_chan = tubes_chan self.text_chan = text_chan tubes_chan[telepathy.CHANNEL_TYPE_TUBES].connect_to_signal('NewTube', self._new_tube_cb) def _list_tubes_reply_cb(self, tubes): for tube_info in tubes: self._new_tube_cb(*tube_info) def _list_tubes_error_cb(self, e): #logger.error('ListTubes() failed: %s', e) pass def _new_tube_cb(self, id, initiator, type, service, params, state): #logger.debug('New tube: ID=%d initator=%d type=%d service=%s ' # 'params=%r state=%d', id, initiator, type, service, # params, state) if (self.game is None and type == telepathy.TUBE_TYPE_DBUS and service == SERVICE): if state == telepathy.TUBE_STATE_LOCAL_PENDING: self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].AcceptDBusTube(id) tube_conn = TubeConnection(self.conn, self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES], id, group_iface=self.text_chan[telepathy.CHANNEL_INTERFACE_GROUP]) self.game = ConnectGame(tube_conn, self.initiating, self) class ConnectGame(ExportedGObject): def __init__(self,tube, is_initiator, activity): super(ConnectGame,self).__init__(tube,PATH) self.tube = tube self.is_initiator = is_initiator self.entered = False self.activity = activity self.ordered_bus_names=[] self.tube.watch_participants(self.participant_change_cb) def participant_change_cb(self, added, removed): if not self.entered: if self.is_initiator: self.add_hello_handler() else: self.Hello() self.entered = True @signal(dbus_interface=IFACE,signature='') def Hello(self): """Request that this player's Welcome method is called to bring it up to date with the game state. """ @method(dbus_interface=IFACE, in_signature='s', out_signature='') def Welcome(self, sdata): self.activity.app.restore(str(sdata)) def add_hello_handler(self): self.tube.add_signal_receiver(self.hello_cb, 'Hello', IFACE, path=PATH, sender_keyword='sender') def hello_cb(self, sender=None): self.tube.get_object(sender, PATH).Welcome(self.activity.app.getsdata(),dbus_interface=IFACE) except ImportError: pass if __name__ == '__main__': toplevel_window = gtk.Window(gtk.WINDOW_TOPLEVEL) mdirpath = os.path.abspath(os.curdir) app = flipsticks(toplevel_window,mdirpath) toplevel_window.add(app.main) toplevel_window.set_title('FlipSticks') toplevel_window.connect('delete_event', app.delete_event) toplevel_window.connect('destroy', app.destroy) toplevel_window.show() gtk.main() sugar-flipsticks-activity-1.orig/flipsticks.activity/activity/0000755000175000017500000000000010715422424023566 5ustar janijanisugar-flipsticks-activity-1.orig/flipsticks.activity/activity/activity.info0000755000175000017500000000027410715416404026306 0ustar janijani[Activity] name = FlipSticks service_name = org.worldwideworkshop.olpc.FlipSticks class = flipsticks.flipsticksActivity icon = activity-flipsticks activity_version = 1 show_launcher = yes sugar-flipsticks-activity-1.orig/flipsticks.activity/activity/newbad.activity-flipsticks.svg0000644000175000017500000002007210715416404031555 0ustar janijani ]> sugar-flipsticks-activity-1.orig/flipsticks.activity/activity/activity-flipsticks.svg0000644000175000017500000000612610715416404030322 0ustar janijani ]> sugar-flipsticks-activity-1.orig/flipsticks.activity/MANIFEST0000644000175000017500000000076010715416404023067 0ustar janijaniflipsticks.py icons/50x50blank-trans.png icons/big_left_arrow.png icons/big_pause.png icons/big_right_arrow.png icons/camera.png icons/clear.png icons/down_arrow.png icons/filmstrip.png icons/left_arrow.png icons/logo.png icons/old_pause.png icons/old_x_clear.png icons/pause.png icons/pink_arrow.png icons/reset.png icons/right_arrow.png icons/sound_icon.png icons/up_arrow.png icons/yellow_arrow.png lp-en/An_Overview.txt lp-en/Lesson_Plan_1.txt lp-en/Lesson_Plan_2.txt lp-en/Lesson_Plan_3.txt