fontypython-0.4.4/0000755000175000017500000000000011742300067012576 5ustar donndonnfontypython-0.4.4/fontypythonmodules/0000755000175000017500000000000011742300067016570 5ustar donndonnfontypython-0.4.4/fontypythonmodules/help/0000755000175000017500000000000011742300067017520 5ustar donndonnfontypython-0.4.4/fontypythonmodules/help/common/0000755000175000017500000000000011742300067021010 5ustar donndonnfontypython-0.4.4/fontypythonmodules/help/common/README0000644000175000017500000004371611742276530021712 0ustar donndonnSection One : Copyright ======================= The following images are Copyright (C) 2006, 2007, 2008i, 2009 Donn.C.Ingle fp1.png.cr.png fp2.png.cr.png fp3.png.cr.png fp4.png.cr.png fp5.png.cr.png fp6.png.cr.png fp7.png.cr.png fp8.png.cr.png fp_already_in_x.png fp_removing_a_font.png fp_normal_item.png fp_ticking.png fphelplogo.png break.png Section Two : License ======================= GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. fontypython-0.4.4/fontypythonmodules/help/common/break.png0000644000175000017500000000257211742276530022617 0ustar donndonnPNG  IHDRU< PLTEϿͽ˹ɵưx*Å5IDATX۲ EdEp1L@=1Nf!)f n\]NI='9]5 ˢΨ芲f ͎QsR9lт*?BM$?c q 7*1^W&Nм 7 |Gq,H(ߏ9 s'@~!wrkpwrkٷ"oP@v=QjQfׅQbn" .>~~"O2Ba.4^j~RCA5%P'zsT v 4[/cIތJ"#ϤBOŲˬ +y7ɭvV l-l9h+vQmXgyQԕIo+THIKmbN)55VaMĽ9|ARVCA"/4A)[If4+j<1U4iwBB GZñhk|z!M|l yR#<V ZO)42=UrݗB/eD{ "a\'jn%D muJJf vƦTuEvgkII?~؊{IENDB`fontypython-0.4.4/fontypythonmodules/help/common/fp1.png.cr.png0000644000175000017500000000154111742276530023402 0ustar donndonnPNG  IHDR((msBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<IDATXK`_AK_ATJDV!(ya춿`λvl! Vj8)NKil=$ݩi06дOjZpـuJRI%FB`=7|p0wa)2qu}sc\N&ǐ̀xVocPhydIDATX՘O[eǿݡen2ka8p-hQM|ILv^{k$i,f`_qݠt ]چzsw><"fQ@1ԥvds%HD.* _15zZ#C]4Γ]%`1Ÿ,nM,o h\$|\cF#krBdz[ 0Z«/7sbgK19仰cERX<>Ї X|edwbh) zଽ$Aݽ=8S+ߥu>gN%Wܲhe t]t +h뱞L)|Hok'Z9qa֐^LZQ Eȉ?x^ln)sak 5 $W%JwagkYv#}Vr߅}-(Yv6iLL@KQ}>t1tUZL BA$܄ӱIZL/p~T*|s勂}+~+sՌ% ;b,R;puY-h* jlٍd,CgupQ$݂ cxL_.ȋN8:..y /edb6aW{OSoT&=SUA7HIENDB`fontypython-0.4.4/fontypythonmodules/help/common/fp3.png.cr.png0000644000175000017500000000236711742276530023413 0ustar donndonnPNG  IHDR((msBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<tIDATX՘[LU?^JJ .I8e$Qgib|6a/FMKeKȖ P , ]m\˴@/mOwх0;X R(Iq|̋G Ve76kBb}:ľ):z302ʪ:fEdPvoͪ,-^0 w|kq!. 4- KڰRx{bED "MLɷTN>R<s5ڭGlCs]Qp:NVpԙ p3<Ē$102hN\`9-,rs9xFUe%kE$ 8W[z"l&l'#=6kiea8.P OцJ˲3=,r΋dl4a dࣄiެ1*ۥib62*KRTzJ3mo<Á {ClXx8Hdjv ~^/eKT3vk!\|Ub ZX^]%̽|¤b1_,2͚0fIȃF E,u$c2b2#E̷gj66Ili>z<"ˢ8)Kfl9-O A(r{&*WĐvLܟfrv4 GwU9"Fw*@C CJ N{6N?_or~P X.HG샎)/tmi}>#BHo7WH\y+bu |7NՂN~XR1 ̊"wF}8Ǔ^QNoOaBM̋|PW>FeiqҡUYZ!n,nɔa6nCxԎ~~Sj>`n֎}_^:IENDB`fontypython-0.4.4/fontypythonmodules/help/common/fp4.png.cr.png0000644000175000017500000000201611742276530023403 0ustar donndonnPNG  IHDR((msBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<IDATX՘KLQiX@"ҦA<#/ *DH\(1.;nݹ2ntƈ JBB4jTA:R30δ2owen>NH[kыufLpL0j4j́D2]1(*w!w~917I9Y*R4VC_TA\nYlB N 帄B(( Z[ ˲ brf6)bY*B!_eY<}5ח&wJ~ZєmxT?LٴFcrfv3j_:`002׃*J%Y#k~ 㴡4ORѤr}C.b?uV*qZ@.\nxciكflÉc ɉ9A07 {zT _AoIlD[YMXpk{Rk+k p2w $,Bי def&i },] ܔLQtw _{N|<pS:&΅] cnM56xK6d'j4ACckjAZE`+kM4}ÏDFC5PMho+_[!υLq6GRAw!DBLW,s7Í 𰿏rN3!T4t$&o(Je ;`i>ppBԘM*ħlG; q{:U3x~rN7 B!=p1قs9E>VgB"R!,Uѽ&N;i-[#>i]~㓶pҶ|Ф}l2.qs?IENDB`fontypython-0.4.4/fontypythonmodules/help/common/fp5.png.cr.png0000644000175000017500000000233611742276530023411 0ustar donndonnPNG  IHDR((msBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<[IDATX՘oLeǿwnnJ)i408{#ًWڷ+b%dM(+tЃzO}^ZcT=~y~d2DSI7B0/X!mAmC<ǁLfxWeO-.VOana;q=e%FԹ6QQHT€o A]/TǍmxʟ?QȄܡ ,Wb,op3tu`0ewGPw(Î޻2;}Y5}鼹UK35T`$*h4Aa`v{͹h.t|cǞֳxFr o yK1pepz0V)GSTLbHE*#Iitr Yׇ"Ԁs bw p^ Q213sj\ٍc^ +KSBb؉Mٲ9>9~GQ:NE/:׆a1г06m0$DםC6+ji (*oQULa~i;{Dm4:qj`,`7ЂdމN x`9DpRQj= ˲pcjvT2҄^T*,=XGw(GoBZB8ظl$/[Jijv@P. 0gs~EQ0#gʳo2A[pNj<-=,a7zS0]U1ۅζf m |`&KE]<xPEQxhW2L1bL reEf#Xc.3}]p0 \ϭPcCGso% P;{Xi8,LlRF_މX/l8mը2:.]lp 6 gfZ2$A{Sӕ++ب/CC$,'! uT 6x&Xp.:t,E *{x0⫻8#s Y': jJDq |4O ZjR&#\]#t5uTlǡ<5+i^WC ;|A`/"ltE{hQqRpye24n1"kL+ ^/% =ŧ߸%Y:8o`/rY]],_U*&#  eo'3#KRQ>ݬ O槡ɍTjEGKTU^${ ; |i12+[=`*7 3S{oO0CIENDB`fontypython-0.4.4/fontypythonmodules/help/common/fp7.png.cr.png0000644000175000017500000000201411742276530023404 0ustar donndonnPNG  IHDR((msBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<IDATX՘OQƿB(P,D^Mł؄WbR $` 1T7.G\0n1$ @yX(BuA:tf`뷻dMo眹J&Id pr^H?Ս #QDbb%"VQmM-([ ocܳcYPgD0ªO TkC7xC&t4ln0 0|)`rNa/\J6 HBJZ}c_01ɼ(ضivinW4'{F'$hFqA1QGe5:;V}[chrV2A4^tw-59-ZX!x+S:ń.4'&( z; yl!]Y+kBC[zQ)MQx.qr{S`[EdVp_fa|y XZyRMV6>Ig砉6盌P neNyQ0|/ ƟQ٨,'Yx2s1tZPL8,ZeGF3*y)_Z&i5(lW( R>{Q sK-x{GrY:O͇BDRQTf)]~AV ge"|ٍ6 "@KQ!a*XÕ=&c>︊m }BV+ a6`3G_Zt)) NBB/v=^t|aKMdV謅*PrT%eH4f1 jW6-IWBPi}&T^`U^J[W 6IENDB`fontypython-0.4.4/fontypythonmodules/help/common/fp_already_in_x.png0000644000175000017500000002040511742276530024651 0ustar donndonnPNG  IHDR]s;YEsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org< IDATxil[\Dwvɲ%-Y;Eh&$N3)j"E;E0I`p---)ur PgΜRZFEEE_LFޢaaZ2-++7:XB!8ND"A8 6WX1==rOT:.cy$ 5%Z@mmmC rB8{,"h\D"ܺuK,^‰n޼z vaZ155XvmSDl=BT2XVbnfffDItgggW.8b1t8.5SI$Xh)wR\tI4RW:TX4oD7Vh4&Y"n׮]G|ɷM&r[^^S~rhظ1כ~{{;ZmJ*++#!Ij: D (D%F3It"1NzA-O U$ŇEtRh$b`[Y;$˓B;Y6X^bfYt@Nb#x. `07m$`hhB9`. . ^z^0hD(lFss3VZ,nܸ!/~v8( ff2D"p: L&f3t:݂4D"Aww1H$ ݎx<_.,fܥRq{j!%`0ÁYCl6)L,v ɽlu#a=9/`q6￟m4$<VQYY 8Xx<Ǔ,LhooO87x!J4 L&jjjR*=qI.7BTSSZSDY&֭[x)m63 ØN+莎2"9Yp׮]t;33Wbjj mmmsSKg* L&.^8oU:>ϟGOOm1KW0*^|N3gh6 X ֭tg43&I'cxxVU=@ ,]dz\nBUU7ܹs}I4N=zt)j4nr9 1;;ׯ37xǃH$2gr FWNsDEHv+$|ݖ{!QVV{---QV{ge:luŞL&7GП ! 5ۡhT*a4ޞU R̳tX!OT0m*$@+ ].D D- 0 䕶|cX&:4_`2Rt:};c12`>1=_;jf3Z0G?IӉvV~澟LYٮbYj_7oVMMMU*UQ }gYYLy"X2>ѥv+,٬-p'Xblj/D"l:(boRn~@)y Ս 9eR@jKXtYCVL@η8cZ)Jt3!$RTX,]_Yfnlyר שl(Lx*hO۔j MT}Jd]Ae vbi||omm+JU#Bn$úAJ!˫TX]B,Áq444cjjJpjyyyƗ0`6!Hx0>>T>!J#ơP.Kt"}yy@" QU֖Fsss5(.+ B&"ҿ$֯_/Ytgff7 Il\QQyF&8Cl3Bib>$A!@V V( hW\BT*ͪOn$7W]]-yVr8s sZ`0`xx9+3?X1w/0888ϯbkR!V^qRF0Hɲa0,$EXJ\δk)^l JoXL eqAE~ZZƦMr:LAK kl$A㮻Jف$6l`ZQ<+Dk*# nnhwfս+|o*Dۍ LMMeM&ZZZD+A0*L@cc#$쑑TWWϫJL* k׮覭 333L[׬Y|R]O(v?H']h8PF? vҽʢ̧G"LOO##dPYY RpTLfL&lF}}=>c+D"VEee%jjj2ZL^T*Sv;xU(qI:h#zuuu0L*"gkk+n޼)(NRUUUY>Jg{bv+(Feeeɶg0{-DQ\|9RUV+ZV1LV NN'Fz155NɄʼ cn7 z= Fc^0t:z/ʬv9MrPQQTUUӘdB]]]F `1n"D"AmmhʖRYFvvr JmO茶>AkMPuuu[g8VkȪꬺ]bqxpu(J䞢q1}ݷ/<ˇޣ܌ebG344K9ψX NyP(P^^Z `#^k֬^OmB__ͰZ;XyF,?{aFapͬjr=a~|>X,dZ`r֭[ r3bBp:p:gJ%aX^5<# 2% v"`͚5^Е^K3A"("$AED A] "BKQDHt .AD!%("$AED A] "BKQDHt .AD!%("$AED A] "BKQDHt .AD!%("NtSp+w+Xإ$gXϛ`eϞ=aSbs8^('?ɡT*JAF }JsΑ}hV;v`Æ 9'Ɖ'K/AfwϞ=ؽ{'|֭K^opQŀ $ z=vؑyCu[7󅗞%{?8|{amMwLSĻwq޽{bTɓɊq…o{nq a߾}KJtӡ(FgաD"JJc1tnږ&wty& ~{qqHR<χ͛7'Io[np80xQ]]noooJwѣGq)$@MM ֆ/;nO#x'c:tHm?ك͛7xײ.GDP(BhZqdy;v,cxFhmm;BP\u3z&[jEw.Mwtܶ]BHdT*SO=5yftvvbxxċ/(//ǯk¡Cetwwܹsp wu6n܈sΡ/o|رcxGaeߖ-[o>ĉxg_'goWWWF/^ė_~g}8t`>=C&jkkꫯ2K<$y]}lݺ]]]8|Vq%,ѱ15 = ]7Y^Q r -p+6ȄQ }]ա\f3oy='|;wCCCx v!n.?b$/ .-k CVGw?1>|F27ؿ?9oСC8|0L&[o!T*|{Kq(l~ڵxg{⡇DZm6gsr6mG}T{18pGAOOd2m۶mػw/BP\usnwAߋ ͟F4cc*M "ԩS|2~=.g1wޢ '?S"ATVV'@]]]SD Op(p(yYV+E'6x Xˉ+Pxz'fKHlـ2ݵ%ym|hW.@iU'Aα1VUkFqEIC+u2 U*G,9 { p8y/-ZF_G.h7AD>Z1S8nYRkQU׀ٯ*)$#ӗ⧛Qi#%bI2Ot9`?e ѹ:hFhR/ɧ?݌'x oyB͸8z(~<эÈbPVSDpw1|÷?M5+e!FovQ-\Ӛ9 b93OtVaRDžـm6>R؏SϡEּD\Ťwh7״#~NXvv:|NFH8&N;zkA2r@*4!L׷?(dDR4, d9R @JEvn[{ܳl Wzw$8.8sU9?hnnBƍSvzka>|P(hnn_W~Z`/# J_x&29% |MX,TTT`׮]Bq% g?***P]]?)c^yTUUAR駟lNqr`X]'Lƃ)e29TpZ?gCƀ4xgy_رcpx'=χ/'Nu9KW_͛7qu `lll B O ִB/ׇavLkp8ƅ g7p={vJoa4OwIq;g``~v(9\8>^p^ wvsڸʺ9,MMM%N.ihh?qYU[[ $suuu9%\*L~_=00׋8.oJMMMܵkגm6gX8㸫Wr\$8"̍2M`FyY;_LSoG?{hll*QrUm:W3Ƥśz pGx<䪫㪭g8sI+k C{>nn,yz:N:]}޺2""0 *˰ `0VY",2 aA`0E͛7C.C&˗[9`3DZxb >FRRMS<~7oYfaƍ8b4jH^``)1xc &XuVtvv_Miβzj2d.w)kYҪU+:3)r}"sprd&wd_=Rؘd=z$X.E}gʕ,M,5R;w$bHCʇ֨Q套gR---,OIIAFF)"11/Ǝ-[ ++,Laa!L2F{= 6 glr >c{Xr`_tǦMп`̙8}4jQ6BQQcxwжm[ov.\AAAhҤ &Ol]JQYY,ZpuuE֭1qD>|X9u M63j(L7B\ h4p@}駟ٳgJ2JIIX y„ zj*0BK. Q/^L 4/o߾MqqqСSNNJd6l9::rь3˒|,Fnn.P||<=ZhA2s&&&BJ۷od-|fq'"9I;v "rx@;v~͘!%n5;wN}{{{***2yUTt!5j9;;_PĉPf͚I9rH\jj*mVT&""bbbk׮dQVeqq1uQ\xx8ٲi&;wG) $",4h$qѳg8۶,5DDDH իѱOVCff]r4Ȫjh$@o`[SLkĈT^^N~!'P;vE}XݗyyyFݾ}yI J 3DJΎ;FF{sm3K.۷,kѣDZ[ *J|)g hҤ .u5z\\\M6&۱uV/={fH cƌ0;QUUe΄RXzw ڶ,5tl|QpY֭.{ᔱQj_}Eu~e(//缩X*&Jɪu.{{{Kr}2'N˫>Ú|<`ye:u̷Y={o1ٷo***x*Y+vލ?}􁋋$|zA9HNN$ رcΜ9ÇK댉Tu\Ν /ۖ>Ը"Lo/#y?{3>[]Bעc`כ̙3GP͟?Μ9CW\@I[#G{q_&O'[RRBQQQr\u9t萨dI~0i<~ cʒԶ\.4JOOÇ ~Ud2=}F̒.\x\\\DRSS9ۭ떈hѢE}ᕱNüe>>>ҥKѫW/kׯ}1Hqz!66VTU~5ʖ@ƍ%۲e :w-[bȐ!غud޽YV}V}9s;vԩSEr9g~}_|sW蒆MGrj4h@/oȐ!8y3gΘmr2r]crMQ IFtt"`p1o<9R/W^~ EmI>7oaÆW+ylޜ[敱Izvx={DΝe^*zjh֬ٺkڵE(UΙcJԘ9$I ӧO;ICDD,׉Slݾܭs+c {Ur\}m¥KL x9ǍYlFhh` 2D YOMXdpq:HN}_|}}!ѹsgE\\v؁4ǃE#?JKK)::ZH6mL^]gϖx\bb"}$]%פ k'ھ-|fqtQqyo}_DD ]jauسgIsrr|g,Y"؇-[_d}kڴ)=RMdgg'zzOMcI %o5J+J=[:}>{eMfخ`tXbN3g>Znm ^TYYI,;;;I-߶m'74J_߾}˴~zvvv횊*\|GYb'MdAK}^bp%9;)::WZcǎȑ#2FIn?==(Ἲ.\({qHMM ѣ%utAիWM`MmwǕ4c A???z㺕r@N ͥӒ%KhkݛV\IRlZv-C5wyGt"蒟O_|u҅Wuޝ/_{^Cjj* 6SW˖-)..޽+CVSrr2q@ ߨYPP@cƌէOڻw[Bj\~S4arYvgҥKgϞ;0a۷OeEEEΝ;F[6lH>;f g ***GٳߟƌCɔoZ""z mٲƍG>>>Զm[1c۷ҝE4|p#F͛ ^-7nĉI&{ѹs֡Vѣ4n8rww=zw}'a.~_B~~~4}tq`d5ܺuVXAԬY3 KJj 9^TTD{j޼9iӆ>_wDTo+::^Zt)KnWXAM41cК5kŋ7"%F̙39s&ZjHt;w|8؍֘"bmT*c,Em9aXhNZN) [!"у9 tÀkqꨉAԨ:Cm)"66۶mj {Ɛ!C0tP}6Fa콗}˗]i۶Um4]M6vI?Idk1?&B!9`Fт @ށ,nwqq};vxDg rիIB7r޲_v8qu&jL&ݻӢE?Eڮ>cn5ZFVVvڅ$ܼyӪmׯ‡9Ӵ6Qɡ ӉRj ͳx= !!!ţG,NujeZ :t@ii)ߏ]vOL!**  °aì~!** 8tu!۷… 7zL3FZNaa!n݊ 6H:^;1p@E믿ޫy}9r'O-ۭ >cXC\z?#~G7j gƻ+zpu}amXddd8}4RSS0amm^a Xe0 +b)2 F}md z,`Xe0 +‚,`Xv`02 a;Y"l'`0VY"&?VRR,m`)ROT ;^>{V6`0j/wDg().Ǚh!aptt‹/m'`JL\@j52F~n6":# YG>&*^kAN`0 N B) P$׋Xe0 }8yKgFn#6to@34`@*-gʕn[bLB5X/r\n67sSƌ0DVw'垢ʈHRtTP <<w֖G(Y~=\rIuۧvZIKj]k5h׮/^uի;/ܬ]s<>]Xm.% [YQJzl=// PPPRu?! mlܸQ;y*++{nW(((@NNVXs`sn*|,Aurv+ Q^Ze| ̔O<5(}6 ___t .\AP૯BѢE ڵ D/SNhҤ z @Pp>>>ٳ']ƫWWV#l2lR/paكӘvkt>}!!!HNNڡIvqB'|7ƌ_777m8cǎMח!%%"Yfuy>}>sk'k!p-?pm~˿3jb{zzd{0a>|/g֖rܺu 6lg}"Bll,MtkxiFD5kƏc9s&^]Y7| <UVaL4I'ƴ+V裏g[Bc{>o׮?~lt􄏏-Z~A[7>f̘t.C6M^^^rssqF,Xlܬs<>Eշ3RM|₸8šPpK//_ رCslgsvW@""R*m󣄄2RIiiionyG`rqq9scǨM6@aaa? 2e 5h@}E电DbO>MM4xZnyzz;}ƦrW)ScJJ  Đ$>#rww'www-n;5n|Y \J9 l޼ѣG_y>>>W6c6Ғgpu{QL&Cpp0l2>} - nQLx.cVUUU!;!C`Yʼ;{ӧ1^xa) `Njdܽe":Ҷ1 FGDg().Ǚh!apttBvvd0ZIA ;^>{cm b}ϟ?`0 nlm`YmW a=Xe0 +b} d Ê,`XͯSIENDB`fontypython-0.4.4/fontypythonmodules/help/common/fp_removing_a_font.png0000644000175000017500000002532211742276530025372 0ustar donndonnPNG  IHDR]d%fsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org< IDATxwXTWǿmEAAAn51MLbfSvc#ZcĈ%klE]cP+Fq){0x>s{y{;g=EDD`X`0 ftRׯ[[ шѽ{HJXrx1м5a0?&MbcL%++W1c0F"/22@\10ޓe߾ =@"DҌ`4B,3ҝ=x/v˖C+W "h4CR-`0Ƭ#˗/cΝpI" yzNj..%oK ~T*`d`Z/O>AV尷b128tbbb8#%%N۷ mKF0DEEM6U !y ^"## @ ^zTuQ(zHs""jT*tsF} wyzzoΝ;nbƌ:Y$QHH?~WIF~ EtQQDo7DiEG4 Ӎ7(%%Ο?O T*iEׯ_)SPRRfX~}jڴ +BAexb^9FN4 FƒgЋǍUK?е+矀'矡EQQn߾ׯ pvvD"Çp$&&BTZ,m0?~ACCCh5-[Ǐs|27ijSg0 п?h:cbffŀT @~~>]?eee󃇇lll,bp5 ֯_h{zy'aK-{hh(6o,}E_F|6\FjL{K믁|(/hxPz:DvVX{~-[]!222p ,, ~¸qt1x1އ gggq 2F=\]]F5ja4=PϚ1@l0dӸt104ap.^2#00-_dҥzme2oftK-x#;;3QŋF7u*Y#zAiccxb4T|KNzDݻp>}.]Byy97oPZতɓzmޙѵ]bccI"-]vu-?d1coV™D"B^9nt}:M4&O߷hAOD" SrőյNiѢE,XaÆU;55ڴiuO;wu֙ kw"/22"5kuV̈́w}WpAAADDEgԨQT\\3mk:[7""JJJgϞ{{{m4 ٳNI.[oE_ݻ:w[nD0Z4 )Jz!޽{iŊ駟RHHPB8@N(Oɉa-X}]۔uCR>@77{WZ;ߣG wڵ:JL8ٽ{`b18p knɓ'uҶfޫӮ]; J_GVKLz饗8?~`Yo+h4sƯލn%Khʔ)u¿ P z~!͟?ON'Ox:SV Z˲بxj@F<=jF.ܛoY'mk::u2Y>'8GW6kz'Oԛօ ˩~[A.}vD&l6HX [[[xxx $$Kp]xxٯ~quŃP^^t  T*-rGTTq`c;#QW?D$ z)8<bǡCj<{VLJw;Vſ/BsDm֬^:JwUSN}x@[_mݺ!''就?"##gA,ѧO 9U6m _*dزe ;2c$~{g`_|Q5\^!'/D||6\\\;mǎ(//럐`~[}FW. nׂW|mBF(|KgԶXboC*`Y _PJT OOOlС+ F#G>S{pg 7M3qqqZ€ǰaj<ٳ'.^(B\nVR 1d͚5Ð!C<]pqqjZx6h >|7cǎB}[OO]o-[+]PTT`t:t@PP; \HD""""FV۲M$Ҷm[޽Ń~yxx8^yA2tj3TfBIt'Һuk޸~jB={聎;r=zzzbĉu!Vq#X6P~4˗3ٳi4đ.PщO8׿ygbty t$lx=|hQû`e ˷2.et=z/Fj w!FHZ捯/9] ¤t 6|?ЪU+~Įs;;xwFۗefz9uo^PpJN>w_[z\[e7бcGHHH-[ƹ AQii) :i͚5t]M3>Y쒝9N,d6ʢtS\\\-H… ū֭[Iё#Ght|M(I˖-7ƍ髯޽{ MefzWt)Gٳ3뷵իdJMM=ё>|rrrD%"Zt)g{r'2hǴ4tXG#jIšClHHiHlA-4wexxx+oҤIdQPPAe$m5~t lj'jB4q?h dDD dD۷U666tΝΞ=[ꍖ=]ɓ֔)Shݺu4j@@\R_P(tƟ;wؤIDX,=]Vh1r\o[Q~Au]g FW5;w.g]$OBk?dccwĉy!2.\B>}zyMlْDUG#mܸ ٳDM..5dełϞ=[g7|=gK۷/={vN, m"a Tm*XK9}ܸq7ꛢoM/GGGڴigT*JՇP>}8Cd58rZ-]9%:D"˗/QEϧ4JLLEoAeRi 9IuԫYjp-2RSS_F㬟-:JDDVܮ4o^WOd2|RڬϞ[vн{w[nׯ @2---5^,CxV 0c lܸY-лwo 4s8~ѽs8=*mlⱍ R)F...~yy9޽4ۇ͛!~{+Wk8ohH_ƍQQQx0a„ަMB _y߹sG3ǧܹs=z4޽{wނ2&#ɘ1s۴x8q"}ayKDsY%%%tZz5ܹJ~^d${> \{\霝i̙n׮]f׻W-[=]gt<5xNrJ9Ynnd5FLZ-pU;/XVdl܈aooLvgVvttDXX =xˌݻd%vv8\5IS"R^^^ѣqUݻ+QԹ3lmmѝ9s&ڷoRܹ۶m3UH///#::Đ!C'pBѐH$سg h׮f͚˗ѣfKY.3Fs<== ހ`0B@-[>>u"d2[oFW&#())i00ƅEGZJ5 mߎj#?4UM-VO=^֭((({x`05@0GGGHax}~u 󹞞Uk!- "Css2b CIDATe0ߑ쌰0 Bѣh"{{$899b;|*Qҥ JT*̖ 1 bL&b1d2s~x:P9hJ*W3x{{#[EYYT*D"b`0f#]H[[[B*/^}2&HFV Z `07V"DT TԘZnpuuRp]a0]6j 2 Jpwwze ^)He0fŠmTqe;Z,[\\lU⅑t <,r889n^pZF1YJC^^^Z [[Fq5:`FH,-FIQ!޿ ;4 D"J22Ua`4F:eZd޼Uh۶mt []luɫ^֖:FWU^F{GKĞ(]CGnn.VX>k#kIIIUIR… {Y[`mqa26:F(*ȃ@ŷBۼŒFoo:~׮]:ɓ "r_Bfмysl۶ DӧOCGBBB\ ";w=z􀗗z .[=ne 5@tt4~oߎ4$]2=0lڴJJW]/]y^.g0>+:::VǴ4Tn˲2/HNN6m>{mv|}򪗱:9ֺ-^H?}= g?+A 9r$Ν[@y;w_~iӦUʕ+Xj>3f̘'"##~~~Ur=zێ0uT?cʔ)zV[5k߿_ dhZZ ƍQ&ć~۷^k8*um۶ 6\ٳ?Tw}'OFFFF(Og=B@RRfΜim>mv|]j4,8h({n#й :U3f5|||j. (vsT*ѤI FǏ#88999zV 5k눏̙3¼ãGn: /ɰiӦKtZ-j^;\srrtQuY=~s /}V[W=z{{#33N}%)) ʂV.Lѽg6ߐ0h0D Gg]@nnn֭[cŊ{.rssP(+ש>,, ۶mR֭[Q-m6<~7oFxx8\LÇǾ}{n|75N<֭Ä LN+͛1uTٳD:tJ֭/\+o@rssGBBPPPY//s_Llٲ6kǯ@fd""T9JLLᗛKiiiԫW/ [ݿvSHHkUV$J)""~WNǏ';; 裏t5G|=J4o>lll ?fog|X˙t]U8t"R^^kb׮]ؿ( Ͱ< M>ڱj0~33!Dk M7Ņptqe3 0&]Zw * .6{:\\!AYYtb0FQ#]jyssкcwBR[7ht^@DP߅E7E0 dAFW,.p'JJJPZZZ:2 FuZ* * JX`0 feeY[xne^ a9e0 b:]`2 M IENDB`fontypython-0.4.4/fontypythonmodules/help/common/fp_ticking.png0000644000175000017500000002676311742276530023660 0ustar donndonnPNG  IHDR]d%fsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org< IDATxwxTǿg76ɦHB`R r. "^z\^.pQ RBPP\5@Bz/lvw~-i89;930 B VCRYP( 5PQl& B4 >?xi 5P(Vs8t)`a= F CG\ܺLS .!$B1ݛ7obʕ;v,0Lk͚5̮e(,.""#G ѣzchVVjXaʟXtSNE||?ha<$xWcooo  +WDW^yr=L0gѽtz-cȐ!q}Qie5 X`N:*??cx饗УG%%%z.[ ԩfϞCgk]QWW^zz:{=DDD]v/#GeY- شi&MOOO<رcoos΂q&O,,H`XvBII ITTJ{M}]/Z/t?6;4y&yyyDRJE֭[Gŵ!V"*J/_NVo&qqq$443M>}ʕ+I^^^$$$ &LƚÃ̟?\xѠz䢠$&&+W)S@0 kK.m6>>rָd׮]th23wBx׿vM!DT_Soo߾$55Ր*%P}Duu5ILL$/|3g6J[WWg~̙3KRRVV&(͍F!&'O&VVV˗_&ͅ#sذa$''T*r9ңGA=Ill,8p ٺuY˰iY}N׽{wRYYH-[Ng̈́%KߟBHNN3f41115,3sջ>҆J2|pQIzz`]hGI&5KNN6[Ց+kFH]VKy%6f =Ycƌ!eee7滦Mf2lZEEE}v3]x QiͶСCuH$رcݠg2diw[]޽{NkP~SLMxWD˚8q"Q*f:4 믿Λ^GxT:w\;8 n@ؐnݺZM˲:k@N*V pM=]3fhw[],d#,\rEt҅3W_}%}/V = ƲkL- GTZEDDi`ii٢Qf%J1|pvv؁'N4Qˌ|:-o9@XX(9o8'*63ٗ| ȤI@m-kxRHW-ۇ#Ftެ#B; !!!!ɰ{n>}O?1_Meҥh75-\ @VXmGD=pT*gx\\lmmE3wՇrZx 0u) '''oӧOK.v)|??ohѯgnsee%ٳ`:9E}>,(#!!AT9T*CSO=%JC3III!w%G}kz1 CU~\l牍`d|ouWRR?~-!{iG!VGt9P(UVaի6nHЋC;PVUN:q޼yŋӵ櫬{ w>۶mCqa˖¹e#YS> ݷo_̙3G03}s[};>zhA:Zr]S @M/dedhZX[[77n8a)/_U+ ~.]Dh}kãZ0ȩŶájA0pppTQ&!&&5J0}G"4475ij6n8Q2J{(3!0 fϞfPL˼i[.\ԋ\#]C =wxt80xrH1poP`XY5\Q_(Dh.'wzskF}wmݻwӉ\\rE0onSW|ѭ^z hn'8s9MX't// l02 B7˗VFڵkaޢFk\-M{0U֑(vӦM |\~]0-o0wf!ZRJ@d.AJ];x08J$899!00AAAԽxx;q wgr^inڋ=~x ԍf\kwRAشV* Bt6nd `+T2 ll7^meGAHHHr%1A{/31F~b5rb.oo^F5 9 &8'ϝJNY%M+#44;wnϚG֦P˱ .FVFFkw1FcMwmB niۂ1 5c"@ @ϟ?~ҥJ/`h;B@@YИ~W {ґ$:??>\pǏMVF䓼mQfw#?^>}DmJnp[o}#opvvF1}taHII܀حkUUU$::Z-[LBs[.u].B]ɕ+Wk K/s_lذ\tTVV\r!&#gZkB|2y9EDDgh!OdtbA͍|GdΝdΝd$22R0]@@`mQfwZM~7.L+W-Z$*]~LbccyqnkB֯_ϛMOSRRD?4b KC%@ #GX`$Gj57nA`J/Dpuu%HDDy扒%z/D  o23G_p ]BCCqYگX\|K%ѣG]nozB `rSM 픡 _?aڢsoVМ:S"\s 3f%+''Q=J$у;vzr9EqҶil<CaŊx8Kܮ,chQ+ű߮!滰0  pww%4_m"v^>c[>cNƠA$'b xIII i23Go767{͛7`.쐐e˸IvoO8!8g+芞^5k D æt/>@\{{2oK^}U}tRV%w5HݻsŲeDjp=Vɢ\ t}W\\,ܬ]C5|I[bh[FI ֡-z{6W;#MA._[vZ;vL4q!&M"nọ{yy >UPP@!ϟ'DB;ؿ/2`N% 2dYf 社d2aVYAAA$..2Z-IHH aaax{{ 6>L:Uֈ#ªj6 ƍy?vYYY3gK.G[)j*2l0baaB 3g$htfYY7IKK3 sssɧ~JkK/$hiO#=5j?I;&L&2rQh"ENJHqq1jܹs%Z# a}7N-?{v(wٲeСCÇ*xOWWW2qD7;r[ ׯ_'/2ԩyWə3g jѣGILL qtt$C%_|(l#d޼yۣq-vZM|||?Yj)((0>mQf{YYٿ?%~~~[n;_V\4͋ρYj)//;>$۶m#111DP=zRio׮]K:uDNJ>#ry`ٵ`Zeee|2Ip$fAp""MPP"## KKTN>  88۷//YPDSѴXf ̙yk-..ŋqy[OL o"j-, HP(0aCfn>2ruzzpq_Q `С~0d9G/it ::jCii)/^;w6 Fdd$ƍ7sN; Lңx!Í:! .[oĉMQpwލӧ5_E.ĕ+WpmkZ? #6P@s#nsf6Nyޚ3LRְAO4˖-0 (=Æ 39ZfNj7@᭮n0oȽ{w(dF~лwo|yV}K)Nxg b!''{֭[qȑ#&/11QY 4ӎ\fǏVqbic`qKυӧOǁ?ܮ/+l,WNAnQ㭕e8pgLe3ͅ\.oav!!!(((0h{1t2<~6660`nBƍDX4{z"၁P~4~b(F 螳<ݨirW5;ӧpAݻפSTB@@@z1c`„ -EٳXv-F={B* {Ʋe'ԩSf˷#UjP*իWq-,JLuCtt4:bg>)X<}*\sW  ܜp̜8BEii)oߎM6GGG$$$ **͎qUox֊޿III8y$Ξ=kPfK]Û`x GF^xvvXp!],RK%c 8: ~!ܼ,}9k+._o~-ɪXhf̘!-3Jk&F7555µkpM;+ ~7+LD"5kxw3GA.rL{jtj,4,Ղ};c4NFBOZvt׼>:M>x|Ҳ~.Ӄ2&|}{VgkK|=O+P(Sh{ĭ Xr0^D^^`vvvP*d?k"|u'\)ӽ왧P('m:ա0 nܸ|&NQPYXB"=i@FEwXё.BiiZd D(/++NN.! :o|=nu CG ̈x_е̼fy'GhBP0mx r *>2n>=\rkeeOOOB<DGj0 !accFgGFvzf]iO%NHhZ:@PZL/0 0 N\ѳ)Pqlpxr@&:uD"i0jkk!y[[[B`e)CQy)Z`e)\ <ҕJ/)Ş# '7OwQp;C̱2 hZC.7^h4S1ڵ@ b L]]VW"aA!>5Ԇy YHxTtRq0 !E^^n޼7n ]tAdd$||| KRԪ rbne)e dIDAT4 bnJeս%r K7_|";;ݻ7ݛ%H JQ\V.x\FS  Uajkk22 G~9~k.@x~|ʫ9D эztbJ `]q'PcKP K/\FJNG3Axybj]L}zʒ2 +++( 8::B"\J*BiX$$*D"jCr- XX4^pAxQ('NJHeP(IٸO(y'AKY Bi^0 lak_O43ٔoAP(3FoP]4U5 q+>ȢB0z+#!4 5 k>7>tBiw0 DW]_ 6. cEERIG Jaee ݭrG֊v'`iXn԰"iokNSzkzkKK=yXZHP(BKB*AmmjkL+kuI?|Ča]T*JOP(a"5=(]}Q]]kxYnYq!ܬw䌪2hZE|. 3Qfa'Duu5ϥP(kkke=lNyA;Ɂt{A 2Anf:z k[F+K{~vR^>. .B ,,,HX..ozDjtUVʺѽKgN70^⧜:#! Ι&}&BR֌+( =&`rsEtPxZ)kwscGuu54j5J Q^R:e5_u+++偠Ν J-h4h4[ ҮJ()`52^puvB^q lm05I -3Y0v@XYHYG;3pQ[{G{V]VZTWW(//GEEQ[[+hpyŢ/?B0ĐgxWGK=hٴm^ۦ~sշT*t⥪Æ}plۍ 3#7R5% ۰Y"87^ptv; 9 -ֿt.ѽ{w۷Msٸq#.]8;;sF>SQiMy.q[BtqqA^Ek?rmm6M&OKJJXJmq>BJ:73u* lP1SRRB|gx7*)EEEn<6oИo߾ͯQRR<]K.mkuL 1e79F#"8J\y3A#]K++Xآʪ/xf*g/"7 }6ƌwwwΝ!r@ݻ?CN G.r9!t BaÆʕ+rү^AAA@Ϟ=qBW_!**s/_|SN!$$ z.}؞+\.FaH}kǔ۷t/Kݳ!11,Ӷf\˘uP(.+ &ǘ6 g}L!\wʄ~ݻJ{iػw/k.ʕdm?yd$%%СCOŝ?>n݊9s昜/_]va…8|0!puuʼn'T*u\k򿰰O!..U_Bϲ|r|ݻ`mv̶4}ӿXwqtwesf`;t ^~f<:{N쇬i|==PWWvbn*nnnP(3gV^,<>>_}777^yׯƍkt|غu+O>W3зo߆uL<z Baa!hr|Go.6oތ˗W_EXXA()X[[cXjz\n6l؀`Aw*nf͚0\rŬm}MnbQpvǀnfd^ W2=CPTbGQZ|ڀnpv7lGA֩pן0`S(,^BARѣG[=B(((h)_}[ZZʚs<\QR!+*ψmX/&QUY[l&oʟ www0 .]`Æ m~fҶ瀯kkkaiiXWW~Q90y0jJwk69MP( a2rbqFƕ?]v{P(JGa888 ' ZTTT5dt܄!=zP( VVVppp@iE%q=m2DEQ\CA(BR sr9¡ u%9‹oeY @ w=7o֊Lds+דiMo ʻǼ՚tضIFnM0=7\y PdEjkeߎ-Ģu%vwG[G0E/@ 5Gio)VNe[ݏ,ˬ쨺֝)^?zdt2s:RLMUΎeGxw1M @ ~} g_x]rxO{+_9puT+ēOa>#_W[OX.)@ |oLEBAtUؾa]e[Gʂ{-00c%oK4Ktc_ @ $/|l bTE7?du?xzt&]T(ol#{CUz,@ ^3O_t&U'IRg.]kUWso6wOݕ}%\ʍe~`mw=9@ @p/I3շ+YQ$ۚ˖SKOpZV3oU@lZsϏ+@ h8u}lZ[f d٫o1HzZcWoW%k@ E[Sm/Y&Ioȭ GƼS3<ЂSNuwrgf_'ä2nlT %:o?7?@ bkڪz[˖]~ϖ-EʂsDٶ}پlk7>1Yb2c%W @ u몹N;scg/Wds˗ gyf卬 g_V\NTje',{…es9{N@ NV&g>Fe }=U;8}J|? ҙ,34GyRa@ inV|>2ss20tZjko\-e/=w9mfqO/I;6SS+=y8}O.~5޶\.χ|ڧ"@ T$[ioYkc[dsyLg~*<Ésk:1Au,Z~OY@ `77vrzsWs l#[W,'S<;|E5Q# AG3| R2*{%VN.g>`.d>d.`>`vnޱPRp/~@ lppCӘgf.<#c%ChZ>7IgdrKf>e`Y~Akcij1O_hPH$gvn9^,T .6np詧 h8L4"$7Fǹ96ح ,Q5@ /eC۶,ˢMkzYӧ>䣏> \i>W/B(g^6饾.L2^'N`xxEQeEQP eYFZvYi}*kml l,Lƶllr[m#I͍dt4153{'Osm#Y@ VNGKG_rd*0v{r:[ٴf@m?P>XEgk3vn\.ǫʏ~#^xE4ik:*nЯ(*RDWcOSv:^ mYMiaοMteG좿x"Npy9BV_V&yD/@>piUMUU-IEO}H6H َƶ7mۘE޴0G6#oryrf+oa6mM1[p?+69E} @ Tf^xpwJô,CFnM3tڛiojUuLOqMg_kzyt}hp33ͱ[Ǚ3;'ϳ{&vlUru ٿk;0;;˟ٟWdY'xuP`0H("0|>tMG54U2#ˑѻs%{?=? d#!ŶB۲]-i:2iL?}x<磡p8L(.! >k*f%Go$!KieYƶYɬR\QԂil'y26m,*h}&i fs3ҙ,tt&K6Ĺܞ_~wzcc>T]EeAcY@ شbpTu/ʗ{XK9:ΙKWW,k!, g'S+$C{ټx??b||#ZWG]4J]4J.J4%v{?JqdOc2$#nɑH3Dc(TxdIrz-F6mlۖXo3 ]'NH9)~}K|_"cY&A$;"@ X.Ru]BGTOOU6U[oو/t- _/> }??EQ":kB aN^VdTEqzKn \ȾKDO1t*~YUZyT!/Wvd< ئd[hn躆h(r$i7[w~/ 3rx |8D/@@W{m]zym_u- UE!ۼdYIkit6ews=  H,#k$Z% uUQѧg)IWed$7c_KW`)+ @.MGV,GcLLJ_c˲Yvj*˨,IēH^e/X"@  ,,/ΰ/恭ٴvscVZeYvCse0pphf54F 躎fN`jeYFV$$iTX#R8;n JC|dll[vl7mYHmخǶ@-$IEdA[3 p}xW=S؉su_H2&_d@ `6.NW\ʃ;yշ59EW[ =g K_|xmnݙ*y|>/gi |\|'xT*E]$BCc#-Mʹkh Quڻ(řV^0_4*4*˫Z,)`۞9ۖHHHXd[H6X30P%eaZ&iSݱws$$\ّ$@ @S}L汓e۷6#x(64|"7z] ԣp=ni򏟽 %v[k~_ya7MMBCCPHr4EP5 UՐUYq|Iv{Ez Òޘ./PmI_KES:2H da Ȗm.lr Ngc&||$sW4Ͼ_=XUUcWbmog/pi&-N۲Lt4UO?ߏ>T@}nfYv~$Y^q3^F_*_ IBYjz{H@6@Vcˎ#0MMFCCp062}>t5G3 TMGVN!eOs_=U_/P8k!Ʉ$o!.?,969+)}~@4\㙧噟%N%e3No/<@ DBAegUyz"}8K=TV\[,/I|/`XvZZZoh 9zptU7P 23mBfǹƶbUdcؖgȕWa۶-J]y IB %YFgUEEu|i(̙KW !17L\.eEp/@ A=dY&g>β@kc'喝}YjWIdxx?Fiom#ѝ^7|Y{Eq;.o/(- -ib?e@߉% ]I-@A#;{Yv;εHutMG&gfhk%ϓre:|3oz@ )*4/^|dޮe5eSX}7 ?L$L[P//KJ}A:S;eXf3'˓r~TMǶP4M˝E`aPH?آbiHhmE*p~R)'9׊;0@ sĢuU_m\Y|M~ZMUy^~>6s)~9^46h' + WjȪ4r/a*[N4@YZP4 \.ieSo#ɒ[[\ƒd$v=%FB%$ 5UEQd,fjf^ҩTLʕdyLm@ *p ~%|7ٽms=\<ȭ B}[6pܥW˲طc+iC!hN׽Z{DR:Z;|>G.%8 ?L*\Ѷmxˊ(c#yg/ˎO?%2 LLͰv LL:E6!by,t9E/@́W]?O037}ML0;/(9^|x`c_g"Wkz89rH]z9M4Mu<Ms:*әV܎^*p hl;Ao*E<>O"'H8,f>_S3Y&$P$UW%TX -%[F,"#dY7dr4l @ |K:#8w}^9[6-:O^|zis_E,ˢ]OdAQhj#r_bg47bnvɉgffD2I66 J[35g;A}>dIt,FRC$_fvV˒345D"d%sg)LQm~Q@ O E#mk5Zk`צ|UQx}/ZO,y F d]I((G[_V " |.G:dvza"ѿf-}kע x!m+d#!1t6DeygfP\E57*Ӕ p /$yXuM#V>!* td:M*&ΐʤ/ TJ@_ 4Yɠ<eKϮ@ rhnZb Uכk}Ps)I@vn߹:e!I;9r444D~?i(EAOAc|.G*bnvIٵkcWIm/J2OL7s";$G^9Y.4*XmVjk*D r$5kMhDn=bs.:ol>.@TA⫤3UȧڮlgE4B`G4TqQ\iםBk'ϓIH'8p`?e{LNN.he"YL2ϛOͬKBn:rJ iq,Ʋ݆^owOH|n:jVQ3㢪hx9r"$TD$iklŅٸAxim]i.|+74U{\"K:E?}9$YwEAR16[vwOT&z ^,_~ >C/ۨ. ৯kjk+S STERMz۶S8k[E>%͒L:{3g011d]IE)P( 2q{etb۶QTUQQ5I*8$ *R0,,/h$ \тLype̶|۫A4 2L e_ %FWk ]- ə՛xٶ~-zHӜ*9Thʗ\@$qUE44M0xFIhm-ح{z`|?zu#eg&{?w,tU%r\Dr IDATٟ EQ|Wc>*rcNVY^w,2-E'G*$L߿˿t2 ǾnE ٓAbeqe),)N*ƶ ~TдС7 aΟp رc3 WQMӝ8Nς{SHC$Bw[+m}zn|> $w)KBȬbdžu%7[w0Mg༸Υ@$\Upsd7n +2cHnY|~g(d+LZQE&~O_Wx\g>rl`PO PIW-Z۶l۴lZ?5T|-so ;De4M0 ]ml7;@nmprU tڕh9ެT;|l[mc&f2 ')(`bjccM>q9TUgZ(N=2"Od}מ|7َ>aM2 ãނD_{bѺO,ZNj[Vs/:}F.G5z[li.sy1# 麗-)- E~t\\yݻ8{;'C@C*mwoJNZMUPeIYز&l.7˲[Nmcct%$Ir2Ryvϑ9u芯kxdW05=M2P_ύ!6,+o:Ml]fmnJ$.]{"'/=d̫psdT2.4yĩUN& t^M @ *޺ZcCRcl+O%>@2'/?u6_x|v\[ƓՎ\yhbbk׮P_ag)nѫy/՟0/0v5̖g'ɐLHe2ٳ7o22<42 pHH]p?tub6[6mbfnD2C8DWUEy=Z[жض`cy2iՓf6qqHU^_?|8uҳ,7"eI7±l5UeS_r90-gNQ ՇجGחG޷dp0p:DEU1 9O R 244\jNfaO ^c6sodZx+ޯ\qE*?wW\3'9?p}8~r3 ,ƫѣGQ0|Nq +YzCQQ)Np+岤R)Ru~* Dꨫo Tsd:*0Ȳ( K {A~ArMteA(v41-ӴisLp dYqm9W$/Nޣ(ʒ | >8 f Tvc:ax.H${ co-If,Y `NV𩰾Js󌎎:ߙ>g/`4,\c4MT.2(ɫ _!U&,}6ce jc}>]'-00H]8*?XQxbn[x \MϷ9TkW1 87|>tKBi}`~.8Xs24T۶*GA*uO   E ϢX02>(ξtUQe'tmZH8vxn:7 t ֛%tEDTauah]i EQ]+S UuyUUQU 0 ~SH֖e!>4PUA*7yG4޽s߸I2Gu$YF׍iK%Y*q̡ TUs]AM ֕0HfDPDXۓt3qҙ,-*U$[64RҶm;c'yފdZcOYŭUU(_-}ӕ5D˫6'7e$ ҩ4?[hnrFTrI N$IbքJZdrsq jfV۵̛E}8*\pdX;!N]F h=3Np騺jaZޅB*[~Z}%Ib27n$J9Z֧n{ O{mo;򒚫ȤHeN΢BYƆ x{UU7Xf ǻ׈NnZu#cv$K$aӏ#xJ|>HW[yOlYlpdzenݙM$fgg9U\kL'5\g|YUUYjB>orOdU$Yrd.nV.6WȂd[%V9s#?wc,WnЋF Ȋ^7l:@`(D(RG8RG(!\G$ݝYTE1Ǝh'w,_KY "ԅWxU8}4G˶+/(E- l{^ZV h' V=¿CeZnmAS(2- Vkqڗߵm׮8`=P7Yk}ߓJEi+~{^bdIuݝh :| nj^&ZVGxʲ773r)p:vrQsgy_q36eX]xI.# *ܠ ~ٱhVdUl/^)}q~3 uPȊ_M0tXhsƾ^$cw, ;x}}$LX]pIܚb|rir|K젫d?=7G0w-؏ml& 2O:GvNnֲt۶%h$Lkc#KD*یLf>\\18JSC=mM ^ó-kp{j[3|q-¾*IQhFibc%y*ylws6oYr'rcW0R ۶ :YIgK3#ns nu6,>f룬`]O'~op &ʚP,Il_þ[ʭ0ECC=+I%)IR6q%/1.fk;ҿ]h!oݞ8^B.(ƶmtMu]uy5+i14~\!LP|Ϡ:[ }\e7Fz TIزݴ572twNܕkN-x.'J`5ɫŒ*8>C')cZo;${$I|i:~LCC]M=^ |i^ #gYKXX\t2I*b ;rYrfk[/NTZFB|t4zkM~ɥ%GcZ{&r#qR #˴56޶jVZ[[9ss5M|G#cMʹ57[& E&elb;LNO;B*,Dabub:צ*t47c6GNfbf+$ MXA_G{źHWtώ`c_ wn\yYdD$b 76a w~=t3H0<~C\:[[hkF+^IDKXydmn3{M$ ]X}uĢuUߺ#'ϔ4k ']%ʲDgk3ٶwOkNUZA5]:l4Mr Gɛͱuwɮصys\Υk'J޻mM1ܿf7Qqy P@%";RغVOg{a:+ԏBW[ ]m-l۰D{kQ]Slg]O=?w"FoGwfnW4:lm Mk{ٴ4ͳ&oZ%,l\[% ܿ}=;ēby O;3sT2m{I%a>$N1+ѥ7짡ʍ䁭F¼Q*Z˱[j=zUQ}C=I T,ؖm;Ǵ\}*E:N:N)՝ U-60:yΠba֠ݝ+jh( zXE"?L^.W$ .7g0vs@pu a㷰Q,GsvM@Y? ?{c{0Ӵ;@e[C_WR6hm;s9K&/ woڮc+RfR4HLV6vU3~Z_"/>\"IsldƐ׉D/|\Ɏ J4WXViBݻu<?>2:akNG[Gj,gVg5 {۶xa ݵ,x;AvNLf&tT2A:ar9QW5͑躗WdVZ4t UUl/Qx:nx`3jpלltN-`NVejTcdt|>O>#ϑmjbmUʫAQzfs|xw}"=j\yGQVڵ{166zclbHArܞ JbY&-5L}l.9wնk s #@=8C2<8+k-7y<2i0d?Ww2??b;'YQp_$_BVd;wSůqgjY׿1XBeiV;O?)$MڴClQ+uoDW[+'(b~9Iϡj:-͍<}pMw>+O>mY6~L*f@Iɲ{4606qh$I*Khx,4^MOG_9ŕؼsFr%fggQUu񣩚.yӛK$򚻸NlfHgҤ2wɓd2"ynhQQiu%M^+US5V(lOc|`q,8Xn4-b,sEd)STUPU ̀?J!ϑf45ԳλA&&JIeL^վ$Ifٷk'5}R)2=?Wk^\<,,sJ |j\{]nkeK2K/t4/GN3*hikO\dzzD<Vu^}]:jr`}D~24l2Wd9Ys/%_< u+pŅ<& 8 ߸}. \f̻&3&:H,ٸ{mw3Jr\~cU+cNɤSd@\8:|ׯR Cٿ^$e.?};<2=vKc|1~ʛҙeG[ߏ0tG"5:|5rdmltyU*"pA._D[[;`H&hhh.! 7VBpQd&vlGQN\)蚎khc)a],qwCad%n_Br1t /: 7d[LNM!!(2fQsn/|%D`pt_7I%?nxJT 2:LĂDƒ"bX砣vNs.AG%Ufjexp&Vm $nߙZU`&:I{[mYť˗$#?Duz?}\tB,+^7L&_xiqp>ZV۶АٓeT-i-kU0YKQL37!V_b *ӳs$R0Kqe*LUUs@Ҳh"~)"tyϜŁs9|pEWd H.G3 B4^UFT#͐N&iZJ,G49r#⫇)bn8Ao `(Y}64ckB# IDAT||>7 -,{yv$.4rcuE0 ~_/_ƶ 2_EoKWܪX˲}g;sB8"  8uuu_׿N9Gމ(ڞpyD7 ==<ô\s;4]$J.z~UϮTeZVǟr9CiWff3r>ZCA6syR4M5 4dYTҩ'G?6U7?7ޢ>lݴ[Sŋ)'w--!d9@wΓ*g/l*_~L/?~"xpwwa^y/ןzDsT '/Qͫ@FF]4sa NT WQQ=;"f̢h94|ջH[+A,uG?wxi%+}$$vα"(,#+Ng7^}eYIT:JkrOA_r[KPUSimie֭>~jzN{qgj ۶1 ?wB5DYǚQ r,3twהL$KydY&Lp%x?W ` Sq;6M5dGFlR[i:?{##id\n&N3Qv\׹Wꆎh3@`(ʔ$?3=gly$GɔH$R )9n4bJㄪ U gݽV=©s=2JB0%IFδo57MaOXdq1 K*EQ.ڻwtzO_TWY;I#AL^0x!W[{{dHtEQ8g@_:, \yw)wڄ{oY6,˂iX ŋ :t&602z݉*<`ͷ¹(LGJq8<'Ԧm{]d2iDTR( 5N[[ݸς BeTD8NPM}d{EAuBD( 'r^NbTY=*BRtR493Iʤ/7/m[riu!(:;xfJ<`yiIhuAr9A31Ӈ_෷wۡ,9c@?\u ȉ~Vq]%{}ӝt-W:/nM1t2-8*yw_x lrz(zӾX HhE?oöuke*.i12>x42k0q}cT!jecxlA\݁1i#E#Zxmd|_ Fk[{mڤVWJ lEJ.sl~p%,!rmnhݒ(-Ȋ"AΜd39I@kJqٹ].t8 ۱7M+ ͟+_s68@6UQ'&'199 I"_F n| , <$Iс<hUUa;6}-#GLIeFvwDs)reE|CTU0" 3yIH4m9Lh5 B8"==g _ X/ N @%\r/_PcMn߆$+l @PQ^6E섙ct,,NJ`a";; I24MCV3{l+!Q ?t+yرuc ǻ;A=;i71?}Vcu ezXTn^^z=NxYD(!t:޾~LeԊV_7-pDSR4.[jV8[X;3[qR iNi?sx "Q˖͛kA 0@GQTB'P\k帞4zOހؔ$BdM$~x.$B {ziI HykZ|yDo2-Ϝ۷=4 K2F2jc'OÃꓢPU#amۑNŨ3OzvG$ {bhE+gcLg[lUcX\Sx4x4X G9,FGO9?`Mg$ YgO_[6~ê, %:cՙ3g8TMa[V\a(@#4>SJ>OzSpu Vba/O -F޲˛XZW_%QGJPTr2]0y+zJw"V$mD4O);t#M $S9T6qP^ܸu/]~J"8u%u锼 ShP4 A"FS,.'x; W |e"I2?n> t^x*$>&u]'~]nukŁ(Ԭ Q`{$acD"܉V0MP=B2NgI5 kPYEnx^:&SY(FR,U&<\~G!J#NmIG#E,ohl|2əi醮!lVl; "74Dڙ櫨b ٶ@xEA'NȺaPUߋ[Dp!$ 訚,%?;nXة8f(8drnãնmô,dyu+^}5 2קXafHqEU)0"PhɐͶ6z-+JgfasS9~CA3\+P)??ຨ p2N>IV +*wr#(qd5a.8r#9Yݠ ݀p7POf,yk@@DU5hUUe:}l :E+eyx%kO&d2A O{_&ubMU*TE뺰CTjlk-NLb|Y+àEK3:|Mw"H$ш8U#3QCz ~/rύE&WZ۶˙mMs5EQ |0?RP^R)"kI 5Z{S\$˰y광+4Ri<}y3Q8un`A~;@ dB0D&gRD0ͩ= (tE&@3@*"-t>i, ʉrTPlۋ: ##J'gZ9P0%*r/}TAA$U˶HBVU~YĖNh>ZDi9CkN\$)JџF):+v_Kcxt qǑNѠ֟$IH's-B5O៟>+^̓a@V, ACk,Μ<9yE_/F d/gT&m8r5UW] P@~~&Xb3WfZcOoG$018s $Y{{A&ŨsQb̝CviKD|r/o} VO5bf:.N84zoY&r<6^CkqvP5 "[$[vmMe 469תj0GdF(-gĹ"ӢB "ӛeojU 2 lV{⡂P9r:w3p-6gލu(x|q]CG#' hOyeMUQaltE#04 tIiLcP:JSU"'I[ xW,Ż]<Ӳ?ÇM\Ǧ{Spva& 2~OAUG=z4F/Ϭ$ z [0TC)&ȥ)/mta Sr  fj+>dI CO[_TP̂f_\Eo®=(>,;g m9 !?8p&*JjB4#Izrg>}mk5Vh$e^X ]Q8`&F@PY.W=EQB]T@Ӫ'I"_+dPtKTs8L-)\UUZFaY9(hEl;g \clÒ'܎x4U˖0ƾCGdz-zUѩ7/Ek:,YX3Mw\nEpwp\#;ɞfQN9ո 4M>isP0qh/}LUsQrlplyD:d:t4b:k~H5Guhv}H T%4 y+7 ?v||((,zÌq]?]uCQV=o&JQ_"6uGt=0-.LҦOrɦbXn3SUGYa\( x/'&p1]_I ;  g*#AE>mFȕzYF ŢPe"p IoiDEYJZ2SU v.$*[a:.y d\ lwvNYa@AF9z,#T,-Z>s5g1-kVi˱$V/'΍k ^3JT;2T.$W-E&TcqM5\$GӋk;q ,ŲE'O(I0t+"P?#ϽS+lP4= =mbT8plPs\o[6L6d*TQ]ǓwA#C80K!KBl>D0R24NLL=ݼkÜ+Ei,8eebQy_Q m?C"zj+1MLNpD9 JbpMuV~"""*3np=]'@p8x@Q5TP[ ptdtwn4/vh ţRafD*J_fe%Y??Ȯ QgaiEQi놚[>(R(gY[{gqx *ZSU[dyӞV퓷aE #fgSmhtlNpN T~YEo|##B hF4 dcstU 1H@AZ Y aaM ws`*$(BVP̺ .me!8X _y=Mׂ-x*bR;SysY:+~<?+0eZ>LKb[5h>뮋漿P5ܒ$9},)q]dLS<\%rz@~u"YY"@[GǼ); cxtX `auuhg4Mt%:|s>X۴G"/Z>{MA-qgʲY"زvUDhj#bsYeY)ڶyd杌'Q9^4J7cbEiiDP95aQ޺Z@{2D*LU cu qJv: l[nϚ!ZPx,Fo_G ,lݼK5%!.~D IDAT} ѯ~QRR];vKć;PYS8B4\;Lӧ᩽`TNe^++J{YS]rJEc\i+W J. #B? Cyч JiSu+S뢲,[ZZ³< ".Q߳k״\EUyÁt]ogfh3",X3=27UY _gȣn[ъV&m.9,}m)E3vA4/NJE1Acx=Su}8gv P#2(3jYvr'T9dLve[[&ryL &Si4-[g q?GT:L&Ӵ{<}} H#0"c){"3(C$$ L^ ΌIQR4 C7g 7V`ˢ,tqdd_ K/?4D;[|O `m9~#(O_uT;~4nwpPٔ$ V6̚E2 jL"|yЙvmۊ[ v 6<_U>>IT>;:X2}cvE߃ XZۿ9ﱈ $ ѱ1U]"/ZE|GB|'w@5LQC׊/< ~o:e:Ź+װuj;V#jHe u=6ϣ2FIhnnF,#lir.ƚ[QpϢo-e6MX68\f^( YYB\ ^Bwup\8!T!Ǵm&Lfr<}3JbQtvv>+W8gc8%()+Ch !T/z_/baM 2,bT*ߢ;7n7n\}$bs@e&gAVAu(݂!ط^'WdfnzOi96َKq`6lӂiB|D#ϣqy=ݾef?s)FƨNM`D"^ZҲr!VZH4F epi~<ʳ٢ZcΝƺ ^΍e6?0yJ$kK \ǁ>"Nuتfițf~cǐoگzeY$]b}uV`[Y^X^m?h"2E4$wp?oDE:x=_vo+wFFFͤ*6Z1q=e*\b xGq]<ОOt}?_vlҕZ灝w5΂|" kjxMM'4hNLLsoX{m*شך<_|Ih*S#C)V; lM f[֬\S?~8on4E(\گZ1ESc1?ED[g7GF{qE83&IF@;u1:>S#c?0T*ERa( ]\7nfT&_||翌fI?#>>viI2UEU_l`pt!yISC{pE\od7I˯sъVYn1p~e:g6>˭ػm?+O?7B:;U_P^eӼ~?k;qi>â0o!%&Bjl˂#Jald##HN&ISȢDoltϬh^`.lƯ'Kذ-"cAEV.CSRʐ7qu>ܟ4 :J/GIY98 # M5Gxy\.7o⥋f2p}<^mصm6o4dKH $Y*liQA۶?@:!_N$\kkCi<U}Pգ mC>+ mNC3Me$"I)+2DTWT`AѱQC?u(pl v3 \ũDV"N=Q)(0 ൷~NzMUG{z$yOC۷`i}OƹKͤt;izV<""{`G`IA?Oa64Mt}Co#O?]۷5, <_|c[fkvW;jVɼBD8~ =XgGelۼWo.,V`یvtD/Q".O#65,ő5tmiOX+qpYȊ+YUh |[,~P6,ˆ!Jbp`FGf/ê5bpl#\._*24UDah *JP[U(/M:k_yd p`/KaDĢZN %e A7tf^9("7Q]CTD⎅}}hrW6\eŅ$Kذv-nڌښvlgΝÁC14<ē$+ ݈<˗cI]|2DkڊZ11T`n:NqWDmԦ|>-8ZZ[aT!嫭Ş۱r9u]>{?}p*<*Z8N(k8r,vlXE\D7!Ξ? ̩A({p[Pz+b-h\ygZI6Á}J 0UMnLjH2DFF[~9A~6>={/ d+v}N$Im_?cAE~QsMd#LzJw{o?d~_G]a~+WL&QQQMӠKhHOSi1D)3iB|JuA K42kKk $;K.C&(R.'jDDKQRZJD4#AQ7r `xEn.\~Dge8v$jizijB L6x׮²IA3"Ҫ*4݀n} Ue娫FC}=JJJ`6;q*\mEgw-h jY0YE}>21aڵX|9[Zp\' c"Ԧ397cʕE\OÇ08W4wz.Tko_| ;o/}+X4-ۇ}?L9R˞ {#x\̯@-7n=|g t]xs;8q4?7=C18%lphM;G&|;?b瞞Q)Ӌۇ}piA$Ȫ@~8|gxÃXPY5+q%V7,X::pY:w-WZaeZà(*?/*w_x 1U51Cɜ ʫ㱇bͳy䙳fɣ}N$ebMc6]ri2Ĺ qypd]1Hgx}{؞(Zncqq* @E0v3u ݊45 fNpٍm )(O煼P[0Pblj܏q 2op* ]' hdd^TX]DM'IE.:|Eh,;128 ab|8&&&v6.]6)p ++傈0QD1DcqKJ+)A4VH4 =.M2ܩt [patt.P% YJShVAYI̶ U*ct|~w2nlDmM-::qvzzzyw\-N䛬J T m$qM:J(Z{qYV* Q04:Il˂ ,s:8DJ''{A_Hnrs32 \%_wXer4c&L:ڊ'1XI:z2`L9a2 ~,$IQlq]`&SI.K(+-yxpyR9rDP5@D`49 @,[\A,:{Xrvm߂.?zz|@sd\k~m𚊁A~/C%0e0 tܕpy|t(7?ŋz:=gel}ǟC:8=c[XXϝXu愦X_GQO߁iDWeL,<.܅K6a-زy#FFFzerhw,?St4g&ZoN46,Ckvf#+rHF$W=$xǯ7MŋH$z}a>٢hwocS쁝֛ssHqy3! b]'i'O$#vt3gMPfwl|LT۶n^|EwDqOildEfh6"zXhxXoLOPϊJ:2f*DI^,+EU"bu!&׊b|2 @uwd=ijt=#!**Jj4@:04MBFǫj$ˠk(ܱL:gk.Uά8xf$s:, aD|5"J3qr9 \r0MWb<"p5U+ tmuC,{, $  ݾ ˶@g]?Ǵ;N{O븐h-, TCu(pYAր.ZъY٪e]fFFh$әojjn$*:}Io1{8q$DQnMYQ5O SXޱmXE"ǹ24r,o#Gt/-kp/j/z A%RA J?D8A3tNK2 {NqEU6A,+0<D $rB͢SBmy nR0K6s2MXeDHP5Hh:2'HۆF HVwPŃXll>(:AP,̼+~ìD) lJ.3`ƥO0غv]=T/X[qt%q-t&?0H5r-5 ˗և/|$^UH\VTH;>;YkBe5|ǎ &@@š"˨_TEuxa ¥˸vGs.*+C cX"qjMVd<Nd\+ DA,XoHc\݋8t,<;n~\?t:<!ekli\840&Yl ey͠|NSi>,,Ӭ*n7롐6k9fBWI2)wKۗ!eoqygBpF}BъVÖ/ɋ-ƼՕ+gSw⥷VG'&q{ka ݨ(/'\u0 S@t@O5:7$Yj@˳X_6GChJv\vd$hB}RE7 F@1o6FfǡLja:5,W /|*#8pBz,z#Ӱm_bMk+u|( ߫V!ODZt$(-޽ֲ,X\.ij+#L+Yԙ ze:,J9V/@<11 .00:ɤyS{%4r̩ZM^K+Ѐkr@S-L⅗^E^.奥 ֶɲJG`撞,zˢN$v}ϯ$IxΐTEA4h-8t42<yj/AàUG })gkZYHNJ8HoYAΞ ЙE{wH6l&|.Ky=&N\D"kaad-- &],3ϟ]%g .Hĝs7_}YKI'̂' *P@QH&,Jc3[[1WhEwQKeِU6Zt6m^dg|Na\S2a&,3+G&A: !"= 5H,H$ UCN[iziaعqIs.0*Qe,|l6ed(\~ڱ"$]hPxCf4'vxl%K%灦}@οz#>zo3,m\m?ű>'`?=J,Wc{Wh,x[S1B^I [ȝ@κ;֯'@@El\ӄ%F"/c29Ҕ{cPcڭ[%)e&pU!F`E7ߜp]Oى!$;g2A}zlhZE>>v< ES)&/NϿ/baVE]] L.$J[3.K)_ߢ6˲ܙgYY&6.L 5$J"?VDZZ6ڎ)p%)z 8׳ADȊʳ7m| IV>A?.+c}ъvٲE w$z7LfsČtӲBaǏ,IL6QxζHc|#!6utMk342 ;vKib8e0QmR݃B[!c$AѰdV^[S᠟~iRw̴=o "\ xYQ)jN$q9hy9 ԱJו}N )b;) ׉dLNS8"~s7t kjд|ټ\Fc|sP)MO<{wոb[⽏ahlS$I;x39f齻и4xN >Ȟ@_?>15/(`E @e2\-(w_ :>O3Gb)7۶`;ΡU=Q*"fiGf#&A(p%}x2s\ǟz}3%Gj °fy ]DI|'ƿӚYPhO&qy;4 ϖo4uYW2DKK b4JcñX-U= | 5' NcիWa(dUG$͡b8/x"Q{O!`Ŕ!7bk_xo|pٽ|~p/jui\sm7LץRV̜ssZ056esNutmfPܫ띿и T~^}u_dže_rbs ذv Nɂ't\؀KXiHef:RHz#l Q-XS*ӌ,Ft59enr:8;&ySM % dt=8>͈K5!,ZъXI,u׸g3!򱦂쩿Lsf{ݞc1t3 ( a$q\t oۇ\>%-I&LDz%wv6. fOF{e*2w7O\ŏ^/\"Et`P@ PRYŌ2C Nlt luA/gaƝŘE+Z>][Yxg4cxl>c2 % kpkڋw~9%ɆD G2*=Ih:F*D*Š+DY(h !h X Au{g!¢Z7F?gu* Kc fl7q>N31PwEds9T %:ޠdp W]Csk FGoě iv0nwv#׏޾>  ~w nV,^TDf^oP&s Vbpd LjsGKũ3oSjFȚ$@`NkV_# (Â/ݧ 4G&!t9l]3cSE+mw24 kV,Cy/+(Pѩ㻶}Q-al|Cäpr-ю*G"8r,z#s9_s4r N>oi/{{gGڋK9_qf>\.U`Ydہ(WZ Zmzs's]cc nj pvXʤcY=!234 jEcsFE.i^}rWT)&^?c>8hE?-0SwMq'.Yt1ܼ%9_'>dL: G>(E}ͳJq,BYY f`ilW|I,\cʕ+1w(+D,k:~Zƀ|ue9n݄ŵsBQ/rf2f(Fq^M ׵:Nȱ<8d׌0 oaPRXl6SrPd (b`pK2DZalXoˈFc"'U ln@ BmQ 24VUG L|M?@1FhXhؖ‹}yE+Zm?~PSfAy|p{>1(4bPdy8}uUO?777c|b,#`hpdr&gCLlvӧ xж#ɜOkY(^Kj]0[&hBUa}`ŲشaV f׮cx,掵בV'ok¦RʉnP}܉'h*,D6TEyg.^™hvu%Y zh0t{64MIo=DRޔR鞞؍[׽?.n6voǴ]ީJK$EO ?%ۍx%$b[g]XzX.Kǐw$Iz]X 7q,ޓEpPpsq$Ww> xK-hv?ʦ)òw`( pa=|1ᄚ_;3 NIxav9yN]Mn꺢eAc\dxff3roߌI"H MҮ48[-oW7L՗^sg`rOz:["h2[Tۄk]֥pEouMb!1|:` -7^XڇC~7yPpH3ͭ~Z:.ܸg]K;0J( `mŚM)I[\U MUpwv7o݆aEH K0 Ӯa0)Д‚f6@6Ct'sELe`@m(Drdaٮ=ҞfjD-.XK7 Ν`_UTJk_>uG6z_~5¡쑞$$؋!kQΰۋ]r0 b' ,3,ekU 0 U"ah+ork-Sk4Q,WvMvvzBU,--auuR Z $y~n o l0(b((DQReOe]|~*N) 'ݙT;lgi`9AS5MQ ]נk2XɖofaXۍAi4w#ynNNZ4cxs;.\Rj?M{A>EѶv`$ Xku$ƫ^oМ9jI|'fPavtips4Y,\Zme4C|?@$xN a@{{E9O?Qبl_]kx ?W˷dEO~e&TNFjR5eZ-ȲIf[>]V]0˲v3C*B*B2D$b7qW>2~]< -z(!?YMNˤa4hò08A5hj`T.c˻:,ˁX/O8~Xtq]W_בײd I <μk;. Aۙ|6g\ATh ȖQD8UewzgK>˱~{@,X0 S)!f,Xegi5IMQCbY!xԠ) p jiZ(+>#{6?lA>|f[zx\!4`7[ޙca}:7_z I,˂8B!qZ- {62.4Myxt2 k2$ȯ5[&{fU}daPՀ^.j:KpK݀pw)3!˲b$ǿ vu1F[ϲWaɤqA\G\*Log<э@ a:1ޜRW vkln`bȞ itTwlZE {Y{c!oՒ: O!J@Xt$>=+]KӈD%TƃuϜc:-⣯/AHƢhڏAdžIHD#(Pvd,gND^x/_Sizϲi -vpmyo-<8UC@^ FS06{!1+G˫Fo}%~ߊ] EA(EQ<00vAQ=+W}gN*{ 3u_RTVGV&FuL:IqJ/3l XRp\%@)@TB4]Gae쒲ӓSoBro]H<A- ƣ!pƑe&ū_,ѵK$h%X$z2 ([.qAXAs-LӂEgQf?D@<Fy-$hwrAűS׹B3?I>Ґ j3?1{_Y{.s>~Cv$IaCqkwwqaKݱG{;ɽҳͻ=Д߀sh8d2jPI, LCz[R IDATsEs,!GXW 4MޢM7 Ne  u34E!" H{5 #i:қlpz+b0Kܢ#"̠n4EA-={qx7UͶ40Iﭣ(=2ѐd,jS ao'p40txE#aP ;s^7В:=YH$E ^=BRP$( $ `hI0MhAK |"[w⊡iߜy&Xv}zya0 ?Q?8=益AY0bN$$-uOXaQs)1:)1H 5MhJu`22"x$Ne/aj4E@$A@9tTmK|4$bq}E"@XӾ3^(뉢(S+5[r{Ɨd=Qܙ_E Dz8NYϟ:nIӴm< v|Kx~G\nÝdBHܮ`TAK]̘M! HMS$rr<`"IjmrSx0 wjWL2TUA㣾>U(:I%miڦ{k 0 Fc LoSIJՖ4m4X r]cѺЖ:(+hI]Յ\20j64]G"E,I6Ȧh5ZH8Q7Qk-Eڋs,:OF6$G#tFx{Ua =@cG#9ƴ, idhgOX.Z]}qQ0XEb,nd5]G.E6E4o$D2H 'M慦(DXi4ȫ0 E"^Ц^ih4%fӐ%2ٖ0B=.Ԓ:?_ _~i<&9)o7_ǿc,'ϝsvqB ݵ^$KX@iIƵsߊk4/|Kx#?C ch8=$Yz3`XZ/>c"2kwf>z[4ku\sd6nF]]ErGA L `Xς4MlT(+(0 az4l*\:l*ѣӒ:o=jfQk6Qoh›/=ҍeܘ~;TQ|EڢFi=qgw Nz.z%+*Jڞ ExS8uЦ{eo.ڝYHHٟ|.TMû۴\,R}"4+tӎh"|N4M94ZmpĮG<o{Xgoxx>  rvGF,=<B{= SGo a`,H&yȆ!n*e%0KNļ?RDG"iY`t/9[@8$"c}4T<< sء&Xx-iXlZ"r0yHqa=y4P ՙddx֟r&t'' C'b8!AШ6HD#^e'tmIaBe/s.~1ݼJӶzI6U]J۟n`40, ԑC$GHo܁ I ⥮c#U<pp"I$QTH/8bh)gql&sٞ ˲6$1c p{곧y$I"J JP} 0lt,k= 5߾;A={Eq3d,x_ޝkg;g:j#9/0ˀ>9Gv_]w?;D˚c<}șd? %Y;}Ȏ9Cmb[Jx{כ-ϔᐈs<<[`ªxB@*JvX/>ԶsBxlo']\op=AGQQ#$줦6gȥ845F[d0jpa<:jNUQ@1=Ȳf[Be;֚-4ڽ[i˪ 9׃:L*X#}Ϥ 2Gi`籪i0- ZĀLKh?zY߂Xgҍj"rTFr Ͷŕǟ8 t r2L%I=JbHEհ^į^SM"{$Ijbբ-wԨ֛ݟ>owjB`gi}o{7[QߜGS?x$y\bydr_C| 1'(۸5|Qx~lTHEZyM$IBYHWאǶ ʵ ؍ėnI8Q߃д,/j9[/^AVG*N/z2LD>jߤ U-pޒK8sB]əͱ^=,;.zpȫjPT 7G>6,vQC`&[ez ;aX_I7 ͞&DD /ƱS=a7vRw\nC. [Ԍf3X-n)Ih%a4$)P ~qu}MK녞~/S#`-•;ss $cR7'KcqdPG\ŭ{17Msr}2ŧBGQw?Om^>lK^lx1]M膣սqzKP$|㣈E¶|S!5LAQU(EjK(V쾞jm #]^/zx%S\c~e ,DV`5[;Mv0MȑBqm%+IeYEpdtk4]g/gofE(G[*pknHطpglLgڜ߇gJ75y0.E¾`(oydq_68|c!+ 4cq[(V*XZ+`b$sqRE-*75,n4-hI|O!"I·]tXoO^}"48 ]L#[h}R>9J?HKVz@09Oq ݝI6$ eK{_ c4V{N T&!pC` |kuܘ{˫=&t?fI/|>c=H'?nKWڇ1I\kumY~b!X) ¢X~ P@XGN^j9p?syn@ԂXe9cirN r}2 IJ{gGQQ_q&j@`f[89;! |`퀳ݑ{eY 4{u%tc ӉV hK`NsN>P< Q MX wt\voa4LNfa=񎛉Eٯ˲GBaD?]@Zt.ϟ>*#-[ȧSrӸ|zTS֊]{H? SGԑhI,,9e]s˫x'$I>t;ɗhw8C=2XBV07(Ux>X$X^ 9F^ * GT9i.FѐXf37^r_Rh+!sK+ @X/O;ⳋ# |;n,O|}BƥwO|߳b!,DC!_ff=h.j)*.6;#!$I@4tdruwRޣ[ALTHJOv 6XAkeܸ'0/bS;"a/bh:P"ɞ7<' \!ܝ)DmMxqX1!IQ < qZRiR4xǹ=ϣ <$В:^NЂKSr7$Stsxg1rh TY;ͶQ~Σn)Xw.~Kś3'q5|y'uُJX8VB E(r$GrrlT]ZAFAc?|;?ŵ4]GR 4[\+R>翿C(?4^={{[ƌ0gpd2Cؐd_H b\{(ˊHHϲxL="a_^C* 4gHQPb sK+^6^ f  TM+U84LT 5z prC8$ 獪i ܀ٖ09JT<!EeBOF¾q(oހC0- m#'A6@nNT{q6$I_yk D3 ;:CS7ZpLjb0J*F\O=j ySp|6 H20MS9qF˱Htk2 XxtaxE19 COAx>pNπ-ڟ}) gOwm"CNIDAT|&-HQ ьQ,]I:BigJ[s ;o=߻eYtd1f3ѰTfWpmuj]`"]3i}T8}O?58}8ŽU|z/ +*~އ+/\ʟog/(ё闸57p6"V͒C ā$Iwn&LM. wG'w痼[^9s*09b[e٨I4s'-۠kPX.\z3 `zGZJ8#4F`#+ ;6m,Qyph3hQARԑFX4,ڮiSC]bh{I&O^]\3p}޶7 ~~L#0MkSeu{ nfwu<b'Uu1ң;*-|> DaJ˂iZ@y I/PJ<0 /5 G7Bcܲ,ܚ׳gڲ 4a8~ȪZHߙ_D{ |.*5h?ZR1s$A LxsjKM- X]n7z}&G*sC&HTg: 58iaq_W5$[Sv(nDalaoB@< Mcy4+"%‰>6ʍ; *O/@X2W|BqWHƢx1pԚ-\~΀EHIXCliYi TDO(, ) `Yt3ǰZڀeYX֣<4QmئEaKt`(@$Eh ahb1$ N;b} I[7̉8qp:p4]׋xㅳ=]4Mk v\$ Mae $ $=eM׽~~P/MS0 iY ɹn6viYi"cHOYIA7{e-p!3e9NKXX]SRVTyrue&I4'l2MӧsnO`sA2 4$j7(XzHr-i[máp 0icXAS$ZeYC^ev==&s$ l#,fg̻%+jtv$Y8 ̿}xYPTTrs Da tdEE,43cVӲ`8e?+W1565a_=88~=eYov'Ɂf tdw0BqOC 1w z+ledem2m+Rl4R tq $=0A0Mӗ,ݟ>X-mߖ˷n0ay-}'Hv߿N;o8t~Y䳹C=d \H lL4>vp':#9恉1Fmm |:O'u\j.C 1D?v٧ԭ{u@#jw_t/Z+k`T#Os{w2~wnh]}YefNxm382^ GMq1b^vo뽆mN{qq5ycY :v' L[i4v0m˲V*cTƹ+724rY?0W{-,ңf 1C+2_r߾LD>7=-I{6ZXZ/-u@9: #s/yx{.˫ cyϩx;4ʵ:Vֶ5}y ugtQ0s܀8'qhjo~C8}u'^鸷{˫G?1ɱ3im;zXZ/peCb!b=,$Lv O5TzҳKQ$AD 1N096_8v>fjEŹ+7k,}yL1ˢ-ul٬zÓϒq{T"EQQm4\Iɦb Gsߝw7 E, (P4UjUHbH%bHcJ _$A훶uQUV!CAoc `K'iIeVM_/.шx8fa!1ʲjȒGHvϊY=Tł宽k޶:>kEU}{!~R;Dz8ˁ9˂l$[fUݪn!n PE,dH CyoU[$ x=} nN؅aLC bvQK6Dz0z/٤j0Bo8< HTY"IP$1s$Yš"g2nD_/⛯faaL0tcñv\%Ra:pp$M|A[+,v?"\3ǫF @|vhCV7!l |~X+rS<~s6a8vݳXi}kK o8nkE TY_wcNpxX^8[ZՀVQ6N](<|>xK68Ab^]$P:o7!"j$:F*K:!p&gv&7 bU,ivEQ, N>< rW_{oxy`A}YNv'y& xsr kdC*`&$Mpf6ъ,A9Iq +Km@ ,][uIWқ~0 1|L=A$TJ"݄n|hrlW 6FcG 4;=e Mڰ^h`FI Ճa`NQ3 ׮-h>,ᄑҩ9ΐKR~Lr?<{,%Zyܔ`>ǿ~zWH|pk!Lg I4-QQ/,cjZ!|D~1-GG>*_Vv7vd B{ܳߏ/x~ .DHkR7'!0ycӬǏQGZȢZ@j`j,EF) | BP ;׫q ׁ | BP( woLP( BP( `L IENDB`fontypython-0.4.4/fontypythonmodules/help/en/0000755000175000017500000000000011742300067020122 5ustar donndonnfontypython-0.4.4/fontypythonmodules/help/en/README0000644000175000017500000004340711742276521021021 0ustar donndonnSection One : Copyright ======================= The following images are Copyright (C) 2006, 2007, 2008 Donn.C.Ingle fp_1to8.png fp_pog_icons.cr.png Section Two : License ======================= GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. fontypython-0.4.4/fontypythonmodules/help/en/fp_1to8-nq8.png0000644000175000017500000010112011742276521022616 0ustar donndonnPNG  IHDRŀPLTEÿȾΡ}popprtwKBBDBHyt{||}{|tvvlmndfg\_aYZ[UUVNSVQQRLLMJHI@AB<<<79<356001,,,%*.")-&()%$$!!  . |%R { IDATx{LWD[[H'l)]M&8:;Ҝapt[HGpF- \b ;66`p&M7<( tqnD[QUYݐl^~շ}kPn0 2'jk_'E2rì$B/~/8yko5PW@yHހGX$o79aU#ce$ANȑ7~kTK'үϬ!:W]"Z_UpQ;V[|_V-~[NnK뻭5;::{γgvvv~׹suwwxc壏>ҥK @rիWq2eh?44<4d(&2vs*rCxi{p@7fO=:tٛSƲ]dGf}}X>`Q9z ůln>uηp_|m_8?xev*׎>vQ-_d )>_ L^Ck)>V.HAJ^,>NB$] *H\)Q誋Ϲؾ EH9wB.cxK jo)ֽܿwo_ΞŶ1FdAq.ZҞr[ѩV0;{'bDm”]d yMM i?q_[mRܢi7>.->h?x Zɯ(>ȽRԯ6B77V/ل)?>h> ֵk;܎j[֋JWni94IDښ _~#_^؞&>}7z 0eyO5/bW8}m)*LT"}-i9آD{zODy\V7/`m%nmhm=%LE~\k v[[6:&*J*ڛJ= t?W:> /w}'Lic.#[a~Ww["*J)ޛJ{D y~(w) }׮م)y9{Y5^u;Nն62H#>hvU{@uuJמ?}B߿ ._Ewcmnm.@ -*G }_ _˟R`? WA^}yx/I v$}rDe\jAe/Wiޡ^_B}'t_A42Bv! Hu[ᅡxxLJ?e'D;oՕ?RA~?c}Ly3^({5=*HB9DŶ>x:`eoj EOH^׳ԖP<ia{-NxG6?@mR _]V|,nOblGi.`{@LT%68I{TY+c`0#f^\4* 8doQU10tt j_]㧱F67<`k^K- &$-k% ~Agqy%XOR \jآF߾]lu|IbBl"`uXX.^]g_HfmS^N[QgyB<~i p)#9J¸m KM`%Mc; &!zҌS2O,yB^ #MbCnAb]+*N EM{DZƒ bƲIVbQa VnNo;ꥏjG^Vؑ]`3t=*E!I:+m'vʕ+8" D7a-R9W,($5J,-^&$'7>X.sϞ3~bSoaxl?byaVؑQ)~Ï/~Wa[݆bY[c|ѠEķhz,2>%xV %l Ff1ќ=Nہ-h w 7#p\T^ '  ._ʕ+>3X[.)<rJѶܕ i?w/]D)53΢EԷp-=-IF 2Vؑfhb{E :\@R﹫b v5`0߬Yc] Lk/$ږaxk}8 |U:- wLE{m=x~yf`WnS(R +sHr+cѴg.!NDj'2Wz.#]،tdm=%ؑm(Yɯ%m)jvhǾuvMdxN[me`ѵVe,I6h6n\nj{ o.- lkjW4˭?vi-# mPCMIa.m}]5ۮxEڗLLja/+*m=ض6wtdضmm %?_ge {VigXjȾZ(- <` \'|26@W[`)l0,>[Mhthh?06{)Il8@#iOOuH]#n{JtV&Z'ǩc mz޷|ҡ㙠'LƦfhC< !\6$~]R۳khہD0t,SAB ۮ*R[8^2,Xl:&̶,>[آⅥ~"l4L)il(Rl%/HO=f#P=qܶ]t [+35)LmkaVzͺ[ڶ䰵3vc-_(!`;IaRrl+l޶Kb6失J뺪~y#9{Rlj/KV+[u G ad?y%o4V~,n[8ng4a@W"O/[' wܸjHtRIb?Biy JYPSئ k$=(Bi BIl'%Mb?!D{YI%JVYr,ޕ/y a[תOeU l ߮ G^,\܂;lK^n꟞ݯ23_6MwU~5W6\NuRIFmʇ cls/CCpqL><Xf%{0; &ֈul2sNiR/䱽 -a۾:@}馨BEQ^{-n c}x&όgVW^^E6*gR>vZyh4rخjSRNt2?Xm>#kAަm0GbϫÕA3:b{^PB{2lxPO-/-U[kV!c'ON`Kc56 GvbmKbj _؊%uloD!?WT5\>[Mm%0[;[[clMGeʊ߉!vۿqյXlSe敳ضuC>|٤?ulovub_ڶyf3ۅG ɩ~WQZwa@}y6:Jb:;72OJF!'D.#di17u6~y؞Oo'6eyQ8X*cUٲ0Rmj)#<'S{/jh^Ҽ#ֵuωvoQS ;mmPZGY㏬G#uYwZIY5޾lc3\+[#iœ85qG.nF KlF\%_އͺ6!bc*In4ݻ, ;@]l͘s7Z6͆P[ }r n{{ƶ]Xˤ~^xw'+'[̠ν7KQfDz^2ܻhq/[lYٌudwqXϦvyd.E/ݽ?cf˶M>)0m [MPpƭdy>"wq4.=&/M)IzK.wdTrv/(}md )"ajVZT[i.{+i87R^+yl&~)WՄ*|85PۘH%Sl̲>gZZtÐQ[jv$zyFޡmnI9f7[!8`s1몆)KBݿZͰ1"L P4qoݕ}y-M#VV:jUd3la;[ڢ+!z.4$l]v4߶>^}䥍7@Ѣi~RP2$0*il&Ԍ 7%–-b/ O<dž? v?s`-RY4|4:V9e6Cs]G9/,v)St?C%R`dn<uPd?Sfu*=-exkݺGXp[c)`}nDyXwUcEn2؂Sw x&ѲI=IHFURu+Ŗ -vJ mK$Fo&n{JDaU!|Q #^C7yIrt3^"m3 8R.:7݂ZYC/ ZhEx;W -/nuEqA{#@&y8NdEO>crhs{ I9 H%A!um 6ulost:/&S]jkÂvnZ"P{܌wGXA]( Z4;`rCC1u_4&2*ʄvQȸZ^RN ) H%A!KN6qBFl&c$Z7%:'xmtVs4N[\0i܉t:$9Bx \Ua[.C6\Sp2шK]s%oO3ճ#IcRRBy36ȚaU&c ,5E :K!lΕY$T"Žzp=#-rBu ? CV#t |Nȁ]+` \8Ӷ~zhp8q!:Wܠо.PQg3cc3f' Be)%P)tM-R=iIq8u-9!ޯEr>qz( Ѹ*aVV$mw2^؆@Ga\ʼn ג l os󌿊oz+d.Qg\qXG0qc)%j۔ ?c|Q6Gm4I-Ԯke"eY#И.t+m]<z 54m4I{yuA;D|M9ovɆ5ivHBcPHգ6M6>BUrmkêbluyݘ 럧nS<}Ohx&P"v;}Q$8^h 8g2BC}"~;q"D0"ʖi- {\s²`­,:ʲufV߾1ٌٖM|V8*c;x*/"eS4[.Ώܫ2xPX$1-dZu= ޼v4ɶU-O$׏xU)'n&d3"g;?qQ[l[ Bm VPXD;!9UC׉djY{4ȵ?(fKVz.[ fwF\5VOŗfL kȘQby'(AճmiVi* ӕ6hŮbT1Nػ6+7.1edEߕm\#A)+cm0E/LmR5@3I} :@~śQ"/2}apP[fm4ПL #5>k k4b# 򣙅`*ؑQ[Ί>>kw+U5Sdh h>ۯtZ`KU[p_z'peNp*9 _%^.*x—o*oyٙZ,AZ(a.LdYL,n[V_P4 )_4徖r4H,g~RGvFVAD+P7µc60+U<ֳ44t 1tg&8gSOGe=+T;Wc Vƽe\BTH*Ə#R.Y*&%;>C4`il;Y,)mkh!y}MD"qTute5/noB"YVEWe+h"b0g+7Ъ(&R\soxf ƦҶ2 )%/sɴV4`)iA^ׯ/4ϯܢ@`gEr*09ǧʀl0z`JnT9OA\K܍ [b1vei }m"_B{=W3,iIKvLK9lKY14;Gzn!S\OB,NQ~fC)eѕ;)]"[R$MQwxJrؤf6ˀj}R6\%q.1/,79ZK[;ttܮeO0¸6鬻aA!MQ*8:^iLo;m8 NHu[`B ɎEONNG#zm6 LĮ|N/Ǐr!ls%c}P4mغVc:f{&;C4nE}6^QU7|Qb֝Rl_vWty-+\Fq|-_ū4lSL!~=K+j[}b5ɵRj-5q8lZJHx}u˭3tAY>U" r*)EvUS6y'PxN{j$FX6ӪE$m/gUR\Ğ<O/woFlU{WeeM CEHP`b+m;+tq8 89&%kɸdp{ߧgFWor;d`>pEDh/\wRjL}'tMsl pQߐcj\s/z>~bb[eZI9jI9۔'DE-,N`#N<~\~AxM}dISOMH7>!n[ϫ0EVO4hǖt3il&X36&6ZFRV֥-MJh+H8RkL#)<\<`Eu&mܤo捻94`n`45 <k߱©5 ۈ)x?Z4qrԉIkm#{J7ٗUņB-щT*S jNԴm¤c@҉6 ?d_clvShL#)XV)N޶cU5VIkm C{K~*/}|[eʤ@R9lEcvT?Jsͭ;D i:pM5Rm6I9Mۊh!aRNA \D mGؖl㏔C󮣁@ȕJR¤7׾Vaʂh!q;R̡ґT Va8a6H9IO*cKemc6w#dJFbK=AR?koo!}󊟳&$G839l?$cJr~Ք4%H Q|s__S[O2n2׶+tbbh[̯4p'p! Eu۶nS%X3L<le:RrKoFh{NmKݦj (cHmlc]Wh[N{ L)ukWl '|޶}5Y/p^O67xIO0Xa/;7UM)DG%?o&`Ö$'1C,KCy7 f ۿ<?]&L[JkrJV :+-gтd,]v??<{PۄI9b[o2w7@[9IE*Hۿ/s~cSnq7ʮ_S_?EM" I9S(i`Hjyl7j$LQ"c/4w쮞^=ulc`lWGi03i+xsbrCPPݢG;,yOٿCl6'mvP`\2vö5nK@ fh07kkCõáZx@IS&4 jǼh|ͨ?:xh+AP:zJsc"3Bn`ni06 QA|<~:`{-͒ YxLFp* }9b0D]KK^C6.D"nRݓJ Oʙ?RzqW˱*b1K3Ͱ /$wmu А0'w=Da *U{ByuE0Y77=chҶ}5YmK{ &Ҷ I93+[2&b4gDK:m87 Ex:"Ɩ࡙:VJ6@xLmm#X8~X<LJp#h'WBmuSm"V)), RFᛙa)l*qD!v C䰭3;ꚗe)Sg mq#zD8:XbS7\^>.bށۿ-?&([IxKƓ oH9~ Y2zS0L \ϞS,aR&2Rh\=dÏY7:\O>c?oa0)Gl`Z7%i%5DclwOY?h I'UVaPm-74$cI݆gc*.&Hʩ9$xGtC[imPN{ls&=xG[0ηZc 9^%?sɴcIQ]^ME), ccLjT[quqc3:׾s.m0/tUL8_͵myܪ(ֶj[ H=\QqI9*c+3($ѽTݼ mۗ^rZ5@Xֱ]yFVuP[QanGwZ\7MQ >ꡃViJ$l vvߟz$-Fxdommmԡ/Vi Mo$l c'ONmHv'j29WɔF郄-UMR`kn?'m[;lۗmk^9[yvlss,>JI9Gۂda-#)Ş 'nnO`Ť)ϖQۂdUIVDI9bW)[329 rTnͣȂh(2.S7 )O(j/`9emiylK\(-`ulx&LPǖN[HZ+`M;m()'3l*@R Bl+9{=P҅H ;AL8)Gsmy3'Kw&xD%dYUm_n8+b$qR涭R {*iѤJa]nXEm 'NQד| K0Ċ:Yy.g^Xus6 ;俕[m¤\@%Z 2FLyjU[;_؈6Fl JYn.({B\=&[2R};mȺ:JZlSEl_%vSºR߰b4Yrc MJn%M d\O0u=b-5˽n52sgO oEuUe cMJֶY= mY -eXF]#Ob Sp ;xl"U*~@I~ȓJYzUFR ViPvbmKbMI9G&hnXEznxAu Cf&;hrp)mA#U6-8l Fa/pM\cK @*n VW@9H&[? #¶lIx*$5V0Τ/rU EAxfuoHH;;"aR7_S`bz 8uRK#!AL8)tj=O| akGl 'ͪz4Τ/GI(Sm>Rۿ+-:.uHȕ4gRĶXTҙ ~QcԹvFBMUz*zn՞դm jk<~6,'Mw@tcn_(x[-3΍^d}*#aaKzCۦl$,y5OxW|v,!e&cN}5( .%#i8mJme^'-By[X\D_6p>o}a`E7qgC wKWvJ.W"DxknYp,[! ü >E.E{h9)}=FJgo&DvL%2beҠ-JFq{\њyh spFڨ/oǘެ_>Rᬟ؛~ۅwpV 77D-VkggM!+q 3R,5VoUҶrϴU 2zyPMKO$miYҠ4Nc%mΓ0 '(EDI]qWfzB&#fdd[Z˪@4G52+.Fhdy O5cHf1g#l((%0o }12;l2XJJF,Ŗ $dsl[V*woG%f%.ձe SJT7WD.>ODdC|\Dr\y'ĵmg_ ?9RfGTT<5^4/bKcr{\o% [t۩-"u\PIVm|" 5zD{D|v%v@hNHfUT<>wmV6XU eNIj%C J-"RL)aKp VxIvQMe=rhq:V;aw+67p\'F/e4'!DrԵmuK)߰iҠGjnwb . )B5$*cCt:|HƪM.XH8vp$2{M5AsGKۜF$I [{74kO ۰OMFyQ,q~N[3F-l$` LN9^UM$; &c$DJ [g0N3SV|#15iN IDATS XN`@-bPH4 'xN$ *`[gRغcV԰ȯYQ8EAQqv(4HWMP4WH%v-)lݩT(.>:DA=y8)cWfezS!9p}Af_?Ff/&g~$Fh7)l ֋ІԱ% '4, lcQf2ѵ]-3=̾#}mbA$)lTdԢ4+ylIғx&#l 3Duɭ,C.JceDo&D}ơmeTV|S\Xi7p^eAw^R6*Z0EX/R;C+w =ҹVΏQ$H#}'["iyd$lb5T8YmQƶVJ):QrHKz*:=:2X9"9"T.v: 5cg|F+'ś["iyd$HC6l37ƉEDx K?n(7 F}U%]A~C(M\ NR O!-N]uq;JQ84~"e]:F.nuG,^FH47ίO[5m8KfHYZ[c4+[9][,nX;GgNXmiTŋXIvg@7iG&몭\2Q̉{opv`ty}¯A&Ϟ,gbk|H$'o/ED2='ቜm'ʼnx-Ύ.fՑJ!A !DF&`- }&onrpn1$t9(( KN) 3vWh$Lu3ʸLfR~xRq"#-^%F1'`$Gf\!7fq6hO7l<VΪӹ JshGNc9<"5,-]>sBgӁA5v]#t 松覱atiIѧ67daRE Wʩ% F쫯L^͸q7 d$Ld [#uбE{3KFB{m;B#aʙl0Y¶cs&,F^N[ >H xcK|mi˕q=Yljo$,`H-SlU6$yLmÎ'I 9q 9 RUVe#XVє>u]?ԩ`h]݆댛[^شXN8:دfH~F¤L/ l36NߏֵeӛƿڗEN?1a[X=%G:b[rS uݗ4އ &g$H2GS;wÏfS&k7 ?|w&|a-i kLl3L7Id~#1;G;cnm.;лpE朰شXΝr?ޓ)elx>]_Fjb$`2ϵ:BY>؞͙hm=оr#5ۖZ<(8o՘ ޅk<{c۞3ȶ= VH-ضLRm%$ȥ@R'7J?\nd}9YXƒx%"h! ~ʩ9S|)yY ,Nuן89Q=)y(ؽG+%ᕞ[J ZSLijlۂmS[Wwa[Y-$?; -`[9Ķ ZH[m-+m= ]ym6R o 2TeiAԐm^@JCE9-m'b+)κ@QCeUA2_ l@zGƓ`KQTUuA2vqS ƱtaNU[x"UY|AG Z|umܧ;R%?; [~HLQNjiLFj[nؾ2/@!9_3laXOcwx)tSTĖ[*M$cQ6k-9$}٨߬PO$urnS5XZaK}rٹfi[V fc~L%l ǵ12?nI0XM{bϳUHjmd*`+ |㔷*̞к?%c!㯷,`9oOmDJ9)@q+Y)h+gтd,SQ{[|oxcKro'Afmj)G7hݸ[݋=TE۸IЁ=ow߶.t{o[_ggmJBo?:&~}b˰ʒ]ʨt5}:=}_Ey`ۺ&n,c}( F-a/S fYA \W}KIab0$E{2(.%˝In_;]4 ZрIZ<ݯt%}l|gn>f{8a[zte[-FmQd)2pb)*zzvpEjlĬ:zLǍ"ga)-)|OKŧ?7NexథFoA{9lkyaZfOY D]?0x!ܨazc64\[;%WlFS|)Z Ͳmcw:(8mJk<> FpZ' %NB aD4!{*잃/n[/ S̠YV'Otq3,1/b>-h`04F SoK1gt,6DN O:a2̄' FR =" -t`{Pn!u+n2o%˿\2/|[˱*b1K3Ͱ /$wmu А0x%Vў/P>-]v!(sވ~"h03~C&g ,b]'w ;/n=cަxa)f |AxFzscPQ:mZ*6"ƖxXA{_`ϼmd;33;u!g:H[Dd|5{NN dblW173RT Bla[gv5/R P*ŴlM[qln`Lpͤ/S0YV-RNb $XxP ԫ+kI W+2f?/D|S 3S1) aN5Hl+o+i,Hƒk݀Dٍ'E65imPN3ls ?Bmh>iK.kk-ޣxA2 Z`g4PgJe' g'䒑?A366N+.ЗW׼ݞNem'm(U> Қ您"r>ꎼeR av#-&jc[ ,SRVYudqUHnGae9y=S-DۋzŴy^; EQOf9RKmKAl0Esoߤ;on d|* 1-*=?@B=|ckr*Mqtۂmґ//SԽACimBM6̰IO\QWR \<2/E1J,`[7PQ?#}C磩sHf?籀m~bOoq^"keٻM?z4}ӏ1$ lX6?0}&zUP@}w>Ss==S)45d9trb>MÃCgZBob^)>LŹGo籀mEӄu=FJ.ܥ^S5y,`<e?F^fskTR;YQ;.&كd-`3lG<#vĩTIgSvm}U9lgWvݻPȕ@ 0=34I *a3lG~GSmBɮ-`"'WN_rLWDF6\:}LQ\3>zdeF+lhTsَ8qA|wd݇$#"l.ƶ_v*i[HcK},W{Jejmm8]Ƕ? i$52-{P2N_tZP|yZejm=[P݀aPS}czG3,ڳ ט5l_%d%U3qoUR]'Yca@5lerqF#-9#(`LG kv1<$^[eiV7w0ii%(kY l/&#/cl0jb*298ÖO}~Saؚm˅nr~.3v8P:eZ@aGiKE^'^(I<nxӇaQ/)L-+X}Hh}-/Y~{(2S}Hf?1-lJ{u" vs` :eAYf5d-=Io#Tɨ ~N~ IIZl3H̍oAF#S܂81?X-*eEزvUvzd \ RAv"g!&bQ<}%ճt;Iˉ΋bb^Q%k*,:S05 Npe;:FY:nGwѝj[K]Y9[=w8aa\-d7o/Ev[_3T;/KbE / Qh `D")?GjY!ձn6`;ՙie]U S6s'l+{b-/[9x܂DC 8Y߬;?+[\e&|ZM;biZвiHѧl foTuˬ>-lV'Ƒ`Iwt&\ HP }uW^) CaY;4# X\#v.mMb\2!sȝYUԓVm\_nf7L z0VԤZ/O^IKR.s?9vA8 !5B߷|iGubrN;(NrETD׀Y٥Ԣ>ΰbz%ǁ`.auu{#HYqd*[}9EyZTT4%]l%YV,)cne8b¢R`&~wv6D~rMhE ]T<+"sy=\nZ?i5*j9FdiZ_?.QZueoҗ apR4Ti0i넜Hۍ#Ǣ%2+:n3kߜ?b\W{u"*яX@?Rsfm1',-%%փuOd5wXSd K-[ =Ŝ )9d߾qc'ZIH=$a nxntݳumcvzf? 3F UqN7@έh(6Bf z-T>jm&b( ތZ`Y+?gQ&zM[gb#gҢg 8=bV!< bM vO4\Ic0=ձݪwl+' PS u0qE&3Zm3G$LP狟OJ8kDc`Th*%B%,| 8}Y9mZe' 6>֞8qѶ~"uj%T_[gˑ 9ץ[aM A `BP];`23mڵ9b'#W)|DnB]Nj4fLjSeHB&ڭT0>ia+I FyS޵CNyn} Zul@qB'Ql:dQJGl[IN &VXg*\j~`v=wXj7U t5VdF`LG2T6?[ajRs lSìd -n{Ӏ]&Mv,ֵei9ӧmk6v߿J'Ql:dQJG_̆Ԧm1nѽ2|\Vl"m2Ȯ-vhvwLAF:(`^CarM^x0sPX&ckrZ޽)ybElUnx>d_ ߼o;ַ2ֲ]7C;tŦmd«TH4vX~ڝڶnVڿy4 F6Q(z~`5J{ sHF~mQISIDAT(:[Kbh}M 6m8*+}V;D]^ zPT#l s]E:۶1*率K Ҝ>0X[qd]n-H51a\fb*C]VܬQ}blvo: `$T yV#}p.b[*_QلIjq~X?ޛh˺Ưw|tI9d620ETSbh> j} Abel:@\q9-ݬpnFiKs(J,bmƪᐢ,h,O?یV8l ANӺ6JO%m5`*DW lR;xMY<"-,K._mLxhh~%tΑU=)$~6 0"JfOhZeI iC=Vs)z\X 9\gΐߺDi\ffKlfRV>zD\Qæ8#^b#FCUg,AMMԭ0rk) Ga.jiC~`'7I2;$6ڏvhh7ۮ!P |VY/ߘ5Y+st^ 4(zI/]NbV*a{+b΂dTAׅrbMHFZHFXb/=#MM3|ChS ؚdSk$̦aG䚏qTg:Y ziw@wVj 0A+Ha}t%E^&Ua{VuKIlm5a1Jؖd4 :lzu/E3펑f+YZ}2BiL뽟rk1{Fիyj?,+ôm+D;?+ j$Z9 1IƵz6,rc S-^mk vr !h(pDT4-jѶTϪ/fڋtWi{`i}r7Y.Ѱ*Ee?s-r|T/h T3 SH9^Q "@0Ǘ*IڞaYmAY9Sj~X4|ei< 1RGi#&B0D4lIZ QƘk%F['Q<ϣu0IBuGSGi쵛\5j=ɛjyZW̐ Y^ ǜJNEf  m;eeIn:SEn+JƱ }[[FVOpƦB uFۖA-q_#mڮ]gNwrj pqFƵMi ("H7h"CDK]3JB(sAfO@RU(?aufוPN ,^9a= &B0Ǘ*5Z[7جebl< YN?.j,$Pl'1,LeHWі&вJgBٴUҒi*YTX!j0DEk;1 V>p\ ד^P -m?#EEr i&EVEk+3 KqP- 4-AbqmI VTPٴU"iYTXh `%?,] Me mb\cb5jD$m5-*eU\44N k5*- uܠh[C8G/smMc! 4mYTXOh~LEk g̝@[[hF+r{ן0X,o>Т௙oݏ sH[5)-K&}}BEh%ZL *ê95]ѡIw""X_IX[[_x{IP"i+F]pXڱxP\dNi謳i8] NzeVCLBG9ƿVJ'SMnCG2y#&I["+D!gQ)cU4jA`Rq3*i+͋x:aV8~w$ЫY#F}@zGZeHgwuFLnt'`H(:iK z>IJyVRl&(qE /bvNO|-Az|(2u)ΧVF7?NY:ٞ;hG0u4R k^<7 @I8i+FED[=E%)-*9x‹֧_AZ:>mӬUumQRq,ں*S$Pkm]z$3pWyIJ4uJ=*e*^E"=.)-B>9D[ĝ޹sIw mԮyDۆG *]G=:c-|$?Ᏹz$"[$N`e=Si(#Q-]9pH24J jt"!( /rź+Wp[<+sj9 nJ?l+hU-F6=|HD@GI۩z⪝gWz+::O.~WEiuhڊoO ELִKJ袐O'H6ܼ\xmޱ @Oh}m=2`G4zjA[!x&wh~Uz~Owlti7t[|aAw-2j]4mlAxYTHWZ}۵-+-ԡ|rZgEO΁:N@t_OK^EKkg\+=k* Q!Km"P\,iϔ?A~DzՆ, ?yýQ#D C*1^EalBkk ?n^@mUw᪩W&k2ȓ~jR^E:98kG.\3O۵L#0v΀/U5Vr50QeV1agՅxI3u 5BD)7,r-`EIF[CꡚyrlQ(.޳f7B.G.(KR}fTiVUcR5wk+)mlQ(.6 ;{rH[%%)WsψV4 ,ڐlQ(. ;11Пrd'sτU0.My4J(g>c:N2.ȋ/>"{r*p]?g%h7nEoTEf=9$3?z<=@NșYͬ^fxkB稱]PղE8yF&'yEJ[4{=羸x\ۋ~,i77w\]?k6՛_&Q+z/s4lƫj__Sm*sa{.䘼@&N ŽOB_Xicnr:_7 ^p)~R*;uYnFol|ӚJ':EpI0TDf@: Nqt@م"c^G Aaj;zXEGR4{@RQF/WڪŎmlJg뗌[ڹ!hc*+JT9$ “SaC!Xyrm s܆{l,FuTu+j5*A?ү ~SѱF=k.): b⢈͆l_yjVh @0h[ 8&O y):fx|QKC.l $`kVTb~y]:q0<|0B^6mf@kK66l&Cw7p詃W~VT /Z`@~5JLN^J4) hG#Ea"7ދ6ȚECp]zO԰.5ܠ(eIxp-lb(gHbH3!b ݓH18at{$FAk BڊєgDt帴U 459rojlHiFT / 7#bj|}'eiR./,dv͛16&"i&juy]ޏwuf+ׯmOGVRo):!Rs8%Ln$ Z/{^ ㎑G\ QJ\L˙ok#&!^f;x"jiVe@^`I6ȏkҠ1 IIR}Ģ[wE~VCײD#.=3vdgZz;ӒWwg4mXpmRKH]l4$ʑMo9Kq!ƾa~-6Kq0[Ʉ'5>j?"L[0|(-'o>X TV/Io9:<SmKTqYR+5:&߇\ucEy?3~9s!{17៞ 騜i.{o㻹wej2Cn&.䚏mjJjUgvSW%~ cPW[ēI:b[`I^tu`4x..l䧻SAk[ ߌ֍Ք;m' VD6<):*gڪ=RSS2[jeH LUNF6"/fӐ೑WlI[?ڢ/h͟dH+pz޼yx"'L[Uu>o2&NOɀ-u/#̥|;vS&sW\O$q;#gj4OOɀsa,yNF"ۋLO:""yEm~a&Oikpn0I۝. L1ڋ~A\q( m Y*81P$j-nxV.(J:9e{x̓kr.)"b 5)W3Q"}ۉ0l<4m=!{emV!Iېj HQR>ię.m9Fm( [b=[[X mժTZZ>-"r'@%n@ݝov7du2;3g&39sM4v?HAn$X'yWx}j36DZgԜy״|N/!2h](d)~\/%A$.hf'UE5**( [:.(J^-̾ ~_vCt7D%^\İ% Q%xQ@,544Ire*[r:j_@UUN?BUU*QoEnDɃ$y< yx<^ǃ$9 s+ZI"Hq(ʢ;!j/ ׫瑐 N oxQUQ iI6D4MDET>(UQQ^1.-DƝ(N "Ođjwf4lÔ34;w] M5}t-v|ϗD!f*8bQ9y'\It1b"? ~RϕD#6񆡥ݓdS V$]n64fnl f;h'  g[gI"1hxEP.A"]4ݧc ZS)AMGY<^^׋zE)!qf͚ŷVo_*!+|r_[^BxcwZ^BK;#|}Oꫯf֬Yֹu֑j^UdtҥNz~{Pcy5aVf?!_#6۶mQF FSSGaȐ!;v-[p饗@ZZYYY|G~F,| \[e6oLMM EEE9ϗw 7#eN({KzC{ uy\W^D)1?yףټy31|ҥK6l`<㔔pSYYܹs~ù[9r$7pՔp뭷2i$Zӧs駟K/eȑTUU%읣P9£:ʻ(FDC{{QC^ݻ 6p)~?I&0n8 5jcǎ`ƌw^SQQ;û?y6nܘm%^z#^ sJK;cD5+rWŐ̓>c=-:W]] @YYu0ydbnƙtă. |r<@o9qzzHX)Vu_uQYYի9sf\4d+9~Uo7ќ<o >{U0jDjj*<K,:^ZZJVVoul޽TVV2eʔ?Dž ۷Uehի?b~AӢ WpiuYKQ`W|$??#G0,/^ŋ={6{/cǎeʔ)p o*̙3<СC>f@ZhѢH'^}55'kIMKӝ'J)0fImtv,U;Hyx$DɃ(JѶXw?r0_СCL>4@RF⢋.b锔0~x&OLmm-Ν[nͤ xhUbȑC2UrPYs\}1]V]W7Ν 7;nL$ ]=1kI{0l)gVga݅: $IH^/ ^C9';@#!īƔθ5E~Hp:0 9GUGTN23Nfr08è_azϠlt#'yĔx&!qy[ Go kA"UUVE2hNzd|+VQE0uWA @6٪jql]ETE"QhA;4vE9IvNbm.(f c}WY'9t)TRn-Y**(f/d3:nXw+[%>l"$c S­6#F7wZugOs+[Ktլȡo)O`CÛ|~n.'^44EAkd$1D,.gD#LaaV;WYYɨѣ/D|C)>*++Μ~,~1x $έ/OQUM(֭[ B3=z`РAc[Ml_O' I|7En$I)wS$HM$nc55@HӘ;GÈz>a 0-֛qњH!Dk7q_FEEEHəFL> 7} B1E0({MRDNuϤ`$l$'&LV,8@%c<|Iď+F; )D /vp{L&ȄKblnEZF#jhON?bz ei#fJ|I5x8yQHI~[fSIPQ5"H">D%^MMjl5Ml$Q A ih6 b\4HIhS;5Ʌ%l/bas7 JytEIbH~+v(j'bHΖacA-`wC = y߂&_o'e$J"~ݜlo}nfuhB 8 X^ 5&J.o^rCՋ.U1 9 ]5tuo-w$a ^}H>x[ՇnV ZRw ;~wq:nTI~.7s:ѢR@Lщ} 7u5'% H.ҲQ;iDSU3]A#’y\@6,pT@Joxo<~#' UoJ}Gq,YB}}}o'O n̘1;AZ#Xl\sMsQ7grTS"=^NOI@4IIe7|f2 @OJ)JF dXqgщR<]S{@Js'̝̕k>Z,X@yy9EEEvmEСC̞=tѣ9}kݛXصk(rWPVVFYY7|3^"2dƌn܉-ԇɍ7éoI:i p޸>ӐjXrS7Ϯ~K|jj;\L8;ff̘… yǣ;m۶1p@$IbРAcC YdIs%%%uzxU{Y!;vSCWpG F 獔\Hms;oyw.<̧kxꪫx饗x']SSWWʿ{nΝ$m۶ 0rHC~~>&Lp޽{#"?;D;a:peL+BԫV}PdCh:Mћu τ4dշ ,` >'N믿:?c VXAKK zb̙\uU\Cr1~ikn^k_gԩwC (-F vAPzmU/7]8 vtDlG(j4DgWz]{UU\uvoh;sEP BW (uEײ:a 6jz˿DLs~6A'I7ӊ!28!U-۝vx5`v5 ScUCKځMkgjvH vx Sp.L0v 0cP_շn-BzCN/su2 Ed4!dw#k4ǰhgU5Uӗ(mjRزS=DZ0DDž>ZVU(8j7bςV͑fuh͂T#j|Z`zvMDu,ZmڳHr',YSوRrBx#GSۯ YJLH%Ua +#D2RYF 7N"2޽\:mȩۏlxjW`Z4s4­]ah)әbvSErU4⒁ 0u Յ 8\UcV+{#Ǿ\17sb8#>2e\~"zei$HM$"I|7En6פIEfr4($KBlݱ|8{-L 4x<4 ) 0~% (D$ԁqy ܳӧni"%t͒& is?>7Lƍ>Ņ !~+Qb =GQ\DO)է M̨1su+#8)ϞQk77ccjMv<DzwfkȘDaTEOp2{.дDji 䀐B* P ESj5K./ #=-$~mz~E>_{5ixJ!H_<99I'B #?=ʦ>vo1rG]𴯃ǽ%Ix;$ܵęcQOۧ*=W_}-Qߢ[!&wa`Y2Z6 JSu"M iE3MeUf X#f`ԮJ*t ׸9d,Bέ{BB8XcB9,[wb%~J뮘ypUW}D^c̙'׏4>޾+V,eL V^PMv b#ONBEÇc;|C~ʬ?>|7&2g>O#kiil{X-F21W4]86Fh"xw]3emiݛx?~8---cDEF^UUOII MMMlڴ!CP\\,l޼@ رcijj5)طo >t'%%g$DO9K7 7T l-K9Ys%^0CV} --tŀz#Gxbnvy SOQPP… _Jmm-'NdҤI|[/ku]{50d~aF_7o>(7x#{oB-*ud;jBI=pt:5q DKt*2 ;)Znģd.[IDATlذjVX}gVab͚5lݺݻw3o<-ZDCC{aϞ=꫼ˮk~aKuu5[nTTTOX+OZ[o$ݢYΜqwd&;RI3k£1BЎN'ٳ Nߟ@ uXz5Hj=nRk_*[5Mw}eCۗsZku5gOopzIsæKffoHG"6̹s _ܙo wu999(2%&Njrq&N3qDk!ǏĂ ]rssUSRSixݼ4KչZExr|g /GA獽ZG`.\HUU/BEKHϞ=ٱc+s?77A~FKK+E[ 0шJ|^a!uY.>BgLz%HkG8>#/  B\r%ֱ7xYۼvƌ466*f رcZYE ѣG;*UfSٳ˖ ;NU'<*Dk0?1`}>7x#ٻw/[ne۶mٳk/^)..fڴiSNYyV\̙3)--'''-[΋/Ez!֮]KIIYD%>/;wc Кtgxg>j?R!K'/8ʐ +Kv]vO~z-?3l0-[o~FҝE<#C Ķmx ?f….gʕ+ٷo(2tP6+V`ӦM[S˒FBЫF/!F'==k"D 㰴VYh_JI QU*1'| ~O#jI^nGz 4AcїmhR Hvs+ޅb> =z"fϞ̈́ 4h&L;ΧhbvҌ<}7BU6*#'- c"nqk L/֩h 0roߎ,JU};HX2qgqxnM657saϡ WD2F}RӈN>V곰f/<Q{3Xby'^9 0S<(ذ?GQW1äZu愓*á3 6h{1l^}7IthbxӴC>E؋  !? 2R4ꚡ,lP:A`KnﺋG]/wFBQTW2%V+ozLK\wuy$Y>޾/C_ qe_V6L濟}tLwi?[T-q_ج>r"OmJKeѝ}$ ʊ¶;Y|~מD;wOQix I9)y٣W^}W̾9"Vt$+*ٳo?cדCB ѻW/&OAr6O5i)EvS$HMimIENDB`fontypython-0.4.4/fontypythonmodules/help/en/help.html0000644000175000017500000004427711742276521021765 0ustar donndonn
Updated September 2009

FontyPython is a font viewer and manager for Gnu/Linux. Use it to view, gather and manage fonts. You can install and uninstall fonts to your home fonts folder for temporary use in other apps.

The layout | The Menus | Shortcuts | Tips | Localization | Bugs | Licence

Ye olde Basic Idea

You visually gather fonts into "Pogs". You then install the Pog, and all its fonts will be available to other apps. When you finish your work, uninstall the Pog.

I just tumbled onto the word "Pog", it comes from the middle of "typography". It means "collection" or "group" or "bunch" or "box" or "case" or "stack" or "pile" — you get the picture.

Your fonts never move from where they live, neither are copies made; only links to the original files are used to install the fonts into your home .fonts directory.

For example, you might have a Pog called "Zoo Logo" into which you place all the fonts needed to design a logo for a Zoo. After that, when you need to work with them, you simply install the "Zoo Logo" Pog and start your design app. All those fonts will now appear in Inkscape, the Gimp and other apps. Do your work as normal, and forget about fonts. When you are done designing, you uninstall "Zoo Logo" and all those fonts go away. (The links to the original files are removed from your home .fonts directory, effectively uninstalling each font.)

Fonty is also great for just looking at fonts, wherever they are on your computer, without having to install them first. She also has a command line, allowing very quick use. You can install/uninstall Pogs without having to start the entire gui, which is neat.

Home dot fonts

In your home directory there is a hidden directory named ".fonts". The dot makes it hidden. In there you will find font files of various kinds. Whatever is listed in that directory is a font that your system can use. It's not as simple as this because on GNU/Linux there are other places where fonts are also installed, but it's a handy place to work. You should never need to go into this directory so there's no reason to worry about it.

Latest News

  1. (Sept 2009) You can now zip Pog(s). This puts all those fonts into a zip file for convenient distribution.
  2. (June 2009) There is an "Include sub-folders" check box now. See also the command-line option "-A"
  3. (June 2009) New keyboard shortcuts. Ctrl+LeftArrow and Ctrl+RightArrow will step through your fonts.
  4. (June 2009) Multiple Pog selection. Remove, Install or Uninstall many Pogs at once.

Layout

The interface works from left to right. You select a Source on the far left, then you select fonts from the middle section and finally you choose a Target "Pog" where you want to store them.

Source of fonts.

You can choose a folder or another Pog as the Source, simply choose the appropriate tab.
It's quite nice to get fonts out of another Pog sometimes (it's quicker than trying to find them on a drive somewhere), so Pogs can be Sources too — don't let this confuse you!
Keep your eyes on the label at 2 to see what the current selected Source is.

Sub-Folders: Above the Folders is a checkbox to include fonts in sub-folders under your chosen folder. You can deal with many fonts at once in this way — but beware the trade-off of speed and stability.

Information area.

This section informs you about what is selected in the Source and Target portions of the interface. Along with the status bar, it keeps you informed about what you can and cannot do at any time.

The font view.

The fonts in the folder or Pog you chose on the left will show here.

Please note: An error marker may appear instead of the expected font glyphs. These fonts either cannot be opened (for whatever reason) or Fonty cannot draw them. You can still select these 'bad' fonts, place them into Pogs and then install them. The reason for this is that Fonty Python is not all that good at drawing fonts (it's a long story) but other apps like Inkscape and The Gimp work just fine. So, if you know you need a font and Fonty says it's bad, just ignore the error message and select it like any other font.

Tip: You can change the size of the fonts with Ctrl + mouse wheel (up/down).

This section has various behaviours, depending on what you have selected:
  1. You have selected a Source (Pog or Folder) and a Target Pog

    This will let you tick fonts and then store them in the Target Pog.

    Areas of interest
    1. Character Map Button If you have gucharmap or kfontview installed, this button will show and when clicked will open one of those two apps to let you view the full character-set of the font. You can choose which character map viewer to use in the Settings.

    2. Tick Area Clicking anywhere on a font will either tick or cross it.

      A tick means the font can be placed into a Target Pog — i.e. the one chosen in the right-hand panel.

      A cross means the font will be removed from the Source Pog (The one you are viewing at the moment) — i.e. the Pog currently chosen on the left-panel.

    3. Font Info Here you will find the family and style and filename. When you use the filter to search, this is the text that is used.

  2. You have selected a Source Folder (or a Pog) only

    This will not let you tick anything, you can only look. There is no visual difference.


  3. You have selected a Source Pog only

    This will let you cross-out fonts that you want to remove from the Pog you are looking at now.


  4. Inactive fonts

    This greyed-out font indicates that it's already in the Target Pog, so you can't select it.

Target Pogs.

These icons indicate which are currently installed and which are not.
  • You cannot use an installed Pog as a Target.
  • You choose a Target Pog by clicking one (on the right).
  • By holding Ctrl you can select many Pogs at once.

The filter.

This is the "filter". You can type partial words here and the list of fonts will change to reflect the search. For example, if you only want the italic fonts, then type

italic
(And press ENTER)
When you want all the fonts again, clear the box and press ENTER.

Tip: If you want to search for bold or italic (i.e fonts with either term) then type in

bold | italic
That line (|) is the key near ENTER, above the backslash (\) character on a US-English keyboard. It means "OR" so: "bold OR italic" is what you are saying to the filter.

NOTE: There's a bug I can't find — If you are not seeing any fonts, be sure to clear your filter and press enter; you may have to do it twice.

The action button.

This is the main action button. It will change its functionality as you select various combinations. The text of the button ought to give a clear indication of what it will do. Read it in conjunction with the Info area and the status bar.

Navigation.

These controls allow you to navigate between "pages" of fonts. You can also choose any page from the pull-down. Please go to Tools->Settings (or hit Ctrl+S — for English locales) where you can change the number of fonts in a page. I use the paged approach to reduce the memory demands of the app.

Pog actions.

The buttons in this section all act upon the currently selected Target Pog(s). You can variously delete, install, uninstall and zip the selected Pog(s). You can also create new Pogs from here.

The "Clear Selection" button will clear all the Pogs you have selected.

Go to top

Menu items

  1. Tools menu
    1. Settings: Access the settings for the font view. Shortcuts: Ctrl+S or middle-click on the font view.
    2. Check Fonts: Choose a folder and scan for bad fonts which are then noted to prevent crashing Fonty in the future. Use this if your head is tired of the wall/desktop.
    3. Purge Pog: The Pog you are currently looking at may have yellow items which indicate fonts that are not there anymore. Use purge to remove them. A Pog contains a list of fonts paths. If a font is moved on the disk, say it's renamed or deleted, then the path in the Pog will point to a font that is not there anymore.
    4. Exit: Guess :)
  2. Selection menu
    1. Select ALL the source fonts: While only a few fonts are shown in a page at a time, there may be thousands in the selected source. This will select all those fonts in one go.
    2. Clear ENTIRE selection: Will clear any selection.

Go to top

Shortcut keys

  1. If shortcut keys don't work, click in the filter text box. This seems to kick them back to life. Don't ask me what's going on....
  2. Esc key will close your app (and help etc.) quickly.
  3. Ctrl+LeftArrow and Ctrl+RightArrow will step through fonts like the Next and Previous buttons do.
  4. Middle-click (the wheel-button) in the font view (position 3 above) will open the Settings screen (like Ctrl+S does)
  5. Ctrl + Mouse wheel up/down will increase/decrease the size of your font previews quickly.

Go to top

Handy tips

  1. Try to use Fonty from the command-line (from a console). It's easy, simply type:
    fontypython --help
  2. Pog files are merely text files. They are very, very simple and this was intentional. Here are some things you can do with them:
    • Open and edit them in any text editor.
    • Append fonts to the end of them, just include the entire path and the font name.Note for Type1 fonts:Only include the PFA/B file types, not the various metric files that follow them.
    • If your paths change (say you renamed your folders, or re-installed your O/S) then you can use search/replace to update all the paths to all the fonts in your Pogs. You could do this from the command-line using GNU tools, but any text editor will help you here too.
    • You can backup your Pogs by simply copying them to another folder.
    • One last trick, for those proficient with the Gnu tools, you can do things like this:
      find /home/you/somepath/TTFS/F -iname "Fu*" >> Futura.Pog

Go to top

Localization tips

  1. If localization is not working it could be that there is no translation for your language yet, it can also be a problem with missing packages in your distro.
    This is what I installed on my system (Kubuntu 7.10 as of December 2007) while I was developing:
    • language-support-fr
    • language-support-en
    • language-pack-gnome-fr This one is very important, it has many stock translations for GTK.
    (Replace the last two letters with your own language code.)
  2. ENCODING TIP:
    Check your LANG variable. Open a console and type:
    echo $LANG

    If it reports "C" or "POSIX" or it's blank then you will be running under ANSI (ASCII) encoding only. This means that unusually named fonts and Pogs will likely be invisible to you, function badly, or cause errors. I am putting out fires as fast as I can, but these bugs are hard to find.
    To see what other encodings you could be using, type:
    locale -a

    You should see a list of locales. If you see one ending in utf8 that looks like it fits your language, then change your system to use it. You should do this via your system-settings gui, but you can do it temporarily like this:
    LANG=xx_YY.encoding
    Where xx_YY and encoding are replaced by you. After that, start Fonty again.
  3. If you want to help translate, please contact us via the fontypython list: fontypython@googlegroups.com

Go to top

Fonty bugs

  1. Fatal crashes and Dangerous Fonts: Some fonts stick in Fonty's throat and crash her. If you wait a moment, a window should appear and tell you which font is to blame. You should move that font entirely away from where it is. Start Fonty again to resume. If you are stuck, go into your .fontypython folder and open the file named 'lastFontBeforeSegfault', that will be the culprit!
  2. Check Fonts: I've added a new tool to the Tools menu that will let you choose a folder (and it will go through all the sub-folders too) of fonts for checking. Any fonts that are likely to kill Fonty will be recorded in your ~/.fontypython folder in a file named 'segfonts'. After you do this, you can visit those folders in Fonty and it will display those fonts in yellow. If you find that Fonty is crashing too often, then use this tool!
    There is also a command line to the same tool (fontypython -c /some/folder). Please check the command-line help.
  3. If you get errors post a report on https://savannah.nongnu.org/bugs/?group=fontypython. Please run Fonty from the command line so that you can copy the error displayed (if any).
  4. When Fonty starts-up it checks your Pog files (in your home folder under .fontypython). If there are any Pogs that cannot be read for whatever reason, then they are renamed to .badpog. You should go in there and do some sleuthing.
  5. As Fonty reads font files here and there, it keeps a list of the fonts it could not open. It's in the .fontypython folder. Open "badfiles" in a text editor if you want to see them.

Go to top

Licence

Fonty Python is Copyright (C) 2006, 2007, 2008, 2009 Donn.C.Ingle.

This file is part of Fonty Python.
Fonty Python 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.

Fonty Python 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 Fonty Python. If not, see http://www.gnu.org/licenses/

Go to top

fontypython-0.4.4/fontypythonmodules/help/README0000644000175000017500000000065011742276530020410 0ustar donndonnTo localize your help file, create a directory here using the two letter code, for example France would be 'fr' (It should be the same as the code used in the locale folder.) Then copy the files (and the README files) from en into there. Then edit the files as you want to. Original SVG dev-files will be available on request. Fonty should now pick your language up and use your help file. Send us what you have done! :) /d fontypython-0.4.4/fontypythonmodules/locale/0000755000175000017500000000000011742300067020027 5ustar donndonnfontypython-0.4.4/fontypythonmodules/locale/de/0000755000175000017500000000000011742300067020417 5ustar donndonnfontypython-0.4.4/fontypythonmodules/locale/de/LC_MESSAGES/0000755000175000017500000000000011742300067022204 5ustar donndonnfontypython-0.4.4/fontypythonmodules/locale/de/LC_MESSAGES/all.mo0000644000175000017500000004161611742276536023336 0ustar donndonnl $ Y R [ w    2  .4 :E bm.~:" ? `f x*/B Taq +# 4?"0./+^' >#4Xae/V;v C'=EW^h0!n" k y 1J'2Bu $  - N c q 5!sw& 011b 3H4IM+A BU  !!!!-"G?"8" "E"#/#K#]#o#"w#(#2###:$(U$~$$7$)%i&b&"&''2'L'1h'''' '''('(%(H6(^(-( )I,)v)|)))%))()0'*.X** ****"*+/0+`++ ++<,C,0K,|,A,L,D-DW- -H--# .... ].g.D///09182 U2v22_272/363J3lY3 3G3+4D44 5 5 6 66C6'7F-7%t7N77 888M8h8m8}88"8789 95*9 `98n9/9$99::-o;M;8;$<3<C<8I<_<<V<#O=0s===H=H>Xf>?2?!@4@;F@V@U@/AaAA#A"AAABB+:B7fB2BIB3COC+bCq7#$LTuZ I,wr*Gtj3@B`P_SeRFxa\1fX.4 vJ|:2mb}>=O l-n{!^D/)K&'+[9 gH56 8kc?0zQoyMhNA<Up(ds~WY;"EVC%]i (Also check your file permissions.) Couldn't make the .fonts folder in %s Please check your write permissions and try again. Couldn't make the folder in %s Please check your write permissions and try again. * indicates installed pogs%s already exists.%s has been purged.%s has not been purged.%s is already installed.%s takes two arguments: SOURCE(folder) TARGET(pog)&About&Check fonts&Clear ENTIRE selection&Exit&Help&Purge Pog&Select ALL the source fonts&Selection&Settings Ctrl+S(%s) cannot be found. Try -l to see the names.(%s) skipped. I can't display this name under your locale.(%s) skipped. It's an invalid pog.(Check your filter!)A Pog with no name won't be created, however it was a good try!AboutAbout FontyPythonAre you sure?Bad voodoo error. I give up.Cannot delete the Pog.%sChange settingsCheck for dangerous fonts.Checking fonts, this could take some time.Choose a directory and double click it to startChoose some fontsClear filterClear selectionClear the selection completely.Close the appCopying fonts from %(source)s to %(target)sCould not open (%s).Could not write to the config file.Creates a new, empty PogCreating a new pog: %sDelete PogDo you want to purge %s? Purging means all the fonts in the pog that are not pointing to actual files will be removed from this pog.ErrorFilter:Find those fonts that crash Fonty.FoldersFont cannot be found, you should purge this Pog.Font causes a memory error, it can't be drawn.Font causes a segfault. It cannot be drawn.Font may be bad and it cannot be drawn.Fonty PythonFonty Python - view and manage all kinds of fonts on Gnu/LinuxFonty Python version %sFonty Python, um ... crashed.Fonty Python: bring out your fonts!H&elp F1I am sorry, but Unicode is not supported by this installation of wxPython. Fonty Python relies on Unicode and will simply not work without it. Please fetch and install the Unicode version of python-wxgtk.I can't decode your argument(s). Please check your LANG variable. Also, don't paste text, type it in.I can't find %sI can't find a pog named %sI cannot find "python-imaging" Please install this package. TIP === On my distro I can search for it like this: aptitude search python-imag This returns many results, one of which is: python-imaging I then install it like this: sudo aptitude install python-imaging Make sure it's at least version 1.1.6-1 You can also get the latest version from here: http://www.pythonware.com/products/pil/index.htm I could not find any bad fonts.I have placed %(count)s fonts from %(folder)s into %(pog)s.Include sub-folders.Install PogInstalling (%s)Installs all selected Pogs. Use SHIFT/CTRL+Click on the list above.Jump the lazy dog foxLicenceListing %d pog(s)Looking in %s...NB: If you wanted to use spaces in a pogname or folder then please put "quotes around them." New PogNo config file found, creating it with defaults.No supported fonts found there...Not a single font in this pog could be installed. The original font folder has probably moved or been renamed.Not a single font in this pog could be uninstalled. None of the fonts were in your fonts folder, please check your home .fonts (with a dot in front) folder for broken links. The pog has been marked as "not installed".Nothing to doOh boy...Oh dear,Page length:Please check your arguments, there seem to be too many. (Remember: it's one pound for a five-minute argument, but only eight pounds for a course of ten.) NB: If you wanted to use spaces in a pogname or folder then please put "quotes around them." Please choose a Pog or a Font folder on the left.Please choose a Source.Please restart Fonty Python after you have moved:"%s" to some other place.Please use a number for %sPog cannot be written to. Check your filesystem.%sPog is already installed.Pog is empty.Pog is invalid, please hand-edit it.Pog is not installed.PogsPoint size:Purge font?Put fonts into %sRemove %s, are you sure?Remove all ghost fonts from the selected Pog.Remove fonts from %sRemoving (%s)SORRY: UNICODE MUST BE SUPPORTEDSample text:Select ABSOLUTELY ALL the fonts in the chosen source.Selected fonts are now in %s.Selected fonts have been removed.SettingsSome fonts could not be uninstalled. Please check your home .fonts (with a dot in front) folder for broken links.%sSome fonts did not install. Perhaps the original fonts folder has moved or been renamed. You should purge or hand-edit.Sorry, (%s) does not exist. Try --listSorry, can't find (%s). Try -l to see the names.Sorry, only Gnu/Linux is supported at the moment.Starting in %s:Target PogsThanksThe fonts from %(folder)s are *already* in %(pog)s.The fontypython config file is damaged. Please remove it and start againThe process is complete.The target pog (%s) is currently installed, you can't use it as a target.There are no fonts in here.There are no fonts to see here, move along.There are no pogs available.There is no such item.There was an error writing the pog to disk. Nothing has been doneThere was an error writing the pog to disk. Nothing has been done.There's some problem with the font named below. Please use the Check Fonts tool in Fonty (from the command-line or the Tools menu) to go through this directory and mark all the dangerous fonts. (You could simply move this font elsewhere, but others may remain to cause trouble.) These two are the same Pog.This folder has no fonts in it.This font is in %sThis pog is emptyThis text cannot be drawn. Hey, it happens...Unhandled error: Please move (%s) away from here and report this to us.Unicode problem. Font may be bad and it cannot be drawn.Uninstall PogUninstalls all selected Pogs. Use SHIFT/CTRL+Click on the list above.Viewing (editable Pog) %sViewing (installed Pog) %sViewing Folder %sViewing a folder.WarningWelcome to Fonty Python version %sYou can append fonts to your target Pog.You can remove fonts from the selected Target Pog.You cannot change an installed Pog.You cannot use a folder as the target argument. Try --helpYour Source and Target are the same Pog.Your active Target is %sYour pogs are the same! Try -eProject-Id-Version: PACKAGE VERSION Report-Msgid-Bugs-To: POT-Creation-Date: 2009-10-13 08:20+0200 PO-Revision-Date: 2009-09-28 10:11+0200 Last-Translator: Donn Language-Team: LANGUAGE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (Auch die Nutzerberechtigungen prüfen.) Konnte den Ordner .fonts in %s nicht erstellen Bitte die Berechtigung prüfen und noch einmal versuchen. Konnte den Ordner in %s nicht erstellen Bitte die Berechtigung prüfen und noch einmal versuchen. (* kennzeichnet installiert Pogs)%s existiert bereits.%s wurde gelöscht.%s wurde nicht gelöscht.%s ist bereits installiert.%s nimmt zwei Argumente: QUELLE(Ordner) ZIEL(Pog)Ü&berÜber&prüfe Schriften&GESAMTE Auswahl aufheben&Verlassen&Hilfe&Bereinige Pog&ALLE Schriften im Ordner/Pog auswählen&Auswahl&Optionen Ctrl+O"%s" nicht gefunden. Versuchen Sie -l zum Anzeigen aller Namen der Pogs."%s" wurde übersprungen, Name kann mit der eingestellten Lokalisation nicht angezeigt werden."%s" wurde übersprungen, kein gültiges Pog.(Filtereinstellungen beachten!)Ein Pog ohne Namen wird nicht angelegt, aber immerhin ein netter Versuch!ÜberÜber Fonty PythonSind Sie sicher?Schwerer Fehler, ich gebe auf.Pog konnte nicht gelöscht werden. %sEinstellungen verändernAuf gefährliche Schriften überprüfen.Prüfe die Schriften, einen Moment Geduld bitte.Wähle ein Verzeichnis und Doppelklicke daraufWähle einige SchriftenFilter leerenNichts &auswählenHebt die Auswahl komplett auf.Fonty Python beendenKopiere %(source)s nach %(target)sKann "%s" nicht öffnen.Konnte die Konfigurationsdatei nicht schreiben.Erstellt ein neues, leeres Pog.Erstellt ein neues Pog: %sLösche Pog%s soll bereinigt werden? Bereinigen bedeutet, dass alle Schriften in diesem Pog, die nicht auf eine vorhandene Schrift verweisen, entfernt werden.FehlerFilter:Folgende gefährliche Schriften wurden gefunden.OrdnerSchrift kann nicht gefunden werden, Sie sollten das Pog löschen.Schrift verursachte einen Speicherfehler, sie konnte nicht angezeigt werden.Schrift könnte beschädigt sein und nicht richtig angezeigt werden.Schrift könnte beschädigt sein und nicht richtig angezeigt werden.Fonty PythonFonty Python - betrachten und verwalten aller Schriftarten mit GNU/LinuxFonty Python Version %sFonty Python, .... ist abgestürzt.Fonty Python : hole mehr aus Deinen Schriften!&Hilfe F1Entschuldigung, aber installierte Version von wxPython unterstützt Unicode nicht. Fonty Python ist aber auf Unicode angewiesen und wird ohne nicht arbeiten. Bitte besorgen Sie sich die Unicode-Version von python-wxgtk.Ich kann die Argumente nicht dekodieren. Bitte überprüfen Sie die Umgebungsvariable LANG. Kopieren Sie nicht den Text, sondern geben ihn direkt ein.Kann %s nicht findenKann %s nicht findenKonnte "python-imaging" nicht finden! Bitte dieses Paket installieren. TIPP ==== Bei meiner Distribution kann ich auf diese Weise suchen: aptitude search python-imag In der Liste sollte auch zu finden sein: python-imaging Mit diesem Befehl kann das Paket installiert werden: sudo aptitude install python-imaging Die Versionsnummer sollte mindestens 1.1.6-1. Die neueste Version kann ebenso von hier heruntergeladen werden: http://www.pythonware.com/products/pil/index.htm Es konnten keine beschädigten Schriften gefunden werden.%(count)s Schriften aus %(folder)s nach %(pog)s kopiert.Unterverzeichnisse einschliessenInstalliere PogInstalliere "%s"Installiert alle gewählten Pogs. Benutze SHIFT/CTRL+Klick zur Mehrfachauswahl in obiger Liste.Der rötliche Vogel springt über das bläuliche Faß. LizenzListe %d Pog(s) aufSuche in %s...NB: Wenn Leerzeichen in Pognamen oder Ordnern verwendet werden sollen "setze sie in Anführungszeichen." Neues PogKeine Konfigurationsdatei gefunden, wird mit Standardvorgaben erstellt.Keine unterstützten Schriften gefunden....Keine einzige Schrift aus diesem Pog konnte installiert werden. Möglicherweise wurden die Original-Schriften verschoben oder umbenannt.Keine einzige Schrift aus diesem Pog konnte deinstalliert werden. Keine davon befand sich in ihrem Heimatverzeichnis. Schauen Sie unter ~/.fonts/ (WICHTIG: versteckter Ordner mit Punkt als erstes Zeichen) nach verwaisten Verknüpfungen. Das Pog wurde als "nicht installiert" markiert.Nichts zu tunOh Junge...Oh nein,..Seitenlänge:Bitte die Argumente prüfen, es scheinen zu viele zu sein. TIPP : Wenn Sie Leerzeichen in Pog-Namen oder Ordnern verwenden, setzen Sie "Anführungszeichen darum".Bitte ein Pog oder Schriftverzeichnis auf der linken Seite wählen.Bitte eine Quelle für das Pog wählen.Bitte starten Sie Fonty Python neu, nachdem Sie "%s" verschoben haben.Bitte verwenden Sie eine Zahl für %sEs konnte nicht in das Pog geschrieben werden. Prüfen Sie das Dateisystem. %sPog ist bereits installiert.Pog ist leer.Pog ist nicht gültig, bearbeiten Sie es bitte von Hand.Pog ist nicht installiert.PogsSchriftgröße:Schrift löschen?Lege Schriften in %s abSoll %s wirklich gelöscht werden?Alle verwaisten Schriften vom gewählten Pog entfernen.Entferne Schriften von %sEntferne "%s"ENTSCHULDIGUNG, ABER UNICODE MUSS UNTERSTÜTZT WERDENBeispieltext:Wählt RESTLOS ALLE Schriften im Ursprungsordner/Pog ausAusgewählte Schriften befindne sich nun in %s.Gewählte Schriften wurden entfernt.OptionenEinige Schriften konnten nicht deinstalliert werden. Schauen Sie in Ihrem Heimatverzeichnis unter ~/.fonts/ (WICHTIG: versteckter Ordner mit Punkt als erstes Zeichen) nach verwaisten Verknüpfungen. %sEinige Schriften wurden nicht installiert. Vielleicht wurden die Original-Schriften verschoben oder umbenannt. Entweder löschen (-p) oder von Hand bearbeiten."%s" existiert nicht. Versuche -l oder --listEntschuldigung,"%s" nicht gefunden. Versuche -l für die Anzeige aller Namen.Entschuldigung, nur GNU/Linux wird zur Zeit unterstütztBeginne in %s:Vorhandene PogsDankeDie Schriften aus %(folder)s sind *bereits* in %(pog)s.Die Datei ~/.fontypython/fp.conf enthält Fehler. Bitte entfernen und Fonty Python neu starten.Vorgang abgeschlossenDas Pog "%s" ist im Moment installiert und kann daher nicht als Ziel verwendet werden.Hier befinden sich keine Schriften.Hier befinden sich keine Schriften, gehe weiter.Keine Pogs verfügbar.Element nicht vorhanden.Ein Fehler trat beim Schreiben des Pogs auf. Es wurde nichts verändert.Ein Fehler trat beim Schreiben des Pogs auf. Es wurde nichts verändert.Es gibt Probleme mit den unten aufgeführten Schriften. Bitte das "Überprüfe Schriften"-Werkzeug in Fonty benutzen. (von der Kommandozeile oder vom Menü "Datei" aus), um alle gefährlichen Schriften zu markieren. (Diese können an einen beliebigen Ort verschoben werden, aber andere Schriften können weiterhin Schwierigkeiten verursachen.) Quell- und Zielpog sind gleich.Es befinden sich keine Schriften in diesem Ordner.Diese Schrift befindet sich in %sDas Pog ist leer.Dieser Text kann nicht angezeigt werden, soll vorkommen....Nicht abgefangener Fehler: Bitte entfernen Sie "%s" hier und senden uns einen Bericht.Unicode Problem. Schrift könnte beschädigt sein und nicht richtig angezeigt werden.Deinstalliere PogDeinstalliert alle gewählten Pogs. Benutze SHIFT/CTRL+Klick zur Mehrfachauswahl in obiger Liste.Zeige einen (veränderbaren Pog) %sZeige einen (installierten Pog) %sAngezeigter Order %sZeige einen Ordner.AchtungWillkommen bei Fonty Python %sDas Pog kann um Schriften erweitert werden.Sie können die Schriften vom gewählten Pog entfernen.Installierte Pogs können nicht verändert werden.Ein Ordner kann nicht als Ziel-Argument verwendet werden. Versuche --helpUrsprung und Ziel sind das gleiche Pog! Versuche -eAktives Pog ist %sQuell- und Zielpog sind gleich! Versuche -efontypython-0.4.4/fontypythonmodules/locale/fr/0000755000175000017500000000000011742300067020436 5ustar donndonnfontypython-0.4.4/fontypythonmodules/locale/fr/LC_MESSAGES/0000755000175000017500000000000011742300067022223 5ustar donndonnfontypython-0.4.4/fontypythonmodules/locale/fr/LC_MESSAGES/all.mo0000644000175000017500000002226711742276535023355 0ustar donndonnTq\ $!YFR"6NU[.l   +* V k v     # C L     - 05 nf 122 L$Z     !+MsVw&B0i HI9+UA3 ESe"m(#:(Ao`(bf\ .9?FO &!7M/bOV^ g8t- Unr4 E6I3Z,">T4d2}R F F@! !l!V"W" o"!"!"X"-#&G#n### ###.#I"$$l$%$#>+9 ,KG:$%SPOQ8;&1!*6E.'NJCFRL T"M/ ?D3AI 57)<=0(@24HB-  (Also check your file permissions.) Couldn't make the .fonts folder in %s Please check your write permissions and try again. Couldn't make the folder in %s Please check your write permissions and try again. * indicates installed pogs%s already exists.%s has been purged.%s has not been purged.&About&Help&Settings Ctrl+S(%s) cannot be found. Try -l to see the names.(Check your filter!)AboutAbout FontyPythonAre you sure?Bad voodoo error. I give up.Cannot delete the Pog.%sClear selectionClose the appCopying fonts from %(source)s to %(target)sCould not open (%s).Delete PogDo you want to purge %s? Purging means all the fonts in the pog that are not pointing to actual files will be removed from this pog.ErrorFilter:FoldersFonty PythonFonty Python: bring out your fonts!H&elp F1I cannot find "python-imaging" Please install this package. TIP === On my distro I can search for it like this: aptitude search python-imag This returns many results, one of which is: python-imaging I then install it like this: sudo aptitude install python-imaging Make sure it's at least version 1.1.6-1 You can also get the latest version from here: http://www.pythonware.com/products/pil/index.htm Install PogInstalling (%s)Jump the lazy dog foxLicenceListing %d pog(s)New PogNo config file found, creating it with defaults.Not a single font in this pog could be installed. The original font folder has probably moved or been renamed.Not a single font in this pog could be uninstalled. None of the fonts were in your fonts folder, please check your home .fonts (with a dot in front) folder for broken links. The pog has been marked as "not installed".Page length:Please check your arguments, there seem to be too many. (Remember: it's one pound for a five-minute argument, but only eight pounds for a course of ten.) NB: If you wanted to use spaces in a pogname or folder then please put "quotes around them." Please choose a Pog or a Font folder on the left.Please choose a Source.Pog cannot be written to. Check your filesystem.%sPog is already installed.Pog is empty.Pog is invalid, please hand-edit it.Pog is not installed.PogsPoint size:Purge font?Put fonts into %sRemove %s, are you sure?Remove fonts from %sRemoving (%s)Sample text:Selected fonts are now in %s.Selected fonts have been removed.SettingsSome fonts could not be uninstalled. Please check your home .fonts (with a dot in front) folder for broken links.%sSome fonts did not install. Perhaps the original fonts folder has moved or been renamed. You should purge or hand-edit.Sorry, (%s) does not exist. Try --listSorry, can't find (%s). Try -l to see the names.Target PogsThe fontypython config file is damaged. Please remove it and start againThe target pog (%s) is currently installed, you can't use it as a target.There are no fonts in here.There are no fonts to see here, move along.There are no pogs available.There is no such item.There was an error writing the pog to disk. Nothing has been doneThese two are the same Pog.This folder has no fonts in it.This pog is emptyUninstall PogViewing a folder.WarningWelcome to Fonty Python version %sYou can append fonts to your target Pog.You cannot change an installed Pog.You cannot use a folder as the target argument. Try --helpYour Source and Target are the same Pog.Your pogs are the same! Try -eProject-Id-Version: fontypython 0.2.0 Report-Msgid-Bugs-To: POT-Creation-Date: 2009-10-13 08:20+0200 PO-Revision-Date: 2008-01-22 19:46+0200 Last-Translator: Donn Ingle Language-Team: French MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plural-Forms: nplurals=2; plural=(n > 1); (Vérifiez également les permissions.) Impossible de créer le dossier .fonts dans %s Please check your write permissions and try again. Impossible de créer le dossier dans %s Veuillez vérifier les permissions d'écriture et réessayer. * indique les pogs installésPog %s est installé.%s n'a pas été nettoyé.%s n'a pas été nettoyé.À &Propos&Aide&Options Ctrl+O(%s) ne peut être trouvé. essayez -l pour voir les noms disponibles.ou videz le filtre ci-dessous.À ProposÀ Propos de Fonty PythonÊtes-vous certain ?Erreur maléfique vaudou, j'abandonne.Impossible de supprimer le Pog.%sNe rien sélectionnerQuitter Fonty PythonCopie des polices de %(source)s vers %(target)sImpossible d'ouvrir (%s).Supprimer le PogVoulez-vous nettoyer %s ? Nettoyer signifie que toutes les polices du Pog qui ne pointent pas vers des fichiers existants en seront supprimées.ErreurFiltre:DossiersFonty PythonFonty Python : redécouvrez vos polices de caractères !&Aide F1(String needs new translation)Fonty Python dépend de "PIL" - Python Imaging Library. Veuillez installer "python-imaging" en utilisant les outils de votre distribution. Voyez sur http://www.pythonware.com/products/pil/index.htm Installer le PogInstaller le Pog (%s)Portez ce vieux whisky au juge blond qui boitLicenseAffichage de %d pog(s) Nouveau PogAucun fichier de configuration détecté, création avec les paramètres par défaut.Pas la moindre police de ce pog n'a pu être installée. Le dossier originel a du être supprimé ou renommé.Pas la moindre police de ce pog n'a pu être désinstallée. Aucune d'entre elles n'étaient dans votre dossier de polices, veuillez vérifiez le dossier ~/.fonts/ (sans oublier le point). Le pog a été marqué comme désinstallé.Longueur de la page:Veuillez vérifier vos arguments, il semble y en avoir trop. NB : Si vous souhaitez utiliser des espaces dans le nom d'un pog ou d'un fichier, alors veuillez les entourer de guillemets.Veuillez choisir un Pog ou un dossier sur la gauche.Choisissez un dossier ou un pog.Le pog ne peut être enregistré. Vérifiez le système de fichier.%sPog est installé.Le pog est vide.Le pog est invalide, veuillez l'éditer à la main.Le Pog n'est pas installé.PogsLongueur de la page:Supprimer la police ?Placer les polices dans %sÊtes-vous certain de vouloir supprimer %s ?Supprimer les polices de %sVisualisation de (%s)Texte affiché:Les polices sélectionnées sont maintenant dans %s.Les polices sélectionnées ont été supprimées.OptionsCertaines polices ne peuvent pas être désinstallées. Veuillez vérifier votre dossier ~/.fonts/ (sans oublier le point).%sCertaines polices n'ont pas été installées. Peut-être que le dossier d'origine a été déplacé ou renommé. Vous devriez le purger (-p) ou l'éditer à la main.(%s) ne peut être trouvé. essayez -l pour voir les noms disponibles.(%s) ne peut être trouvé. essayez -l pour voir les noms disponibles.Pogs CiblesLe fichier ~/.fontypython/fp.conf semble être endommagé. Veuillez le supprimer puis relancer Fonty Python.Le pog (%s) est actuellement installé, vous ne pouvez pas l'utiliser comme une cible.Aucun fonts disponible.Choisissez un dossier ou un Pog,Il n'y a pas autant d'éléments.Il n'y a pas autant d'éléments.Il y a eu une erreur pendant l'écriture du pog sur le disque. Rien n'a été effectué.Vos pogs sont les mêmes.Ce dossier ne contient pas de fichier.Le pog est vide.Désinstaller le PogVisualisation de dossier.AttentionBienvenue dans Fonty Python %sPlacer les polices dans PogVous ne pouverz pas modifier un Pog installé.Vous ne pouvez pas utiliser un dossier comme un pog cible. Essayez --helpVos pogs sont les mêmes! Essayez -eVos pogs sont les mêmes ! Essayez -efontypython-0.4.4/fontypythonmodules/locale/it/0000755000175000017500000000000011742300067020443 5ustar donndonnfontypython-0.4.4/fontypythonmodules/locale/it/LC_MESSAGES/0000755000175000017500000000000011742300067022230 5ustar donndonnfontypython-0.4.4/fontypythonmodules/locale/it/LC_MESSAGES/all.mo0000644000175000017500000003635511742276536023366 0ustar donndonn| $ Y RX     2 9 @ M e k q |  . : "B?W */Iy  +#;T kv" -05.f' > !#?cle:E;e C,4F^W0!n Z hr {1J21d ~$  -= R ` 5!s w&0 1Q 3H#I<+AD`-G8 T Eb   " ( 2!#A!:e!(!!!'w#c#\$`$z$$$<$$ %%7%=% D% O% p%{%5%C%#&,&3C&w&& &"& && ';$'5`' '''%''((*(1C(u(( (v(').) 6)W):`)B)@) *C,*p*#*.* **+D,[,".62.i. . .I.5./#/3/tF/ /A/0%0%01 1 122?3Y3Dy33934 -4+84d4x4|4 44"4%44 5+5K5;]5"5&5 556)C76m7=7 77888U@88[8 9#!9E9]9Mx99(9:#:37:ck:R:";L2; ; ;%;-;-;&-<@T<8<<l>8%Rko1]n$u6|BU/ Q,0V3^@f}pzN{2*~#_wEM W)I=jTy!GX<;Ah q .:&xd\JDOS PY4v9-+gb5e'F`"(7 cr?KZtiHLCsm[a (Also check your file permissions.) Couldn't make the .fonts folder in %s Please check your write permissions and try again. Couldn't make the folder in %s Please check your write permissions and try again. * indicates installed pogs%s already exists.%s has been purged.%s has not been purged.%s takes two arguments: SOURCE(folder) TARGET(pog)&About&Check fonts&Clear ENTIRE selection&Exit&Help&Purge Pog&Select ALL the source fonts&Selection&Settings Ctrl+S(%s) cannot be found. Try -l to see the names.(%s) skipped. I can't display this name under your locale.(%s) skipped. It's an invalid pog.(Check your filter!)A Pog with no name won't be created, however it was a good try!AboutAbout FontyPythonAre you sure?Bad voodoo error. I give up.Cannot delete the Pog.%sChange settingsCheck for dangerous fonts.Checking fonts, this could take some time.Choose a directory and double click it to startChoose some fontsClear filterClear selectionClear the selection completely.Close the appCopying fonts from %(source)s to %(target)sCould not open (%s).Could not write to the config file.Creates a new, empty PogCreating a new pog: %sDelete PogDo you want to purge %s? Purging means all the fonts in the pog that are not pointing to actual files will be removed from this pog.ErrorFilter:Find those fonts that crash Fonty.FoldersFont cannot be found, you should purge this Pog.Font causes a memory error, it can't be drawn.Font may be bad and it cannot be drawn.Fonty PythonFonty Python - view and manage all kinds of fonts on Gnu/LinuxFonty Python version %sFonty Python, um ... crashed.Fonty Python: bring out your fonts!H&elp F1I am sorry, but Unicode is not supported by this installation of wxPython. Fonty Python relies on Unicode and will simply not work without it. Please fetch and install the Unicode version of python-wxgtk.I can't decode your argument(s). Please check your LANG variable. Also, don't paste text, type it in.I can't find %sI cannot find "python-imaging" Please install this package. TIP === On my distro I can search for it like this: aptitude search python-imag This returns many results, one of which is: python-imaging I then install it like this: sudo aptitude install python-imaging Make sure it's at least version 1.1.6-1 You can also get the latest version from here: http://www.pythonware.com/products/pil/index.htm I could not find any bad fonts.I have placed %(count)s fonts from %(folder)s into %(pog)s.Include sub-folders.Install PogInstalling (%s)Installs all selected Pogs. Use SHIFT/CTRL+Click on the list above.Jump the lazy dog foxLicenceListing %d pog(s)Looking in %s...NB: If you wanted to use spaces in a pogname or folder then please put "quotes around them." New PogNo config file found, creating it with defaults.No supported fonts found there...Not a single font in this pog could be installed. The original font folder has probably moved or been renamed.Not a single font in this pog could be uninstalled. None of the fonts were in your fonts folder, please check your home .fonts (with a dot in front) folder for broken links. The pog has been marked as "not installed".Nothing to doOh boy...Oh dear,Page length:Please check your arguments, there seem to be too many. (Remember: it's one pound for a five-minute argument, but only eight pounds for a course of ten.) NB: If you wanted to use spaces in a pogname or folder then please put "quotes around them." Please choose a Pog or a Font folder on the left.Please choose a Source.Please restart Fonty Python after you have moved:"%s" to some other place.Please use a number for %sPog cannot be written to. Check your filesystem.%sPog is already installed.Pog is empty.Pog is invalid, please hand-edit it.Pog is not installed.PogsPoint size:Purge font?Put fonts into %sRemove %s, are you sure?Remove all ghost fonts from the selected Pog.Remove fonts from %sRemoving (%s)SORRY: UNICODE MUST BE SUPPORTEDSample text:Select ABSOLUTELY ALL the fonts in the chosen source.Selected fonts are now in %s.Selected fonts have been removed.SettingsSome fonts could not be uninstalled. Please check your home .fonts (with a dot in front) folder for broken links.%sSome fonts did not install. Perhaps the original fonts folder has moved or been renamed. You should purge or hand-edit.Sorry, (%s) does not exist. Try --listSorry, can't find (%s). Try -l to see the names.Sorry, only Gnu/Linux is supported at the moment.Starting in %s:Target PogsThanksThe fonts from %(folder)s are *already* in %(pog)s.The fontypython config file is damaged. Please remove it and start againThe process is complete.The target pog (%s) is currently installed, you can't use it as a target.There are no fonts in here.There are no fonts to see here, move along.There are no pogs available.There is no such item.There was an error writing the pog to disk. Nothing has been doneThese two are the same Pog.This folder has no fonts in it.This font is in %sThis pog is emptyThis text cannot be drawn. Hey, it happens...Unhandled error: Please move (%s) away from here and report this to us.Unicode problem. Font may be bad and it cannot be drawn.Uninstall PogUninstalls all selected Pogs. Use SHIFT/CTRL+Click on the list above.Viewing a folder.WarningWelcome to Fonty Python version %sYou can append fonts to your target Pog.You can remove fonts from the selected Target Pog.You cannot change an installed Pog.You cannot use a folder as the target argument. Try --helpYour Source and Target are the same Pog.Your pogs are the same! Try -eProject-Id-Version: Fontypython 0.3.0 Report-Msgid-Bugs-To: POT-Creation-Date: 2009-10-13 08:20+0200 PO-Revision-Date: 2009-07-07 12:35+0100 Last-Translator: Pietro Battiston Language-Team: Italian Translation Project MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Poedit-Language: Italian X-Poedit-Country: ITALY (Controlla anche i permessi dei file.) Impossibile creare la cartella .fonts in %s Per favore verifica i permessi di scrittura e riprova. Impossibile creare la cartella in %s Per favore verifica i permessi di scrittura e riprova.* indica i pog installati%s esiste già.%s è stato epurato.%s non è stato epurato.%s richiede due argomenti: SORGENTE(cartella) OBIETTIVO(pog)I&nformazioni su...&Controllo font&Ripulisci TUTTA la selezione&EsciA&iuto&Epura pog&Seleziona TUTTI i font sorgente&SelezionePreferen&ze Ctrl+SImpossibile trovare (%s). Prova -l per vedere i nomi.(%s) skipped. Non riesco a mostrarne il nome con la locale attuale.(%s) saltato. È un pog non valido.(Controlla il filtro!)Buon tentativo... ma non creerò un pog senza nome!Informazioni su...Informazioni su Fonty PythonSei sicuro?Errore voodoo maligno. Mi arrendo.Impossibile cancellare il pog.%sCambia le preferenzeControllo font dannosi.Sto controllando i font: potrebbe prendere un po' di tempo.Doppio click su una cartella per avviare il controlloScegli i fontRipulisci filtroDeseleziona tuttoRipulisci completamente la selezione.Chiudi il programmaCopia di font da %(source)s a %(target)sImpossibile aprire (%s).Impossibile modificare il file di configurazione.Crea un nuovo pog vuotoCreo un nuovo pog: %sCancella pogVuoi epurare %s? Epurare significa che tutti i font del pog che non puntano a file effettivi saranno rimossi dal pog.ErroreFiltro:Trova i font che crashano Fonty.CartelleImpossibile trovare il font, dovresti ripulire questo pog.Il font causa un errore di memoria, non è possibile raffigurarlo.Il font potrebbe essere corrotto, non è possibile raffigurarlo.Fonty PythonFonty Python - visualizza e gestisci ogni tipo di font in Gnu/LinuxFonty Python, versione %sFonty Python... ehm... ha crashato.Fonty Python: porta i tuoi font allo scoperto!A&iuto F1Spiacente, questa installazione di wxpython non supporta l'Unicode. Fonty Python necessità di Unicode e semplicemente non può funzionare senza. Per favore procurati ed installa la versione Unicode di python-wxgtk.Impossibile decifrare il/gli argomento/i. Verificare la variabile LANG. Attenzione: non incollare testo, ma digitarlo direttamente.Impossibile trovare %sImpossibile trovare "python-imaging" Per favore installa questo pacchetto. Suggerimento === Nella mia distribuzione posso cercarlo così: aptitude search python-imaging Restituisce vari risultati, tra cui: python-imaging Lo installo quindi così: sudo aptitude install python-imaging Assicurati che sia la versione 1.1.6-1 o più recente. Puoi sempre ottenere l'ultima versione qui: http://www.pythonware.com/products/pil/index.htm Non ho trovato alcun font dannoso.Ho sistemato %(count)s fonts da %(folder)s in %(pog)s.Includi sottocartelle.Installa pogInstallo (%s)Installa tutti i pog selezionati. Usa SHIFT/CTRL+Click sulla lista sopra.Ma la volpe col suo balzo ha raggiunto il quieto fidoLicenzaLista di %d pogControllo in %s...NB: se si vuole utilizzare degli spazi nel nome di un pog o di una cartella è necessario metterlo "tra virgolette".Nuovo pogNon ho trovato il file di configurazione, ne ricreo uno standard.Nessun font supportato qui...Non è stato possibile installare neanche un font di questo pog. La cartella di origine dei font è stata probabilmente spostata o rinominata.Non è stato possibile disinstallare neanche un font di questo pog. Nessuno di questi font era nella tua cartella dei font, per favore controlla eventuali link interrotti nella cartella .fonts (con un punto all'inizio) all'interno della tua home. Il pog è stato segnato come "non installato".Niente da fareO cribbio...Oh caspita,Lunghezza della pagina:Per favore controlla gli argomenti, sembrano essere troppi. (Ricorda: un argomento da cinque minuti viene una sterlina, ma se ne compri dieci paghi solo otto sterline.) NB: Se il nome di un pog o di una cartella contiene spazi, mettilo "tra virgolette".Per favore scegli un pog o una cartella di font sulla sinistra.Per favore scegli una sorgente.Per favore sposta:"%s" in un'altra posizione e riavvia Fonty Python.Per favore usa un numero per %sImpossibile modificare il pog. Controlla il filesystem.%sPog già installato.Pog vuoto.Il pog è invalido, modificalo manualmente.Pog non installato.PogDimensione (in punti):Epurare font?Metti i font in %sSei sicuro di voler cancellare %s?Rimuovi fantasmi dal pog selezionato.Rimuovi i font da %sRimuovo (%s)SPIACENTE: L'UNICODE DEVE ESSERE SUPPORTATOTesto di esempio:Seleziona ASSOLUTAMENTE TUTTI i font nella sorgente scelta.I font selezionati sono ora in %s.I font selezionati sono stati rimossi.ImpostazioniImpossibile disinstallare alcuni font. Per favore controlla eventuali link interrotti nella cartella .fonts (con un punto all'inizio) all'interno della tua home.%sNon è stato possibile installare alcuni font. Probabilmente la cartella di origine dei font è stata rimossa o rinominata. Doversti epurarli o modificare manualmente il pog.Spiacente, (%s) non esiste. Prova --list.Spiacente, non trovo (%s). Prova -l per vedere i nomi.Spiacente, al momento sono supportati solo sistemi Gnu/Linux.Parto in %s:Pog destinazioneGrazieI font della cartella %(folder)s sono *già* in %(pog)s.Il file di configurazione fontypython è danneggiato. Per favore rimuovilo e riprova.Il processo è completo.Il pog destinazione (%s) è attualmente installato, non puoi utilizzarlo come destinazione.Non ci sono font qui.Qui non c'è nessun font da vedere.Nessun pog disponibile.Non c'è un tale elemento.C'è stato un errore nella memorizzazione del file. Non è stato fatto nulla.Questi due pog sono lo stesso.Questa cartella non contiene alcun font.Questo font è in %sQuesto pog è vuotoImpossibile raffigurare questo testo. Oh, capita...Errore non gestito: Per favore sposta (%s) da questa posizione e riporta l'errore ai programmatori.Problema unicode. Il font potrebbe essere corrotto, non è possibile raffigurarlo.Disinstalla pogDisinstalla tutti i pog selezionati. Usa SHIFT/CTRL+Click sulla lista sopra.Visualizzazione di una cartella.AttenzioneBenvenuto in Fonty Python versione %sPuoi aggiungere font al tuo pog destinazione.Puoi rimuovere dei font dal pog destinazione.Non puoi modificare un pog installato.Non puoi utilizzare una cartella come destinazione. Prova --helpIl tuo pog origine e quello destinazione sono lo stesso.I pog sono lo stesso! Prova -efontypython-0.4.4/fontypythonmodules/things/0000755000175000017500000000000011742300067020064 5ustar donndonnfontypython-0.4.4/fontypythonmodules/things/README0000644000175000017500000004440411742276534020765 0ustar donndonnSection One : Copyright ======================= The following images are Copyright (C) 2006, 2007, 2008, 2009 Donn.C.Ingle aboutfplogo.png cross.png fplogo.png splash.png icon_source_16x16.png icon_source_folder_16x16.png icon_source_pog_16x16.png icon_target_16x16.png pog16x16.installed.png pog16x16.png pog16x16.target.png view16x16.png tick.png ticksmall.png clear.png font_info_item.png font_no_draw.png font_not_found.png font_segfault.png button_regular.png button_regular_down.png button_italic.png button_italic_down.png button_bold.png button_bold_down.png icon_cdrom.png icon_drive.png icon_root.png icon_closed_folder.png icon_open_folder.png Section Two : License ======================= GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. fontypython-0.4.4/fontypythonmodules/things/aboutfplogo.png0000644000175000017500000007107511742276534023140 0ustar donndonnPNG  IHDRN;wsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org< IDATxydWy'%"r}/6TڅJP%vY h, nnO3=m؇>>>fi۸{llih/l6RFk UI* IUYY;|˽/"2+3+kIYx~fBHFrvŞ/0 JĦJɳJgsu5`1gێd$L&~M_0q YVyY\E'2˲ܹk#%iFr$#Y{rAyBaVG򼼹lyQv(Ȝ˝s8gVyvF2}?+$snK򛊲r,۝lEYdyV89cm cFH/xA#@<eySvjv,y<3HFh 5stYV585=z ǎñqo=cǏczzǎ?>3'f0;;ٙtpwgav}R_ aX51Փt;15rrcguڸ+qW;~|=:A6G[)ipUWƫwbǖMp-C{Ž݇w"0MͮE *LM,})NO5@*yarr'&fr;n .ގ55x+wO=X1G;I4W W]v1ܐ#6^7< 4Z&Zk J_KoS$`(|yok;@SQ;V٣@@Xj/x;^c;.߱㝶vظ~-^Eow܅Ǟ|[xk` <_xK>amîk W^VY l~ԧ}?ffffYxNsfSk`yOWe;D+M$  0!4?qZ\c;^pv\}Zec^/z'|;#Z@o'g㺵++:1D:Oԧ?{<' "Mc}~,>GexeW\?lL= {')C@HHY&@|٣xpC9*z.[ p%;p%;؏P>U< e 1[ϔw*a]u3[6yԧ>~;B֪6sEpep_ιA&<'Z/&M.GQ h s'5|{Oyy>xP{y9^{6oOm}5涯`c,`G϶o>a/uW\xyzzƧ>)|K_BUU dY)rG_$~7~'0;;|ƚJg?}>wXjv ˻ߎv^ɿ@"x=XBa[xp9dY,Q𭀭, Ev(e( YNeYDYck R3 `o[q<4. =Q0C%\k:9A Ϛ/GoWը=WkxoQU5G~׼{nnĚU'::!8“ X}Lx|uR |_58p@y"$岅,PZeBhJ21Y~󜚕x1<`햆]:9 '@Vlk^pNl3!l'9|U5*CWWWpFճG xo- ۰=E/ïܿoǎg9!' Lx#ny+nh/} Їp74\(Č, ;Z5Z^hۼMoS}7g-`mϖk 4@*#˃5vX qtWGc'"&c9r!|k$#5 =.#!x*^CUȳثеʠk<> ;mlݼ|3'@_5Xm^yۏ`u}݇__ŭ6`R&hZhZ(喵[Y YQFaVHcuiH=`c`%ZoorlȅdlR˾@/ƃ<>"`iha}uCXGYTUЫ*tCWaZت^U7'?oOXf5VONۿƇ?b;{9e!X,K~M7-yVݺ~7я~5;bREcchh1:6VjYp:sҰߦ&%YKH@#@ "O-%oz|r' ljv{LjZ'+`Ԁ2 פj됹 ϐZ=Zz]k`L*jVG3Xj[7m/}@dftI$2sxכ_^uc_}ػwo 0ČltnCnQ99會3"K7'DKYiԄdMgMDJ O\D@י>`ʤ s&@ZA5=Ʉ iI&(0Α&Y,2IgR-WD쫍Eu:t:h(˒BixJeEQ&J$OD6$H.PӸUnæ~BԾ!:qDh5dI4X0B7qmYXrqڀ ) bsQg;??G^Eڽ;%b_%Ⲥ $_XˬeUU_%Q×+`GBBYprov2  ZS*&_ӯ[>_0Qp0ESY' $1x8ȏ bަ W J֐?hA3'џE.w=~_ƻ:OĻo܇cSӔ1Se|x\0-Cc]ch넩i2ɲ eY`bb661r6+%9DIqy˕؆&f08]41`oKj} yBIKGbeSYރtnA ("?>M\K?/dhe~sdx /ގ)O|'x[*K2'11>1t0>1AIYPBgxjJ:J̍-!V9@AF48 kjj2eUVgl(Iwr P-M@yM `B 33\JD մ}kaB :umg^#Dpz@0?~~Vz!^Ÿ}C0u% t>Ǡd8tPN1>>vV)`.s&p.j< nk@̞܄Ĵl-mZi&ٲ\qY {ׁo!#0aWFԖ\5xAYr 8Z`&9r dsJV.x_ x?}'n~,`ê+/1oވz4›o=2EY ^Bj, dyJ3 d|9lC5r+D;B<RߍEWY^K3k~5>X6{V ̤:O`-SЃԨu{* ! 5R#z΃ʍoջouk}V%{ìUs09_]yoѣGմ,f,'&&0nbr86ƹl2e[)Aq9%NędEMJ%JNfOBRڧܦ;>Pʍ11  \ s[ݿZevuעk+,d 5ޖ _ɓ'csŕlfv8Y~1a"$JR1arl| N;̾o]e @/Č q9ݖC1 ,}T@_F5چfLcB. b=RETSJRg-,!!cS*yK/4kǫPW5|NVId\Xez\کjby:LOnw4ag9\4&B)Gr$h<aVXʲgA(T+F/ONKo4Cn7Q^ NhuV{Zk`j'N`Ub5x1u" ]]klbK{N!_{=)g6+8C3N\CYeTbfeHd@N}99=I"o9UvdrZTU[@ 43E8~f`Mv ɚزa@#j:RyIŋ1A3_uuϒYը u-߉')4߅(Z.&DGݓ?J_kjMO:+-6vWxF'|9x3NqFi1Daކn-<1/{a J8Xxq P?A'&&CtI |\cy7Ig?x@4'paw˸sQI@rkH2@:D8% &ePPk+]={=t|UQ<0$VB)܊3 \1)1TZȲ PgN$LfCR`(ny8(? ̍6}zhhS]ũ^Y>vh;*(8^J]TVL,rf-e$0?DR>(C:(ϣ48 ۝Cf9 m2aXOӐkaʁ.s|| 2˭ I T 6c@N-lؕb:rȁȣR [ &c PW,JMjb2jդdTM?à7D«6ַp]w h;"ݝRt. $h>]r-53ө85CbI̞<391ٓEw^C]R [k7`ĉSoah=7Q@q33i)ioM$AXP:Q6I}ɰ3T=|W3g~rܝ۟ Qâ튂*#Y%4'f|V;|Sjw/5d>JYzILOOcj8lj8y$溨z=U\Y]ynL̜zŊ\82P:wdai(bْ!oI&İ0Ox&O>б٦U)}=6!D <6[[7 x߈|غu_DpIE(#@Y$b,CBԲ [%T32$#h;Ԍ L!D_rreb-{mE3SfFj Cq4|s/m.N%!JbyŒ@k]UŜ38yr3'sN| Oٚ B$qq<)S8M.OrQ21/l& ɒ|Mbr3%:<~/ifGCB8(tUkT%Q[ٓ>, w(|A$fgg^qՄ6CĄ:IWA+zDOHHiaK%Y|>`/%/lU, 㧟}UUHa! 4gF5:AB jhsMt,Wt}mOaIW%H|_neI g,9hY$3/ Ih/GMY~׾2vƟ'5ゾ\h. `&rE/<1oÙ"@>DMd"~ aLD 3S̜~p%])c11t]ݻz$|@<0VLzfQKvAuJ #4F׋ڮEUWxի^ۿ[l mzc ٣G!,TCYN} m2=>iMOr}g3"^bf^}׿YN#UR:|:甭fd3# Bhltj)c^wNS^7;dx5t:?}t, q^~ m4 - Y}mw@LDVMNuцesc.<"ܷO/9Cq:=sI?tHv@.K$4M25k*FkqZU%^m>nK)aiʲ@p,9zy`:kc?/PYЋM1gHFD=5MG"q86 w>ȋ"))L!RBb-FS x9Rlžݻu7pbf)~P.g̈́k|Y遗|zooiْ$ ha B& S5!vޣ`%/k,{h"<עTKŻi]rDl!44^xFdʼn#g%YQ s)~/%f4o5S bP5ܽ\0㾌/5n{4L1/r Hq\SK]Mψ$&ޠ9x)Xk.#mY^$j}oL%jFo2Ttj<߿ %q-6;XAy睪k,/YΕ .jM˦YƲċ4aITX Q^u];8b> ,GVs:A4-8W^@/*ue&mCG;,"m2$n1")c1gfhPHYcamG'f7 /p)zi, w̥C2 9a`R@9K#fbMe^bfu稾;9`,,+(7DžꫯACp< 7!5QepiEʢcS;K&6|XJذI_K/ڎOṩi$sGqyAe ;!V,F?ާƞZUF0q;〃mČƋxLm0BAroݺ5khY{zAeQNf"f =CHӡLV'.yj]P'"~;=w`3;+XsSs6?-/rEa -\l*/d)&Xb B!ng'aT#: F5yq.i>RgՓDRER-@Jم$1:Ѱze(D0.JR1r"Smw5I 3 >yd@J?h0Jor}! 7RvS[q2l̝FtDLKQx0+c)p16[.tVB'm6o9?ww;"B岪\ ̒}>^3mLL_Sn{K9|k_K!"d[_L&c@Q8x=J7ɉ ]5{ K/M'lbZ }o P3".G#q}+e359CL^ZIx0owK 7FXo[1;O4-ʀ*R_(<ߓ}=zz2c|9iKO7lEssdV]t<,U[}^H|45_[=C3k+ IKRer^ik 3KcNk&HYҰFh$[ƛdՖp-J8t*2YfR*Po>eC~RiFH1[:= ķyzl4Ώd,V=07Obt\HI`KBl2\d*#OibX{*HUX~=.R~oj3)V)A7 X-J~ [jcF%:~|Ȍ !86:bCwf,h!ILB= W! c4ׯ^fK mše_q^Z K:PLE4+ӊD C45;#154\Ӏ _s*VvxnCѣH bb:`Eyh[N![7m$'fNcS ȚN$ ҈›WR:fE6+.IUb4A`/jN& "DXh̚0lC_o}XjB?g&G'ia&^G=a4=FSK@9DϣM88ê0BzW0'n̛DN3'U F5S|&X'"i3$VkWMhL,#{Թ[Y䌐*'0ieD~Fsz-LOO98y[\[v :m >cSƴmL%VI̔:ԵWNUdv <DXp46NB>bIF!\e"Z;8&W`iXwH'/=/i Vx0 (Y32 >FS&Zף_xhf}=zhbT&E@)jj2XS\8OtNjjnS?]b4%ӈQH@]^Yzc^ڷoj_7g6|<d+Y}_^\ğԴv~q"wxǛ_p84=zE1̭|- ,<\,;ѧ%nPa44G3)zxZ2ɢh$,-_,6~Gc[.mq"$4:U4|^ATU=8^{={nMl6M~KIkx Q֥q)PyWµ//񍍼q/yƹNz#!8y:oc'y^U)k!FX5>M3hZ+Xv:&pHުC=h(&C'>H%^\WYc mBڑX#pt{쉩bxI`1/U<~id9e,C,caH1H[DY@ -_!ձ_g9ha47#N!NqΔTkNrdWΑNd]_* bz `;j"%Tλ"Ĭk 1:NhɵZ-t;ˋ͙vl߾ܜ֎Y "B0R=4]b JRD'+'j ʜ%aDhA(P%.ٶY?رc3ƜF8ǦfJ 7erLbCMMDݽlYWK4 @+1YQvt* 3&Wabr.VmS `xe `8* LyEcb,[@]`^9c!jS0U/<o#hzz>JL,/t0IL6Ҙi 8 39P`h8B@@u.[ 8ZeOW]lزeQdCǶ$U L(F7{֒mDy&ld2+]w뭷3sh[u<_nxcHElO9tVf XC@tnPy%[,7…@c{le+G/ic#{H 9@;xϸ$E2V̯kT191&so6ꒆ -<&Fn'2汭]4mԓ2 ˼܎b@b ڠ-Ĕ[ #vv7z \6[jheETİ3vrn" NR4xB H1s=97Ǭeۣ;|0z衘7ƭ4>"\R͋mq3Q _ xYSO{>9T`=9ˊE} JVPI•6)I k0ʩ>b( 䭃g_ԵϰMx݉<ƭA9ќ}9:jazP53$ߒdU) 'HG1%Z 8 >um,袠U0x ظKjedW]RWf{ac4\?oӿOIQbs`Ps P5ڣZ"pe'z}l_Z>4g/18qPV3㬕SG1N.ȤO't/k:z|"B9! T8o'Mm+mOQ͙)Md[m:\b{?_qdJ v;+Ql!IKc-Rzᬘ"e{aK/,YBS ]sW+3p,% jzF @Ws۫M]<ڛu4fN Y5f+@@ib4Ή]Jk4 m>,i]+-M#"R %$waZ2DGb!>PH5Luy^-p)5A:S},0iFJ,gLKQQL駢i5D[LÕbsۀdyV&[ee?(.P7 椒*lrz]t.U]W:|0>03mۉsͧ Ni)Y cؿ\$Ǧ&`cs5cf)W<]i$f:rDO4t@fUdbr9n6uUW`ˆ=~W~SQiJX3G8Νڿ; cby5ib]%h:d1A)~,P1XY0r$5%% dՌv&>؜v|ɶu$S]t=u{ v }YvwcNjΛämG<}ÿK;FhV _MV1GZ磔g <4d;Әe$KHyQ<('k5@-eUc\׫]o|-Ƙt !~a.)Q2iA̲ Vƍ-df+:k@VVnIr`b3>w;y 98NZ(g׾h6?„I~ V/ၾh1^bzrLo~S#ˣʗbGD﮻ĜV9,WI.iv4\9klش׾uunsV)ykzC "i|%l>F|h5hؚ c08 s@HB_nIX-=S*t{l^ȴvi$Z W/jw}7~߯˵ar4-5G89#D$'&Fo{/NtiA[%ruFUjT5͗b;9mYmoDơ<M$.sf$+7ۓal@?Ubߢ%_S"7Suyђh9+.gŠ=sgWAާ_ &d[{1Z9hc odL RWWլz\ٹ.֍o}:"mԯ#Qj"j@R@gV9+ZƖjbQU, [!I; /z< ! b!Н ~QK,|M;nQL r͉2$GAD(1և#RF[{*s@Wcf-_moV\52,B `w'ЂsBİ>+۲i>GSO=ctђfhk% ˻NEMxDK};( 5dB4k<GM@1Q3*<'?I+W5 s\*=\R5DG>~CC3S"Ie Qpr?vN42gx~^8wĎNZc;5̴!7=CkBrOtz﯑_ Gr5L0bZj܆hzzBP Uhg/svX1^]W_9%̸ۗud.-FRk@vIQ۝tKw`c+.ˑ ,vA4$~Ѵ+5s}2|´,AH<2s&M mSNQs=yTnQkDPLaVoƘ->b1j" Se9kp%W $mL&T B8S8O:FKNfӄHF|9c,Z "}@/4 6}μI3.*0^zL>'>!CaSs$?F#pXo#3n^҂jUns1WǮkwu/ Q}YO$o&I+-9B@W( pEY"\Nsj9 NT9[z<ѣ淾s%pUR6 (D%$Raj#A fLg|rlfl ."")W`ˢEO |8FիQy^5z2Tmހ7̝Dۇw8p`펦e1:b.Y%x %~n5w ə^mklf2kbt TZ2P.e0c< /O/f*Y!"L$rɦgBʲ_KxGѱ M .(n6'IV$d`[{/sx>|Uר8(^pU]]W 7\_;;_eTU:5 dy,-tEt_ :-NgL a͎bqTR1W쥈\`)a"5iZZU<EAx=cT)[-j1 ˖1C@GT> *ztDeL@s/Z.p x.Nؼ ݺ]̀/c=g$Z;I[YPZ([mEA^Rmѐ~gg4K9cE@X*$I:kۑ㺮뜪ED$(Љ)JJ)8 E/10D!$-ɰAɀDrpgꙞ!,Zkϝ}frֹDkƑ֚o4+u[oIz Y2 sAk.\oIMYk:֠:1-13瞝!ϟg}.Ra2l1ƫl, ]Lߗ,,cG7q5FWUg6F~XQfjJρ, ~c5)9kA[hxAnL.][GC]W{P7}tc#xR|BͶ ^@HEh[uqӶ8| ?98>xo&^}U˹cAVw1$xlxc&ފl %F z'y7 ʲlU\)+ A69 ] ՗OlֺGMP%@U{*_AH8v/yJ%*FUG>JP׊-?p\6F.qHf^;H)? Z?s%J##%WZ*e" L0'(U]ٸZd왿$c >:ǘl bFZ&8/cvE!?8w$qGgc]x7 >Ay%q[ԕl̉s'fhh5t1m"ސX#|۾xb9ݯIr)t'{ )3NZ* ݿ{w'䅋MF+oxAUAܒo%R"h'{I{ķ?ǷSOÑÇfV˸pg?Yo!}d0>9 ג-ʪlR٩AɧiNmct,JѺT.giR܊z 7wR;ԈJUȋ7_֐9+N'P45l12ezC/GQ:+'ne8|} O;'8o{VV6 co… Ϸ޲dsLNr `Rmntp5H6q4M_p›x?ݾpcrxf6InlJdDBw*nZfaě6F{E1ڥ_?q% |u1&[]+v,je(6YCxWxe]+%o.rCow/K+}/FsVv)KK2"!Y'RlhJd\'p7T82"sI9+7mʉ~"`Űs!*OA&_EX EI8Am_ƍ~:]7nNX}:K-#^>FRY#|d ^!`&D̗ڜR!Ji,]I>t;d"ޑ#9u|gȲ 1jdx +JS e:-#]w{rE47)ߠk[{ы?믿Yctn :?5t}+]m,K{%KMJʙH (p)5/od D1u8llfϱlOY"EoFc4m|h*FcR~#wXØ|v2BmӠq5msLo].;};Y2{xw/OCqݯh?u, iBqf) BG8jl&olҎ$gtX\yf`u1:s ڏ_(jzRYgIDATp'+Q6,>١}'ӶQXgNѣk\r%$ ^*KU|k觰U/ q,q_F#ZZ9s*hEg]X],_2i"H,x\8NgX/Ih8 l)ZN]x7ztpJ{,3߾5^r""p/Y\6I w7e\I$n:Ԑ+E<})k-̔S1uy7ڹzy<:ɲ3\3mcݮ5ۓi;cҥKL:-d¸r.b?z_ KׯYi~=KGSޒ,r4ǯ6Ⴖ/pҝ*2(?3ph; Dtb1  Āp ua&oh?Lhm%mIP7 <N~>kKu8O(*wwX9+Lz+?mkf'Ә% bԷTlZ{I>Mc$L8x-6Fe|G'"9s'Xi8,^ї>`1Z'E@ӍKM~e(e;wD'OkBR@{ײۖ/0( - :qIҚ\?Qβ'|s,ډNim{VNbO+OYu]3JI רX[%N)tF5k}ȠxZ#]MU霞q7{׺шخv3l|t]p%\&:,Hs>V-/j k)pqr-pZkދ;p]u!.]JHr %޷xd?|ActT-Vϸ0:ӝ`gt3OVJT@ 3Lr?H+4FgZ T@f#*G'Lo"Z(2[9JCKS+v;Vӑ4j1|fڥ>'ތ_5F;m-Kagh\:e O[u'xGWnVipnhi/}~ZX:2D8uSaS6%t1Y ytq.֣xh*G{zeAN (SxGXj+F%eĺP7ᬡ5MmQ n"%Vq*XigΜAe/$αjfF^/Sq )]$;)< S OLdvIHTJ2΍d#wR?A PWsHQLvgWN脅1u?IXZмVy`].HNXq}uU*4ms/ҥKA2⍼T~^C)M=b7k/Md\9>N~&\sDT ƥu֍Ä#,xrpmh*$p:9n(gd9qNWjH$ L۠mlѼ} ku_<.ŋ{](')#7a(vtn5}[tyvP'f >βngG1: 87Sya#Hʭs@;99ִFj `Sg%464K,&s^g39&/hT6QXVnQ9'Z7" DwI,s%\.(%LfӶej(AC(ktgNfWnY~s_'oM'80R75+js#G| >P-2mR$Ʉ\ىјdOa` ~"7n|5CI2=>O%Ķ7}e2S򃦭NqrIz("V[_-g5v=͢g={˗rd\J|4OL?(_?| BcCBu~AB,^6'؉ׯ{8ixx7sY6;2e(>Oxl( yܹM]E1$Vjs4FI%'t+)cG9p%>6\BSO=WQ5$}BtU(&d4P7Q",Fpں\15yΪ/ }"[~'\g}Jti91ѭ:}=+oL 8EUuͤIu. xCM*m(Fu < yF$l2Au](K iR م kClxw}I'6Y }ŒV^=uTe͗_zhckGI*&Ay'-ޓǏa<>#ܽ{%$Y`AYUA\ЉFmm%Awy'$t3>xZhN@G,&)(_?!OC|7s =BJhfp[g=UF 94,!hE W\kHt' TYRHcx`9yC8G+*m87.""b]W&0EG,'DD,{ pGiIENDB`fontypython-0.4.4/fontypythonmodules/things/button_charmap.png0000644000175000017500000000127311742276534023616 0ustar donndonnPNG  IHDR CsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<8IDATHNQ/23FM$Di4q>Dߥn&>Aw.441i0jQj?`B% c_2{'{nnrRJ&P~,lj*3q tFow2)%]MeR=.u+x8[s]Y*䗏[R[J)H)ǯlXJ] `},IOE^‚"f5X-󎰘)*~{(J(!-b%X-x]! ZUA zt(6gYskWf,yZuʴPqh֪uB ^w2ý] DW3]äCQ5s7\Y_<%]z1-"imе:j+ҍОesk۟ -,PY;!r('Hefy+Lz{4k',=٘P .9R;9y.]5IENDB`fontypython-0.4.4/fontypythonmodules/things/button_charmap_over.png0000644000175000017500000000145211742276534024650 0ustar donndonnPNG  IHDR CsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<IDATHKa_߭yM_MB}#/%xeۤ*H^$IfQ[gH&r9^<[BQ6O ysUUi06SW;1ᠵ tpFDriIENDB`fontypython-0.4.4/fontypythonmodules/things/clear.png0000644000175000017500000000113511742276534021673 0ustar donndonnPNG  IHDR R|sBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<IDAT(OHqu{]vMz΢DEfKC;^E $0(u/k(]%S%~z{qzNS&D4q\>#kAdEJčͱO3X^a) N²ʘK%}nK]z19ji S\&4)z:=zT*1vu`h 9Ū j0\.3KTMO$ ,,C8DSc#,ۘ\XB.Y/ldi28L|H*Fo޾gu>/Yvb1 $'OH7 e)_N ^^[uYX1W U _y\8&MAE2Ovn7]<IENDB`fontypython-0.4.4/fontypythonmodules/things/cross.png0000644000175000017500000000527211742276534021744 0ustar donndonnPNG  IHDR6@Q>sBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org< 7IDAThy]U%%iB &L RFTep\P5n@ TUtơ)B-J KgR%#Q8(a,YLNo^[~NuwϽ|"FcVW^:Meٕr\,;_ #^O)ܸ9Wj4NK<8Zj7ˉKϼbl$6$N$AVn^ Ul%M&_ 4 c1U'YRb)'Wď@j41G$jAL x$/ aN8bARtb!$uFb]rG$ 1m}$/&~H] q&.Ļ0=xA@z@ 0\\qJnY3 4jnĘø%e lTψL"~ȓĵm, Q(WlFwo?Yb>2VĄT:<@Y%nx?s1 !fiʙ\s颧r%5Ex&Q|_Z*fY$liL?™cl?1x(72699+WSn}#`Ď"f[pf-GRR'8m)>4"I ٯ {7<؆wqfv7J,,ܕeF u e;?x F;i/󷓹ukd lԯ^@ `/6 3y ObNvEuQbSܿ5~lj] i<NJ!@v+M?{yb>D, &YcAp 0M,0 ?üZ&vmK,KZ%E8rKtQlS/ ;Ip ETH;(P8m&iok,ber{0 ~nâ1lK]n]fDV#ĚZ]Jyo?|"SìMrZe+v@QqYv .v+bm5i~O-`J'eZ]n't]Ų;"{z>7jpKTuXy4k,BW:➁ UEHvig̨RbWA*>ǣ9$TuX>]ƺ{+9UlXo*d(]%^ּWDn8?/i`7Z#S} |)2XH"RN=Yr׋ eYlURsU"MHE$nd8zLnE!}k&Ԫ@9oa&sfZ#OT{EQVksZ.U+Xe5|bW 'nݪZ$׃}{\UUM,NZ7DIѶ 12rr]X%pⓢP1vcϳSr]&}o?ϝeʺVؼzo|$2avD4eu_I~>gaG21Uq_)'[|P )Yʲz<KQMbK6%- *GD?p`4$~5z aȰ̿nTNǥ|~KdS e8HAc$ar/7_F"ew7Ă-k̓4rm͊#*H=bEs;r`ȿ *5!qK# ˢXAh@D"rLśX+LlSJ)˲^w7~ -bVe^l:k˲RJzD`Df/5֐AD0*om+F{QqBm+|\݂xnʚ?_l,fS,ʍMLjDGƺERJ;1B`hw ?,EhvIENDB`fontypython-0.4.4/fontypythonmodules/things/font_cannot_draw.png0000644000175000017500000000122711742276534024134 0ustar donndonnPNG  IHDR szzsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<IDATX՗=kQ`#)- 0X "6"~D)RؤBDmDD pY;_K^8̝{}{=a**@_w_`q`p= YdOsbJ²;=&BQ2 ľ!-iU~BjKSC1[ R%$o ST+ɚꎘ:# @W0 OdVt,`H <{!A7j eu} ZUS[Tow" z`Y' ';6Bov`1l4ƏZdǀg_+2ƜV :@-z],4y#*F[YtD֣qgF=%`L0Robo@ؘ% ؘ%u VFRDTv׸nB 2NU(4*uA3heN&^EYZ ̤VFN;` 0Hȉe1wuŅTiedSVqgYǑM[]*!مYQ_<5Z\`[Ֆe5wS|>"I>~*+bq.]aE|\޳8$&c֬~q=>3DGK<_y(N}%34=>G~{g3^Յ:3 p~@Qkh즫;+#f֮}glMM-ci><%\Nd<اHj-Zf1̾T/t,?{| _QP0c6v+vJn(=t5joѷW?5ʎZ72O/ iZRxJ$bO}RR2/2V?VM$ ??w . $̝rJXDD_!ž4gd -ZPYi~'#Y,[?n_ats:G>oI &5"I 6e ǎZGRB]!fIENDB`fontypython-0.4.4/fontypythonmodules/things/font_not_found.png0000644000175000017500000000113711742276534023630 0ustar donndonnPNG  IHDR szzsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<IDATXŖ=kA BZ5DAP b^[UUBċ!`WA}lww)y9;sv-Tۀs1`b(X{FFخ^Qmuz0n#~X}!\PU)ou6nM ~J]L8"DĵjHD}GгǫDd|P `n,D}܀כ*A&յJ}Aϸ)jOa[0\&KwωcCDbWɳvrFozwPn7WG@z]Mw MgGkji` IG*ϫm | T/GMі ,S`&p6t1,a%}`gM-I H_ft8_ \OOrŻf` E]O.ƭIENDB`fontypython-0.4.4/fontypythonmodules/things/font_segfault.png0000644000175000017500000000125211742276534023445 0ustar donndonnPNG  IHDR szzsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<'IDATXŗkA?+kaI1*eB`! je#"4QQtCH`<|Ⴡ7}$?qM 0 |6%ے*F=VRS%&Xv`.=sLtidWA?mszX{CN%  C\ꑹmaq'X(u`nXZjLڂv+ǁɦ3kXԢ9-i'4hDZcTI%]ap6%MK:!霤}J{FDzp'> +7d[p6Z# U9p?Y>a0"5:R kIG=I OaAR_+<k],":2Q[ȢR$@p*Dx8v-0\%y\ eD]*~JL ,f4_SD :~vvCIENDB`fontypython-0.4.4/fontypythonmodules/things/fplogo.png0000644000175000017500000000264611742276534022103 0ustar donndonnPNG  IHDR szzsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<#IDATXŗ[Lg]亰 ʥ DlkVKч>6hoIUӴ6-iFMIKBrr[dXv>첲67?9|e P˕VyRԼCD11¬Ӊ1J(54$Sc݁ٔNZr">ۭ0>`htƖwGmJa^k?n( ’G $FFvn+fSw:QYjj+;xaQx"LސւȲ̷΅ub<MMo0t1ݒ@NPQx!ݻ+/#I9 J0d~`y ؼ1 k׮ p$Iby;Z$I < iqDA ;3UUiii P]] 7~ahY|m 7g3 #-I?@fz:p8B:0lXp&h4϶aSf:@ Vr͙4Gկh$>y Am I@N +,, шZbeeEYv[gHdA`jfe;xS__'8|}݀[Ql4yh|ҳžF!Ąx&''hUl6C#Qnoh 7FCyY#ҍdoD{`5())`0@ "]^L|5?rEݳX} 7iӓMTdY#j* # ɘF~,9|odqi ;ӄ(`w R܊‘ "z>I|6h݊owZ։~>59foFHZ*o:keQ^wpށa>`z.eF`uuUU\,K,\A<Ȅ4G@w='GzDc2Ӣ( W๤vGuX$QYY`ht%ʮ@_̜3zv G+*li 5wHpIENDB`fontypython-0.4.4/fontypythonmodules/things/icon_cdrom.png0000644000175000017500000000122711742276534022723 0ustar donndonnPNG  IHDRasBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<IDAT8kaǿ&%9.T\2BAICd1tp29RZS&E!Kdq ė3鎜<w)ɜϿ'=xj/iڀ u>YF X4byw57>"+?/_-a+5 }M#?~Z~N l=陣Xza89=[xAVnj{ckk<3J16#14[mO,&aMk2g+jnw'KW\2gVN#,bp66ԕn1e3u,b4>YcSr-T>Yƽi @H'PlG z;Q?}Z7 B:O=R,ybi)~ ?IENDB`fontypython-0.4.4/fontypythonmodules/things/icon_drive.png0000644000175000017500000000067511742276534022736 0ustar donndonnPNG  IHDRasBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<:IDAT8JAE̎l2: 5~@`m"?`c/$&MD Xٸ%3fY1iܹoH@s B3IlZ6 @̌fM5|֬d: L60D007ZtC x>0a:VWJ͜X,սݝRDwf"Rhp8Y_G*)"Qn "8ha/X}O03̙ORJ Qrk]lֺ~l̨ OU\ވ6zZ>J]gZF[QLIENDB`fontypython-0.4.4/fontypythonmodules/things/icon_open_folder.png0000644000175000017500000000071011742276534024107 0ustar donndonnPNG  IHDRasBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<EIDAT8NQϽ, Q*5+G6E* |BC16DJpwcY{?ѐ —L7͙bIŽ*) R*#j?ߝi ŵuU?m\mB$e2=i*\z6t*l_#պQV{5@HI5ƫJ9y^_bv祋 e+Aai4\_$!V A2V*- ~mB1xQtN G6z?B4r\auqxZTi@ĂeSVnA09Hżhx{V_ĸ `ٔ4vIENDB`fontypython-0.4.4/fontypythonmodules/things/icon_root.png0000644000175000017500000000071411742276534022602 0ustar donndonnPNG  IHDRasBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<IIDAT8=KBqƟsL4% D-4G5Ej/P ypQ(4? E08=encH%P_:+`uy`zH%PYY;`xmQGcsAjjԤkT[124rש GKP+_ 뛐Rbb|\/)ӲIA(PU d>z{|> G!hOp{w_VT8"c8&D# !$4twu?#6IENDB`fontypython-0.4.4/fontypythonmodules/things/icon_source_folder_16x16.png0000644000175000017500000000111011742276534025306 0ustar donndonnPNG  IHDRasBIT|dtEXtSoftwarewww.inkscape.org<IDAT8jawɌ6mDd@,o@Z((R](^ Tx 7B;p%x٤Z\2͸ws΁}{giB bM#!q-5.O3̜9s~Lp{?BQVZT k y&1iDq4$laHBzlRשP#D8pYCi$"J VsTͥ;s[˷y8x%ǣ¦Hz#"+4[ fiUaj1% 7 60NNՇH } :i@[+T= ʁkUtWr+fP5O@Uv"df{hkmA6kP5 eh)&1յg5 H PX 0 mH@J<>;WeYe$YK82yFVB@`ԅ7߁.:K(Ǡ2B<߈?М b@v`WJ,Z)tl'0=_RpP4eLe}75V?$nHHZ0h&r]κ-q $Zkca&Ȳ Y4fژ`4IENDB`fontypython-0.4.4/fontypythonmodules/things/pog16x16.png0000644000175000017500000000120311742276534022074 0ustar donndonnPNG  IHDRasBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<IDAT8NQ{si3i(w!aG >/Cؚhb؉qNKig.@ BIr'{Y뇵@ѻ \RݵϞ-1~NK}Njь"Z69o6Lb/^ 76 q̽p iZ~Qã?ڲ96ϑL&FxZ"2՘ (| ^(4uktsK,!AP,si:X v{KaHme0RK9&XuOaZj.$3fԼX()% VWE}ZK!PJEqsh<^_G)uswdYFfLӔd1 ?xwp0!zCW{11шy _}C!z䮫JM [(;Rg-9] IENDB`fontypython-0.4.4/fontypythonmodules/things/pog16x16.target.png0000644000175000017500000000151711742276534023371 0ustar donndonnPNG  IHDRasBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<IDAT8Uk\Us;i4&]tjRid-n\8_dѥ YJ6 2 Rm86eLGfr̝yn溘Sp΁D և|Q4dX2zӡ0dt{tERyq~eПxWB93jNXۉ|1gXrb!lyq^+B8gCDE0& ^P ~~p |yq^ 犛녙~5<padF^|Uһ~۬qMrv1:_Wsk= 0@R , ty3|囷oi(*Z33JcYPxtNMJq4#VBb `H2*P*@ӝ}]L[mĄ๺K56 O(_])l R0,+C3"Y|dJ,3algDSB]T6^[Uen{S6JŁ*kuRY{뇇mOʥ{woҎ{#S#u8Y:_wwNvvSڃ:@'1 'G;cy{|&H =W?vvgډtgxf<ђq lЬtX{әv ݺ㻕.X?HU)@IENDB`fontypython-0.4.4/fontypythonmodules/things/splash.png0000644000175000017500000007436711742276534022120 0ustar donndonnPNG  IHDR(jsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org< IDATxi\y&|Yw*R\@ZHe)-iʑJr*dRΏd2eO2glٱGTTy-mI HN$! "}/?[N^Su}>wye4hР9mtپӠA!f<҃E=~%A h(NP5k'Q9 m ߵq+c'NHoW`4h-~i5ԠAx/x RXNEgN+@i^lРO24gs~鳸q.r7A%ݙ1wc{ 4x 8N%ݺ[65ԠAucعeӢY/ 4hp9Xc$,M XjРA)4Y VAŸa \oA5z;' A5XVF8WwlKTCd>&(3W퇅jW$Aȳ ! gv hcAl3.ʲ0?pjnH*`ǂepes9F06{ΞÙ PU|PՐzaaZ4ӺqI;-ٱ [6ald18~8y<3xW_&''1== >ZhjdFM/{<0`dh۰glƱQqˍZ7q9|v 0GP dNLA$Ak,Mpݮػs;6E#Gx"zgsarjjNd.,c1OU+$}7ތtZ$e`mo2ʲ›/K0xJޝqa.lۼ6o¶͛;n˯ϼx '!cɊW Q]>VIZC][7];}&_,VJ{>_C=48Bp8ٟ3udJq-KXJR`000 4gZyw=݌[ߋ#!?\rHCT냦 5,]߂1Oo|o',9\J$B@H )%RB& 8cdt]p,&Mފ%10Z9( Jh%,M?%{x+شq }ط{'މgԹ\@T¾>)`_c!b5(ԠޒZC ;oOL??>= d"!"r5VT(xM ׉in{-hlc?|;>ɲ̒P,ϑg,CF'I,K)Cp8gnCdA&M[icJ86*2ƥxI)Ȫ*{n6 GLJmF'jHjXM&֡`>p/o:/+zY!2Z-Z-;+,GH"2̦n\ יR8n86Ϣ\!QKEVFk @i#H,+eFNYK ePTR)ye:wW4KPU:Et94p%HF* $2A" t{]^%J_bjfz՗11=LU0T N&TI~F"%~]=;ַEHV @!  jn!r$-K!,) ݶkS-Rc|dAkPKp(E50YR[66K'7`065dh00]9bB KPAH)+D@ .zV2QT{c&پO4ʦZ0!%lYER IԠLS ~RM|RJTnw:0@3N4ϑIduLIp"E1oD`ː @ (J<\:疠jq &t@E&Qt˶0`BHwspc_{|??JUк ɠoSZ{kCkvG $o~ۿ;$ԑk۞GF0<4AV&WcBBH5 L\:Y"|n4gұP _A @ ơ c>2a,`b+TH8Ӷ8&Ce<SxOAk L`>[o#ռWZk޶9Ǒ#G|'OD[- P42: c3Vm5MY&nĕ .CAzǯ჏Cy_6Nc=iFԻ~iLs A~q 6 }ڏ`K[r.9I Ja]A]-hi?AdiGӟ'N!KN## :$LS?KE$t'(GPAʹBxTQj dy{/g\&T- e6%'&~2p#3ڦyܒ3*ԍڎT'/|=,ݟ|>(  &՛AI\>A tp'>idYfSaalֵmdk2H /wQZG5'7XsF:#s g _#e~~Vk4׵:cwC#b0 M&OS-|p # tAJiBUhy6m;G}.~^ `LXToXtԥ!{efffO} o'lۀ c>rju:,GM[GP>b ]:>4ͽ}^l9CŒ1$i`Q6uhip3C6cL0Ts3>3fv 6@$2*Q|%6|x䰕jxyE",rXmy8{wBkʯ駟FehZƆ1mڤ)SKi(*'g1/tKN DϪf 4/| e3W@AY¢ږ4(W+@ 4*"M+Je4yY6YUy, \ gg,AcY'-%g R Ha ʺV8`ǎ(z=zz9HQ)DRA9FŻ`߃4IpY([g I"!9L99sz{nfcgvC!Ʃ]VFS䭁QKq>r8caEHUb3Ţ 0ھg.4Iistco^-αsv~4C/"+Z(K9)PL!4.}ZcQ ˿*q :i2h/\HktB'|DDZHh R$Rs|WjCq;c !BPE3V`Or`n˪A]Qʪ¥I bϞx EeQP9D*@H`J5.޵ |30;188,MILB`]-(HI{BҴh@)UU.m>Ă2m^E&Y#=ZBkiBc *üȓ+knXs !eݹ 0:4}KHEA_%"Ot`-Jf,kja ~7~1IbGY14mIZ- `phvY+ÿND׶v3ڍ"'wi*=9)eiLML`b|.cjj ^ -2;PC E&nCr -bFw!v^ZfU-bVGH{*MMM4N9ү5-3Fk듮-qqhjPW `ώm췾m! oYmdE8~yԞ?M4Mk==LMŋ8.\ ]M*qWcrrzտ P.$$yAJj'Ҽ!10hkl+թGibԧ&jxUEç 3 005,JP 8~ {=^}Un30vڦ8 xιXD'%ȵd*YLOŋy;wSS[}7\ƐmV|1::zb$5x33"!b"nn܇l6b8)̽Uy j!Ҫ?ʉ\͹6jj˷x=sm_wJE+.rpgjDLIBU(z]LMMazr.]%s,3ra/\LQf;d$5 H0z\+CǔO>4@x?JkE]'u4ҶؠH~U`sV t=o IYq)!(sU Gu 1om bvfSSӘ߁_g{1:ugϞEUUR (nV<{J+H$t 6l4ɬiLpUٳPc!m_ڷFPSSySKRFOFZQ@%"BMӼ_mǏ^>Z5: Z_g8:gɥwT(OۉqnɈһ f,!X4z2a(aI qqAu=zpۭxFFbk# -xykbDbzkgBpFK x )00Ie]&Wcc/xçcrŋ*lXOU?%jP ٱ P%|I+/2Y,ͬ扢*#wd '.0N[yY:(zR Kxaj˼By0x%tg^'8Oe DR,*~yА-ԲS9]`Lvv^zؼm`.mMA#z nvۺ*4M|zg"Ee};j̠W(p~`dXR>}ֺg>ǧς1ac aUQDR{Fc"=;(Gڏ lټsqnHj/iPGA]a{=?,CFu'sNt=s{eA ⺈UWn@$:p?9-L$ٽuWp"RxHy3s]:gL۷5(=4B_Αc++uAhuQ+d%,o"b f ;njOD"KSKNR9.>B;|r]\hM O%$m6ť4{%r ns06%\JL @Ə՞?㖼#K]G*VCc"%{L̾zȲ9DPWZ{z2% 4q+;6+OckNd' UPi^h-a.zrwPþ "KHQj05k:&yh\@CPW{wnORi4ϑ"D//  5[fY( =)p<[PḨyvI>bHo ՋA"9g)f^;|*~GC]OZAily٪/g'T[O2 贬^ÇSF靐F1[+?/ ^PJU(5+Kt1yE2i4B<ːɺBy"dٹ_wc4߽;7~a%a6}x>rpzGmzG,I#O/^5OTqPegweUhva6#^VKs=0Ơȑ#Զw'`,s"ykٱ @,pE<*J"Pan˂r+E18Oa;MSJᥗ_Eu6| ,m7X#ӓO>^Ii<vKlm$|d ٓh0B.neQ``'@Y4IrrD҅iXwlQgO}ףLF_כZȏ!zw]ṋ@5XMu%?9&.kǞJ\tG<`(Oؚy+m?ןo)H.&cQeT5ԉS퀰H@"9DRX~Cπ+M肺 ;x@ړDA5yH!kgN LB)*U}Hb-'rDEr|DqӍ78x(ԟHu|\+*H-Hyq[ TSNjZ޹7PJ65 JE:xTvQjP8A-Zgh۷n{,ol7 좧Pw ~ETf[\܀T18LBRщRӲt=i}3gmTG-NPh* !騃l"W 1n#{fӪl4˸pBYjO2ؔ)gj'6I >.l^ Qs+ԟt@8h)rZZc϶-` x%vҦxRJ/5Y )Y˨%5uƆ+ /]j.B]Ġ-M j :th΀p9~yAއB+2"X~9hCq𝳾I Hg1ZuдipH`"rp&ysnޅ͛..b _.\g ynZyE 2sA*>d4&\zOM3lXF.ph:xK ' EZA5@LiNEu$E({)y1IFtN9g  @"$4Agy" `B& =_Fc !9: iumFرsDCq10{HĦlj݂#$yKwl/q 7RmJۮV7o@i:!u lngyXiBǹ0hAҲ%:tld o`F(UU2ʵ!M[cxbT's`ֵ@=+l΃8~IGQC4tcu@ xc]SMohjw ?(v'$e;=`(*03:Ld eU@)KNn]Ncט]OW,vyp3# t;BOXح7h\Owݺu ]٦*4^OpB䉔[1DwX/p*'6Y@k["ZMu=gpDSj_Z!ū+pVK)PVIstpÃ}SgĭMZ# .n-[xd!Z6\ͅqk3 ?}e5dG=p=d'tQ#]g?}k# ZZnTd߻q|q> @ ʪBYK{o8y$y/ቺ_VCR+BCPk  繍L8}k~cUkIAݗM'\\NJqGlX}!gBj(cl4I heJ(zU ۍA?庼`%~ VN^pG?' Ԧx5LMCr\fik&V{LKs"k嫧:c(Qmw2@[kO0`nQz?n;L}1|G!%2E~ vq| 4*B5[1x~( *LJeup+]ڜ +cBh]Sw߉!}_u: N; ;As7\vuqY̕WǑ#.3dgPV EYagwn[/|\jb4Z 96o®@.8@D5'?(7 `: QddVg@_hn}P+PV {$eY_*D"H%):DN+F!4ݴmff>lh.]ÎHiU~=+Eҹ?i޵'I>'8#Bf}*蝴! EY+03EE( {cǎQDL e 8rr)^:҄՟ͼa@8mpCԄ2ʑ`H|AEz]l:({G8i M!\Zb\kM:J봂R+~YRzw]x}`#=ц9w$j4բ!DAa@8C&ui|\Bl8JtMa]8%:AN G+ACɭ$GJQԱLY!fai.f{=ؼ s`;ԧPUX!m-^Mȟ~"!kѤwрn~t .2lwTw&yv~044Z\-_ZAd47y[ -1FC+"0m}QA|unwApO=' rRy,JP(Ƙj] A 3 agopzsyi Ud):{ &,r͓j~ 4j9ԕ9Rr; P]BQV(D(0;C($ȇ}&?~xJqON/Ȋ5:MWi ]U |w*+4 e6 nnio6"&&ƉX0)2dY yVV=VBjY}C^[ 4IdYf7dP't @ɰT] u3ge@;^nKV"ZPs혙.q/S4MuafS9I9*QgNѮ:]n߲yl^\GSz=|_ܹ)]9EN%vc#sbS@?/4͐2<'Җ->r!5CCP 9vomblT}u(`T(*.r2EEY;EwvxϻeOu}Gy||/2z)<3xѣ(ҿgV:$VD"0F[-'|ax6\viif'~O8}Rhjp}YLMM!IhQf]LNNBklvoQsR˜w3+.sP.&&099Yw{yLOSF@Z0wf#'UWJd\2kCCPh:t@=jr433GQ̷(&1;;;x߅1g" Rk^5uԐO4Z)"G4ʲ 1je`uɦbTX䳳Z^>t*o;OڑGg $Z!F04Ġ,KcP). ֻ淟ꥪwt|!\BJj|[rjp5 Om_p>'~c7 I˛@P$EV 3kmj!s+5N`#&4vgݪBUޞיJy1C-q_߽[)_ Oܦw|ʍڠ5Vwj. ᄎ (\6/}k7""O"&\CCP+MbGF!ԟKҾ`6Z[Lx JGw;p3DNMZCCP?=9qZ*UeLFzՈY@o2 xKnm5VC(VH8HZIHZi=e2Z 6 95fJI\pM(z׉x@[x]bkDJ tg)!+Kt{.MN'kNPYX;TܭaNӓRʺK*LLM(zN+ǎ-03ũsoBC*I` KsAs{l.!5M yb-8:niH$0=S/&FQU.Nٮ9A]{Ɔ,,N,qa|, N="e!b__c- wIusDEMS t/դ!5@ݰ o;m\Gv=V=yHYHݰs)hq%c09=DH bj& M aޙȑK{EIeZF d `0d]|/}0|ɀl-$yMhF3ClYYYQE6L@̈ţ %OO)DJ8^(/qyqT2Al8~yW͓EoxKeDAd ,RGK%HƢa¥yMVd,0!0"i:xD ewtTR ..md?}VEIDH3@ s@1"Ak?, |> àZoPk4䎨7ڟ"t4 sxD+#Si($i:~FY5u`~jEBܾ׃$I݅v!LdajV^.D݃rx:I:jI"STdk⎧}>>K37TMJЕ? EO'fUڷ4AKSv%" iw:n<1 *jRWp2/vN #aol #f~jǛd 7%SI7 IɱS8'vm=d-Av1NTU6~vGEvQU eO잷0 WDT]EQd$'R0Md4')q${ann` H@qE>8*8^Td4BfekD4KK4˓DӄىQF e֪Hƭ8 vIl3tx ow."~JK$ى1[8Xs0#avwxDӱ4ZYvhy<1~;{:8pljtvC: "f EmMGEn`x./+;}0?Qx8aHa|"iRk4 @ 9 Gar4ͨ#"\˅CހkϿ~EA喐AgyE[Hꆁ4(rId4;0 +k[o,179QD<̌ ,M%)(X\ix n Dz(JfBPo4g< i4ӱ I Ve$Q$47C,bk-4ݚ(2L ȗ*DCA3YI^r Yvl8I'bLIĨ5Tju&XyTUe0pui_ye^/[;lg0cRzy=n7Xd,›/}J^6GXRq#DÖ }˧ 'E"! F|ZHZm[6XT.Q4XHkXҢyIGkɕGU`ʇWQuKsӜfnx'Y&W(. Pp󣇶FToݯ ӓ~[%U4 ݺCZXzNf4Ks322;9F} Osa~1Lqnf?o)^G^>[Kiڶk&q 23q2hbJER ey.-̢:`}.bqwbj/r1Ί, O: KMDQThH'b$t_mf'm%yY޳y;4%0шmfCei^E+=fxwp\LxUM;+y׮01S14wG &G©׶TZt7P/mBK5Slg]!#S(UpBzE wߗσdo G,az,ing[C(j&ѻ,ol}aBuFuAچ{=7 KO?&9* :WXӄt0_d07k_ֽ1y+LoL;QB)wj&,۴AW8?U4KP4JU,2$l=-yA(ݨ~enDnS e4FAX062dQ2[k5TmM趣\v&K`sĦJPIDATׯ$>`?ԿM@{⫯x~QmGLݔ*UǎMwɗtT+}"ϋGVPZ_cq2@$)n7B7gjɟ썵$Iq%I=K}DpAC:VfsVHiKѠǼ||Tfy}WP.# bP Y* /+jB7$X|`]^ |oo}Cn\^Q&;b<}M t"> tCxtCG /_…89*0t㑰5}j B O?[́[Mv9:]n2>e4[mVZR=*iVL.pcKbvdPd˲Ly=$T6 ѰcrV =`y= UC-l xMrσ:n}^ϳ{K3W&V\~S#-h?u=0Լ5y144к=,|(Ob'hqoeG[2%G[$*`hp0"!wgyԂC*e}֊>!d,k:эS;H Mȓ=OSi~ 4ns2M8x2m9iH5] "<;_N0;܌er''[᠉91Cx]. UT4ꍆ5샃8;yH8`G둏O|ݭ)OWOr6p:VU 0An@K>앵I-nile>1l5M;w=NK.л~,ׯE O޿jsC<1-@6v}PN`~jW^|?0_$W>v4.-bBaOq=Sk4l_u7vbt]|}\I)KvOv]TS}sX^˓+r{phkRvb>[m Qd7Xt` %}/s h`=>DoI:4&>vt&b Bq`OQQC z܏PDuISC^? vvnK%LSyB{M&P#'WM n0y<<=^:i O';m:Z;VxiL4MB뤢2le8 ԏ$9~f`Mc$XĹx= pudG0O$:5C:aq|a/]|g'ƭеgyZ# 'ﱛ=th9ZNGpe͞<AISw:*VA`h>($FZJ9=j4w942'ZMԹH s\C9^x s#R=aO̹iIɁ0MS98a ~,-:GD/tnIyb$@Wy= ^X1k㣨f/l'KHtfYoy9}xp@K/WkB4vHX8Dݦhe>|L!9lOiAvG/2[+QA_ﱶW(u(0L`&bߒy"|abbDߠǬ NGcaI//s"xQ(WlegŊIŝJvY/iKe]xcwt=&hK/:Hdy%PUh/zRF<2h\>7O n9KsD*iOFkl]ZC((by d7ٮja+넃k.st ZRm_esw4$!",QχJ۴d% 6򏥒|ƋgYڦX*7K%6߽aΞCa@8/F0 XJ_[CH̑dlX/^gH"1۷)zPd7^G+<CGy>Zv&h8T8=\`m{B$zc֐"x=  #ֻ0!vM%v rlU /UN .;ArI©PuL%4a HƢdrT@"! @h(,G;چCy=N,>͗qiqcv (Ck_/쳾hO)vt õ Z߇K0LLi:jb@^'z,;Y6zdth4[TjuzA98T$Qģ3;޿s?oir~nDJbnڨGQ촢\+d:j#,[:za=^6za4 *:6x+]&Bviw:,onrIG/G5߾O;`!|A?X)~¡5()U*:* PTQ;t]'rxǣ(LxjF@\tRwzB)w=h v3Y=izmW_{_~%|Tep}aE6֩v8P H&vis];n^'uWB&/4;=eW o:5w$YoS;{?rD"MQZZm* ;BbѨB +Lݡiۭ89>F8 K7l᷿k>7xûO{|;o;1N<o7n(=Zs70k:f Coo(ne24MFi:fP9qFizx#A[cR7ީ. QZa>{le2n7con b~?c$cJBv q$LDnz;vVm85U8*ȟX\EQ$3-R*z|~{Q<)H?mF5,oU\k41UVliFբ BA`E&#$5%Ihw`%?hmRpblu`go8_P /rٴ430(+,9KݦjQT&G?:J0p~<ً l2OVC3s2Y2+՟«5 2{˫4 gOTo49*渿)llE`rl{v3=Xɶv0N^I  _ /]`iWo6pƐKv}eJcmP,R(:W <OaK2!Cj6y8*e+}ȴ4Z*:JvҾZFʕ9՜$ 9 Lf-ΠizA`qn9iڄÕ< /:Uos3<óyL<'K%n7i0Nq^@ޠjYo~x,_D{яjj֞h6W)v3 *ԩJ$ xZlmQ<>>Sא$k ]7tzAXB&ϝ791amPqc'V8zK֜SUH:Sk+LOMzu&FFnv391N<CuVVVе(ʤV @=pdwu Ec2N:mR$hP0H,jmT j9~.M8nNYfum empa$PtxGOP$R*iџs ]g(*H$6X QjN( E gA* =pg8óO=uI>^g8 Ks,ZudB_ѿiܼSc:pO f~r/\y )g%p3<🰔%+?{z!3 gtkc:p _(@^NIENDB`fontypython-0.4.4/fontypythonmodules/things/tick.png0000644000175000017500000000422611742276534021543 0ustar donndonnPNG  IHDR=?SsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<IDATh{Uv[rQP4E?R4^0FŨ 4bT@$k5k@J)-vٖ^xlgwwx\/J5^&tJ?v҇^ެ `& tJ_MrkG8a% 3S?kʔ~-W6 mbY.)foލ{ņ`COiVn,"4C쌎-4&ui h>|Gv.@tK9؟~7j*-K"&2ai0)cNn'5w:~ڨV]k[*bǾԌqچH,^xv}Ǖ:ގ[wi!45)}} ?Ig5f6j˓+c*DN0=u=5e4]X_ur^zOiA†SYXWo9o e mc{T2WJĴ_&*+ʛB-w6iܶpޜ{ߺzz%E1`%:qKS:Ϭ:j#Ǎ4p0)]6| nJbV7|Y${D(z@tg人<)j_ӻ+,vOV^݌-=_ZR;4}OT*jEMX;.{MBK'Sy[J'!~3gTYrVuo] t70rg#gpx?Ǒd$,]Xu}ӺG+K˝1kܓ)h{o#C<\#^3j?< )u+#bׄ\OՖN|7X}KJOJ ngH) +ozQL5RmPS+V\οJE{b`\.<;jUVCby/9mJKDžVf?Y*sN)'_f^>Js9gTrGeܬsΥNAz=|}z",6Z.4]G8{Bz |cRx/Axq_ό9~gwИ.J™D:21=^bo"y3IENDB`fontypython-0.4.4/fontypythonmodules/things/ticksmall.png0000644000175000017500000000064711742276534022577 0ustar donndonnPNG  IHDRasBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<$IDAT8ұJ\A^$`Z yt [ .\y%@^@$! a,W9gsLRU,&Nb1nFxCBkAU_2C:[ 5V.>|/?B ~ wRŇ\IlŐ~#F+qQ-+ ߟRoDBOq013,o`-;AbHY򧑻I+A\` 96,ʒOu1Yo#xZ?IENDB`fontypython-0.4.4/fontypythonmodules/things/view16x16.png0000644000175000017500000000111611742276534022264 0ustar donndonnPNG  IHDRasBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<IDAT8KQƿ;Z "MMpەXDjUAAE+H5,.օPh5؍BEfZ@b EDp~|%?)l6zPcBHTvdo?V0M$Ir#kƆHnu3ΒIs +*}) JGNȲ1EfQZR⸧/Vu۳> `Z36k!agG. ## fpsys : fonty python system. ## I debated calling it fpglobals. ## This is a common-ground for variables and defs that will be used from ## other modules - so they are global to everything. import os, subprocess, errno class CharMapApp(object): ''' Base class for whatever character viewer apps I may support. ''' def __init__( self, appname ): self.appname = appname self.is_installed = self.do_i_exist() def do_i_exist( self ): for path in os.environ.get('PATH', '').split(':'): if os.path.exists(os.path.join(path, self.appname)) and \ not os.path.isdir(os.path.join(path, self.appname)): return True return False def OpenApp( self, *args ): pass def Cleanup( self ): pass def Run( self, cmd ): proc = subprocess.Popen( cmd, shell=False ) ## gucharmap: Fonty actually holds still and waits here until gucharmap is closed. ## kfontview: Fonty just runs-through. kfontview is a different beast. ## Both still work and Fonty stays active. Multiple instances of the viewers can be opened! proc.wait() class Gucharmap( CharMapApp ): ''' The wiring needed to support gucharmap. It requires a dodge before and after spawning the app -- one must temporarily install the font to be viewed and then remove it again afterwards. ''' def OpenApp( self, *args ): src=args[0] dest=args[1] self.dest = dest fam=args[2] sz=args[3] cmd = [ self.appname, u'--font=%s, %s' % (fam, sz)] ## gucharmap requires the font to be installed already, so fake it: self.already_installed = False try: os.symlink( src, dest ) except OSError, detail: if detail.errno != errno.EEXIST: # Not EEXIST means the link failed, don't open the charmap return False else: # Error EEXIST: file exists. # User may have installed it previously (or something). self.already_installed = True self.Run( cmd ) def Cleanup( self ): # Remove the fake installed font -- if it's a candidate: if not self.already_installed: try: os.unlink( self.dest ) except: # What to do? Start yelling? Nah... pass class Kfontview( CharMapApp ): ''' Wiring for kfontview -- really easy to use. ''' def OpenApp( self, *args ): url=args[0] cmd = [ self.appname, u'%s' % url] self.Run( cmd ) ## Oct 2009 class CharMapController(object): ''' Control the character map viewing objects (above) that Fonty supports. UNSET is always the initial "chosen app" when this instantiates. ''' def __init__( self, config_callback ): self.config_callback = config_callback SUPPORTED_CHAR_MAP_APPS = { "gucharmap":Gucharmap, "kfontview":Kfontview } ## Which of the supported apps are actually available? self.AVAILABLE_APP_DICT = {} for appname, klass in SUPPORTED_CHAR_MAP_APPS.iteritems(): ## Instantiate an app class: i = klass( appname ) if i.is_installed: self.AVAILABLE_APP_DICT[appname] = i ## Flag to signify if there are available apps to use. self.APPS_ARE_AVAILABLE = False if len(self.AVAILABLE_APP_DICT) == 0 else True self.__CURRENT_APPNAME = "UNSET" self.QUICK_APPNAME_LIST = self.AVAILABLE_APP_DICT.keys() def SET_CURRENT_APPNAME(self, x): ## If the new name (x) is UNSET or some appname that is not available ## then give x a new value of the first thing in the list of what is ## actually available. if x not in self.QUICK_APPNAME_LIST and self.APPS_ARE_AVAILABLE: x = self.QUICK_APPNAME_LIST[0] self.__CURRENT_APPNAME = x ## It's possible that x is "UNSET" self.config_callback( x ) ## go set the config's app_char_map var too. def GET_CURRENT_APPNAME( self ): ''' This is only called when APPS_ARE_AVAILABLE is True: See dialogues.py Think of this as raising an error if APPS_ARE_AVAILABLE is False! ''' if self.__CURRENT_APPNAME == "UNSET": x = self.QUICK_APPNAME_LIST[0] return x else: return self.__CURRENT_APPNAME def GetInstance( self ): ''' This is only called when APPS_ARE_AVAILABLE is True: See gui_Fitmap.py in can_have_button method. Think of this as raising an error if APPS_ARE_AVAILABLE is False! ''' ## Fetch an instance from my dict return self.AVAILABLE_APP_DICT[ self.__CURRENT_APPNAME ] fontypython-0.4.4/fontypythonmodules/cli.py0000644000175000017500000003133111742276540017722 0ustar donndonn## Fonty Python Copyright (C) 2006, 2007, 2008, 2009 Donn.C.Ingle ## Contact: donn.ingle@gmail.com - I hope this email lasts. ## ## This file is part of Fonty Python. ## Fonty Python 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. ## ## Fonty Python 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 Fonty Python. If not, see . import sys, locale, os import strings import pathcontrol import fpsys import fontybugs import fontcontrol ## replaced optparse with this one because optparse chokes on ## Unicode strings. import getopt class options(object): """ Imitate the previous optparse 'options' thing that could not handle unicode properly, coz I've got all this code written and don't want to hack it. """ list = False points = None numinpage = None text = None purge = False install = None uninstall = None check = False all = None allrecurse = None zip = None ## If non-ascii chars get entered on the cli, say a Japanese word for ## a pog's name, we may have a problem. ## So, I am going to (try to) decode those byte strings into Unicode first: tmp = [] for a in sys.argv[1:]: ## It seems that a is always a BYTE STRING, but I'll just test anyway: #print [a] if type(a) is str: ## This happens when text is PASTED onto the cli when that cli ## is in a LANG that can't handle that text. ## I don't know what other cases may cause this. try: a = fpsys.LSP.to_unicode( a ) except: print _(u"I can't decode your argument(s). Please check your LANG variable. Also, don't paste text, type it in.") raise SystemExit tmp.append(a) uargs = tmp try: opts, args = getopt.gnu_getopt(uargs, "hvlc:ei:u:s:n:p:a:A:z:",\ ["help", "version", "list", "check=","examples","install=",\ "uninstall=","size=","number=","purge=","all=","all-recurse=","zip="]) except getopt.GetoptError, err: print _("Your arguments amuse me :) Please read the help.") print str(err) # will print something like "option -a not recognized" raise SystemExit for o, a in opts: if o in (u"-c", u"--check"): dirtocheck = os.path.abspath( a ) options.check = True break if o in ("-v", "--version"): print strings.version raise SystemExit if o in ("-e", "--examples"): print strings.examples raise SystemExit elif o in ("-h", "--help"): print strings.use print strings.options raise SystemExit elif o in ("-l", "--list"): options.list = True elif o in ("-i","--install"): options.install = [a] if args: ## Any trailing 'words' are taken to be other pognames ## and added to the list. If they are not, they simply won't ## be installed. options.install += args elif o in ("-u", "--uninstall"): options.uninstall = [a] if args: ## Same as install. options.uninstall += args elif o in ("-p", "--purge"): options.purge = a elif o in ("-s", "--size"): try: n = int(a) except: print _("Please use a number for %s") % o raise SystemExit options.points = n elif o in ("-n", "--number"): try: n = int(a) except: print _("Please use a number for %s") % o raise SystemExit options.numinpage = n elif o in ("-a", "--all", "-A","--all-recurse"): ## var a is whatever comes after the -a flag. options.all = a # save to flag a test later (line 310) if o in ("-a","--all"): options.allrecurse = False else: options.allrecurse = True if len(args) != 1: print _("%s takes two arguments: SOURCE(folder) TARGET(pog)") % o print _("""NB: If you wanted to use spaces in a pogname or folder then please put "quotes around them." """) raise SystemExit elif o in ("-z","--zip"): # a is the Pog name we must zip. # This only does one pog, not several at once. # (due to the limits of gnu_getopt) options.zip = True options.pog = a else: ## We should not reach here at all. raise SystemExit #### ## Ensure we have a .fontypython folder and a .fonts folder. iPC = pathcontrol.PathControl() #### ## Let's handle those options that DO NOT require args. ## Check fonts if options.check: if not os.path.exists( dirtocheck ): print _("I can't find %s") % dirtocheck raise SystemExit def printer( pstr = "" ): """A func to print strings to cli, called back from checkFonts.""" if type(pstr) is str: pstr = fpsys.LSP.to_unicode( pstr ) print pstr fpsys.checkFonts( dirtocheck, printer ) raise SystemExit ## List - Quick and dirty. if options.list: poglist = iPC.getPogNames() poglist.sort( cmp=locale.strcoll, key=lambda obj:obj) #28 May 2009. Hope this works for other locales... if len(poglist) == 0: print _("There are no pogs available.") raise SystemExit print _("Listing %d pog(s)") % len(poglist) print _(" * indicates installed pogs") for pog in poglist: paf = iPC.appPath() + pog + ".pog" try: f = open(paf, "r" ) # It's a plain byte-string ascii file. installed = f.readline()[:-1] #Strips the \n off the end f.close() except: print _("Could not open (%s).") % paf s = " " if installed.upper() == "INSTALLED": s = "*" print "%s %s" % (s,pog) raise SystemExit ## Sep 2009 : ZIP if options.zip: if fpsys.isPog( options.pog ): todir="." #always where we run this ipog = fontcontrol.Pog( options.pog ) ipog.zip( todir ) print _("Zipped as %s.fonts.zip in this directory.") % options.pog else: print _("I can't find a pog named %s") % options.pog raise SystemExit #### ## Size ## This one can mix with other args, so don't exit. if options.points > 0: fpsys.config.points = options.points #### ## View ## This one can mix with other args, so don't exit. if options.numinpage > 1: fpsys.config.numinpage = options.numinpage #### ## Text ## Removed Oct 2009 : It was useless. #### ##Handle purge if options.purge: pogtopurge = options.purge # for clarity if fpsys.isPog(pogtopurge): pog = fontcontrol.Pog(pogtopurge) try: #raise fontybugs.PogInvalid #testing pog.genList() except fontybugs.PogInvalid, e: e.print_error_and_quit() try: ## pog.purge() Raises ## PogEmpty ## PogInstalled pog.purge() except (fontybugs.PogEmpty, fontybugs.PogInstalled), e: e.print_error() else: print _("(%s) cannot be found. Try -l to see the names.") % pogtopurge raise SystemExit fpsys.config.Save() print strings.done raise SystemExit #### ## Install: if options.install: for pogtoinstall in options.install: if fpsys.isPog(pogtoinstall): pog = fontcontrol.Pog( pogtoinstall ) try: pog.genList() except fontybugs.PogInvalid, e: e.print_error_and_quit() try: ## pog.install() Raises: ## PogEmpty ## PogAllFontsFailedToInstall ## PogSomeFontsDidNotInstall print _("Installing (%s)") % pogtoinstall pog.install() except (fontybugs.PogEmpty, fontybugs.PogAllFontsFailedToInstall, fontybugs.PogSomeFontsDidNotInstall, ), e: e.print_error() else: # not a pogname print _("(%s) cannot be found. Try -l to see the names.") % pogtoinstall raise SystemExit fpsys.config.Save() print strings.done raise SystemExit #### ## uninstall if options.uninstall: for pogtouninstall in options.uninstall: if fpsys.isPog(pogtouninstall): pog = fontcontrol.Pog(pogtouninstall ) try: pog.genList() except fontybugs.PogInvalid, e: e.print_error_and_quit() try: ## Raises: ## PogEmpty ## PogLinksRemain ## PogNotInstalled print _("Removing (%s)") % pogtouninstall pog.uninstall() except (fontybugs.PogEmpty, fontybugs.PogNotInstalled, fontybugs.PogLinksRemain), e: e.print_error() else: print _("Sorry, can't find (%s). Try -l to see the names.") % pogtouninstall raise SystemExit fpsys.config.Save() print strings.done raise SystemExit ## Install all fonts in folder to given pog. ## May 2009 : Based on code by another author (names lost in email crash). if options.all: count = 0 existingPog = False POGNAME = args[0] FOLDERNAME = options.all try: folder = fontcontrol.Folder(FOLDERNAME, recurse=options.allrecurse) except fontybugs.FolderHasNoFonts, e: e.print_error_and_quit() ipog = fontcontrol.Pog( POGNAME ) # whether it exists or not. ## If it's an unknown POGNAME, make it and write it: if not fpsys.isPog(POGNAME): print _("Creating a new pog: %s") % POGNAME try: ipog.write() except fontybugs.PogWriteError, e: e.print_error_and_quit() ## Fill it with fontitems. ipog.genList() ## get a list of what (in the folder) is NOT already in the ipog (assuming it's non-empty) fl = [fi for fi in folder if str(fi) not in [str(fi2) for fi2 in ipog]] #str(fontItem) returns glyphpaf which has been decoded already. ## Add those fresh items to ipog for f in fl: ipog.append( f ) count += 1 try: ipog.write() except fontybugs.PogWriteError, e: e.print_error_and_quit() del ipog, folder if count: print _("I have placed %(count)s fonts from %(folder)s into %(pog)s.") % {"count":str(count), "folder":FOLDERNAME, "pog":POGNAME } else: print _("The fonts from %(folder)s are *already* in %(pog)s.") % {"folder": FOLDERNAME, "pog":POGNAME } raise SystemExit #### ## If there are > 2 args then there is chaos: if len(args) > 2: ## The user may have chosen a pogname with spaces and no quotes print _("""Please check your arguments, there seem to be too many.\n(Remember: it's one pound for a five-minute argument, but only eight pounds for a course of ten.)\n\nNB: If you wanted to use spaces in a pogname or folder then please put "quotes around them." """) raise SystemExit #### ## Handle Cases : A = None B = None fakearg = False ## If there are no arguments, then we should fetch the last ones used from ## the config file. if not args: args = [] fakearg = True lv = fpsys.config.lastview #print "last one:",lv if not fpsys.isFolder(lv) and not fpsys.isPog(lv): lv = "EMPTY" args.append(lv)#Fakes an arg, will be last pog used (recovered from config) or "EMPTY" ## Get the args into simple vars: A = args [0] if len(args) == 2: B = args [1] ## Let's ensure that, should A be a pog, that it exists, BUT only if it was not a fakearg: if not fpsys.isFolder(A) and not fpsys.isPog(A) and not fakearg: ## It's a non starter: print _("Sorry, (%s) does not exist. Try --list") % A raise SystemExit ## Disallow Folder in arg B if B and fpsys.isFolder(B): print _("You cannot use a folder as the target argument. Try --help") raise SystemExit ## Let's ensure that B exists, else we must make it. ## This is because when you call VIEW TARGET and ## TARGET gets created (the file) if it's not there. if B and not fpsys.isPog(B): ipog = fontcontrol.Pog(B) try: ipog.write() except fontybugs.PogWriteError, e: e.print_error_and_quit() del ipog ## Build the fpsys structure ## Calls to instantiateXYZ are vital. They are where the View or Target Objects get ## generated - i.e. where all their fontItems are built-up. ## One arg: if A and not B: if fpsys.isFolder(A): try: fpsys.instantiateViewFolder(A) # creates a state.viewobject globally. except fontybugs.FolderHasNoFonts, e: e.print_error() ## Let it continue fpsys.config.lastdir = os.path.abspath(A) if fpsys.isPog(A): try: fpsys.instantiateViewPog(A)# creates state.targetobject globally except fontybugs.PogInvalid, e: e.print_error_and_quit() ## Because we are catering for a potential full gui, ## we must make an official "targetobject" set to None fpsys.SetTargetPogToNone() ## Two args: if A and B: if fpsys.isFolder(A)and fpsys.isPog(B): ## "FP" try: fpsys.instantiateViewFolder(A) except fontybugs.FolderHasNoFonts, e: ## Let it continue fpsys.config.lastdir = os.path.abspath(A) try: installed = fpsys.instantiateTargetPog(B) except fontybugs.PogInvalid, e: e.print_error_and_quit() if installed: print _("The target pog (%s) is currently installed, you can't use it as a target.") % B raise SystemExit if fpsys.isPog(A)and fpsys.isPog(B): ## "PP" if A == B: print _("Your pogs are the same! Try -e") raise SystemExit try: empty = fpsys.instantiateViewPog(A) except fontybugs.PogInvalid, e: e.print_error_and_quit() if empty: print _("This pog is empty") raise SystemExit try: installed = fpsys.instantiateTargetPog(B) except fontybugs.PogInvalid, e: e.print_error_and_quit() if installed: print _("The target pog (%s) is currently installed, you can't use it as a target.") % B raise SystemExit ## Your arguments amuse me :) Please try -h fontypython-0.4.4/fontypythonmodules/dialogues.py0000644000175000017500000004017611742276540021136 0ustar donndonn## Fonty Python Copyright (C) 2006, 2007, 2008, 2009 Donn.C.Ingle ## Contact: donn.ingle@gmail.com - I hope this email lasts. ## ## This file is part of Fonty Python. ## Fonty Python 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. ## ## Fonty Python 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 Fonty Python. If not, see . import os, locale import fpsys #import fontsearch import strings import wx import wx.html as html ## Setup wxPython to access translations : enables the stock buttons. langid = wx.LANGUAGE_DEFAULT # Picks this up from $LANG mylocale = wx.Locale( langid ) ## langcode = locale.getlocale()[0] # I must not use getlocale... ## This is suggested by Martin: loc = locale.setlocale(locale.LC_CTYPE) # use *one* of the categories (not LC_ALL) ## returns something like 'en_ZA.UTF-8' if loc is None or len(loc) < 2: langcode = 'en' else: langcode = loc[:2].lower()# This is going to cause grief in the future... class DialogHelp(wx.Dialog): def __init__(self, *args, **kwds): kwds["style"] = wx.DEFAULT_DIALOG_STYLE wx.Dialog.__init__(self, *args, **kwds) ID_ESC = 1001 self.accel = wx.AcceleratorTable([(wx.ACCEL_NORMAL, wx.WXK_ESCAPE, ID_ESC)]) self.SetAcceleratorTable(self.accel) self.Bind(wx.EVT_MENU, self.Escape, id=ID_ESC) dbox = wx.BoxSizer(wx.VERTICAL) btn = wx.Button(self, wx.ID_CANCEL) btn.SetDefault() win = TestHtmlPanel(self, size = kwds["size"]) dbox.Add(win, 1, wx.EXPAND) dbox.Add(btn, 0, wx.CENTER | wx.TOP | wx.BOTTOM,border = 4) self.SetSizer(dbox) #self.SetAutoLayout(True) #sizes it properly... dbox.SetSizeHints(self) #made it variable size, stops at 'size' as a min. #dbox.Fit(self) #self.Layout() win.SetFocus()# magically enables ESC key too! Go figure :) self.SetTitle(_("Fonty Python Help! Help! I'm being oppressed!")) _icon = wx.EmptyIcon() _icon.CopyFromBitmap(wx.Bitmap(fpsys.mythingsdir + 'fplogo.png', wx.BITMAP_TYPE_ANY)) self.SetIcon(_icon) def Escape(self, event): self.Close() class TestHtmlPanel(wx.Panel): def __init__(self, parent, size): wx.Panel.__init__(self, parent, -1, style=wx.NO_FULL_REPAINT_ON_RESIZE) self.html = MyHtmlWindow(self, -1, size) self.box = wx.BoxSizer(wx.VERTICAL) self.box.Add(self.html, 1, wx.GROW) #A BACK button. I used internal 'top' links instead #subbox = wx.BoxSizer(wx.HORIZONTAL) #btn = wx.Button(self, wx.ID_BACKWARD) #self.Bind(wx.EVT_BUTTON ,self.OnBack, btn) #subbox.Add(btn, 1, wx.GROW | wx.ALL, 2) #self.box.Add(subbox, 0, wx.GROW) self.SetSizer(self.box) self.SetAutoLayout(True) ## Find localized help, or default to English. packpath = fpsys.fontyroot helppaf = os.path.join(packpath, "help", langcode, "help.html") if not os.path.exists( helppaf ): helppaf = os.path.join(packpath, "help", "en", "help.html") self.html.LoadPage( helppaf ) self.box.Fit(self) #def OnBack( self, e ): #self.html.HistoryBack() class MyHtmlWindow(html.HtmlWindow): def __init__(self, parent, id, size): html.HtmlWindow.__init__(self, parent, id, style=wx.NO_FULL_REPAINT_ON_RESIZE, size = size) if "gtk2" in wx.PlatformInfo: self.SetStandardFonts() class DialogAbout(wx.Dialog): def __init__(self, *args, **kwds): # begin wxGlade: MyDialog.__init__ kwds["style"] = wx.DEFAULT_DIALOG_STYLE wx.Dialog.__init__(self, *args, **kwds) self.nb = wx.Notebook(self, -1, style=0) self.notebook_1_pane_2 = wx.Panel(self.nb, -1) self.notebook_1_pane_1 = wx.Panel(self.nb, -1) self.notebook_1_pane_3 = wx.Panel(self.nb, -1) self.bLOGO = wx.StaticBitmap\ (self.notebook_1_pane_1, -1, wx.Bitmap(fpsys.mythingsdir + 'aboutfplogo.png', wx.BITMAP_TYPE_ANY)) self.AboutText = wx.StaticText\ (self.notebook_1_pane_1, -1, strings.aboutText, style = wx.TE_MULTILINE) self.emaillink = wx.TextCtrl\ (self.notebook_1_pane_1, -1, strings.contact, size =(200,-1 ), style = wx.TE_READONLY) self.GPL_TEXT = wx.TextCtrl\ (self.notebook_1_pane_2, -1, strings.GPL, style=wx.TE_MULTILINE|wx.TE_READONLY) self.THANKS = wx.TextCtrl\ (self.notebook_1_pane_3, -1, strings.thanks, style=wx.TE_MULTILINE|wx.TE_READONLY) ID_ESC = 1001 self.accel = wx.AcceleratorTable([(wx.ACCEL_NORMAL, wx.WXK_ESCAPE, ID_ESC)]) self.SetAcceleratorTable(self.accel) self.Bind(wx.EVT_MENU, self.EscapeAbout, id=ID_ESC) self.__set_properties() self.__do_layout() self.notebook_1_pane_1.SetFocus() # end wxGlade def __set_properties(self): self.SetTitle(_("About FontyPython")) _icon = wx.EmptyIcon() _icon.CopyFromBitmap(wx.Bitmap(fpsys.mythingsdir + 'fplogo.png', wx.BITMAP_TYPE_ANY)) self.SetIcon(_icon) def EscapeAbout(self, event): self.Close() def __do_layout(self): # begin wxGlade: MyDialog.__do_layout sizer_1 = wx.BoxSizer(wx.VERTICAL) sizer_3 = wx.BoxSizer(wx.HORIZONTAL) sizer_thanks = wx.BoxSizer( wx.HORIZONTAL ) sizerPane1 = wx.BoxSizer(wx.HORIZONTAL) sizerPane1.Add(self.bLOGO, 0, 0, 0) textsizer = wx.BoxSizer(wx.VERTICAL) textsizer.Add(self.AboutText, 0, wx.ALIGN_LEFT | wx.ALL, border = 10) textsizer.Add(self.emaillink, 0, wx.ALIGN_LEFT | wx.ALL, border = 10) #textsizer.Add((10, 10), 0, wx.ALIGN_LEFT, 0) sizerPane1.Add(textsizer, 1, wx.ALIGN_BOTTOM, 0) self.notebook_1_pane_1.SetSizer(sizerPane1) sizerPane1.Fit(self.notebook_1_pane_1) sizerPane1.SetSizeHints(self.notebook_1_pane_1) sizer_3.Add(self.GPL_TEXT,1, wx.EXPAND, 0) self.notebook_1_pane_2.SetSizer(sizer_3) sizer_3.Fit(self.notebook_1_pane_2) sizer_3.SetSizeHints(self.notebook_1_pane_2) ## THANKS sizer_thanks.Add( self.THANKS,1, wx.EXPAND,0 ) self.notebook_1_pane_3.SetSizer( sizer_thanks ) sizer_thanks.Fit( self.notebook_1_pane_3 ) sizer_thanks.SetSizeHints( self.notebook_1_pane_3 ) self.nb.AddPage(self.notebook_1_pane_1, _("About")) self.nb.AddPage(self.notebook_1_pane_3, _("Thanks")) self.nb.AddPage(self.notebook_1_pane_2, _("Licence")) sizer_1.Add(self.nb, 1, wx.EXPAND, 0) self.SetSizer(sizer_1) sizer_1.Fit(self) sizer_1.SetSizeHints(self) self.Layout() self.Centre() # end wxGlade class DialogSettings(wx.Dialog): def __init__(self, parent): wx.Dialog.__init__(self, parent, -1, _("Settings"), pos = wx.DefaultPosition)#, size =(450,-1)) verticalSizer = wx.BoxSizer(wx.VERTICAL) nb = wx.Notebook(self, -1, style=0) PANE1= wx.Panel(nb, -1) PANE2 = wx.Panel(nb, -1) ## The layout of PANE1 begins: font = wx.Font(16, fpsys.DFAM, wx.NORMAL, wx.FONTWEIGHT_BOLD) labelHeading = wx.StaticText(self, -1, _("Settings")) labelHeading.SetFont(font) label_1 = wx.StaticText(PANE1, -1, _("Sample text:")) self.inputSampleString = wx.TextCtrl(PANE1, -1, fpsys.config.text, size = (200, -1)) self.inputSampleString.SetFocus() label_2 = wx.StaticText(PANE1, -1, _("Point size:")) self.inputPointSize = wx.SpinCtrl(PANE1, -1, "") self.inputPointSize.SetRange(1, 500) self.inputPointSize.SetValue(fpsys.config.points) label_3 = wx.StaticText(PANE1, -1, _("Page length:")) self.inputPageLen = wx.SpinCtrl(PANE1, -1, "") self.inputPageLen.SetRange(1, 5000) # It's your funeral! self.inputPageLen.SetValue(fpsys.config.numinpage) self.inputPageLen.SetToolTip( wx.ToolTip( _("Beware large numbers!") ) ) PANE1sizer = wx.FlexGridSizer( rows=3, cols=2, hgap=5, vgap=8 ) PANE1sizer.Add(label_1, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL ) PANE1sizer.Add(self.inputSampleString, 1, wx.EXPAND ) PANE1sizer.Add(label_2, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL ) PANE1sizer.Add(self.inputPointSize, 0 ) PANE1sizer.Add(label_3, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL ) PANE1sizer.Add(self.inputPageLen, 0 ) PANE1_buffer = wx.BoxSizer( wx.HORIZONTAL ) PANE1_buffer.Add( PANE1sizer, 1, wx.EXPAND | wx.ALL, border=10 ) PANE1.SetSizer( PANE1_buffer ) ## Layout of PANE2 ## Sept 2009 - Checkbox to ignore/use the font top left adjustment code self.chkAdjust = wx.CheckBox(PANE2, -1, _("Disable font top-left correction.")) self.chkAdjust.SetValue(fpsys.config.ignore_adjustments) self.chkAdjust.SetToolTip( wx.ToolTip( _("Disabling this speeds font drawing up a fraction, but degrades top-left positioning.") ) ) PANE2sizer = wx.BoxSizer( wx.VERTICAL ) PANE2sizer.Add(self.chkAdjust, 0, wx.ALIGN_LEFT | wx.BOTTOM, border=10 ) # The Character map choice self.CMC = fpsys.config.CMC if self.CMC.APPS_ARE_AVAILABLE: self.CHOSEN_CHARACTER_MAP = self.CMC.GET_CURRENT_APPNAME() rb = wx.RadioBox( PANE2, -1, _("Available character map viewers"), wx.DefaultPosition, wx.DefaultSize, self.CMC.QUICK_APPNAME_LIST, 1, wx.RA_SPECIFY_COLS ) rb.SetSelection( self.CMC.QUICK_APPNAME_LIST.index( self.CHOSEN_CHARACTER_MAP )) self.Bind(wx.EVT_RADIOBOX, self.EvtRadioBox, rb) rb.SetToolTip(wx.ToolTip( _("Choose which app to use as a character map viewer.") )) PANE2sizer.Add( rb, 0, wx.ALIGN_LEFT ) else: self.CHOSEN_CHARACTER_MAP = None no_app = wx.StaticText(PANE2, -1, _("Could not find a supported character viewer.")) PANE2sizer.Add( no_app, 0, wx.ALIGN_LEFT ) PANE2_buffer = wx.BoxSizer( wx.HORIZONTAL ) PANE2_buffer.Add( PANE2sizer, 1, wx.EXPAND | wx.ALL, border=10 ) PANE2.SetSizer( PANE2_buffer ) ## Add the panels to the notebook nb.AddPage( PANE1, _("Quick settings") ) nb.AddPage( PANE2, _("Voodoo") ) ## Add label and a space to the vertical sizer verticalSizer.Add( labelHeading, 0, wx.ALIGN_LEFT ) verticalSizer.Add( (0,5), 0 ) ## Add the notebook verticalSizer.Add( nb, 1, wx.EXPAND | wx.ALL ) verticalSizer.Add((0,10),0) #space between bottom of grid and buttons ## Make a std button group btnsizer = wx.StdDialogButtonSizer() btn = wx.Button(self, wx.ID_OK) btn.SetDefault() btnsizer.AddButton(btn) btn = wx.Button(self, wx.ID_CANCEL) btnsizer.AddButton(btn) btnsizer.Realize() ## Add button group to vertical sizer verticalSizer.Add( btnsizer, 0, wx.ALIGN_BOTTOM | wx.ALIGN_CENTER_HORIZONTAL, border = 5) ## Make a 'buffer' to keep the insides away from the edges of the frame buffer=wx.BoxSizer( wx.HORIZONTAL ) ## To get border to work use wx.EXPAND | wx.ALL buffer.Add( verticalSizer, 1,wx.EXPAND | wx.ALL, border=10 ) self.SetSizer( buffer ) buffer.Fit(self) self.Layout() def EvtRadioBox(self, event): self.CHOSEN_CHARACTER_MAP = self.CMC.QUICK_APPNAME_LIST[event.GetInt()] class SegfaultDialog(wx.Dialog): """ Dec 2007 Runs from the wrapper script (which runs start_fontypython) so that we can tell the user that there was a segfault and why. """ def __init__(self, parent, culprit): wx.Dialog.__init__(self, parent, -1, _("Oh boy..."), pos = wx.DefaultPosition ) ## The layout begins: font = wx.Font(16, wx.DEFAULT, wx.NORMAL, wx.FONTWEIGHT_BOLD) self.labelHeading = wx.StaticText(self, -1, _("Fonty Python, um ... crashed.")) self.labelHeading.SetFont(font) font = wx.Font(12, wx.DEFAULT, wx.NORMAL, wx.FONTWEIGHT_BOLD) self.ohDear = wx.StaticText( self, -1, _("Oh dear,")) self.ohDear.SetFont( font ) self.sadStory = wx.StaticText( self, -1, _("There's some problem with the font named below. Please use the Check Fonts tool in Fonty\n(from the command-line or the Tools menu) to go through this directory and mark all the dangerous fonts.\n(You could simply move this font elsewhere, but others may remain to cause trouble.)\n" )) font = wx.Font(11, wx.DEFAULT, wx.NORMAL, wx.FONTWEIGHT_BOLD) self.culprit = wx.StaticText( self, -1, culprit ) self.culprit.SetFont( font ) verticalSizer = wx.BoxSizer(wx.VERTICAL) verticalSizer.Add(self.labelHeading, 0, 0, 0) verticalSizer.Add(self.ohDear, 0, 0, 0) verticalSizer.Add(self.sadStory, 1, wx.EXPAND, 0) verticalSizer.Add(self.culprit, 1, wx.EXPAND, 0) btnsizer = wx.StdDialogButtonSizer() btn = wx.Button(self, wx.ID_OK) btn.SetDefault() btnsizer.AddButton(btn) btnsizer.Realize() verticalSizer.Add(btnsizer, 0, wx.ALIGN_CENTER_VERTICAL| wx.ALIGN_RIGHT, border = 15) buffer=wx.BoxSizer( wx.HORIZONTAL ) buffer.Add( verticalSizer, 1, wx.ALL, border=10 ) self.SetSizer( buffer ) buffer.Fit(self) self.SetSizer( buffer ) self.Layout() class LocateDirectory(wx.Dialog): """ Sep 2009 : A nicer (than std dir dialogue) dialogue for locating a directory. It starts in the cwd. """ def __init__(self, parent): wx.Dialog.__init__(self, parent, -1, title = _("Locate a directory for the zip file(s)."), pos=wx.DefaultPosition,style=wx.DEFAULT_FRAME_STYLE) sizer = wx.BoxSizer(wx.VERTICAL) self.treedir = wx.GenericDirCtrl( self, -1, dir=os.getcwd(), style=wx.DIRCTRL_DIR_ONLY ) btno = wx.Button(self, wx.ID_OK) btnc = wx.Button(self, wx.ID_CANCEL) sizer.Add(self.treedir, 1, wx.EXPAND) sizer.Add(btno, 0, wx.EXPAND) sizer.Add(btnc, 0, wx.EXPAND) btnsizer = wx.StdDialogButtonSizer() btno.SetDefault() btnsizer.AddButton(btno) btnsizer.AddButton(btnc) btnsizer.Realize() self.SetSizer(sizer) self.SetAutoLayout(True) def GetPath(self): return self.treedir.GetPath() class DialogCheckFonts( wx.Dialog ): """ 18 Jan 2008 Open a dircontrol to locate a folder, a text box of some kind to show the progress, and build the segfonts file/list """ def __init__( self, parent, startdir ): wx.Dialog.__init__(self, parent, -1, _("Check for dangerous fonts."), \ size=(800,400),pos = wx.DefaultPosition, style=wx.DEFAULT_FRAME_STYLE ) ## LEFT leftsz = wx.BoxSizer(wx.VERTICAL) font = wx.Font(12, fpsys.DFAM, wx.NORMAL, wx.FONTWEIGHT_BOLD) title = wx.StaticText( self,-1, _("Choose a directory and double click it to start")) title.SetFont( font ) leftsz.Add(title,0,wx.EXPAND | wx.ALL, border=4 ) self.treedir = wx.GenericDirCtrl( self, -1, dir=startdir, style=wx.DIRCTRL_DIR_ONLY ) leftsz.Add( self.treedir, 1, wx.EXPAND|wx.ALL) ## RIGHT rightsz = wx.BoxSizer(wx.VERTICAL) self.output = wx.TextCtrl( self, -1, "...", \ size=(200,-1), style = wx.TE_MULTILINE | wx.TE_READONLY ) rightsz.Add(self.output,1,wx.EXPAND | wx.ALL) ## Because I want a CLOSE button -- I have to do all the button ## stuff manually. StdDialogButtonSizer only provides certain buttons ## that are not appropriate for this form. bsz = wx.BoxSizer(wx.HORIZONTAL) self.btn = wx.Button(self, wx.ID_CLOSE) self.btn.SetDefault() bsz.Add(self.btn,1,wx.EXPAND) self.btn.Bind( wx.EVT_BUTTON, self.OnClick) rightsz.Add(bsz,0,wx.EXPAND) sz = wx.BoxSizer(wx.HORIZONTAL) sz.Add(leftsz, 1, wx.EXPAND) sz.Add(rightsz, 1, wx.EXPAND )# this wx.EXPAND got the text control to fit the height. self.SetSizer(sz) self.tree = self.treedir.GetTreeCtrl() self.tree.Bind(wx.EVT_LEFT_DCLICK, self.__goFigure) def OnClick(self,e): self.Close(True) def printer( self, txt=None ): if txt is None: txt = "\n" self.output.WriteText(txt + "\n") wx.SafeYield() def __goFigure( self, e ): self.output.Clear() wx.BeginBusyCursor() dirtocheck = self.treedir.GetPath() fpsys.checkFonts( dirtocheck, self.printer ) wx.EndBusyCursor() ## May 2009 - Busy ## June 2009 - Given up on this code for now. #class PopupInfo(wx.Frame): # def __init__(self, parent, id, title, fmap): # wx.Frame.__init__(self, parent, id, title) # self.box = wx.BoxSizer(wx.VERTICAL) # self.list = wx.TextCtrl(self, -1, style=wx.TE_MULTILINE|wx.TE_WORDWRAP) # self.box.Add(self.list, proportion=1, flag=wx.EXPAND) # font = fmap.fitem # info = fontsearch.getInfo(font) # try: # self.SetTitle(info['Name Records']['Full Name']) # except KeyError: # self.SetTitle(font.name) # except: # self.SetTitle("Font Information") # text = str(info) # self.list.AppendText(text) # self.butClose = wx.Button(self, id = wx.ID_OK) # self.butClose.Bind(wx.EVT_BUTTON, lambda event : self.Close()) # self.Bind(wx.EVT_COMMAND_KILL_FOCUS, lambda event : self.Close()) # self.box.Add(self.butClose, flag=wx.FIXED_MINSIZE|wx.ALIGN_CENTER) # self.box.Layout() # self.SetSizer(self.box) fontypython-0.4.4/fontypythonmodules/fontcontrol.py0000644000175000017500000007604611742276540021536 0ustar donndonn## Fonty Python Copyright (C) 2006, 2007, 2008, 2009 Donn.C.Ingle ## Contact: donn.ingle@gmail.com - I hope this email lasts. ## ## This file is part of Fonty Python. ## Fonty Python 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. ## ## Fonty Python 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 Fonty Python. If not, see . import os, sys, locale, glob, errno import Image, ImageFont, ImageDraw import fontybugs, fpsys from pathcontrol import * ## Sep 2009 : zip functionality import zipfile zcompress=zipfile.ZIP_STORED #we default to uncompressed. try: import zlib zcompress=zipfile.ZIP_DEFLATED #i.e. we can compress using this formula. except: pass class FontItem( object ): """ Represents a single font file. It has the ability to provide a font image and query a font file for the family name and style. Ancestor to the specific classes per font type. Never instantiate one directly. """ def __init__(self, glyphpaf ): ## glyphpaf must be whatever it is. unicode or a byte string ## This is used to access files themselves. ## When the LANG encoding is utf8, its Unicode. self.glyphpaf = glyphpaf #print "FontItem init, glyphpaf:", [glyphpaf] ## I want to have a var I can use when I display the glyphpaf ## either in the gui or onto the cli. This should be a unicode ## object, so I must make sure of it's type before I do so. self.glyphpaf_unicode = fpsys.LSP.ensure_unicode( glyphpaf ) ## The same goes for name. It *must* be unicode. self.name = os.path.basename ( self.glyphpaf_unicode ) self.name = fpsys.LSP.ensure_unicode( self.name ) self.ticked = False # State of the tick/cross symbol. self.inactive = False # Set in fpsys.markInactive() self.activeInactiveMsg = "" #Say something unique when I draw this item. ## These are lists to cater for sub-faces self.family, self.style = [], [] self.numFaces = 0 self.pilheight, self.pilwidth = 0,0 ## I'm not bad in any way, until I turn bad that is :) self.badfont = False ## If I'm bad, what should I say? self.badfontmsg = "" ## What kind of bad to the bone am I? ## One of FILE_NOT_FOUND, PIL_IO_ERROR, PIL_UNICODE_ERROR, PIL_CANNOT_RENDER self.badstyle = "" ## We need the family name and style to be fetched ## because we have that filter thingy in the gui ## and it uses those strings to search for terms. ## ## We also want to know what flavour of bad this item will be ## and we must open the file and query it to know that. self.__queryFontFamilyStyleFlagBad() ## Vars used in the rendering stage. self.fx = [None for i in xrange(self.numFaces)] # Position calculated for best top-left of each face image. self.fy = self.fx[:] #Damn! Make a COPY of that list! self.top_left_adjust_completed = False def __queryFontFamilyStyleFlagBad( self ): """ Get the family, style and size of entire font. If this font has a problem (PIL can't read it) then we set the badfont flag, along with the badstyle & badfontmsg vars. badstyle: FILE_NOT_FOUND, PIL_IO_ERROR, PIL_UNICODE_ERROR The last kind of badstyle is set in generatePilFont() and is set to: PIL_CANNOT_RENDER This is tricky because FontImage.getname() is fragile and apt to segfault. As of Dec 2007 I have reported the bug, and a patch has been written but I don't know how it will be implemented yet. NB: InfoFontItem overrides this so it does not happen in that case. This is why I made this a method and not simply part of the __init__ above. """ i = 0 ## Step through all subfaces. #print "BUILDING:", [self.glyphpaf] while True: try: fileDoesExist = os.path.exists( self.glyphpaf ) if not fileDoesExist: self.badfont = True self.badfontmsg = _("Font cannot be found, you should purge this Pog.") self.badstyle = "FILE_NOT_FOUND" ## If the multi face font is damaged after the ## first face, then this won't catch it... break # it's at the end of the sub-faces except: print _("Unhandled error:\nPlease move (%s) away from here and report this to us.") % self.glyphpaf raise try: font = ImageFont.truetype(self.glyphpaf, 16, index=i, encoding="unicode" ) except IOError: """ Means the ttf file cannot be opened or rendered by PIL ! NOTE: Sets badfont """ if i == 0: # fubar on the first face: self.badfont = True self.badfontmsg = _("Font may be bad and it cannot be drawn.") self.badstyle = "PIL_IO_ERROR" ## If the multi face font is damaged after the ## first face, then this won't catch it... break # it's at the end of the sub-faces except UnicodeEncodeError: """ NOTE: Sets badfont """ ## Aw man! I thought I had this taped. This error does not *seem* to ## be related to the encoding param passed to ImageFont. I have ## mailed the PIL list about this. ## ## In the meantime, this will have to be flagged as a bad font. self.badfont = True self.badfontmsg = _("Unicode problem. Font may be bad and it cannot be drawn.") self.badstyle = "PIL_UNICODE_ERROR" break except: ## What next on the error pile? print "CORNER CASE in FontItem.__queryFontFamilyStyleFlagBad:", [self.glyphpaf] print sys.exc_info() raise ## Abort the app because this is an unhandled PIL error of some kind. if not self.badfont: ## *If* 'check' is run, there will be a file containing pafs of the ## fonts that segfault PIL. (To my best knowledge, at least.) ## This file is held in the 'segfonts' list - opened in fpsys ## So, before we do a getname and cause a segfault, let's ## see whether that font is in segfonts, and if so, skip it. if self.glyphpaf not in fpsys.segfonts: # This writes to lastFontBeforeSegfault file. Just in case it crashes the # app on the .family call below. fpsys.logSegfaulters( self.glyphpaf ) ## ## Sep 2009 ## It has been reported by a user that some fonts have family names (and other info?) that ## are not English. They appear as ???y??? etc. in the font list. On my system Inkscape ## draws tham with squares (holding a unicode number) and a few Eastern characters. ## I am not sure AT ALL what to do about this. Is it a font/locale I should have installed? ## ## This is bug number: https://savannah.nongnu.org/bugs/index.php?27305 ## ## I await help from PIL list. #self.family.append( font.getname()[0] ) # old code ## No point Try-ing here, this segfaults when style/family is Null. self.family.append( fpsys.LSP.ensure_unicode( font.getname()[0] ) ) self.style.append( font.getname()[1] ) i += 1 else: ## It WAS in the list! So, we can flag it and get on with life :) #print "SKIPPING:",[self.glyphpaf] self.badfont = True self.badfontmsg = _("Font causes a segfault. It cannot be drawn.") self.badstyle = "PIL_SEGFAULT_ERROR" break self.numFaces = i def generatePilFont( self, enc="unicode" ): """ This function seems too similar to the __queryFontFamilyStyleFlagBad one and in many ways it is. I am forced to work with PIL and it's not ideal at the moment. This function is called from the GUI in a tight loop. It provides (generates) pilimage objects with the font's text rendered onto them. Fonts that cause errors are marked 'badfont' and provide no image. They can then be 'displayed' and can be put into Pogs etc., but they cannot be seen. """ ## text gets extra spaces at the end to cater for cut-off characters. paf, points, text = self.glyphpaf, fpsys.config.points, " " + fpsys.config.text + " " i = 0 while (True): try: font = ImageFont.truetype(paf, points,index=i, encoding=enc) w,h = font.getsize( text ) ## Some fonts (50SDINGS.ttf) return a 0 width. ## I don't know exactly why, it could be it could not render ## any of the chars in text. if int(w) == 0: w = 1 pilheight = int(h) pilwidth = int(w) pilheight += 10 ## Sept 2009 : Fiddled this to produce alpha (ish) images. pilimage = Image.new("RGBA", (pilwidth, pilheight), (0,0,0,0))#(255,255,255,255)) if self.inactive: col = (0,0,0,64) #alpha makes it gray else: col = (0,0,0,255) ## Well, I have since discovered that some fonts ## cause a MemoryError on the next command: drawnFont = ImageDraw.Draw( pilimage ) # Draws INTO pilimage drawnFont.text((0,0) , text, font=font, fill=col) ## All is well, so we step ahead to the next *potential* sub-face ## and return the font image data. i += 1 yield pilimage#, pilheight, pilwidth except MemoryError: """ NOTE: Sets badfont This one CAN ONLY BE CAUGHT HERE. **IDEALLY**, it should have been caught in __queryFontFamilyStyleFlagBad but for reasons explained below, it cannot. So, we have a badfont flag being set here too :( """ ## I found a font throwing a MemoryError (Onsoku Seinen Plane.ttf) ## that only happens upon the .text() command. ## ## UPDATE: Clever tricks don't work. Onsoku *only* barfs on "TE" and not ## "A" or even chr(0) to chr(255) all in a string... ## So, it's virtually impossible to know at this point what will ## cause the MemoryError in the rendering step. self.badfontmsg = _("Font causes a memory error, it can't be drawn.") self.badstyle = "PIL_CANNOT_RENDER" self.badfont = True break ## These two must be caught, but are already known about ## from the exact same test in __queryFontFamilyStyleFlagBad except IOError: ## The font at index (i==0) cannot be opened. break except UnicodeEncodeError: ## Already handled in __queryFontFamilyStyleFlagBad break def __str__( self ): return self.glyphpaf def InfoOrErrorText(self): """Used in Fitmap code to draw strings and things.""" if self.badfont: l1 = self.badfontmsg l2 = self.glyphpaf_unicode return ( l1, l2 ) ## Create some subclasses to represent the fonts that we support: class InfoFontItem( FontItem ): """ This class is only instantiated in wxgui.CreateFitmaps It's used to indicate when a Folder or Pog is EMPTY and if a single font is bad in some way. It's the only Font Item in the target or source view list at that time. """ def __init__( self, glyphpaf="" ): FontItem.__init__( self, glyphpaf ) def __queryFontFamilyStyleFlagBad( self ): """Overridden so that it does not happen for this class.""" pass def InfoOrErrorText( self ): """An override : InfoFontItem needs only these words""" l1 = _("There are no fonts to see here, move along.") l2 = _("(Check your filter!)") return ( l1, l2 ) class TruetypeItem( FontItem ): def __init__( self, glyphpaf ): FontItem.__init__( self, glyphpaf ) class TruetypeCollectionItem( FontItem ): def __init__( self, glyphpaf ): FontItem.__init__( self, glyphpaf ) class OpentypeItem( FontItem ): def __init__( self, glyphpaf ): FontItem.__init__( self, glyphpaf ) class Type1Item( FontItem ): def __init__( self, glyphpaf, metricpaf=None ): FontItem.__init__( self, glyphpaf ) self.metricpaf = metricpaf def itemGenerator( fromObj, sourceList ): """ Prepare for hell... This is a *generator* function that yields a FontItem instantiated according to the type of the font. Call it once-off, or in a loop, to get one FontItem after another. Pass it a sourceList that contains pafs. VERY NB: When the app is run from a utf8 locale, this func generates UNICODE glyphpaf vars. When run from C/POSIX/None it generates BYTE STRING glyphpaf vars. sourceList is not a predictable beast. It comes in mixed strings/unicode """ #print "sourceList comes in:",[sourceList] #print def ext(s): return s.split(".")[-1].upper() def stripExt(s): return s[:s.rfind(".")] listOfItemsGenerated = [] ## So, [paf,paf,paf,paf,paf] comes in. ## If it comes from FOLDER then it's full of ALL the files in a single dir. ## NB: It may or may not include 'type1' files and their 'metrics' ## If it comes from POG then it's just pafs of the basic glyph files ## thus it does not include the afm/pfm files. ## So: this is a special case. ## We must "fill-up" the list with the 'metric' files that are matched ## to Type1 files - i.e. AFM and PFM files that belong to the fonts ## of type 'type1' which we are detecting by extension as ".pfb" and ".pfa" if isinstance( fromObj, Pog ): tmp = [] for paf in sourceList: ## paf : /some/path/somefont.pfb (or .ttf, or whatever. Do them all.) tmp.append( paf ) # add it to what will replace sourceList dir = os.path.dirname( paf ) # /some/path filename = os.path.basename( paf ) # somefont.pfb ## Find metric files with his name in his dir wild = os.path.join( dir, stripExt(filename) + ".[PpAa][Ff][Mm]" ) metricfiles = glob.glob( wild ) ## Add what we find (if anything) to the tmp list for metric in metricfiles: tmp.append( metric ) # merge them in ## Replace the sourceList del( sourceList ) sourceList = tmp ## Now we have a sourceList that is complete - full of files ## TYPE1 stuff. 10 Jan 2008 ## Jump through hoops to find the 'metric' files (AFM then PFM) ## for each Type1 font that's in the list ## ## As per advice on the freetype list I am doing this: ## For every PFA/PFB file, I look for a matching path and filename ## starting with AFM extensions, then trying PFM extensions. ## AFM is preferred over PFM. ## Make Type1Item objects and associate the 'metric' file found (or none) ## Filter some lists from sourceList to step through: PFABs= [[stripExt(e),e] for e in sourceList if ext(e) in ("PFA","PFB")] # all type1 files AFMs = [[stripExt(e),e] for e in sourceList if ext(e) in ("AFM")] # all AFM metric files PFMs = [[stripExt(e),e] for e in sourceList if ext(e) in ("PFM")] # all PFM metric files ## Those lists look like this: ## ["/some/path/file", "/some/path/file.pfa"] ## [0] is paf sans extension, [1] is all of it (*) ## (*) We have to worry about case sensitivity, so I store more data. ## Go through the (maybe empty) list of PFA and FPB files for pfab_tup in PFABs: foundAFM = False ## Looking for AFM files for afm_tup in AFMs: if afm_tup[0] == pfab_tup[0]: ## We have found an afm file for this pfa/pfb file ## so make an object fi = Type1Item( pfab_tup[1], metricpaf = afm_tup[1] ) listOfItemsGenerated.append( fi ) foundAFM = True break ## If we found no AFM then try find a PFM foundPFM = False if not foundAFM: ## Looking for PFM files for pfm_tup in PFMs: if pfm_tup[0] == pfab_tup[0]: ## We have found pfm file for it, make an object fi = Type1Item( pfab_tup[1], metricpaf = pfm_tup[1] ) listOfItemsGenerated.append( fi ) foundPFM = True break ## If we found neither: if not foundAFM and not foundPFM: ## Just make an object without a metric file associated. fi = Type1Item( pfab_tup[1], metricpaf = None ) listOfItemsGenerated.append( fi ) ## Do the other font types TTFList = [ paf for paf in sourceList if ext(paf) == "TTF" ] if len(TTFList) > 0: for paf in TTFList: fi = TruetypeItem( paf ) listOfItemsGenerated.append( fi ) OTFList = [ paf for paf in sourceList if ext(paf) == "OTF" ] if len(OTFList) > 0: for paf in OTFList: fi = OpentypeItem( paf ) listOfItemsGenerated.append(fi) TTCList = [ paf for paf in sourceList if ext(paf) == "TTC" ] if len(TTCList) > 0: for paf in TTCList: fi = TruetypeCollectionItem( paf ) listOfItemsGenerated.append(fi) ## NB: listOfItemsGenerated can contain MIXED byte strings/unicode ## Sort the list: I use the glyphpaf_unicode var becuase it's unicode only. listOfItemsGenerated.sort( cmp=locale.strcoll, key=lambda obj:obj.glyphpaf_unicode ) # Try to sort on that field. ## Supply it: This is pure magic! for fi in listOfItemsGenerated: yield fi class BasicFontList(list): """ Ancestor to the Pog and Folder classes. """ def clear(self): del self[:] # works. It was real touch and go there for a while. def clearInactiveflags(self): for fi in self: fi.inactive = False class EmptyView(BasicFontList): """ Imitates an empty Pog or an empty Folder. """ def __init__(self): BasicFontList.__init__(self) ## Public properties: self.name = "EMPTY" self.installed = False self.empty = True def label(self): return str(self.name) def genList(self): return def isInstalled(self): return False class Folder(BasicFontList): """ Represents an entire Folder (from a path given by user clicking on the GenericDirCtrl or from a command line string.) This is called from fpsys.instantiateViewFolder Contains a list of various FontItem Objects. Supply the start path and an optional recurse T/F param. """ def __init__(self, path, recurse=False): BasicFontList.__init__(self) #print "path:",[path] ## I reckon self.path is always coming in as unicode. ## From the gui, it's unicode anyway cos of the dir control. ## From the cli, I converted args to unicode there. self.path = os.path.abspath(path) # fix relative paths ## Added June 2009 def safeJoin(apath,filelist): ''' It seems filelist cannot be relied on to be anything other than a mixed-bag of unicode and/or bytestrings. I will join each to the apath and force the result to bytestrings. ''' returnList = [] for f in filelist: paf = fpsys.LSP.path_join_ensure_bytestring_result( apath, f ) if os.path.isfile( paf ): returnList.append( paf ) return returnList ## All recursive changes June 2009 if not recurse: ## Note: If self.path DOES NOT EXIST then this raises and OSError ## This can happen when we use the --all cli argument (see cli.py) # Calling os.listdir here is okay because self.path is unicode, but # listOfFilenamesOnly *should* be a list of pure unicode objects as a result. # It's NOT - I have found problems... see safeJoin func just above. listOfFilenamesOnly = os.listdir ( self.path ) # Get the unicode list sourceList = safeJoin(self.path, listOfFilenamesOnly ) else: # Recursive code sourceList=[] # Force P to be BYTE STRING from unicode<-came in as P = fpsys.LSP.ensure_bytes( self.path ) for root, dirs, files in os.walk( P ): ## I need root and each file to be UNICODE, so I must decode them here R = fpsys.LSP.to_unicode( root ) F = [ fpsys.LSP.to_unicode(f) for f in files ] sourceList.extend( safeJoin( R, F ) ) # At this point sourceList is full of PURE BYTE STRINGS ## Now employ the generator magic: ## Makes FontItem objects for each paf in the list. for fi in itemGenerator( self, sourceList ): self.append(fi) if len(self) == 0: #print "EMPTY FOLDER" raise fontybugs.FolderHasNoFonts(self.path) def __str__(self): return str(self.path) def label( self ): """ A handy way to refer to Folders & Pogs in certain circumstances. Pog.label returns the name Folder.label returns the path """ return os.path.basename( self.path ) class Pog(BasicFontList): """ Represents an entire Pog. Contains a list of various FontItems. Dec 2007 - adding OTF and Type 1 Supply the pog name. Must call genList() if you want actual font items in the list. """ def __init__(self, name ): #, progressCallback = None): BasicFontList.__init__(self) self.__pc = fpsys.iPC # A hack to pathcontrol. ## Public properties: ## ## name always comes in as a byte string because ## we built the path up to .fontypython from byte strings ## Make a unicode of that name: uname = fpsys.LSP.ensure_unicode( name ) ## Stores a unicode for access from other places: self.name = uname self.__installed = "dirty" #am I installed? ## ## NB NOTE: self.paf IS A BYTE STRING ## ## Note, name (not self.name) is used here. It is a byte string. ## appPath() is a bs, name is a bs so join leaves this all as a bs. self.paf = os.path.join( self.__pc.appPath(),name + ".pog") ## OVERKILL : self.paf = fpsys.LSP.path_join_ensure_bytestring_result( self.__pc.appPath(),name + ".pog" ) self.badpog = False #To be used mainly to draw icons and ask user to purge. def label(self): """ A handy way to refer to Folders & Pogs in certain circumstances. See around line 1296 wxgui.OnMainClick() Pog.label returns the name (in unicode) Folder.label return the path These are both the full paf of the font. """ return self.name def __openfile(self): """ Open my pog file. Raise PogInvalid error or return a file handle. """ ## NB: NO error is raised if an empty file is opened and read... ## If there is some chronic hard drive problem, I assume Python will quit anyway... try: #print "Trying to open:", [self.paf] ## In theory, any file can *always* be opened - no matter what ## locale. POSIX deals only in byte strings. So, this next ## line will never fail. ## I am going to open it as an ASCII file: f = open( self.paf, 'r' ) # ASCII byte string file only. except: print "CORNER CASE in __openfile on paf:", [self.paf] print sys.exc_info() raise SystemExit ## Let's see what kind of line 1 we have line1 = f.readline()[:-1] self.__installed = "dirty" # unsure as to the status if line1.upper() == "INSTALLED": self.__installed = "yes" if line1.upper() == "NOT INSTALLED": self.__installed = "no" if self.__installed == "dirty": ## We have a bad pog. #print "ABOUT TO RENAME POG" self.__renameBadPog() raise fontybugs.PogInvalid( self.paf ) ## At this point, we have a valid pog file: ## It has a valid line 1 ## It may or may not have paf lines below it. return f def isInstalled(self): """ Passes a raise PogInvalid error through. Any other will abort app. """ if self.__installed == "yes": return True if self.__installed == "no": return False ## Else it == "dirty" and: ## We must open the file to discover the status: ## Will raise an error, so don't handle it, let it propogate upwards. f = self.__openfile() #sets __installed flag f.close() if self.__installed == "yes": return True if self.__installed == "no": return False def __renameBadPog(self): """ This is a bad pog, My plan is to rename it out of the .pog namespace. No error detection ... yet """ newpaf = self.paf[:-4] + ".badpog" #kick out the .pog and append .badpog #print "Invalid Pog : \"%s\"\nRenaming it to \"%s\"" % (self.paf, newpaf) os.rename(self.paf, newpaf) #just going to hope this works... self.paf = newpaf def genList(self): """ Generate the list of font items within myself. Access the disk. Build the object up. All attribs and the list of fonts. Passes any PogInvalid error directly through. """ f = self.__openfile() #sets install flag, raises PogInvalid error. self.clear() #clear is in basicfontlist.py sourceList = [] ## Right, ## If a line of the CONTENT of f is encoded differently to what the locale is ## then the for paf in f: line throws a UnicodeDecodeError ## This means that paf can't be read, but perhaps others can be... try: for paf in f: #This continues from line 2 onwards ... paf = paf[:-1] #Strip the damn \n from the file sourceList.append(paf) f.close() except UnicodeDecodeError: ## I can't even display the paf because it's not been set ## (paf is the last value that was read, since this is an error condition) ## I don't think I have a choice here but to simply pass pass ## Not using this anymore. #raise fontybugs.PogContentEncodingNotMatched( self.paf ) ## Now to make Fontitems out of sourceList for fi in itemGenerator( self, sourceList): self.append(fi) # store them in myself. def purge(self): """ Purge method - remove fonts in the pog that are not on disk. Raises PogEmpty PogInstalled """ ## can't purge an empty pog if len(self) == 0: raise fontybugs.PogEmpty(self.name) # RAISED :: PogEmpty ## can't purge an installed pog if self.__installed == "yes": raise fontybugs.PogInstalled(self.name) # RAISED :: PogInstalled else: ## Let's build a new list of all the bad font items. badfonts = [] for i in self: try: #prevent weird errors on path test... if not os.path.exists(i.glyphpaf) : badfonts.append(i) except: pass # it's bad through-and-through! It'll be axed too. ## Now go thru this list and remove the bad items. for bi in badfonts: #print "purging:", bi.name self.remove(bi) self.write() def install(self): """ Install the fonts in myself to the user's fonts folder. NOTE: Even if ONLY ONE font out of a gigazillion in the pog actually installs, the POG == INSTALLED. If we have a font that cannot be sourced, flag BADPOG For Type1 fonts - The choice I have made is: I will ONLY reference the PFA/B in the Pog file. When we install a Pog, the metric file must be sought in the original folder and linked. Raises: PogEmpty PogAllFontsFailedToInstall PogSomeFontsDidNotInstall """ def linkfont(fi, frompaf, topaf): ## 15 Sept 2009 : Catch situations where the font is already installed. try: os.symlink(frompaf, topaf) #Should do the trick. return True except OSError, detail: if detail.errno != errno.EEXIST: raise # File exists -- this font is already installed, we can ignore EEXIST. ## This font has been linked before. fpsys.Overlap.inc(fi.name) # Use the class in fpsys to manage overlaps. return False ## If this is flagged as installed, then just get out. if self.__installed == "yes": print _("%s is already installed." % self.name) return ## We start thinking all is rosey: self.__installed = "yes" ## Now we make sure ... if len(self) == 0: self.__installed = "no" raise fontybugs.PogEmpty(self.name) # RAISED :: PogEmpty ## Now we go through the guts of the pog, font by font: bugs = 0 for fi in self: ## These os.path functions have been performing flawlessly. ## See linux_safe_path_library remarks (at top) for details. dirname = os.path.basename( fi.glyphpaf ) linkDestination = os.path.join(self.__pc.userFontPath(), dirname ) ## Link it if it ain't already there. if os.path.exists(fi.glyphpaf): if linkfont(fi, fi.glyphpaf, linkDestination): #link the font and if True, it was not overlapped, so also do Type1 step 2 ## Now, the Type1 step 2, link the metric file. if isinstance( fi, Type1Item ): ## It's a Type 1, does it have a metricpaf? if fi.metricpaf: linkDestination = \ os.path.join( self.__pc.userFontPath(), os.path.basename( fi.metricpaf ) ) linkfont( fi, fi.metricpaf, linkDestination ) else: bugs += 1 if bugs == len(self): # There was 100% failure to install fonts. ## We flag ourselves as NOT INSTALLED self.__installed = "no" self.write() raise fontybugs.PogAllFontsFailedToInstall(self.name) # RAISED :: PogAllFontsFailedToInstall elif bugs > 0: ## Some fonts did get installed, but not all. so, we are INSTALLED self.write() raise fontybugs.PogSomeFontsDidNotInstall(self.name) # RAISED :: PogSomeFontsDidNotInstall self.write() #print " [INSTALL COMPLETE]" def uninstall(self): """ Uninstall the fonts. NOTE: If any font is NOT removed POG = INSTALLED Any links that are not found = just ignore: They could have been removed by another pog, or this could have been a bad pog anyway. NO BAD POG flag EVER. Raises: PogEmpty PogLinksRemain PogNotInstalled """ if len(self) == 0: raise fontybugs.PogEmpty(self.name) # RAISED :: PogEmpty bugs = 0 if self.__installed == "yes": for fi in self: #print "*Uninstalling candidate %s" % fi.name if fpsys.Overlap.dec(fi.name): #print " Going to leave this one here" continue # If it overlaps then we skip removing it by going to next fi in loop. #print " Going to REMOVE this one" dirname = os.path.basename( fi.glyphpaf ) link = os.path.join(self.__pc.userFontPath(), dirname ) ## Step one - look for the actual file (link) if os.path.exists(link): try: os.unlink(link) ## The Type1 special case - its AFM/PFM may be here... if isinstance( fi, Type1Item ): ## It's a Type 1, does it have a metricpaf? ## It may be None (if this pfb happens not to have had a afm/pfm.) if fi.metricpaf: pfmlink = os.path.join(self.__pc.userFontPath(), os.path.basename(fi.metricpaf)) if os.path.exists( pfmlink ): os.unlink( pfmlink ) except: # e.g. Permission denied [err 13] ## Only bugs that imply that the file is THERE but CANNOT BE REMOVED ## are classified as bugs. We are making a sweeping assumption here. bugs += 1 ## Okay, we are currently INSTALLED, so what is the result of the loop? if bugs > 0: ## We still have fonts in the pog that could NOT be removed, ergo we stay INSTALLED raise fontybugs.PogLinksRemain(self.name) # RAISED :: PogLinksRemain else: ## Okay - there were no problems, so we are now done. self.__installed = "no" self.write() #save to disk #print " [UNINSTALL COMPLETE]" else: ## self.__installed says we are not installed: raise fontybugs.PogNotInstalled(self.name) # RAISED :: PogNotInstalled def write(self) : """ Write a pog to disk. """ try: f = open( self.paf, 'w' ) # Going to make the contents ASCII only. Byte strings. i = "not installed\n" if self.__installed == "yes": i = "installed\n" f.write(i) #Now write the font pafs for i in self: ## since the glyphpaf can vary it's type ## we must encode it to a byte string if it's unicode. gpaf = fpsys.LSP.ensure_bytes( i.glyphpaf ) f.write( gpaf + "\n") f.close() except: raise fontybugs.PogWriteError(self.paf) def delete(self): """ Delete my pogfile, then clean myself up, ready to be destroyed. """ try: os.unlink(self.paf) except: raise fontybugs.PogCannotDelete(self.paf) self.clear() self.__installed = "no" def zip(self, todir): """Sept 2009 : Add all the fonts to a zip file in todir.""" ## Start a zip file: I am not sure if a filename should be bytestrings or unicode.... file = zipfile.ZipFile(os.path.join(todir,self.name + ".fonts.zip"), "w") self.genList() # I forget how to handle errors raised in that labyrinth... sorry world :( #print "ZIP:",ipog.name bugs=False for fi in self: ## zipfiles have no internal encoding, so I must encode from unicode to a byte string arcfile = fpsys.LSP.ensure_bytes(os.path.basename(fi.glyphpaf)) try: file.write(fi.glyphpaf, arcfile, zcompress) #var set global at start of this module. except OSError,e: bugs=True # e.errno == errno.ENOENT: # No such file or directory print e # whatever is wrong, print the message and continue file.close() return bugs # a flag for later. fontypython-0.4.4/fontypythonmodules/fontybugs.py0000644000175000017500000001024311742276540021172 0ustar donndonn## Fonty Python Copyright (C) 2006, 2007, 2008, 2009 Donn.C.Ingle ## Contact: donn.ingle@gmail.com - I hope this email lasts. ## ## This file is part of Fonty Python. ## Fonty Python 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. ## ## Fonty Python 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 Fonty Python. If not, see . import locale import fpsys """ testing i18n with fontybugs try: raise fontybugs.BadVoodoo("bad voodoo") except fontybugs.BadVoodoo, e: print "error:", unicode(e) try: raise fontybugs.PogWriteError("/some/path/po.pog") except fontybugs.PogWriteError, e: print unicode(e) """ ## The %s must be OUTSIDE the _() construct. class Errors ( Exception ): checkperms = _("\n(Also check your file permissions.)") messages = { 001 : _("Bad voodoo error. I give up."), 100 : _("There is no such item."), 200 : _("Pog is empty."), 300 : _("Pog is already installed."), 500 : _("Pog cannot be written to.\nCheck your filesystem.%s") % checkperms, 600 : _("Pog is invalid, please hand-edit it."), 700 : _("Some fonts did not install.\nPerhaps the original fonts folder has moved or been renamed.\nYou should purge or hand-edit."), 800 : _("Pog is not installed."), 900 : _("Some fonts could not be uninstalled.\nPlease check your home .fonts (with a dot in front) folder for broken links.%s") % checkperms, 1000 : _("Cannot delete the Pog.%s") % checkperms, 1010 : _("Not a single font in this pog could be installed.\nThe original font folder has probably moved or been renamed."), 1020 : _("Not a single font in this pog could be uninstalled.\nNone of the fonts were in your fonts folder, please check your home .fonts (with a dot in front) folder for broken links.\nThe pog has been marked as \"not installed\"."), 1030 : _("This folder has no fonts in it.") } def __unicode__( self ): return u"%s : %s" % ( self.__class__.messages[self._id], self._item ) def _format_error(self): ## As of Python 2.6 e.message has been deprecated. ## Turn 'self' into a 'string like object' by calling __unicode__ above. msg = unicode(self) msg = fpsys.LSP.to_bytes( msg ) return msg def print_error(self): print self._format_error() def print_error_and_quit(self): self.print_error() raise SystemExit class BadVoodoo ( Errors ): def __init__ ( self, item = None): self._item = item self._id = 001 class ErrNoSuchItem ( Errors ): def __init__ ( self, item = None): self._item = item self._id = 100 class PogEmpty ( Errors ): def __init__ ( self, item = None): self._item = item self._id = 200 class PogInstalled ( Errors ): def __init__ ( self, item = None): self._item = item self._id = 300 class PogWriteError ( Errors ): def __init__ ( self, item = None): self._item = item self._id = 500 class PogInvalid ( Errors ): def __init__ ( self, item = None): self._item = item self._id = 600 class PogSomeFontsDidNotInstall ( Errors ): #Some fonts did get installed, but not all def __init__ ( self, item = None): self._item = item self._id = 700 class PogNotInstalled ( Errors ): def __init__ ( self, item = None): self._item = item self._id = 800 class PogLinksRemain ( Errors ): def __init__ ( self, item = None): self._item = item self._id = 900 class PogCannotDelete ( Errors ): def __init__ ( self, item = None): self._item = item self._id = 1000 class PogAllFontsFailedToInstall ( Errors ): def __init__ ( self, item = None): self._item = item self._id = 1010 class PogAllFontsFailedToUninstall ( Errors ): def __init__ ( self, item = None): self._item = item self._id = 1020 class FolderHasNoFonts ( Errors ): def __init__ ( self, item = None): self._item = item self._id = 1030 fontypython-0.4.4/fontypythonmodules/fontyfilter.py0000644000175000017500000000215411742276540021521 0ustar donndonnimport fpsys # Global objects import re """ June 2009 Created this file with the intention of more complex searching using the FontTools module. This has not come to fruition, but I will keep this module just in-case. """ def doFilter( filter_string ): ##filter_string is a unicode object ## STEP 1 : get the current view object (pog or folder) filteredList = fpsys.state.viewobject ## if filter is not empty if filter_string is not "": ## Okay, we have some kind of filter. ## This idea was suggested by user Chris Mohler. filteredList = [] ## We allow regex in the string. Is this wise? test = re.compile(filter_string, re.IGNORECASE) ## Go through each font item and match ## the regex against certain fields. ## EXTEND THIS TO PANOSE AND other fontTools criteria. for fi in fpsys.state.viewobject: ## Make sure we don't try fetch info from a bad font. if not fi.badfont: if test.search( fi.name + fi.family[0] + fi.style[0] ): filteredList.append( fi ) else: if test.search( fi.name ): filteredList.append( fi ) ## We return the filtered-list return filteredList fontypython-0.4.4/fontypythonmodules/fpsys.py0000644000175000017500000004156011742276540020324 0ustar donndonn## Fonty Python Copyright (C) 2006, 2007, 2008, 2009 Donn.C.Ingle ## Contact: donn.ingle@gmail.com - I hope this email lasts. ## ## This file is part of Fonty Python. ## Fonty Python 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. ## ## Fonty Python 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 Fonty Python. If not, see . ## fpsys : fonty python system. ## I debated calling it fpglobals. ## This is a common-ground for variables and defs that will be used from ## other modules - so they are global to everything. import sys, os, pickle import linux_safe_path_library LSP = linux_safe_path_library.linuxSafePath() import pathcontrol import strings import fontcontrol import charmaps import wx import subprocess ## Oct 2009 Default Font Family (System font) DFAM=None # Set in wxgui.py in class App() ## Ensure we have a .fontypython folder and a .fonts folder. iPC = pathcontrol.PathControl() #Make an instance - hence the small 'i' (Boy this convention *sure* lasted....) ## Borrowed from wxglade.py ## The reason for this is to find the path of this file ## when it's called from an import somewhere else. ## There is no sys.argv[0] in this case. root = __file__ if os.path.islink(root): root = os.path.realpath(root) fontyroot = os.path.dirname(os.path.abspath(root)) ## Where my images and things are. mythingsdir = os.path.join(fontyroot,"things/") ## Sept 2009 class Overlaperize(object): ''' If a single font is in many pogs, then we count each 'overlap' and control the removal of them until there are no overlaps anymore. i.e. When no other installed pogs are using the font, it is safe to remove the link (should that last pog be removed by the user). ''' def __init__(self): self.OVERLAP_COUNT_DICT = {} self.DISABLE_THIS = False # In case all this makes a horrible mess : users can flip this to True.... def inc(self,key): if self.DISABLE_THIS: return True if key in self.OVERLAP_COUNT_DICT: self.OVERLAP_COUNT_DICT[key] += 1 else: self.OVERLAP_COUNT_DICT[key] = 2 #starts at 2 because there is already one installed. #self.report(key) return True def dec(self,key): ''' Return True means : This font overlaps Return False means : This font can be uninstalled ''' if self.DISABLE_THIS: return False if key in self.OVERLAP_COUNT_DICT: self.OVERLAP_COUNT_DICT[key] -= 1 if self.OVERLAP_COUNT_DICT[key] == 0: del self.OVERLAP_COUNT_DICT[key] return False # it does NOT overlap anymore. else: #self.report(key) return True # It still overlaps # It gets if the font is totally unknown to the OVERLAP_COUNT_DICT return False #It therefore does NOT overlap. def report(self,key): print "%s has overlap count of %d" % (key, self.OVERLAP_COUNT_DICT[key]) def sleep(self): '''Save the OVERLAP_COUNT_DICT to a file (if it has content). Called when app closes.''' if self.DISABLE_THIS: return if not self.OVERLAP_COUNT_DICT: self.OVERLAP_COUNT_DICT={} # Ensure there is a blank overlap_counts file! paf = os.path.join(iPC.appPath(),"overlap_counts") fr = open( paf, 'wb' ) # pickle says use 'binary' files, but only Windows makes this distinction. I use it to be safe... pickle.dump( self.OVERLAP_COUNT_DICT, fr, protocol=pickle.HIGHEST_PROTOCOL ) fr.close() def wakeup(self): '''Restore the OVERLAP_COUNT_DICT from a file (if any). Called as app starts.''' if self.DISABLE_THIS: return paf = os.path.join(iPC.appPath(),"overlap_counts") if os.path.exists( paf ): fr = open( paf, "rb" ) self.OVERLAP_COUNT_DICT = pickle.load( fr ) fr.close() ## start it up! Overlap = Overlaperize() Overlap.wakeup() ## Jan 18 2008 segfonts = []# Global var def getSegfontsList(): """Runs (below) on startup""" ## On startup, open the 'segfonts' file and keep a list in RAM ## This file is written by the 'check' routine. global segfonts paf = os.path.join(iPC.appPath(),"segfonts") try: if os.path.exists( paf ): fr = open( paf, 'r' ) # byte string only ascii file segfonts = fr.read().split("\n") fr.close() except: ## CORNER CASE: Some error or other. raise ## Call it. getSegfontsList() def checkFonts( dirtocheck, printer ): """ Jan 18 2008 Scan a tree for fonts that can cause segfaults. Write a file 'segfonts' and create a list 'segfonts' that gets checked to exclude them. printer is a function of some kind. Can be called from the cli or the gui. """ global segfonts code = """ import ImageFont try: font=ImageFont.truetype("%s", 24, 0) dud=font.getname() except: pass """ def checkForSegfault( pafbytestring ): ## Uses Ajaksu's idea : 17 Jan 2008. Thanks! segfault_I_hope = False ## I have ignored ALL catchable errors (see code var) ## This is because I want to (try to) only catch SEGFAULTS ## and leave all other flavours of font-related errors to ## the fontcontrol module -- where fonts are still useable ## if not visible. retval = subprocess.call( ["python", '-c', code % pafbytestring] ) if retval != 0: segfault_I_hope = True return segfault_I_hope printer ( _("Checking fonts, this could take some time.") ) printer ( _("Starting in %s:") % dirtocheck ) printer () ## dirtocheck comes-in as unicode - let's stick to byte strings: dirtocheck = LSP.to_bytes( dirtocheck ) seglist = [] # our local list of newly found bad fonts gotsome = False for cwd, dirs, files in os.walk( dirtocheck ): printer(_("Looking in %s...") % os.path.basename(cwd) ) ## We only want certain font files: fontfiles = [f for f in files if f.upper().endswith( ("TTF","TTC","PFA","PFB","OTF")) ] if len(fontfiles) < 1: printer (_("No supported fonts found there...")) printer() for file in fontfiles: paf = os.path.join( cwd, file ) bad = checkForSegfault( paf ) if bad: gotsome = True seglist.append( paf ) printer ( " " + file ) # show it on-screen somewhere. if not gotsome: printer(_("I could not find any bad fonts.")) ## Now write the segfonts file: if seglist: ## Add the new fonts found to the ones in global segfonts list for bf in seglist: segfonts.append(bf) ## Now remove duplicates tmp = list( set( segfonts ) ) segfonts = tmp del (tmp) ## Now save it. paf = os.path.join(iPC.appPath(),"segfonts") fw = open( paf, "w" ) # byte string ascii bytestring = "".join([line + "\n" for line in segfonts if line != ""]) #print "about to write bytestring:" #print [bytestring] #print fw.write( bytestring ) fw.close() printer() printer(_("The process is complete.")) def isFolder(thing): """True if a folder. False if not - but that does not mean it's a pog.""" if os.path.isdir(thing): return True return False def isPog(thing): """True if a Pog. False if not.""" ## thing comes in as UNICODE ## iPC.getPogNames() is a list of BYTE STRINGS ## We must encode thing to a byte string to avoid warnings: if LSP.to_bytes( thing ) in iPC.getPogNames(): #getPogNames contains byte strings! return True if thing == "EMPTY": return True #Special case return False class FPState: """The global vars to hold the state of the situation.""" def __init__(self): ## Contains the Pog or Folder being viewed self.viewobject = None ## Refs the view object *after* the filter has been applied self.filteredViewObject= None ## Contains a Pog (or None) that is the Target self.targetobject = None ## Represents the situation in a letter code ## P for Pog, F for Folder, E for Empty, N for None self.viewpattern = "" self.targetpattern = "" ## Will be "NOTHING_TO_DO", "REMOVE" or "APPEND" (Add fonts to Pog) self.action = "" ## Can an item be ticked self.cantick = None ## The View and Target pogs chosen are the same. self.samepogs = False ## How many tick marks. self.numticks = 0 state = FPState() #The only instance of the state object -- app-wide #### ## Save and Load the conf file class Configure: """Makes/Loads the conf file. Supplies size, pos, numinpage, text string and point size to other objects.""" def __init__(self) : ## Private vars self.__dontSaveNumInPage = False ## PUBLIC vars : Set some defaults: self.size = (800,600) self.pos = (10, 10) self.numinpage = 10 self.text = _("Jump the lazy dog fox") self.points = 64 self.lastview = "EMPTY" # a pog name or a folder path. self.usegui = "wxgui" self.max = True self.lastdir = iPC.home() ## Added Dec 2007 self.leftSash = 200 self.rightSash = 128 ## Added June 2009 self.recurseFolders = False ## Added Sept 2009 self.ignore_adjustments = False ## Added 3 Oct 2009 self.app_char_map = "UNSET" # A string of an app name. self.__setData() ## Oct 2009 -- The Character Map Controller. self.CMC = charmaps.CharMapController( self.app_char_map_set ) if os.path.exists(iPC.appConf()): try: pf = open(iPC.appConf(), "rb" ) # Binary for new pickle protocol. self.__data = pickle.load( pf ) pf.close() except: ## Dec 2007 : Let's try erase and rewind os.unlink(iPC.appConf()) if not os.path.exists(iPC.appConf()): print _("No config file found, creating it with defaults.") self.Save() ## Now get them into the instance vars: try: self.size = self.__data['size'] self.pos = self.__data['pos'] self.numinpage = self.__data['numinpage'] self.text = self.__data['text'] self.points= self.__data['points'] self.lastview = self.__data['lastview'] self.usegui = self.__data['usegui'] self.max = self.__data['max'] self.lastdir = self.__data['lastdir'] self.leftSash = self.__data['leftSash'] self.rightSash = self.__data['rightSash'] self.recurseFolders = self.__data['recurseFolders'] self.ignore_adjustments = self.__data['ignore_adjustments'] self.app_char_map = self.__data['app_char_map'] ## We must also set our instance of the Char Map Controller: ## This can be "UNSET" (default first run) or an appname ## That appname may be valid or not (it may have been uninstalled...) self.CMC.SET_CURRENT_APPNAME(self.app_char_map) except KeyError: ## The conf file has keys that don't work for this version, chances are it's old. ## Let's delete and re-make it. try: os.unlink(iPC.appConf()) except: print _("The fontypython config file is damaged.\nPlease remove it and start again") raise SystemExit self.Save() def dontSaveNumInPage(self, flag): self.__dontSaveNumInPage = flag def __setData(self): self.__data = {"size" : self.size, "pos" : self.pos, "numinpage" : self.numinpage, "text" : self.text, "points" : self.points, "lastview" : self.lastview, "usegui" : self.usegui, "max" : self.max, "lastdir" : self.lastdir, "leftSash" : self.leftSash, "rightSash" : self.rightSash, "recurseFolders": self.recurseFolders, "ignore_adjustments": self.ignore_adjustments, "app_char_map" : self.app_char_map } def app_char_map_set( self, x ): ''' A callback from the CharMapController: when the CURRENT_APPNAME is set, this gets called to keep the config version of the appname current. ''' self.app_char_map = x def Save(self) : #If we are NOT to save the numinpage, then fetch it from what was there before. if self.__dontSaveNumInPage: self.numinpage = self.__data["numinpage"] self.__setData() try: pf = open( iPC.appConf(), "wb" ) pickle.dump(self.__data, pf, protocol = pickle.HIGHEST_PROTOCOL ) pf.close() except IOError: print _("Could not write to the config file.") Overlap.sleep() #sept 2009 : Save the OVERLAP_COUNT_DICT ## Our config instance - it will have one instance across ## all the modules that use it. config = Configure() def instantiateViewFolder( foldername, recurse=False ): """ Creates a Folder object and fills it with FontItem objects according to what's in the folder's path. This is the VIEW - i.e. what you are looking at. """ if state.viewobject: del state.viewobject ## Default assumptions in case of raised error. state.viewobject = fontcontrol.EmptyView() state.viewpattern = "E" ifolder = fontcontrol.Folder(foldername, recurse) #raises : fontybugs.FolderHasNoFonts : BENIGN ERROR. ## Only continues if there is no problem. state.viewobject = ifolder ## Because we have a new view object, we must reset the last filteredViewObject state.filteredViewObject = None config.lastview = foldername state.viewpattern = "F" markInactive() flushTicks() def instantiateViewPog( newpog_name ): """ Given a Pog Name string, make a Pog object. This is the VIEW - i.e. what you are looking at. A VIEW Pog can be EMPTY. This happens on the first run when there is no config file. There are other arcane situations too, but I forget. """ ## print "COMES IN to instantiateViewPog:" ## print "newpog_name:", newpog_name ## print "type(newpog_name):", type(newpog_name) #if state.viewobject: del state.viewobject if state.viewobject: state.viewobject = None if newpog_name == "EMPTY": ipog = fontcontrol.EmptyView() else: ipog = fontcontrol.Pog( newpog_name ) ## Test TARGETPOG to see if this is the same pogname ## The not None test is for first run - there is no targetobject yet just after cli.py calls us, so we ## do not want to access it or we get NoneType errors. if state.targetobject is not None and state.targetobject.name == newpog_name: state.samepogs = True else: state.samepogs = False ## Must gen the Pog to get a count of items: ## Errors raised in genList (and company): ## fontybugs.PogInvalid (only valid from cli pov) ## ## We 'handle' this by NOT catching it, pass it up. ipog.genList() ## Continue if all ok. state.viewobject = ipog ## Because we have a new view object, we must reset the last filteredViewObject state.filteredViewObject = None config.lastview = newpog_name if len(state.viewobject) == 0: empty = True state.viewpattern = "E" else: empty = False state.viewpattern = "P" markInactive() flushTicks() #print "instantiateViewPog says viewpattern is:", state.viewpattern return empty # this return is only used in cli.py def instantiateTargetPog( newpog_name ): """ The app could begin with NO TARGET POG chosen. After that (in the gui) either a pog is chosen or NO POG is chosen (i.e. None) Therefore - there can NEVER BE a targetobject called EMPTY The CLI install/uninstall/purge DO NOT use this routine. """ if state.targetobject: del state.targetobject ipog = fontcontrol.Pog(newpog_name) ## Must gen the Pog to get a count of items: ipog.genList() # Raises fontybugs.PogInvalid error THIS ENDS THE APP. ## TEST the viewobject which is the stuff being ## LOOKED AT IN THE MIDDLE OF THE SCREEN (which could be a Pog OR a Folder) ## If it's a Pog then we may have chosen the same Pog (on the right) ## that we are looking at, so check that: state.samepogs = False if isinstance( state.viewobject, fontcontrol.Pog ): if state.viewobject.name == newpog_name: ## The pog clicked in the TARGET is the same as what's ALREADY selected in the VIEW state.samepogs = True quickinstalledflag = False if ipog.isInstalled(): quickinstalledflag = True state.targetpattern = "P" state.targetobject = ipog markInactive() flushTicks() return quickinstalledflag def markInactive(): """ INACTIVE means the font displayed is already inside the chosen target pog. So, it's not 'active', not clickable etc. Mark each font item as inactive, as needs-be. Clear the ticks. Sets the message to display in the fontmap. """ if state.viewobject: state.viewobject.clearInactiveflags() if state.viewobject and state.targetobject: ## What's in TARGET must be inactive in VIEW ## pafBlist is a list of UNICODEs ## glyphpaf_unicode is UNICODE, so I will use it instead ## because we compare it to pafBlist pafBlist = [i.glyphpaf_unicode for i in state.targetobject] for iA in state.viewobject: if iA.glyphpaf_unicode in pafBlist: iA.activeInactiveMsg = _("This font is in %s") % state.targetobject.name iA.inactive = True del pafBlist def SetTargetPogToNone(): state.targetobject = None state.targetpattern = "N" def SetViewPogToEmpty(): state.viewobject = fontcontrol.EmptyView() state.viewpattern = "E" def flushTicks(): for fi in state.viewobject: fi.ticked = False state.numticks = 0 def logSegfaulters( lastPaf ): """ Writes a string to ~/.fontypython/lastFontBeforeSegfault """ paf = os.path.join( iPC.appPath(),"lastFontBeforeSegfault") try: f = open( paf, "w" ) lastPaf = LSP.ensure_bytes( lastPaf ) f.write( lastPaf + "\n" ) f.close() except: raise fontypython-0.4.4/fontypythonmodules/fpversion.py0000644000175000017500000000150011742277331021160 0ustar donndonn## Fonty Python Copyright (C) 2006, 2007, 2008, 2009 Donn.C.Ingle ## Contact: donn.ingle@gmail.com - I hope this email lasts. ## ## This file is part of Fonty Python. ## Fonty Python 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. ## ## Fonty Python 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 Fonty Python. If not, see . version = "0.4.4" fontypython-0.4.4/fontypythonmodules/gui_Fitmap.py0000644000175000017500000004334611742276540021250 0ustar donndonn## Fonty Python Copyright (C) 2006, 2007, 2008, 2009 Donn.C.Ingle ## Contact: donn.ingle@gmail.com - I hope this email lasts. ## ## This file is part of Fonty Python. ## Fonty Python 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. ## ## Fonty Python 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 Fonty Python. If not, see . import wx import colorsys import subprocess,os import threading import wx.lib.statbmp import fontcontrol import fpsys # Global objects from pubsub import * from wxgui import ps ndc=(200,190,183) # No Draw Color: colour of background for the fonts I can't draw ndi=(227,226,219) # No Draw Inactive. black=(0,0,0) white=(255,255,255) class OverOutSignal(object): ''' Signal an external function when a state has CHANGED from True to False or vice-vera ''' def __init__( self, func_to_signal ): self.announce = func_to_signal self.state = False self.last_state = False def __changed( self ): if self.state != self.last_state: self.last_state = self.state return True return False def set( self, truth ): if self.state == truth: return self.state = truth if self.__changed(): self.announce() class Fitmap(wx.lib.statbmp.GenStaticBitmap): """ This class is a bitmap of a TTF font - it detects events and displays itself. Sept 2009 Added code to adjust top-left of displayed sample text. Oct 2009 Added a 'button' to open a character map viewer. """ ## This class-level dict is a kind of "style sheet" to use in fitmap drawing. styles={ 'FILE_NOT_FOUND': #Needs purging { 'backcol': (255,214,57), 'fcol' : black, 'bcol' : white, 'icon' : "NOT_FOUND", }, 'PIL_SEGFAULT_ERROR': { 'backcol': (152,147,157), #255,140,20), 'fcol' : black, 'bcol' : white, 'icon' : "SEGFAULT", 'ndi' : (216,193,193) }, 'PIL_IO_ERROR': { 'backcol': ndc, 'fcol' : black, 'bcol' : white, 'icon' : "NO_DRAW", 'ndi' : ndi }, 'PIL_UNICODE_ERROR': { 'backcol': ndc, 'fcol' : black, 'bcol' : white, 'icon' : "NO_DRAW", 'ndi' : ndi }, 'PIL_CANNOT_RENDER': { 'backcol': ndc, 'fcol' : black, 'bcol' : white, 'icon' : "NO_DRAW", 'ndi' : ndi }, 'ACTIVE': { 'backcol': white, 'fcol' : black, 'bcol' : (200,200,200), 'icon' : None, }, 'INACTIVE': { 'backcol': white, 'fcol' : (128,128,128), 'bcol' : white, 'icon' : None, }, 'INFO_FONT_ITEM': { 'backcol': white, 'fcol' : black, 'icon' : "INFO_ITEM", } } def __init__( self, parent, pos, fitem ) : self.name = fitem.name self.fitem = fitem Fitmap.styles['INFO_FONT_ITEM']['backcol']=parent.GetBackgroundColour() self.FVP = parent.parent #The Font View Panel self.TICKMAP = parent.parent.TICKMAP self.TICKSMALL = parent.parent.TICKSMALL self.style = {} #Temporary space for style of fitem while drawing. It's a copy of one key from Fitem.styles # Some values for drawing self.minHeight = 70 self.spacer = 35 # Gap below each font bitmap self.gradientheight = 50 self.width = parent.width # Get it from the scrollFontViewPanel. ## The charmap button self.CHARMAP_BUTTON_OVER = self.FVP.BUTTON_CHARMAP_OVER self.CHARMAP_BUTTON_OUT = self.FVP.BUTTON_CHARMAP ## Point to the handler for the signal re charmap button self.cmb_overout = OverOutSignal( self.charmap_button_signal ) ## Go draw the fitmap into a memory dc self.bitmap = None self.prepareBitmap() sz = (self.bitmap.GetWidth(), self.bitmap.GetHeight()) ## Now I can calc the y value of the button. self.cmb_rect=wx.Rect(0,sz[1]-40,19,32) self.height = 0 ## init my parent class self.gsb = wx.lib.statbmp.GenStaticBitmap.__init__(self, parent, -1, self.bitmap, pos, sz) ## Fitmap's over out signal self.overout = OverOutSignal( self.overout_signal ) ## Very cool event, gives us life! self.Bind(wx.EVT_LEFT_UP,self.onClick) self.Bind(wx.EVT_MIDDLE_UP, self.onMiddleClick) #self.Bind(wx.EVT_LEFT_DCLICK, self.onDClick) self.Bind( wx.EVT_MOTION, self.onHover ) self.Bind( wx.EVT_LEAVE_WINDOW, self.onLeave) ## Redraw event self.Bind(wx.EVT_PAINT, self.onPaint) ## Get cursors setup self.CURSOR = wx.StockCursor( wx.CURSOR_ARROW ) if fpsys.state.action in ("REMOVE", "APPEND"): self.CURSOR = wx.StockCursor( wx.CURSOR_HAND ) if self.fitem.badstyle == "FILE_NOT_FOUND": self.CURSOR = wx.StockCursor( wx.CURSOR_ARROW ) if self.fitem.inactive: self.CURSOR = wx.StockCursor( wx.CURSOR_ARROW ) def openCharacterMap( self ): fi=self.fitem dirname = os.path.basename( fi.glyphpaf ) dest = os.path.join(fpsys.iPC.userFontPath(), dirname ) ## I don't want to hold an fitem in the thread to come, so I will ## take the essential info out and make a tuple instead: ## (This is mere superstition and ignorance, I fear threads :) ) argstup=(fi.glyphpaf, dest, self.fitem.family[0],fpsys.config.points ) ## Never done threading before. Not really sure if this is kosher... #~ MICHAEL 4.2011: #~ I tried threading myself, too. But I don't really understand it #~ down to the present day. As I see "Popen" in charmaps.py/Run #~ starts his own thread, so we don`t need to make assurance double sure. #~ By the way, this push gucharmap to work as we want. self.run(*argstup) #~ thread = threading.Thread(target=self.run, args=argstup) #~ thread.setDaemon(True) #~ thread.start() def run(self, *args): ''' Uses the instance (held in fpsys.config) of the classes in charmaps.py. ''' iCM = fpsys.config.CMC.GetInstance() iCM.OpenApp( *args ) iCM.Cleanup( ) def onMiddleClick(self, event): ps.pub( menu_settings, None ) def can_have_button( self ): ''' Because I just can't guarantee that there is a family name and because bad fonts that can't draw (but do not segfault) are so rare that I can't bloody find any to test with (grrr) I make the sweeping fiat that no badfonts will get a button. Other fitems like info and FILE_NOT_FOUND don't get buttons. ''' if not fpsys.config.CMC.APPS_ARE_AVAILABLE: return False if isinstance( self.fitem, fontcontrol.InfoFontItem ): return False if self.fitem.badstyle == "FILE_NOT_FOUND": return False if not self.fitem.family: return False return True def onHover( self, e ): if not self.can_have_button(): self.overout.set ( True ) return if self.cmb_rect.Contains( e.GetPositionTuple() ): self.cmb_overout.set( True ) self.overout.set( False ) #Not 'on' fitmap else: self.cmb_overout.set ( False ) self.overout.set( True ) def charmap_button_signal( self ): if self.cmb_overout.state: self.SetCursor(wx.StockCursor(wx.CURSOR_MAGNIFIER)) self.Refresh() # Force onPaint() def overout_signal( self ): if self.overout.state: self.SetCursor( self.CURSOR ) def onLeave(self, event): ''' Catch the leave event for set the charmap button off, if the pointer goes out on the left edge. ''' self.onHover(event) def onClick(self, event) : if self.cmb_overout.state and self.can_have_button(): self.openCharacterMap() return if fpsys.state.cantick and not self.fitem.inactive: self.fitem.ticked = not(self.fitem.ticked) self.prepareBitmap() # This only redraws a single font item. self.Refresh() #forces a redraw. ## Inc or dec a counter depending on the tickedness of this item if self.fitem.ticked: fpsys.state.numticks += 1 if not self.fitem.ticked: fpsys.state.numticks -= 1 ps.pub(toggle_main_button) def onPaint(self, event): """ Dump the bitmap to the screen. """ if self.bitmap: ## Create a buffered paint DC. It will create the real ## wx.PaintDC and then blit the bitmap to it when dc is ## deleted. dc = wx.BufferedPaintDC(self, self.bitmap, wx.BUFFER_VIRTUAL_AREA) if not self.can_have_button(): return # Draw the charmap button x,y = self.cmb_rect[0],self.cmb_rect[1] if self.cmb_overout.state: dc.DrawBitmap( self.CHARMAP_BUTTON_OVER, x, y, True ) else: dc.DrawBitmap( self.CHARMAP_BUTTON_OUT, x,y, True ) def CalculateTopLeftAdjustments(self, image, i, pilimage): ## Sept 2009 ## Find the first pixel from the top-left of the image (if it's not stored) ## Using this pixel as the x,y I can draw fonts from where their actual data ## begins and not where the pilimage *thinks* it does (leaving big white spaces ## to the left of many fonts.) if fpsys.config.ignore_adjustments: return 0,0 wx.BeginBusyCursor() if not self.fitem.top_left_adjust_completed: W,H = pilimage.size fx=fy=0 esc = False # Scan ACROSS WIDTH and repeatedly DOWN looking for a pixel. for tx in xrange(W): for ty in xrange(H): ap=image.GetAlpha(tx,ty) #image.SetRGB(tx,ty,0,255,0) #image.SetAlpha(tx,ty,255) if ap != 0: #Found X coord, let's kill both loops fx=tx esc = True break if esc: break #uses fact that 0 is False # Scan DOWN the HEIGHT and repeatedly ACROSS. esc = False for ty in xrange(H): for tx in xrange(W): ap=image.GetAlpha(tx,ty) if ap != 0: fy=ty # Found Y coord esc = True break if esc: break self.fitem.fx[i]=fx self.fitem.fy[i]=fy # If we are at the end of the number of faces (for ttc files this is > 0) then flag it true if i+1 == self.fitem.numFaces: self.fitem.top_left_adjust_completed = True else: ## Fetch the values from the cache list. fx,fy = (self.fitem.fx[i], self.fitem.fy[i]) wx.EndBusyCursor() return fx,fy def prepareBitmap( self ): """ This is where all the drawing code goes. It gets the font rendered from the FontItems (via PIL) and then draws a single Fitmap. """ ## Is this a normal FontItem, or an InfoFontItem? ## InfoFontItem is a fake font item for the purposes ## of saying "There are no fonts to see here." if isinstance( self.fitem, fontcontrol.InfoFontItem ): self.style=Fitmap.styles['INFO_FONT_ITEM'] self.drawInfoOrError( self.width, self.minHeight, isinfo=True ) return # Just get out. ## Get a list of pilimages, for each subface: Some fonts ## have multiple faces, and their heights. ## REMEMBER: This loop is all FOR THIS ONE FONT ITEM. ## It only supplies pilimages for fonts it could open and ## render. So this font may indeed have nothing in the pilList[] ## after this loop. pilList=[] totheight = 0 maxwidth = [self.width] # to figure-out the biggest width for pilimage in self.fitem.generatePilFont( ): pilList.append( pilimage ) totheight += pilimage.size[1] + self.spacer maxwidth.append(pilimage.size[0]) ## Limit the minimum we allow. if totheight < self.minHeight: totheight = self.minHeight maxwidth = max(maxwidth) # find it. ## BADFONT cases ## Badfonts are still available for installation, it's just that I can't ## display their glyph or fam/style info (until PIL is patched). self.setStyle() #Go set the self.style if self.fitem.badfont: ## We have a badstyle to help us differentiate these. totheight = self.minHeight if self.fitem.inactive: totheight += 5 #Need more space memDc=self.drawInfoOrError( self.width, totheight ) ## It's *not* a badfont else: if self.fitem.inactive: totheight += (self.spacer-20) #want room for 'is in pog' message. ## Make one big bitmap to house one or more faces (subfaces) memDc=self.makeBlankDC( maxwidth, totheight, white ) fcol = self.style['fcol'] bcol = self.style['bcol'] #Draw the gradient. The fonts will render in alpha over that. self.bottomFadeEffect( memDc, totheight, maxwidth ) y = i = 0 for pilimage in pilList: pilwidth, glyphHeight = pilimage.size try: ## Get the data from PIL into wx. ## Now with alpha! Thanks to: ## http://nedbatchelder.com/blog/200801/truly_transparent_text_with_pil.html ## http://wiki.wxpython.org/WorkingWithImages image=None image = apply( wx.EmptyImage, pilimage.size ) image.SetData( pilimage.convert( "RGB").tostring() ) image.SetAlphaData(pilimage.convert("RGBA").tostring()[3::4]) fx,fy = self.CalculateTopLeftAdjustments( image, i, pilimage ) faceBitmap = image.ConvertToBitmap() except: ## Some new error that I have not caught before has happened. ## It may also be a bad sub-face from a ttc font. ## Draw error message into the memDc memDc.SetTextForeground( fcol ) txt=_("This text cannot be drawn. Hey, it happens...") memDc.SetFont( wx.Font( fpsys.config.points, fpsys.DFAM, style=wx.ITALIC, weight=wx.NORMAL)) memDc.DrawText( txt, 10, y+2) else: #no error happened, we carry on. ## Place it into the main image, down a tad so it looks better. facex = 10 if i > 0: facex *= 2 # Shift sub-faces over a little ## Draw the face into the memDc psx = facex-fx# if (facex-fx) < 0 else psx = facex-fx psy = y-fy memDc.DrawBitmap( faceBitmap, psx, psy + 10, True ) ## Postion texty = y + glyphHeight + 8 ## Now draw the text showing the font name/family/style. ## -- suggested by Chris Mohler. ## Prep the text to show "font family name (font file name)" ## Added Style info 3 Dec 2006: txt = "%s - %s - [%s]" % (self.fitem.family[i], self.fitem.style[i], self.name) memDc.SetTextForeground( fcol ) ## Sep 2009: Trying to draw foreign chars via DrawText memDc.SetFont( wx.Font( 8,fpsys.DFAM , style=wx.NORMAL, weight=wx.NORMAL,encoding=wx.FONTENCODING_DEFAULT)) memDc.DrawText( txt, 28, texty) ## Move TOP down to next BOTTOM (for next sub-face) y = y + glyphHeight + self.spacer ## Goto next face, if any. i += 1 ## Record the calculated height self.height = totheight ## Special message if self.fitem.inactive: mx,my=(25,self.height-20) if self.fitem.badfont else (48,self.height-26) memDc.DrawBitmap( self.TICKSMALL, mx-16, my-1, True ) memDc.SetTextForeground( black ) memDc.SetFont( wx.Font(11,fpsys.DFAM, style=wx.NORMAL, weight=wx.NORMAL)) memDc.DrawText( self.fitem.activeInactiveMsg, mx, my ) ## Draw the tick/cross if it's not a FILE_NOT_FOUND font (can't be found) ## NB: FILE_NOT_FOUND is not available for installation! if self.fitem.badstyle != "FILE_NOT_FOUND": if self.fitem.ticked: memDc.DrawBitmap(self.TICKMAP, 20, 5, True) ## Now a dividing line memDc.SetPen( wx.Pen( (180,180,180),1 ) )#black, 1 ) ) memDc.DrawLine( 0, self.height-1, maxwidth, self.height-1 ) def setStyle( self ): '''Set a copy of the styles key and alter colours as needed.''' # InfoFontItem does not use this, all others do. if self.fitem.badfont: self.style=Fitmap.styles[self.fitem.badstyle].copy() #damn! this was tricky! if self.fitem.inactive: self.style['fcol'] = Fitmap.styles['INACTIVE']['fcol'] self.style['backcol'] = Fitmap.styles[self.fitem.badstyle]['ndi'] return # Not bad font, just get vals from style sheet. if self.fitem.inactive: self.style = Fitmap.styles['INACTIVE'] else: self.style = Fitmap.styles['ACTIVE'] def makeBlankDC( self, w, h, backcol ): bitmap = wx.EmptyImage( w,h ).ConvertToBitmap() memDc = wx.MemoryDC() memDc.SelectObject( bitmap ) memDc.SetBackground( wx.Brush( backcol, wx.SOLID) ) memDc.Clear() self.bitmap = bitmap #record this for the init return memDc #TODO : Pre-calc all these colours. def clamp(self,v): if v > 1.0: v=1.0 if v < 0.0: v=0.0 return v def rgb_to_hsv(self,rgb): #Go from int colour to float colour (0 to 1 range) sr = rgb[0]/255.0 sg = rgb[1]/255.0 sb = rgb[2]/255.0 return colorsys.rgb_to_hsv(sr,sg,sb) def hsv_to_rgb(self,hsv): rgb = colorsys.hsv_to_rgb( hsv[0],hsv[1],hsv[2] ) # back to int sr = int(rgb[0]*255.0) sg = int(rgb[1]*255.0) sb = int(rgb[2]*255.0) return ( sr,sg,sb ) def bottomFadeEffect( self, dc, height, width, step=1.13): """ Baptiste's idea! New implementation : June 2009 "Now a dividing gradient, you can say "wow" ;-)" Donn says, "..Wow!" :-D It goes from backcol and darkens it a little as it draws downwards. """ if self.fitem.inactive: return #step=1.08 #inactive fonts get a lighter colour. col = self.style["backcol"] #from hsv = self.rgb_to_hsv(col) tob=self.hsv_to_rgb((hsv[0],hsv[1],hsv[2]/step)) #to a darker brightness. sy=height-self.gradientheight rect=wx.Rect(0, sy, width, self.gradientheight) dc.GradientFillLinear( rect, col, tob, nDirection=wx.SOUTH ) def drawInfoOrError( self, w,h, isinfo=False ): """ Draw the Info Font block, or an Error message block. Much clearer than it was before. """ memDc=self.makeBlankDC( w, h, self.style['backcol']) if not isinfo: self.bottomFadeEffect( memDc, self.minHeight, self.width ) icon = self.style['icon'] if icon: Icon = self.FVP.__dict__[icon] ix,iy = (6,10) if isinfo else (2,3) memDc.DrawBitmap(Icon,ix,iy,True) textTup = self.fitem.InfoOrErrorText() memDc.SetTextForeground( self.style['fcol']) memDc.SetFont( wx.Font(12,fpsys.DFAM , style=wx.NORMAL, weight=wx.BOLD)) tx,ty = (46,15) if isinfo else (38 ,13) memDc.DrawText( textTup[0], tx, ty) memDc.SetFont( wx.Font(7, fpsys.DFAM, style=wx.NORMAL, weight=wx.NORMAL)) tx,ty = (46,40) if isinfo else (5 ,40) memDc.DrawText( textTup[1], tx, ty) return memDc #def DoGetBestSize(self): #DOES NOT RUN #print " FITMAP ?" fontypython-0.4.4/fontypythonmodules/gui_Left.py0000644000175000017500000002102311742276540020706 0ustar donndonn## Fonty Python Copyright (C) 2006, 2007, 2008, 2009 Donn.C.Ingle ## Contact: donn.ingle@gmail.com - I hope this email lasts. ## ## This file is part of Fonty Python. ## Fonty Python 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. ## ## Fonty Python 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 Fonty Python. If not, see . import wx, os ## Setup wxPython to access translations : enables the stock buttons. langid = wx.LANGUAGE_DEFAULT # Picks this up from $LANG mylocale = wx.Locale( langid ) from pubsub import * from wxgui import ps from gui_PogChooser import * import fpsys # Global objects import fontyfilter import fontybugs class DirControl(wx.GenericDirCtrl) : """ The Directory tree view. Note: Directory names are all UNICODE! """ def __init__(self, parent): if fpsys.state.viewpattern == "F": startdir = fpsys.state.viewobject.path else: ##Let's get it from the config object lastdir = fpsys.config.lastdir if os.path.exists(lastdir): startdir = lastdir else: startdir = os.environ['HOME'] wx.GenericDirCtrl.__init__(self, parent, -1, dir = startdir, style=wx.DIRCTRL_DIR_ONLY) # create the image list: isz = (16,16) il = wx.ImageList(isz[0], isz[1]) # Add images to list. You need to keep the same order in order for # this to work! # closed folder: il.Add( wx.Bitmap( fpsys.mythingsdir + "/icon_closed_folder.png",wx.BITMAP_TYPE_PNG) ) # open folder: il.Add(wx.Bitmap(fpsys.mythingsdir + "/icon_open_folder.png",wx.BITMAP_TYPE_PNG)) # root of filesystem (linux): il.Add(wx.Bitmap(fpsys.mythingsdir + "/icon_root.png",wx.BITMAP_TYPE_PNG)) # drive letter (windows): il.Add(wx.Bitmap(fpsys.mythingsdir + "/icon_drive.png",wx.BITMAP_TYPE_PNG)) # cdrom drive: il.Add(wx.Bitmap(fpsys.mythingsdir + "/icon_cdrom.png",wx.BITMAP_TYPE_PNG)) # removable drive on win98: il.Add(wx.Bitmap(fpsys.mythingsdir + "/icon_drive.png",wx.BITMAP_TYPE_PNG)) # removable drive (floppy, flash, etc) Does not seem to work on Kubuntu Jaunty (2009) il.Add(wx.Bitmap(fpsys.mythingsdir + "/icon_drive.png",wx.BITMAP_TYPE_PNG)) # assign image list: self.il = il self.GetTreeCtrl().SetImageList(il) ## NOTE: The click event is bound in the Notebook. class NoteBook(wx.Notebook): """ Used in the left part of the splitter in mainframe. Has two tabs - Folders and Pogs THIS IS THE VIEW or SOURCE of fonts. """ def __init__(self, parent): wx.Notebook.__init__(self, parent, style=wx.NB_BOTTOM) self.imlist = wx.ImageList(16, 16) pan1 = wx.Panel(self) ## THE DIR CONTROL self.dircontrol = DirControl(pan1) ## The Recurse check-box self.recurseFolders = wx.CheckBox(pan1, -1, _("Include sub-folders.")) self.recurseFolders.SetValue( fpsys.config.recurseFolders ) self.Bind(wx.EVT_CHECKBOX, self.__onDirCtrlClick, self.recurseFolders) #click on check box same as click on folder item. ## Add them to a sizer box = wx.BoxSizer(wx.VERTICAL) box.Add( self.dircontrol,1, wx.EXPAND ) box.Add( self.recurseFolders,0,wx.EXPAND ) pan1.SetSizer(box) box.Layout() self.pogindexselected = 0 ## The SOURCE POG control pan2 = wx.Panel(self) page = 0 s = None if fpsys.state.viewpattern == "P": s = fpsys.state.viewobject.name if s == "EMPTY": s= None #Very first run, the view will be an EMPTY object. page = 1 self.ctrlPogSource = PogChooser(pan2, whoami="SOURCEPOG", select = s) ps.sub(source_pog_has_been_selected, self.OnViewPogClick) ##DND: class NoteBook ps.sub(select_no_view_pog, self.SelectNoView) ##DND: class NoteBook ps.sub( add_pog_item_to_source, self.AddItem ) #DND: class NoteBook ps.sub( remove_pog_item_from_source, self.RemoveItem ) #DND: class NoteBook # Get a ref to the dircontrol. self.tree = self.dircontrol.GetTreeCtrl() ## Dud tree events, causing bad behaviour: ## EVT_LIST_ITEM_SELECTED ## EVT_LEFT_UP ## Bind to another event solve the problem of EVT_LEFT_UP firing when the little ## open-branch/tree arrow was pressed. ## 5.3.2009 Michael Hoeft self.tree.Bind(wx.EVT_TREE_SEL_CHANGED, self.__onDirCtrlClick) ## Had a context menu, but not using it. #self.tree.Bind(wx.EVT_CONTEXT_MENU, self.OnContextMenu) box2 = wx.BoxSizer(wx.HORIZONTAL) box2.Add(self.ctrlPogSource,1,wx.EXPAND) pan2.SetSizer(box2) box2.Layout() self.AddPage(pan1, _("Folders")) self.AddPage(pan2, _("Pogs")) source_pog_icon = self.imlist.Add( wx.Bitmap(fpsys.mythingsdir + "/icon_source_pog_16x16.png",wx.BITMAP_TYPE_PNG) ) target_pog_icon = self.imlist.Add( wx.Bitmap(fpsys.mythingsdir + "/icon_source_folder_16x16.png",wx.BITMAP_TYPE_PNG) ) self.AssignImageList(self.imlist) self.SetPageImage(1, source_pog_icon) self.SetPageImage(0, target_pog_icon) self.SetSelection(page) self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.onPageChanged) # Bind page changed event ## If the app is started with a Folder as the Source, then ## check if we must recurse. If so, fake a click to kick that off. if fpsys.state.viewpattern == "F": if self.recurseFolders.GetValue(): self.__onDirCtrlClick(None) # Fake an event def onPageChanged(self, e): self.ctrlPogSource.ClearLastIndex() if self.GetSelection() == 0: # The dircontrol ## I want to force the dir control to clear the selection. ## Reason: When you return to this control (from Pog page), the selection ## from last visit is still there. Clicking on it again does NOT UPDATE ## the font view. This is wierd. So, clearing the selection makes this moot. self.tree.UnselectAll() # Found this method in the wxpython book. #def OnContextMenu(self, event): # # only do this part the first time so the events are only bound once # if not hasattr(self, "popupID1"): # self.popupID1 = wx.NewId() # self.popupID2 = wx.NewId() # # self.Bind(wx.EVT_MENU, self.OnPopupOne, id=self.popupID1) # self.Bind(wx.EVT_MENU, self.OnPopupTwo, id=self.popupID2) # # make a menu # menu = wx.Menu() # Show how to put an icon in the menu #item = wx.MenuItem(menu, self.popupID1,"One") #bmp = images.getSmilesBitmap() #item.SetBitmap(bmp) #menu.AppendItem(item) # add some other items # menu.Append(self.popupID1, _("Add fonts in this folder to a Pog.") ) # menu.Append(self.popupID2, _("Add fonts in this folder and sub-folders to a Pog.") ) # Popup the menu. If an item is selected then its handler # will be called before PopupMenu returns. # self.PopupMenu(menu) # menu.Destroy() #def OnPopupOne(self, event): # print "\n" #def OnPopupTwo(self, event): # print "Popup one\n" def __onDirCtrlClick(self, e): wx.BeginBusyCursor() #Thanks to Suzuki Alex on the wxpython list! p = self.dircontrol.GetPath() try: fpsys.instantiateViewFolder(p,self.recurseFolders.GetValue() ) fpsys.config.lastdir = p except fontybugs.FolderHasNoFonts, e: pass # update_font_view handles this with a std message. ps.pub(reset_to_page_one)# reset before updating! ps.pub(update_font_view) wx.EndBusyCursor() wx.CallAfter( self.SetFocus ) def OnViewPogClick(self, args): """ args[0] is pogname, args[1] is pognochange """ ## Check pognochange, it means this is the same pog as last time. if args[1]: return ## instantiateViewPog calls pog.genList which bubbles: ## PogInvalid ## BUT - this error only makes sense from the ## cli pov. By the time the gui is running, that ## pog has been renamed .badpog and therefore ## won't even appear in the list. So, don't bother ## catching it. fpsys.instantiateViewPog(args[0]) if fpsys.state.samepogs: #forbid same pogs selection ps.pub(clear_targetpog_selection) else: ps.pub(reset_to_page_one) ps.pub(update_font_view) def AddItem(self, pogname): self.ctrlPogSource.AddItem(pogname[0]) #[0] bit is because pogname is a tuple from pubsub. def RemoveItem(self, pogname): self.ctrlPogSource.RemoveItem(pogname[0]) def SelectNoView(self): ## Purpose: To select no viewobject and clear view pog list selections ## Called when a TARGET item is clicked AND samepogs it True wx.BeginBusyCursor() self.ctrlPogSource.ClearSelection() fpsys.SetViewPogToEmpty() wx.EndBusyCursor() fontypython-0.4.4/fontypythonmodules/gui_Middle.py0000644000175000017500000005564511742276540021233 0ustar donndonn## Fonty Python Copyright (C) 2006, 2007, 2008, 2009 Donn.C.Ingle ## Contact: donn.ingle@gmail.com - I hope this email lasts. ## ## This file is part of Fonty Python. ## Fonty Python 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. ## ## Fonty Python 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 Fonty Python. If not, see . import wx import wx.lib.stattext import wx.lib.buttons as buttons ## Setup wxPython to access translations : enables the stock buttons. langid = wx.LANGUAGE_DEFAULT # Picks this up from $LANG mylocale = wx.Locale( langid ) from pubsub import * from wxgui import ps from gui_ScrolledFontView import * import fontybugs import fpsys # Global objects import fontyfilter ##The SearchAssistant idea was to have a panel that opens to give tips and interactive ##help for searching. We were going to have field and PANOSE access via fontTools but ##this dev. has paused -- until someone else with a clue can help.... ##So, this code will just remain as a remark: #class SearchAssistant(wx.CollapsiblePane): # def __init__(self, parent): # self.label1=_("Click for Search Assistant") # self.label2=_("Close Search Assistant") # wx.CollapsiblePane.__init__(self,parent, label=self.label1,style=wx.CP_DEFAULT_STYLE)#|wx.CP_NO_TLW_RESIZE) # self.Bind(wx.EVT_COLLAPSIBLEPANE_CHANGED, self.OnPaneChanged) # self.MakePaneContent(self.GetPane()) # # def OnToggle(self, evt): # self.Collapse(self.IsExpanded()) # self.OnPaneChanged() # # def OnPaneChanged(self, evt=None): # #if evt: # # self.log.write('wx.EVT_COLLAPSIBLEPANE_CHANGED: %s' % evt.Collapsed) # # # redo the layout # self.GetParent().Layout() # # # and also change the labels # if self.IsExpanded(): # self.SetLabel(self.label2) # else: # self.SetLabel(self.label1) # # # def MakePaneContent(self, pane): # nameLbl = wx.StaticText(pane, -1, _("Search Assistance.") ) # border = wx.BoxSizer() # border.Add(nameLbl, 1, wx.EXPAND|wx.ALL, 5) # pane.SetSizer(border) class FontViewPanel(wx.Panel): """ Standalone visual control to select TTF fonts. The Panel that holds the ScrolledFontView control as well as the buttons etc. below and the text above. """ def __init__(self, parent): wx.Panel.__init__(self, parent, id = -1) self.firstrun = True self.pageindex = 1 # I start here self.total_number_of_pages = 0 self.filter = "" self.TICKMAP = None self.TICK = wx.Bitmap(fpsys.mythingsdir + "tick.png", type=wx.BITMAP_TYPE_PNG) self.CROSS = wx.Bitmap(fpsys.mythingsdir + "cross.png", type=wx.BITMAP_TYPE_PNG) #Sept 2009 self.SEGFAULT = wx.Bitmap(fpsys.mythingsdir + 'font_segfault.png', wx.BITMAP_TYPE_PNG) self.NO_DRAW = wx.Bitmap(fpsys.mythingsdir + 'font_cannot_draw.png', wx.BITMAP_TYPE_PNG) self.NOT_FOUND = wx.Bitmap(fpsys.mythingsdir + 'font_not_found.png', wx.BITMAP_TYPE_PNG) self.INFO_ITEM = wx.Bitmap(fpsys.mythingsdir + 'font_info_item.png', wx.BITMAP_TYPE_PNG) self.TICKSMALL = wx.Bitmap(fpsys.mythingsdir + "ticksmall.png", type=wx.BITMAP_TYPE_PNG) self.BUTTON_CHARMAP = wx.Bitmap(fpsys.mythingsdir + 'button_charmap.png', wx.BITMAP_TYPE_PNG) self.BUTTON_CHARMAP_OVER = wx.Bitmap(fpsys.mythingsdir + 'button_charmap_over.png', wx.BITMAP_TYPE_PNG) ## Main Label on top sizerMainLabel = wx.BoxSizer(wx.HORIZONTAL) self.textMainInfo = MyLabel(self) sizerMainLabel.Add(self.textMainInfo,1,wx.ALIGN_LEFT) ## Page choice and Filter controls sizerOtherControls = wx.BoxSizer(wx.HORIZONTAL) ## The clear filter button: added 10 Jan 2008 bmp = wx.Bitmap(fpsys.mythingsdir + "clear.png", type=wx.BITMAP_TYPE_PNG) self.clearButton = wx.BitmapButton(self, -1, bmp, style = wx.NO_BORDER) self.clearButton.SetToolTipString( _("Clear filter") ) self.clearButton.Bind( wx.EVT_BUTTON, self.OnClearClick ) ## The filter text box self.textFilter = wx.StaticText(self, -1, _("Filter:")) self.inputFilter = wx.ComboBox(self, 500, value="", choices=[],style=wx.CB_DROPDOWN ) self.Bind(wx.EVT_COMBOBOX, self.EvtComboBox, self.inputFilter) self.Bind(wx.EVT_TEXT_ENTER, self.EvtTextEnter, self.inputFilter) self.last_filter_string = "" ## The pager pulldown self.choicePage = wx.Choice(self, -1, choices = ["busy"]) self.choicePage.Bind(wx.EVT_CHOICE, self.onPagechoiceClick) #Bind choice event #self.SA=SearchAssistant(self) ## put them into the sizer sizerOtherControls.Add(self.textFilter, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) ## Quick search Bold Italic Regular buttons idBold = wx.NewId() idItalic = wx.NewId() self.idRegular = wx.NewId() self.BIR = { idBold: {'style': "bold", 'label': _("b"), 'truth': False, 'instance': None}, idItalic: {'style': "italic", 'label': _("i"), 'truth': False, 'instance': None}, self.idRegular: {'style': "regular",'label': _("r"), 'truth': False, 'instance': None} } for id, dic in self.BIR.iteritems(): bBIR = wx.ToggleButton( self, id=id, label=dic['label'] ) self.BIR[id]['instance'] = bBIR sizerOtherControls.Add( bBIR, 1, wx.BU_EXACTFIT ) bBIR.Bind( wx.EVT_TOGGLEBUTTON, self.onBIR ) sizerOtherControls.Add( self.clearButton, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL | wx.BU_EXACTFIT ) # Clear button sizerOtherControls.Add( self.inputFilter, 7, wx.ALIGN_LEFT | wx.EXPAND ) sizerOtherControls.Add( self.choicePage, 0 , wx.ALIGN_RIGHT ) ## The SCROLLED FONT VIEW panel: self.scrolledFontView = ScrolledFontView(self) buttonsSizer = wx.BoxSizer(wx.HORIZONTAL) self.buttPrev = wx.Button(self, wx.ID_BACKWARD) # Also not in Afrikaans. self.buttMain = wx.Button(self, label=" ") self.buttMainLastLabel=" " ## This stock button has not been translated into Afrikaans yet. (Dec 2007) ## I can't tell you how this fkuced me around! self.buttNext = wx.Button(self, wx.ID_FORWARD) self.buttPrev.Enable(False) #Starts out disabled buttonsSizer.Add(self.buttPrev,0,wx.EXPAND) buttonsSizer.Add((10,1) ,0,wx.EXPAND) buttonsSizer.Add(self.buttMain,1,wx.EXPAND) buttonsSizer.Add((10,1) ,0,wx.EXPAND) buttonsSizer.Add(self.buttNext,0,wx.EXPAND) ## Now the sizer to hold all the fontview controls self.sizerScrolledFontView = wx.BoxSizer( wx.VERTICAL ) ## The Main label self.sizerScrolledFontView.Add(sizerMainLabel, 0, wx.EXPAND | wx.BOTTOM, border = 0 ) ## The SIZER FOR THE SCROLLED FONT VIEW self.sizerScrolledFontView.Add(self.scrolledFontView, 1, wx.EXPAND ) ## The Search Assistant #self.sizerScrolledFontView.Add( self.SA, 0, wx.EXPAND) ## Choice and Filter self.sizerScrolledFontView.Add(sizerOtherControls, 0, wx.EXPAND | wx.TOP | wx.BOTTOM, border = 3) ## The buttons self.sizerScrolledFontView.Add(buttonsSizer,0,wx.EXPAND) self.SetSizer(self.sizerScrolledFontView) e = wx.EVT_BUTTON #was wx.EVT_LEFT_UP self.buttPrev.Bind(e,self.navClick) self.buttNext.Bind(e,self.navClick) #self.buttMain.Bind(e,self.onMainClick) self.Bind(e,self.onMainClick,self.buttMain)#.GetId() ) ## Advertise some local functions: ps.sub( left_or_right_key_pressed, self.OnLeftOrRightKey ) ##DND: class FontViewPanel ps.sub( toggle_main_button, self.ToggleMainButton ) ##DND: class FontViewPanel ps.sub( update_font_view, self.MainFontViewUpdate ) ##DND: class FontViewPanel ps.sub( reset_to_page_one, self.ResetToPageOne ) ##DND: class FontViewPanel #def DoGetBestSize(self): # DOES NOT RUN FOR A wx.Panel def OnClearClick( self, event ): self.inputFilter.SetValue("") #was .Clear(), but that does not work for a combo box. self.filter = "" # Clear the BIR toggle buttons self.setAllBIRFalse() ## Now command a change of the view. ## First, return user to page 1: self.pageindex = 1 self.filterAndPageThenCallCreateFitmaps() self.buttMain.SetFocus() #a GTK bug demands this move. Restore the ESC key func. def setOneBIR( self, id, truth ): self.BIR[id]['truth'] = truth self.BIR[id]['instance'].SetValue( truth ) def setAllBIRFalse( self ): for id in self.BIR.keys(): self.setOneBIR( id, False ) def onBIR( self, e ): id=e.GetId() self.BIR[id]['truth']=self.BIR[id]['instance'].GetValue() if self.BIR[id]['style'] == "regular": # can't have regular with bold/italic self.setAllBIRFalse() # switch all off self.setOneBIR( id, True ) ss = "regular|normal" else: self.setOneBIR( self.idRegular, False ) ss="" for id, dic in self.BIR.iteritems(): if dic['truth']: ss += "%s%s" % (dic['style']," ") # Builds AND regex (space is and) ss = ss[:-1] self.inputFilter.SetValue( ss ) self.startSearch( ss ) # Capture events when the user types something into the control then # hits ENTER. def EvtTextEnter(self, evt): o=evt.GetEventObject() termsstring = evt.GetString() history=o.GetItems() if termsstring not in history: o.Insert( termsstring,0 ) #record this search in the top of the 'history' self.startSearch(termsstring) self.buttMain.SetFocus() evt.Skip() # When the user selects something in the combo pull-down area, we go here. def EvtComboBox(self, evt): cb = evt.GetEventObject() termsstring = evt.GetString() self.startSearch(termsstring) self.buttMain.SetFocus() def startSearch(self, terms): self.filter = terms ## First, return user to page 1: self.pageindex = 1 ## Now command a change of the view. self.filterAndPageThenCallCreateFitmaps() def filterAndPageThenCallCreateFitmaps(self): """ Figure out what list of fonts to draw, divide them into pages, then go make Fitmaps out of them. """ self.total_number_of_pages = 1 # A default ## Is there anything there to view? if len(fpsys.state.viewobject) > 0: ## JUNE 2009 : Changes made ## If the filter string changed from last time, signal so. filter_changed = False if self.filter != self.last_filter_string: filter_changed = True self.last_filter_string = self.filter ## If the filter did change OR we have a blank filteredViewObject, then make a new one. if not fpsys.state.filteredViewObject or filter_changed: fpsys.state.filteredViewObject = fontyfilter.doFilter( self.filter ) # Uses the external module to filter. ## STEP 2 : Figure out how many pages we have to display current_page = self.pageindex - 1 num_in_one_page = fpsys.config.numinpage total_num_fonts = len(fpsys.state.filteredViewObject) ## Many thanks to Michael Hoeft for this fix! I suck at math :) # I miss the right words to explain this step, therefore an example: # 23 / 10 = 2 # 23 % 10 = 3 > modulo > bool(3) = True = 1 # ----------------------------------------- # 2 + 1 = 3 > 3 pages # # 40 / 10 = 4 # 40 % 10 = 0 > modulo > bool(0) = False = 0 # ------------------------------------------ # 4 + 0 = 4 > 4 pages self.total_number_of_pages = (total_num_fonts / num_in_one_page) + bool(total_num_fonts % num_in_one_page) start = current_page * num_in_one_page #leaf thru the pages to the one we are on now. fin = start + num_in_one_page if fin > len(fpsys.state.filteredViewObject): fin = len(fpsys.state.filteredViewObject) #Make sure we don't overshoot. ## Extract a single page of fonts to display sublist = fpsys.state.filteredViewObject[start:fin] ## Empty the choice control. self.choicePage.Clear() ## Now refill it [self.choicePage.Append(str(n)) for n in xrange(1, self.total_number_of_pages +1)] self.choicePage.SetSelection(self.pageindex-1) ## The viewobject is empty anyway. else: sublist = [] if self.total_number_of_pages == 1: self.choicePage.Enable(False) #I tried to hide/show the choice, but it would not redraw properly. else: self.choicePage.Enable(True) self.scrolledFontView.CreateFitmaps( sublist ) # Tell my child to draw the fonts self.EnableDisablePrevNext() #self.firstrun = False # After all the fitmaps are drawn, the sizer knows how wide it is, so we trip this flag (see getWidthOfMiddle) def onMainClick(self, evt) : """ Removes fonts, or Appends fonts. Depends on situation in fpsys.state """ xPos, yPos = self.scrolledFontView.GetViewStart() #Saved by Robin Dunn, once again ! ! ! wx.BeginBusyCursor() doupdate = False ## Let's determine what kind of thing to do: if fpsys.state.action == "REMOVE": ## We have a pog in viewobject and we must remove the selected fonts from it. vo = fpsys.state.viewobject victims = [] dowrite = False for fi in vo: if fi.ticked: victims.append(fi) #Put it into another list dowrite = True for fi in victims: vo.remove(fi) #Now remove it from the vo del victims if dowrite: fpsys.flushTicks() bug = False try: vo.write() except (fontybugs.PogWriteError), e: bug = True ps.pub( show_error, unicode( e ) ) doupdate = True if not bug: ps.pub(print_to_status_bar,_("Selected fonts have been removed.")) else: ps.pub(print_to_status_bar,_("There was an error writing the pog to disk. Nothing has been done.")) ## APPEND - Copy font to a pog. if fpsys.state.action == "APPEND": ## We must append the fonts to the Pog vo = fpsys.state.viewobject to = fpsys.state.targetobject print _("Copying fonts from %(source)s to %(target)s") % {"source":vo.label(), "target":to.label()} dowrite = False for fi in vo: if fi.ticked: to.append(fi) dowrite = True if dowrite: fpsys.flushTicks() #Ensure we have no more ticks after a succ xfer. bug = False try: to.write() except (fontybugs.PogWriteError), e: bug = True ps.pub( show_error, unicode( e ) ) doupdate = True if not bug: ps.pub(print_to_status_bar,_("Selected fonts are now in %s.") % to.label()) else: ps.pub(print_to_status_bar,_("There was an error writing the pog to disk. Nothing has been done")) wx.EndBusyCursor() self.scrolledFontView.Scroll(xPos, yPos) if doupdate: self.MainFontViewUpdate() def onPagechoiceClick(self,event) : wx.BeginBusyCursor() if self.pageindex != int(event.GetString() ) : #Only redraw if actually onto another page. self.pageindex = int(event.GetString() ) self.filterAndPageThenCallCreateFitmaps() wx.EndBusyCursor() def navClick(self,event) : wx.BeginBusyCursor() if event.GetId() == wx.ID_FORWARD: self.pageindex += 1 else: #wx.ID_BACKWARD self.pageindex -= 1 if self.pageindex > self.total_number_of_pages: self.pageindex = self.total_number_of_pages if self.pageindex == 0: self.pageindex = 1 self.buttMain.SetFocus() #a GTK bug demands this move. self.filterAndPageThenCallCreateFitmaps() wx.EndBusyCursor() def OnLeftOrRightKey(self, evt): ## This comes along from MainFrame via the AcceleratorTable events. evt=evt[0] # just get around pubsub tuple. id=evt.GetId() ## We can't just pass on to navClick yet because we don't know if ## the button (left/right) is enabled or not. So determine that and then ## pass on to the other handler. if id==wx.ID_FORWARD: #right arrow was pressed if self.buttNext.IsEnabled(): self.navClick( evt ) else: if self.buttPrev.IsEnabled(): self.navClick( evt ) #evt.Skip() # If this is here, the keyboard shortcuts get really buggy.... def EnableDisablePrevNext(self) : """ Enabled state of PREV/NEXT buttons """ n = True p = True if self.pageindex == self.total_number_of_pages: n = False if self.pageindex == 1: p = False self.buttNext.Enable(n) self.buttPrev.Enable(p) def ToggleMainButton(self): ps.pub( toggle_selection_menu_item, True ) self.buttMain.SetLabel( self.buttMainLastLabel ) if fpsys.state.action == "NOTHING_TO_DO": self.buttMain.Enable( False ) ps.pub( toggle_selection_menu_item, False ) return if fpsys.state.numticks > 0: self.buttMain.Enable(True) else: self.buttMain.SetLabel( _("Choose some fonts") ) def MainFontViewUpdate(self): """ Vital routine - the heart if the app. This decides what to do based on what has been selected. It draws the controls and the fonts as appropriate. It also sets flags in fpsys.state """ ## Get shorter vars to use. V = fpsys.state.viewobject T = fpsys.state.targetobject Vpatt = fpsys.state.viewpattern # View Pattern Tpatt = fpsys.state.targetpattern # Target pattern Patt = Vpatt + Tpatt # Patt = Pattern lab = "" status = "" ## June 2009: A default value for this: self.TICKMAP = self.TICK ## E == Empty View - no fonts in chosen Source. ## N == Empty Target - no fonts. ## P is Pog ## F is Folder if Vpatt == "E": #NOTE : TESTING VPATT, not PATT - ergo: this covers E, EN, EP ## Empty "E" - when the chosen Folder or Pog has NO FONTS IN IT. if Tpatt == "P": lab = _("Your active Target is %s") % T.name status = _("Please choose a Source.") else: lab = _("There are no fonts in here.") status = _("Please choose a Pog or a Font folder on the left.") btext = _("Nothing to do") fpsys.state.cantick = False fpsys.state.action = "NOTHING_TO_DO" # We will test this in mainframe::OnMainClick elif Patt == "FN": #View a Folder, no target lab = _("Viewing Folder %s") % V.label() fpsys.state.cantick = False btext = _("Nothing to do") fpsys.state.action = "NOTHING_TO_DO" # We will test this in mainframe::OnMainClick status = _("Viewing a folder.") elif Patt == "PN": #A single Pog in the VIEW #View a pog, no target if V.isInstalled(): ## Cannot remove fonts from an installed pog lab = _("Viewing (installed Pog) %s") % V.name btext = _("Nothing to do") fpsys.state.action = "NOTHING_TO_DO" fpsys.state.cantick = False status = _("You cannot change an installed Pog.") else: lab = _("Viewing (editable Pog) %s") % V.name fpsys.state.cantick = True btext = _("Remove fonts from %s") % V.name self.TICKMAP = self.CROSS fpsys.state.action = "REMOVE" # We will test this in mainframe::OnMainClick status = _("You can remove fonts from the selected Target Pog.") elif Patt == "FP": #Folder to Pog if T.isInstalled(): ## We cannot put stuff into an installed pog lab = _("Viewing Folder %s") % V.label() btext = _("Nothing to do") fpsys.state.action = "NOTHING_TO_DO" fpsys.state.cantick = False status = _("You cannot change an installed Pog.") else: lab = _("Append from %(source)s to %(target)s") % { "source":V.label(), "target":T.name } btext = _("Put fonts into %s") % T.name self.TICKMAP = self.TICK fpsys.state.cantick = True fpsys.state.action = "APPEND" # We will test this in mainframe::OnMainClick status = _("You can append fonts to your target Pog.") elif Patt == "PP": #Pog to Pog if T.isInstalled(): ## We cannot put fonts into an installed pog lab = _("Viewing %(source)s, but Pog %(target)s is installed.") % {"source":V.name, "target":T.name} btext = _("Nothing to do") fpsys.state.action = "NOTHING_TO_DO" fpsys.state.cantick = False status = _("You cannot change an installed Pog.") else: #Not installed. if fpsys.state.samepogs: #Are the two pogs the same? ## The validate routines determined the samepogs value. lab = _("These two are the same Pog.") fpsys.state.cantick = True btext = _("Nothing to do") fpsys.state.action = "NOTHING_TO_DO" status = _("Your Source and Target are the same Pog.") else: # Normal pog to pog lab = _("Append from %(source)s into %(target)s") % {"source":V.name, "target":T.name} btext = _("Put fonts into %s") % T.name self.TICKMAP = self.TICK fpsys.state.cantick = True fpsys.state.action = "APPEND" # We will test this in mainframe::OnMainClick status = _("You can append fonts to your target Pog.") else: print "MOJO ERROR: %s and trouble" % Patt raise SystemExit ## Enable/Disable the Purge menu item ps.pub( toggle_purge_menu_item, False ) if Vpatt=="P": if not fpsys.state.viewobject.isInstalled(): ps.pub( toggle_purge_menu_item, True ) self.buttMainLastLabel=btext self.textMainInfo.SetLabel( lab) self.textMainInfo.Show() if status is not "": ps.pub(print_to_status_bar, status) self.ToggleMainButton() fpsys.markInactive() self.filterAndPageThenCallCreateFitmaps() def ResetToPageOne(self): self.pageindex = 1 # I start here class MyLabel( wx.lib.stattext.GenStaticText ): """ To spice-up the info label I made this control. It draws a shape behind the text. Thanks to Andrea: http://wiki.wxpython.org/CreatingCustomControls """ def __init__(self, parent): self.FVP = parent self.lab = u" " self.infoFont = wx.Font(11, fpsys.DFAM, wx.NORMAL, wx.FONTWEIGHT_BOLD) self.light = (255,255,255)#wx.SystemSettings.GetColour( wx.SYS_COLOUR_3DHIGHLIGHT ) self.dark = wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DSHADOW) self.back = parent.GetBackgroundColour() self.h=100 self.width = 10 self.VIEWICON = wx.Bitmap(fpsys.mythingsdir + "view16x16.png", type=wx.BITMAP_TYPE_PNG) # call parent init after vital settings are done. wx.lib.stattext.GenStaticText.__init__(self, parent, -1," ") self.Bind(wx.EVT_PAINT, self.OnPaint) self.Bind(wx.EVT_SIZE, self.OnSize) def OnSize(self,e): self.width=self.FVP.GetSize()[0] self.Refresh() def SetLabel( self, lab ): self.lab=lab self.Refresh() def DoGetBestSize(self): bestw,self.h = (100,26) best = wx.Size(bestw,self.h) self.CacheBestSize(best) return best def OnPaint(self, event): dc = wx.PaintDC(self) w = self.width w -= wx.SystemSettings.GetMetric(wx.SYS_VSCROLL_X) # minus width of the scrollbar #Now draw the thing: rect = wx.Rect(0,0, w, self.h + 10) dc.SetPen(wx.Pen(self.dark,width=1)) dc.SetBrush( wx.TRANSPARENT_BRUSH ) dc.DrawRoundedRectangleRect(rect, 5) # The text dc.SetFont(self.infoFont) dc.DrawText(self.lab, 27,5) dc.DrawBitmap( self.VIEWICON, 6,5, True) # Old code -- keep for ref.... def OLD_DoGetBestSize(self): dc = wx.ClientDC(self) dc.SetFont(self.infoFont) # How big is the text? bestw,besth = dc.GetTextExtent(self.lab) or (100,100) besth += 8 best = wx.Size(bestw,besth) self.CacheBestSize(best) self.h=besth return best def OnPaintFakeTab(self, event): '''Old fake tab look. Keep for future ref.''' pdc = wx.PaintDC(self) try: dc = wx.GCDC(pdc) except: dc = pdc w=(dc.GetFullTextExtent(self.lab,self.infoFont)[0] or 100) + 40 rect = wx.Rect(0,0, w, self.h + 10) dc.SetPen(wx.Pen(self.dark,width=1)) dc.SetBrush(wx.Brush(self.back)) dc.DrawRoundedRectangleRect(rect, 5) #The gradient under the text dc.GradientFillLinear( wx.Rect(2, self.h-15, w-3, self.h-2), self.light, self.back, nDirection=wx.NORTH ) # The text dc.SetFont(self.infoFont) dc.DrawText(self.lab, 27,5) dc.DrawBitmap( self.VIEWICON, 6,5, True) fontypython-0.4.4/fontypythonmodules/gui_PogChooser.py0000644000175000017500000002064211742276540022072 0ustar donndonn## Fonty Python Copyright (C) 2006, 2007, 2008, 2009 Donn.C.Ingle ## Contact: donn.ingle@gmail.com - I hope this email lasts. ## ## This file is part of Fonty Python. ## Fonty Python 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. ## ## Fonty Python 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 Fonty Python. If not, see . import wx, locale ## Setup wxPython to access translations : enables the stock buttons. langid = wx.LANGUAGE_DEFAULT # Picks this up from $LANG mylocale = wx.Locale( langid ) from pubsub import * from wxgui import ps import fpsys # Global objects import fontcontrol import fontybugs class PogChooser(wx.ListCtrl) : """ Basic list control for pogs - instanced by TargetPogChooser and NoteBook This single class (being used twice) causes terrible conceptual hardships and forces all kinds of twisty tests. I'm sorry for this, we need a better solution. """ ## CLASS LEVEL variables - special things these. __poglistCopy = {} # To help in sorting. __TARGET = None __VIEW = None def __init__(self, parent, whoami, select = None) : self.indexselected = 0 self.lastindexselected = -1 self.parent = parent self.whoami = whoami ## Use Class-level attributes to record the history of ## the instantiation of this class. These vars do not ## belong to the instances, but to this one class. ## We keep refs to the two parents of this class. if whoami == "SOURCEPOG" :#isinstance( self.parent, wx.Panel ): PogChooser.__VIEW = self style = wx.LC_LIST | wx.LC_AUTOARRANGE | wx.LC_SORT_ASCENDING | wx.LC_SINGLE_SEL else: PogChooser.__TARGET = self.parent style = wx.LC_LIST | wx.LC_AUTOARRANGE | wx.LC_SORT_ASCENDING il = wx.ImageList(16,16,True) png = wx.Bitmap(fpsys.mythingsdir + "/pog16x16.png",wx.BITMAP_TYPE_PNG) il.Add(png) png = wx.Bitmap(fpsys.mythingsdir + "/pog16x16.installed.png",wx.BITMAP_TYPE_PNG) il.Add(png) ## Dec 2007 : target icon png = wx.Bitmap( fpsys.mythingsdir + "/pog16x16.target.png", wx.BITMAP_TYPE_PNG ) il.Add( png ) wx.ListCtrl.__init__( self,parent,-1, style=style | wx.SUNKEN_BORDER ) self.AssignImageList(il, wx.IMAGE_LIST_SMALL) self.__PC = fpsys.iPC # reuse the global pathcontrol object self.fillPogList() ## Highlight the pog selected (the last one, or the cli chosen one) if select: i = self.FindItem(-1, select) self.indexselected = i # Set this to help initial icon settings. self.Select(i, True) else: self.Select(0, False) self.indexselected = -1 self.ClearBackground() self.items = None self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.onSelect) ## This one is a double click event ## self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.__onActivate ) #self.SetCursor(wx.StockCursor(wx.CURSOR_HAND)) ## This subscribe line here will register TWICE since this PogChooser object is instanced ## twice by the app... ps.sub(change_pog_icon, self.ChangeIcon) ##DND: class PogChooser def Sorter(self, key1, key2): """ Fetch the strings from our CLASS LEVEL copy of the pognames so that we can compare them via locale. """ s1,s2 = PogChooser.__poglistCopy[key1], PogChooser.__poglistCopy[key2] ## Since the gui is unicode, I *think* I don't have to worry about errors here. return locale.strcoll( s1, s2 ) def onSelect(self, e): wx.BeginBusyCursor() self.indexselected = e.m_itemIndex pognochange = False if self.indexselected == self.lastindexselected: ## We have clicked on the same Pog as last time - ergo do nothing. pognochange = True self.lastindexselected = self.indexselected # Record this for next time around textpogname = self.GetItemText(self.indexselected) # Gets UNICODE !!! if self.whoami=="SOURCEPOG": ps.pub(source_pog_has_been_selected, textpogname, pognochange) else: ps.pub(target_pog_has_been_selected, textpogname, pognochange) self.SortOutTheDamnImages( pognochange ) wx.EndBusyCursor() def SortOutTheDamnImages( self, pognochange ): """ Dec 2007 : This took me an entire day to figure out. Man... Determines the images of the list items. Is called from TargetPogChooser as well (when clear button is clicked) """ if pognochange is (): pognochange = True c = self.GetItemCount() sel = self.indexselected # the actual selection index, does not go to -1 ## Which kind of a McList am I? iAmTargetList = self.whoami=="TARGETPOG" #isinstance( self.parent, TargetPogChooser ) ## If there is an active selection? if sel > -1: for x in xrange(0, c): i = self.GetItem(x, 0) ## Must make a tmp Pog before I can test installed status. tmpPog = fontcontrol.Pog(i.GetText()) if tmpPog.isInstalled(): self.SetItemImage(x, 1) else: ## Handle the other icons (in the target list only) ## that are not installed. if iAmTargetList: if x == sel: ## No change means it *was* selected ## and now it's been selected again ## thus it can't be the target anymore. if pognochange: n = 0 else: n = 2 self.SetItemImage(x, n ) # new target icon else: self.SetItemImage(x, 0) ## Tell the VIEW to imitate this picture. for x in xrange(0,c): ti = self.__TARGET.pogTargetlist.GetItem(x, 0) # the 0 is 'column'. Ignore. CLONE = ti.GetImage()# gets the image index, not an image bitmap. self.__VIEW.SetItemImage(x, CLONE) def __del__(self) : del self.items def fillPogList(self): """ This is among the very FIRST things we do. Fill the list with pogs. This will CULL any bad pogs (i.e. those with malformed content) Thus the PogInvalid error should not happen any more after a run. """ pl = self.__PC.getPogNames() # pl will always be a BYTE STRING list for p in pl: # 'p' is a byte string. ipog = fontcontrol.Pog(p) try: #catch pogs that are not properly formed if ipog.isInstalled(): i = 1 # isInstalled opens the pog file. else: i = 0 except fontybugs.PogInvalid, eInst: ## An "invalid" pog is one that does not have ## installed/not installed on the first line. print _(u"(%s) skipped. It's an invalid pog.") % [p] continue ## Let's try to make a unicode of p so li.SetText(p) can display it: try: p = fpsys.LSP.to_unicode( p ) except UnicodeDecodeError: ## We can't convert it under this locale print _(u"(%s) skipped. I can't display this name under your locale.") % [p] continue ## Okay, we have a valid pog name to use: li = wx.ListItem() li.SetImage(i) li.SetText(p) id = wx.NewId() PogChooser.__poglistCopy[id] = p # record the pog name row = self.InsertItem( li ) self.SetItemData( row, id ) # associate back to __poglistCopy self.SortItems( self.Sorter ) def AddItem(self, pogname): """ Add a pogname to myself, then sort. """ li = wx.ListItem() li.SetImage(0) li.SetText(pogname) id = wx.NewId() self.__poglistCopy[id] = pogname row = self.InsertItem(li) self.SetItemData( row, id ) self.SortItems( self.Sorter ) def RemoveItem(self, pogname): row = self.FindItem(-1, pogname) id = self.GetItemData(row) self.DeleteItem(row) del( PogChooser.__poglistCopy[id] ) # cull from our private store too. def ClearSelection(self): # removes all selections, even for multi-selections for x in range(self.GetSelectedItemCount()): self.Select(self.GetFirstSelected(), False) self.lastindexselected = -1 def ChangeIcon(self): """ Change a single Pog's icon to installed/uninstalled. ONLY called from InstallPog and UninstallPog. """ T = fpsys.state.targetobject pn = T.name index = self.FindItem(0, pn) if T.isInstalled(): n = 1 else: n = 0 self.SetItemImage(index, n) ## Found in wxWidgets documentation! def ClearLastIndex(self): """ We need to reset the lastindexselected so that a click on the same item as last time will register. This is used in the Notebook when the page changes back to page 1, we want the user to be able to re-click the item that was clicked last time. """ self.lastindexselected = -1 fontypython-0.4.4/fontypythonmodules/gui_Right.py0000644000175000017500000002635311742276540021104 0ustar donndonn## Fonty Python Copyright (C) 2006, 2007, 2008, 2009 Donn.C.Ingle ## Contact: donn.ingle@gmail.com - I hope this email lasts. ## ## This file is part of Fonty Python. ## Fonty Python 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. ## ## Fonty Python 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 Fonty Python. If not, see . import wx ## Setup wxPython to access translations : enables the stock buttons. langid = wx.LANGUAGE_DEFAULT # Picks this up from $LANG mylocale = wx.Locale( langid ) from pubsub import * from wxgui import ps from gui_PogChooser import * import fpsys # Global objects import fontyfilter import fontybugs ## Fetch the dialogue classes - used for zip dir dialog. import dialogues class TargetPogChooser(wx.Panel): """ Far right-hand side control. Chooses target pogs. Houses control buttons. """ def __init__(self, parent): wx.Panel.__init__(self, parent, id = -1) self.icon = wx.StaticBitmap( self, -1, wx.Bitmap(fpsys.mythingsdir + 'icon_target_16x16.png', wx.BITMAP_TYPE_PNG) ) self.textInfo = wx.StaticText(self, -1, _("Target Pogs"), style = wx.ALIGN_LEFT) self.textInfo.SetFont(wx.Font(10, fpsys.DFAM, wx.NORMAL, wx.FONTWEIGHT_BOLD)) s = None if fpsys.state.targetpattern == "P": s = fpsys.state.targetobject.name ## The actual list control self.pogTargetlist = PogChooser(self, whoami="TARGETPOG", select = s) ## Subscriptions: ps.sub(target_pog_has_been_selected, self.OnPogTargetClick) ##DND: class TargetPogChooser ps.sub(clear_targetpog_selection, self.SelectNoTargetPog) ##DND: class TargetPogChooser ## The "no pog" button self.idnone = wx.NewId() self.buttNoPog = wx.Button(self, label = _("Clear selection"), id = self.idnone) self.buttNoPog.SetToolTipString(_("Deselects any chosen Pogs.")) ## The buttons under the pog list ## Giving them all id numbers so my single handler can tell them apart. self.idnew = wx.NewId() self.idinstall = wx.NewId() self.iduninstall = wx.NewId() self.iddelete = wx.NewId() #Sept 2009 self.idzip = wx.NewId() self.buttNew = wx.Button(self, label = _("New Pog"), id = self.idnew ) self.buttNew.SetToolTipString(_("Creates a new, empty Pog")) self.buttInstall = wx.Button(self, label = _("Install Pog"), id = self.idinstall ) self.buttInstall.SetToolTipString(_("Installs all selected Pogs.\nUse SHIFT/CTRL+Click on the list above.")) self.buttUninstall = wx.Button(self, label = _("Uninstall Pog"), id = self.iduninstall ) self.buttUninstall.SetToolTipString(_("Uninstalls all selected Pogs.\nUse SHIFT/CTRL+Click on the list above.")) self.buttDelete = wx.Button(self, label = _("Delete Pog") , id = self.iddelete) self.buttDelete.SetToolTipString(_("Deletes the selected Pog(s)")) self.buttZip = wx.Button(self, label = _("Zip Pog(s)") , id = self.idzip) self.buttZip.SetToolTipString(_("Save a zip file of the selected Pogs")) self.sizer = wx.BoxSizer(wx.VERTICAL) self.iconandtext = wx.BoxSizer(wx.HORIZONTAL) self.iconandtext.Add(self.icon, 0, wx.TOP | wx.BOTTOM, border = 4) self.iconandtext.Add(self.textInfo, 1, wx.EXPAND | wx.ALL, border = 4) self.sizer.Add(self.iconandtext, 0, wx.EXPAND) self.sizer.Add(self.pogTargetlist, 1, wx.EXPAND) self.sizer.Add(self.buttNoPog, 0, wx.EXPAND | wx.BOTTOM | wx.TOP, border=5) self.sizer.Add(self.buttInstall, 0, wx.EXPAND) self.sizer.Add(self.buttUninstall, 0, wx.EXPAND) self.sizer.Add(self.buttNew, 0, wx.EXPAND) self.sizer.Add(self.buttDelete, 0, wx.EXPAND) self.sizer.Add(self.buttZip, 0, wx.EXPAND) self.SetSizer(self.sizer) ## Bind the events: e=wx.EVT_BUTTON # was wx.EVT_LEFT_UP self.buttNoPog.Bind(e, self.multiClick) self.buttNew.Bind(e, self.multiClick) self.buttInstall.Bind(e, self.multiClick) self.buttUninstall.Bind(e, self.multiClick) self.buttDelete.Bind(e, self.multiClick) self.buttZip.Bind(e, self.multiClick) self.toggleButtons() ## Catch all the button clicks on the control. def multiClick(self, e): ## NEW if e.GetId() == self.idnew: ## New Pog button pressed dlg = wx.TextEntryDialog( self, _("Enter a name for the new Pog"), _("New Pog"), _("Fonty Python")) dlg.SetValue("") if dlg.ShowModal() == wx.ID_OK: nam = dlg.GetValue() if nam == "": ps.pub( show_message, _("A Pog with no name won't be created, however it was a good try!") ) ## Is it unique? elif fpsys.isPog(nam): ## Nope, it's there already ps.pub(show_message, _("%s already exists.") % nam) else: ## We have a winner. ## Make a pog object and then write it, ipog = fontcontrol.Pog(nam) try: ipog.write() except fontybugs.PogWriteError, e: ps.pub(show_error_and_abort, unicode( e )) del ipog ## Now put it into the list self.pogTargetlist.AddItem(nam) #ps.pub(add_item_to_notebook, nam) ps.pub( add_pog_item_to_source, nam ) ps.pub( update_font_view ) dlg.Destroy() return ## A list of multiple-selected pog names: tl = self.pogTargetlist multipogs=[ tl.GetItemText(i) for i in xrange(tl.GetItemCount()) if tl.IsSelected(i)] ## DELETE if e.GetId() == self.iddelete: ## Selected Pog(s) to be deleted: tokill = multipogs iPogsToKill = [] ##Is any one of those installed? allok=True for p in tokill: ## Michael Hoeft tested pog delete and noticed the bug. Thanks. ## Fixed Oct 2009 iPog = fontcontrol.Pog(p) if iPog.isInstalled(): ps.pub( show_error, _("One or more selected Pogs is installed, fix your selection and try again.") ) allok=False break iPogsToKill.append( iPog ) if allok: ## Build a string for reporting in the dialog if len(tokill) > 1: pogname="" for f in tokill[:-1]: pogname += u"%s," % f pogname += tokill[-1] #We want "remove blah,bloop,zoom, are you sure?" else: pogname=tokill[0] dlg = wx.MessageDialog(self, _("Remove %s, are you sure?") % pogname, _("Are you sure?"), wx.YES_NO | wx.ICON_INFORMATION ) if dlg.ShowModal() == wx.ID_YES: ## Let's do them in: for victim in iPogsToKill: #tokill: #fpsys.instantiateTargetPog(victim) #Makes the fpsys.state.targetobject ## Now kill the file on disk: try: victim.delete() #fpsys.state.targetobject.delete() except fontybugs.PogCannotDelete, e: ps.pub(show_error, unicode( e )) return ## Remove from the lists: self.pogTargetlist.RemoveItem(victim.name) ps.pub( remove_pog_item_from_source, victim.name) ## What if it was ALSO our view object? if fpsys.state.viewobject.label() == victim.name: ## It was! We must declare it Empty. fpsys.SetViewPogToEmpty() ## Now re-draw things ps.pub(update_font_view) dlg.Destroy() ## Select no pog. self.SelectNoTargetPog() return ## NO POG pressed if e.GetId() == self.idnone: ## Select No Pog button pressed if fpsys.state.targetobject is None: return #Already done. self.SelectNoTargetPog() ps.pub(update_font_view) return #No need to tell mainframe about this. ## Prepare for Install/Uninstall POG ## install or uninstall all selected pogs - caters for multiple pog selections ## the instantiateTargetPog must be called on each pog-name in the list ## to setup the globals in fpsys. This is new from my previous one-selection only ## code which assumed that instantiateTargetPog had been called already (when pog ## was selected by the mouse) ## Install if e.GetId() == self.idinstall: wx.BeginBusyCursor() for p in multipogs: fpsys.instantiateTargetPog(p) # sets up fpsys.state.targetobject ok=True try: fpsys.state.targetobject.install() except (fontybugs.PogSomeFontsDidNotInstall), er: ## Show a warning, but continue. ps.pub( show_error, unicode(er) ) except (fontybugs.PogEmpty, fontybugs.PogAllFontsFailedToInstall), er: ## Either Pog is empty, or ## not a single font in this pog actually installed. ## It has already been flagged as NOT INSTALLED ps.pub( show_error, unicode(er) ) ok=False if ok: ## Update GUI ps.pub( change_pog_icon ) self.toggleButtons() ps.pub( update_font_view ) wx.EndBusyCursor() ## Uninstall if e.GetId() == self.iduninstall: wx.BeginBusyCursor() for p in multipogs: fpsys.instantiateTargetPog(p) ok=True try: fpsys.state.targetobject.uninstall() except (fontybugs.PogEmpty, fontybugs.PogNotInstalled, fontybugs.PogLinksRemain ), er: ## PogNotInstalled is prevented by buttons greying out in the gui. ps.pub( show_error, unicode(er) ) ok=False if ok: ## Update GUI ps.pub( change_pog_icon ) self.toggleButtons() ps.pub( update_font_view ) wx.EndBusyCursor() ## Sep 2009 : ZIP POGS if e.GetId() == self.idzip: dlg = dialogues.LocateDirectory( self ) ok=False if dlg.ShowModal() == wx.ID_OK: todir=dlg.GetPath() ok=True dlg.Destroy() if ok: wx.BeginBusyCursor() for p in multipogs: ipog = fontcontrol.Pog(p) bugs=ipog.zip( todir ) wx.EndBusyCursor() extra="" if bugs: extra=_("Some fonts were skipped, try purging the Pog(s) involved.") ps.pub(print_to_status_bar,_("Zip file(s) have been created.%s") % extra ) else: ps.pub(print_to_status_bar,_("Zip cancelled.")) def OnPogTargetClick(self, args): """ args[0] pogname args[1] is pognochange """ ## Made it so a second click on a target pog will unselect it. if args[1]: #pognochange = True, so let's deselect this pog self.SelectNoTargetPog() ps.pub(update_font_view) return try: fpsys.instantiateTargetPog(args[0]) except fontybugs.PogInvalid, e: ps.pub(show_error_and_abort, unicode( e )) return ps.pub(update_font_view) self.toggleButtons() def toggleButtons(self): ## If this is a no target pog situation, hide 'em all. if fpsys.state.targetobject is None: self.buttDelete.Enable(False) self.buttInstall.Enable(False) self.buttUninstall.Enable(False) self.buttZip.Enable(False) return installed = fpsys.state.targetobject.isInstalled() self.buttDelete.Enable(not(installed)) # DELETE button is inverse of installed status self.buttInstall.Enable(not(installed)) # INSTALL button is inverse self.buttUninstall.Enable(installed) # UNINSTALL = True if pog is installed. self.buttZip.Enable(True) def SelectNoTargetPog(self): wx.BeginBusyCursor() ## Go figure out what item gets what image self.pogTargetlist.SortOutTheDamnImages( pognochange = True ) self.pogTargetlist.ClearSelection() #Select nothing. fpsys.SetTargetPogToNone() # Tell fpsys that we have no pog target selected self.toggleButtons() # Disable the buttons on the bottom right. wx.EndBusyCursor() fontypython-0.4.4/fontypythonmodules/gui_ScrolledFontView.py0000644000175000017500000001271211742276540023252 0ustar donndonn## Fonty Python Copyright (C) 2006, 2007, 2008, 2009 Donn.C.Ingle ## Contact: donn.ingle@gmail.com - I hope this email lasts. ## ## This file is part of Fonty Python. ## Fonty Python 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. ## ## Fonty Python 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 Fonty Python. If not, see . import wx import wx.lib.scrolledpanel from pubsub import * ## Setup wxPython to access translations : enables the stock buttons. langid = wx.LANGUAGE_DEFAULT # Picks this up from $LANG mylocale = wx.Locale( langid ) import fpsys # Global objects from gui_Fitmap import * #Also brings in 'ps' variable class ScrolledFontView(wx.lib.scrolledpanel.ScrolledPanel) : """ This is the main font control, the child of CLASS FontViewPanel. Draw a list of fitmaps from a font list object (derived from BasicFontList) """ def __init__(self, parent): wx.lib.scrolledpanel.ScrolledPanel.__init__(self, parent, -1, style=wx.VSCROLL|wx.SUNKEN_BORDER) self.fitmaps = [] self.parent = parent ## At least this one works. self.wheelValue = fpsys.config.points self.Bind( wx.EVT_MOUSEWHEEL, self.onWheel ) ## Make the sizer to hold the fitmaps self.mySizer = wx.BoxSizer(wx.VERTICAL) self.SetSizer(self.mySizer) self.firstrun =True self.SetupScrolling(rate_y=5, scroll_x=False) ps.sub( reset_top_left_adjustments, self.ResetTopLeftAdjustFlag ) ##DND: class ScrolledFontView def onWheel( self, evt ): """ Added Dec 2007 Change point size with ctrl+scroll """ n = 10 if evt.GetWheelRotation() < 0: n = -10 if evt.ControlDown(): self.wheelValue += n if self.wheelValue < 10: self.wheelValue = 10 if self.wheelValue > 200: self.wheelValue = 200 fpsys.config.points = int(self.wheelValue) ## Tried to restore the scrollbar, but it crashes the app ##xPos, yPos = self.GetViewStart() self.ResetTopLeftAdjustFlag() ## Sept 2009 : size change means we need new values for fitmaps ps.pub( update_font_view ) # starts a chain of calls. ##self.Scroll(xPos, yPos) return ## Keep the wheel event going evt.Skip() # Sept 2009 def ResetTopLeftAdjustFlag( self ): '''Each fitem has a top_left_adjust_completed flag. False forced the fitmaps to re-calculate the adjustment for top-left.''' for fi in fpsys.state.viewobject: fi.top_left_adjust_completed = False def DoGetBestSize(self): # This is actually called BEFORE the __init__ to this object! # What calls this function and when is a dark art. It's related to splitter events (at least) # In my big 30 Sept 2009 fix I just ended-up with this solution -- it's not really something I am savvy about :( w = fpsys.config.size[0]# Use the last known width of the entire window as an initial size estimate. wl = fpsys.config.leftSash wr = fpsys.config.rightSash w = w-wl-wr ## This try block is to get-around the odd fact that DoGetBestSize is called prior to __init__ try: ## If this succeeds then we have the width of the parent panel. w2=self.parent.GetSize()[0] ## This is not always sensible, esp. on first run. So, fake it if it's too small. if w2 < w: w2=w except: ## __init__ not run yet, we need a value. Use the default. w2=w w=w2 self.width=w # This property is used in gui_Fitmap best = wx.Size(w,0) self.CacheBestSize(best) #Prevent this def running too often. return best def CreateFitmaps(self, viewobject) : """ Creates fitmaps (which draws them) of each viewobject FontItem down the control. """ #self.InvalidateBestSize() # Reset the cache (seems uneccessary) self.DoGetBestSize() # Force re-call ## Ensure we destroy all old fitmaps -- and I mean it. for f in self.fitmaps: f.Destroy() #Ah, nailed ya! You bastard! I fart in your general direction! del self.fitmaps self.fitmaps = [] ## It's NB to notice that the fitems being put into self.fitmaps are ## the SAME items that are in the viewobject. self.mySizer.Clear() # Wipe all items out of the sizer. self.Scroll(0,0) # Immediately scroll to the top. This fixed a big bug. ## If our viewobject has NO FONTS inside it (i.e. it's an EmptyView object) ## then setup a fake FontItem so we can have a dud Fitmap to show. if len(viewobject) == 0: empty_fitem = fontcontrol.InfoFontItem() fm = Fitmap( self, (0, 0), empty_fitem ) self.fitmaps.append(fm) # I MUST add it to the list so that it can get destroyed when this func runs again next round. self.mySizer.Add( fm, 0, wx.GROW ) else: for fitem in viewobject: #test if not fitem.badfont: continue ## Create a Fitmap out of the FontItem we have at hand. fm = Fitmap( self, (0,0),fitem)# i * h), fitem ) self.fitmaps.append(fm) self.mySizer.Add(fm, 0, wx.GROW) if fpsys.config.numinpage > 20: wx.Yield() #Added Oct 2009 to let app live on loooong lists. # Layout should be called after adding items. self.mySizer.Layout() # This gets the sizer to resize in harmony with the virtual (scrolling) nature of its parent (self). self.mySizer.FitInside(self) fontypython-0.4.4/fontypythonmodules/i18n.py0000644000175000017500000000411411742276540017731 0ustar donndonn## Fonty Python Copyright (C) 2006, 2007, 2008, 2009 Donn.C.Ingle ## Contact: donn.ingle@gmail.com - I hope this email lasts. ## ## This file is part of Fonty Python. ## Fonty Python 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. ## ## Fonty Python 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 Fonty Python. If not, see . import locale, gettext, sys, os ## Had to copy this from fpsys. When doing a proper installation ## the relative links to locale stop working. I need to know ## where fontypythonmodules actually lives. root = __file__ if os.path.islink(root): root = os.path.realpath(root) fontyroot = os.path.dirname(os.path.abspath(root)) ## Dec 2007 ## Try to setup the proper locale to get i18n started: localedir = os.path.join(fontyroot, "locale") try: loc = locale.setlocale( locale.LC_ALL, "" ) # This sets the locale to the system's default. except: print "And now for something completely different..." print "setlocale failed. Please report this to us." raise SystemExit ## REMEMBER: ## locale.getlocale() -- DON'T USE getlocale ## ALWAYS use locale.getpreferredencoding() ## On my system when LANG=C or LANG= ## This returns "ANSI_X3.4-1968" ## The .mo file is called "all.mo" domain = "all" gettext.install( domain, localedir, unicode = True ) try: lang = gettext.translation (domain, localedir, languages=[loc])#have to have last param ... lang.install(unicode = True ) except IOError: ## Could not find the domain.mo file. ## I won't print a message because this file runs twice (fontypython and start_fontypython) ## and that dumps two messages, which sucks. pass # default to English. fontypython-0.4.4/fontypythonmodules/linux_safe_path_library.py0000644000175000017500000000751511742276540024057 0ustar donndonn## Fonty Python Copyright (C) 2006, 2007, 2008, 2009 Donn.C.Ingle ## Contact: donn.ingle@gmail.com - I hope this email lasts. ## ## This file is part of Fonty Python. ## Fonty Python 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. ## ## Fonty Python 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 Fonty Python. If not, see . ## Linux safe "path" library ## It's really a place to do encode and decode and os.join ## I debated calling it linux safe STRING library, but can't decide. """ LESSONS Linux is Posix and that means all filenames are stored as byte strings "Unlike Windows NT/2000/XP, which always store filenames in Unicode format, POSIX systems (including Linux) always store filenames as binary strings. This is somewhat more flexible, since the operating system itself doesn't have to know (or care) what encoding is used for filenames. The downside is that the user is responsible for setting up their environment ("locale") for the proper coding." On Linux: os.path.supports_unicode_filename is always == True On my system, with LANG=en_ZA.utf8 >>> locale.getpreferredencoding() 'UTF-8' Return the charset that the user is likely using, according to the system configuration. With LANG=C it returns "ANSI****" On my system: >>> sys.getfilesystemencoding() 'UTF-8' This one returns the ENCODING (byte string to unicode) needed to convert filenames from the O/S *to* unicode. os.path.join : If any one part is unicode, it's all unicode. (Order does not matter) If all parts are str, it's str >>> import os >>> a=u"unicode" >>> b="string" >>> type(a) >>> type(b) >>> p=os.path.join(a,b) >>> p u'unicode/string' >>> p=os.path.join(b,a) >>> p u'string/unicode' """ import os import locale class linuxSafePath( object ): def __init__(self): self.PREFENC=locale.getpreferredencoding() ## I am leaving these without error catches. Let the errors be handled higher-up ## or barf to the stdout. Recc. that users run app from the cli if it is ## closing mysteriously. def to_bytes( self, u ): '''Given a known unicode, return a byte string''' return u.encode( self.PREFENC ) def to_unicode( self, b ): '''Given a known byte string, return a unicode''' return b.decode( self.PREFENC,"replace" ) def ensure_bytes( self, anything ): '''Given any unknown, return a byte string''' if type(anything) is unicode: byte_string = self.to_bytes( anything ) else: byte_string = anything return byte_string def ensure_unicode( self, anything ): '''Given any unknown, return a unicode''' if type( anything ) is str: unicode_obj = self.to_unicode( anything ) else: unicode_obj = anything return unicode_obj def _safe_path_join( self, want="bytestring", *mixed_list ): '''Private worker. Join a path cast to want from mixed_list''' list = [] if want == "bytestring": for anything in mixed_list: list.append( self.ensure_bytes(anything) ) else: for anything in mixed_list: list.append( self.ensure_unicode( anything ) ) return os.path.join( *list ) def path_join_ensure_bytestring_result( self, *args ): '''Return a byte string path from the supplied arguments''' return self._safe_path_join( "bytestring", *args) def path_join_ensure_unicode_result( self, *args ): '''Return a unicode path from the supplied arguments''' return self._safe_path_join( "unicode", *args ) fontypython-0.4.4/fontypythonmodules/pathcontrol.py0000644000175000017500000000535111742276540021513 0ustar donndonn## Fonty Python Copyright (C) 2006, 2007, 2008, 2009 Donn.C.Ingle ## Contact: donn.ingle@gmail.com - I hope this email lasts. ## ## This file is part of Fonty Python. ## Fonty Python 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. ## ## Fonty Python 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 Fonty Python. If not, see . import os class PathControl: """ 1. Makes the .fontypython path 2. Provide paths for fontypython on Linux 3. Provide list of pog names (without the .pog extension) 4. Provide a list of pog FILE names (with .pog extension) * All these vars contain/return BYTE STRING paths and files. """ def __init__(self, makeFolder=True ): ## __HOME will be a BYTE STRING (Under Linux) self.__HOME = os.environ['HOME'] self.__fphomepath = self.__HOME + "/.fontypython/" # byte string self.__fpconffile = self.__HOME + "/.fontypython/fp.conf" # byte string ## Is there a .fonts folder ? ## ## EDIT ## ## April 2012 - Kartik Mistry (kartik@debian.org) ## informed me there was a bug in some esoteric build ## of some voodoo Debian process and that I should ## simply skip the check and creation of .fonts directory. #if not os.path.exists(self.__HOME + "/.fonts"): ## We gotta make it. # try: # os.mkdir(self.__HOME + "/.fonts") # except: # print _(""" #Couldn't make the .fonts folder in %s #Please check your write permissions and try again.""") % self.__HOME # raise SystemExit self.__userfontpath = self.__HOME + "/.fonts" ## Make ~/.fontypython if makeFolder: if not os.path.exists(self.__fphomepath): try: os.makedirs(self.__fphomepath) #using makedirs - just in case. except: print _(""" Couldn't make the folder in %s Please check your write permissions and try again.""") % self.__fphomepath raise SystemExit def appPath(self): """ Kind of spastic, but I was in a get/set mode""" return self.__fphomepath def appConf(self): return self.__fpconffile def getPogNames(self): ## We pass a byte string path to os.listdir therefore this function ## return a LIST OF BYTE STRINGS. return [ f[0:-4] for f in os.listdir(self.__fphomepath) if f.endswith(".pog") ] def userFontPath(self): return self.__userfontpath def home(self) : return self.__HOME fontypython-0.4.4/fontypythonmodules/pubsub.py0000644000175000017500000000605211742276540020455 0ustar donndonn## Fonty Python Copyright (C) 2006, 2007, 2008, 2009 Donn.C.Ingle ## Contact: donn.ingle@gmail.com - I hope this email lasts. ## ## This file is part of Fonty Python. ## Fonty Python 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. ## ## Fonty Python 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 Fonty Python. If not, see . ## Message topics : they identify the functions to run from CPubsub update_font_view = 10 show_error = 20 show_error_and_abort = 30 show_message = 40 reset_to_page_one = 50 add_pog_item_to_source = 60 remove_pog_item_from_source = 70 print_to_status_bar = 80 install_pog = 90 uninstall_pog = 100 main_button_click = 110 toggle_main_button = 120 target_pog_has_been_selected = 130 source_pog_has_been_selected = 135 change_pog_icon = 140 toggle_targetpog_buttons = 150 clear_targetpog_selection = 160 select_no_view_pog = 170 get_font_view_width = 180 menu_settings = 190 toggle_selection_menu_item = 200 toggle_purge_menu_item = 210 left_or_right_key_pressed = 1000 reset_top_left_adjustments = 2000 ## A hack to allow values to return from published topics globRetVal = {} ## The thing that is held in the dictionary inside CListener class CTopic: def __init__(self, function, topic, key): self.function = function self.topic = topic self.key = key ## When you have a function you want to make available, sub() it. ## When you want something to happen somewhere else, then pub () it. class CPubsub: def __init__(self): self.__ears = {} self.__key = 0 def __del__(self): del self.__ears ## Makes a topic object and stores it internally. ## Keeps a constantly increasing internal key. ## I used a dictionary, but it prob should just be a list. ## Ah well. def sub(self, topic, function): #SUBSCRIBE (was newEar) t = CTopic(function, topic, self.__key) self.__ears [ self.__key ] = t self.__key += 1 ## Go thru all the topics, find any that match and call their functions, passing any args too. def pub(self, topic, *args): #PUBLISH (was shout) #global globRetVal #m = CMessage(topic, messagelist) for key, top in self.__ears.iteritems(): if top.topic == topic: function = top.function if args: function(args) #Pass the args only. else: function() ## Sample of the use of this stuff: if __name__ == "__main__": def dox(*args): print "i run", args def detox(*args): print "yup de too", args top_dox = 1 p = CPubsub() #we subscribe two handlers to one topic p.sub(top_dox, dox) p.sub(top_dox, detox) #we pretend we are in another class/widget and we want to send a message: p.pub(top_dox, 10,20,"AX","BX") fontypython-0.4.4/fontypythonmodules/sanitycheck.py0000644000175000017500000000245311742276540021463 0ustar donndonn## Fonty Python Copyright (C) 2006, 2007, 2008, 2009 Donn.C.Ingle ## Contact: donn.ingle@gmail.com - I hope this email lasts. ## ## This file is part of Fonty Python. ## Fonty Python 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. ## ## Fonty Python 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 Fonty Python. If not, see . import sys import strings ## Quick tests - which is there? ## Using imp will find a module very quickly, faster than import x import imp ## PIL : Is it there? try: import Image, ImageFont, ImageDraw except: print strings.PILError raise SystemExit try: import wxversion ## Dec 2007: noticed that it may not be installed along with wxPython.... wxversion.ensureMinimal("2.8") except: print strings.wxVersionError print try: imp.find_module("wx") except: print strings.wxError raise SystemExit fontypython-0.4.4/fontypythonmodules/start.py0000644000175000017500000000176411742276540020317 0ustar donndonn## Fonty Python Copyright (C) 2006, 2007, 2008, 2009 Donn.C.Ingle ## Contact: donn.ingle@gmail.com - I hope this email lasts. ## ## This file is part of Fonty Python. ## Fonty Python 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. ## ## Fonty Python 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 Fonty Python. If not, see . ## test modules etc. import fontypythonmodules.sanitycheck import fpsys ## Process the command line stuff import cli ## The GUI import fontypythonmodules.wxgui ## End, clean up fpsys.config.Save() fontypython-0.4.4/fontypythonmodules/strings.py0000644000175000017500000002637511742276540020660 0ustar donndonn# This Python file uses the following encoding: utf-8 ## Fonty Python Copyright (C) 2006, 2007, 2008, 2009 Donn.C.Ingle ## Contact: donn.ingle@gmail.com - I hope this email lasts. ## ## This file is part of Fonty Python. ## Fonty Python 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. ## ## Fonty Python 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 Fonty Python. If not, see . import pathcontrol import fpversion import os copyright = "Fonty Python Copyright (C) 2006, 2007, 2008, 2009 Donn.C.Ingle" contact = "email: donn.ingle@gmail.com" done = "Done." ## We use PathControl to get some info, BUT we DO NOT WANT TO MAKE ## the ~/.fontypython folder from this module. ## This module (strings) also gets used via setup.py ## and that has the result of making the folder with root ownership! Bad news. ## So, there is a new flag to manage this now: _pc = pathcontrol.PathControl( makeFolder=False ) version = _("Fonty Python version %s") % fpversion.version warranty = """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.""" aboutText = "%s\n%s\nWritten on Gnu\Linux, using wxPython.\n\n%s" % (copyright, version, warranty) options=_("""Options: -v --version Show program's version number and exit. -h --help Show this help message and exit. -e --examples Show some %$@#$ examples! -i Pog --install=Pog Install the fonts in this Pog to your fonts folder. -u Pog --uninstall=Pog Uninstall the fonts in this Pog. -l --list List the names of all the Pogs. -s num --size=num Set a new default point size. -n num --number=num Set a new default for how many fonts to view at one go. Don't overdo this. -p Pog --purge=Pog Purge the Pog of font files that are no longer really there. -c folder --check=folder Check for bad fonts that crash Fonty. It will recurse through sub-folders. This will build a file: ~/.fontypython/segfonts After using this tool you should be able to browse folders that crashed Fonty. (The reason it's not done by default is that it's very slow.) * NOTE: The fonts that crash Fonty are probably still perfectly good and can be used in other apps. It's simply a bug in the library we use to access fonts that chokes things. This will (hopefully) improve in the future. -a folder Pog --all folder Pog Puts all fonts in this folder into the Pog. If the Pog already exists, it will add only *new* fonts, this means fonts are not repeated in that Pog. -A folder Pog --all-recurse folder Pog Puts all fonts in this folder and *all* sub-folders into the Pog. Rest same as -a. -z Pog --zip=Pog All the fonts inside Pog will be zipped and the zipfile will be named after the Pog. The file will be placed in the current directory. """) use = _("""%(c)s [OPTIONS] [VIEW] [TARGET] VIEW : A place where fonts are. (A Pog or a Folder.) TARGET : A "Pog". A place to keep those fonts. ("%(c)s" on it's own will start the GUI.) NB: Try not to use spaces in Pog names. If you must, then "quote the name." Please use -e to see more info. NEWS : We now support TTF, OTF, Type1 (PFB, PFA) and TTC fonts. %(version)s The basic idea: =============== Many designers have collections of font files in big directory structures or on other media. Fonty Python will let you gather your fonts and structure them into collections -- or what I call "Pogs" -- a place to keep tyPOGraphy. Well, why not? Your fonts never move from where they are (so don't worry). All that happens is that you select fonts visually and place their names into a Pog, then you install or uninstall Pogs as you need them. No copies of your fonts are made, only links to the original files are used to install the fonts. For example, you might have a Pog called 'logos' into which you place all the fonts you have of company logos. After that, when you need to work with those logos, you simply install the 'logos' Pog and start your design app! FP is also great for just looking at fonts wherever they are on your computer, without having to install them system-wide. Manage your fonts on Gnu/Linux! =============================== %(copy)s %(warranty)s %(contact)s """ ) % { "c":"fontypython", "folder":_pc.appPath(), "contact":contact, "copy":copyright, "warranty":warranty, "version":version } examples = _("""The basic format is: %(c)s [VIEW] [TARGET] VIEW = A place where fonts are. A Pog or a folder someplace. TARGET = A Pog, a place to keep references to fonts If you don't include a target then you are viewing/editing only. Tips: ===== * Don't use spaces in Pog names. If you absolutely must then use quotes around the name, e.g. "Pogs of Ni" * If your design apps (for example The Gimp) do not reflect the fonts that you have installed, restart the app. Sometimes the system needs a while to reflect the new fonts in your fonts folder. Examples: All using short options, see -h ========= %(c)s /path/to/fonts/ttfs/a This will start off showing the fonts in that path. %(c)s /path/to/fonts/ttfs/b Trouser This will let you view and choose fonts from the path and it will store them in a Pog named "Trouser". The Pog will be created if it's not already there. %(c)s Lumberjack This will let you see the fonts in the Pog named "Lumberjack". You can also uninstall individual fonts by selecting them. A cross will appear indicating the fonts that will be uninstalled. %(c)s Camelot Spamalot This will let you see and choose fonts in "Camelot" and it will store them in "Spamalot" It lets you copy fonts between Pogs. %(c)s -i Cheese Will install the fonts in Pog Cheese so you can use them in other apps. %(c)s -u Trouser Will uninstall the fonts listed in Pog Trouser, so you can't use 'em anymore.( You Naughty thing) %(c)s -s 128 Will set the point size to 128 - Crazy man! %(c)s -n 25 Will show 25 fonts at a time. Beware large numbers! %(c)s -s 64 -v 10 Pimple Will set the point size to 64, the number of fonts to view is 10 and then display the Pimple Pog. %(c)s -p Glutton If there are any fonts in "Glutton" that are not really on your drive/media anymore (perhaps you deleted them or the cat did) then this will go through your Pog and cull them. %(c)s -c /some/path/to/fonts If Fonty keeps crashing on /some/path/to/fonts then you should run a check on that folder. This will 'mark' the dangerous fonts and let you use that folder in the future. %(c)s -a /some/path HolyHandGrenade This will put all the fonts in that path into the Pog called HolyHandGrenade. %(c)s -A /some/path Tutto This will do the same as -a above: start in that path, but it will then walk down recursivly through all sub-folders too. The fonts will be placed in Tutto. Your fontypython folder is: %(folder)s If you want to backup your Pogs, that's where ya go. %(contact)s %(copy)s""") % { "c":"fontypython", "folder":_pc.appPath(), "contact":contact, "copy":copyright } ## These two are used in setup.py description = _("Fonty Python - view and manage all kinds of fonts on Gnu/Linux") long_description = _("""Manage your fonts on Gnu/Linux. NEWS : We now support TTF, OTF, Type1 (PFB, PFA) and TTC fonts. Many designers have collections of font files in big directory structures or on other media. Fonty Python will let you gather your fonts and structure them into collections -- or what I call "Pogs" -- a place to keep tyPOGraphy. Well, why not? Your fonts never move from where they are (so don't worry). All that happens is that you select fonts visually and place their names into a Pog, then you install or uninstall Pogs as you need them. No copies of your fonts are made, only links to the original files are used to install the fonts. For example, you might have a Pog called "logos" into which you place all the fonts you have of company logos. After that, when you need to work with those logos, you simply install the 'logos' Pog and start your design app! FP is also great for just looking at fonts wherever they are on your computer, without having to install them system-wide. %(copy)s %(contact)s """) % {"copy":copyright, "contact":contact} wxvers="2.8" wxVersionError = _("""I cannot find "python-wxversion" Please install this package - NB: ensure that you use only the "Unicode build". TIP === On my distro I can search for it like this: aptitude search python-wx This returns many results, one of which is: python-wxversion I then install it like this: sudo aptitude install python-wxversion If you get long error messages, you will need to install python-wxgtk*, where the star means the version number and it should be at least %(wxv)s You can also get the latest version from here: http://wxpython.org/download.php """) % {"wxv":wxvers} wxError =_("""I cannot find "python-wxgtkX.Y" Please install this package - NB: ensure that you use only the "Unicode build". TIP === On my distro I can search for it like this: aptitude search python-wx This returns many results, one of which is: python-wxgtk%(wxv)s I then install it like this: sudo aptitude install python-wxgtk%(wxv)s Make sure it's at least version %(wxv)s You can also get the latest version from here: http://wxpython.org/download.php """) % {"wxv":wxvers} PILError = _("""I cannot find "python-imaging" Please install this package. TIP === On my distro I can search for it like this: aptitude search python-imag This returns many results, one of which is: python-imaging I then install it like this: sudo aptitude install python-imaging Make sure it's at least version 1.1.6-1 You can also get the latest version from here: http://www.pythonware.com/products/pil/index.htm """) ## Won't xlate the thanks: thanks = u"""Many thanks to: 1. Robin Dunn - wxPython and much sundry help. 2. Martin v. Löwis - Essential concepts regarding unicode and files. 3. Pietro Battiston - Italian translation. 4. Baptiste - French translation and many ideas. 5. Jason Yamada-Hanff - For the wiki, at least :) 6. Michael Hoeft - For code, friendship and the German translation. 7. Kartik Mistry - Our esteemed Debian packager! 8. savannah.nongnu.org - For the hosting. 9. And all those I have neglected to include. """ ## June 2009 : Get the GPL from the COPYING file rather than a copy of it all here again. try: root = __file__ if os.path.islink(root): root = os.path.realpath(root) fontyroot = os.path.dirname(os.path.abspath(root)) p = os.path.join(fontyroot,'COPYING') GPL = open(p,"r").read() except: GPL = """ GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 The file "COPYING" cannot be found. Please check the installation directory for the licence. """ fontypython-0.4.4/fontypythonmodules/wxgui.py0000644000175000017500000003443411742276540020325 0ustar donndonn## Fonty Python Copyright (C) 2006, 2007, 2008, 2009 Donn.C.Ingle ## Contact: donn.ingle@gmail.com - I hope this email lasts. ## ## This file is part of Fonty Python. ## Fonty Python 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. ## ## Fonty Python 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 Fonty Python. If not, see . import locale import strings import fpsys # Global objects import fpversion ## Now, bring in all those big modules import wx ## Setup wxPython to access translations : enables the stock buttons. langid = wx.LANGUAGE_DEFAULT # Picks this up from $LANG mylocale = wx.Locale( langid ) ## Fetch my own pubsub stuff from pubsub import * ps = CPubsub() ## Fetch the dialogue classes *About, Settings, Help, etc.* import dialogues ## DND: NB--Comments that have DND: in them mean DO NOT DELETE. They are used by me via grep on the cli. from gui_Left import * from gui_Middle import * from gui_Right import * class Splitter(wx.SplitterWindow): """ The splitter used twice in mainframe. """ def __init__(self, parent) : wx.SplitterWindow.__init__(self, parent, -1, style = wx.SP_LIVE_UPDATE | wx.SP_3D) class StatusBar(wx.StatusBar): """ The status bar """ def __init__(self, parent): wx.StatusBar.__init__(self, parent, -1) self.SetFieldsCount(1) self.SetStatusText( _("Welcome to Fonty Python version %s") % fpversion.version, 0) def Report(self, msg): self.SetStatusText(msg, 0) class MainFrame(wx.Frame): """ The main frame for the app. Has some functionality for menu items. """ def __init__(self,parent,title) : ## Draw the frame title = title + " - " + locale.getpreferredencoding() wx.Frame.__init__(self,parent,-1,title,fpsys.config.pos,fpsys.config.size) ## Try to show an icon try: image = wx.Image(fpsys.mythingsdir + 'fplogo.png', wx.BITMAP_TYPE_PNG) image = image.ConvertToBitmap() icon = wx.EmptyIcon() icon.CopyFromBitmap(image) self.SetIcon(icon) except: pass ## STATUS BAR self.sb = StatusBar(self) self.SetStatusBar(self.sb) ## Prepare the menu bar self.menuBar = wx.MenuBar() ## FILE MENU : Changed to "Tools" menu Sep 2009 menu1 = wx.Menu() menu1.Append(101, _("&Settings\tCtrl+S"), _("Change settings")) menu1.AppendSeparator() ## Jan 18 2008 menu1.Append( 102, _("&Check fonts"), _("Find those fonts that crash Fonty.") ) menu1.Append( 103, _("&Purge Pog"), _("Remove all ghost fonts from the selected Pog.") ) self.MENUPURGE = menu1 self.exit = menu1.Append(104, _("&Exit"), _("Close the app")) ## Add menu to the menu bar self.menuBar.Append(menu1, _("&Tools")) ## SELECT MENU: June 2009 menu3 = wx.Menu() menu3.Append( 301, _("&Select ALL the source fonts"), _("Select ABSOLUTELY ALL the fonts in the chosen source.")) menu3.Append( 302, _("&Clear ENTIRE selection"), _("Clear the selection completely.") ) ## Add menu to the menu bar self.menuBar.Append(menu3, _("&Selection")) self.MENUSELECTION = menu3 ## HELP MENU menu2 = wx.Menu() menu2.Append(201, _("H&elp\tF1")) menu2.Append(202, _("&About")) ## Append 2nd menu self.menuBar.Append(menu2, _("&Help")) ## Tell the frame the news self.SetMenuBar(self.menuBar) ## Setup the ESC key and the LEFT / RIGHT keys accel = wx.AcceleratorTable([ (wx.ACCEL_NORMAL, wx.WXK_ESCAPE, self.exit.GetId()), (wx.ACCEL_CTRL, wx.WXK_RIGHT, wx.ID_FORWARD), (wx.ACCEL_CTRL, wx.WXK_LEFT, wx.ID_BACKWARD) ]) self.SetAcceleratorTable(accel) ## Bind the Left and Right key shortcuts. self.Bind(wx.EVT_MENU, self.OnAccelKey, id=wx.ID_FORWARD ) self.Bind(wx.EVT_MENU, self.OnAccelKey, id=wx.ID_BACKWARD ) ## The X close window button. self.Bind( wx.EVT_CLOSE, self.onHandleESC ) ## Bind events for the menu items self.Bind(wx.EVT_MENU, self.onHandleESC, self.exit) self.Bind(wx.EVT_MENU, self.menuSettings, id = 101) self.Bind(wx.EVT_MENU, self.menuCheckFonts, id = 102 ) self.Bind(wx.EVT_MENU, self.menuPurgePog, id = 103 ) self.Bind(wx.EVT_MENU, self.menuAbout, id = 202) self.Bind(wx.EVT_MENU, self.menuHelp, id = 201) # June 2009 self.Bind(wx.EVT_MENU, self.menuSelectionALL, id=301) self.Bind(wx.EVT_MENU, self.menuSelectionNONE, id=302) ## Create a splitter self.splitter = Splitter(self) ## The notebook self.panelNotebook = wx.Panel(self.splitter) ## Notebook label and icon self.viewIcon = wx.StaticBitmap( self.panelNotebook, -1, wx.Bitmap( fpsys.mythingsdir + 'icon_source_16x16.png', wx.BITMAP_TYPE_PNG )) self.viewLabel = wx.StaticText( self.panelNotebook, -1, _("Source, Folder or Pog"), style = wx.ALIGN_LEFT ) self.viewLabel.SetFont( wx.Font(10, fpsys.DFAM, wx.NORMAL, wx.FONTWEIGHT_BOLD) ) ## A horiz sizer to hold the icon and text self.sizer_iconandtext = wx.BoxSizer(wx.HORIZONTAL) self.sizer_iconandtext.Add( (4, 1), 0 ) self.sizer_iconandtext.Add( self.viewIcon, 0, wx.TOP | wx.BOTTOM, border = 4 ) self.sizer_iconandtext.Add( self.viewLabel, 1, wx.EXPAND | wx.TOP | wx.BOTTOM | wx.LEFT, border = 4 ) ## Now the actual notebook self.nb = NoteBook(self.panelNotebook) ## Make a Vertical sizer to hold them. self.sizerNotebook = wx.BoxSizer(wx.VERTICAL) ## Add them to the sizer. self.sizerNotebook.Add(self.sizer_iconandtext, 0, wx.EXPAND) self.sizerNotebook.Add(self.nb,1,wx.EXPAND) self.panelNotebook.SetSizer(self.sizerNotebook) self.sizerNotebook.Layout() ## dec 2007 : Added a second splitter. It was a bitch! self.splitter2 = Splitter(self.splitter) # gets the second slot of splitter ## Font View Panel Control: self.fontViewPanel = FontViewPanel(self.splitter2) # first slot in splitter2 self.sizerFontView = wx.BoxSizer(wx.VERTICAL) self.sizerFontView.Add(self.fontViewPanel, 1, wx.EXPAND) self.sizerFontView.SetDimension( 0, 0, 1024, 0) #self.fontViewPanel.Layout() ## THE FAR RIGHT HAND SIDE ## The TargetPogChooser self.panelTargetPogChooser = TargetPogChooser(self.splitter2) # last slot of splitter2 self.sizerRight = wx.BoxSizer(wx.HORIZONTAL) self.sizerRight.Add(self.panelTargetPogChooser, 1, wx.EXPAND) self.panelTargetPogChooser.Layout() self.splitter.SetMinimumPaneSize(64) self.splitter.SplitVertically( self.panelNotebook, self.splitter2, fpsys.config.leftSash ) self.splitter2.SetMinimumPaneSize(128) self.splitter2.SplitVertically( self.fontViewPanel, self.panelTargetPogChooser) #Don't suggest a size here. self.SetCursor(wx.StockCursor(wx.CURSOR_ARROW)) ## Now to subscribe to have my various def called from other places: ps.sub(show_error, self.ErrorBox) ##DND: class MainFrame ps.sub(show_error_and_abort, self.ErrorAbort) ##DND: class MainFrame ps.sub(show_message, self.MessageBox) ##DND: class MainFrame ps.sub(print_to_status_bar, self.StatusbarPrint) ##DND: class MainFrame ## Dec 2007 - Used on middle click in gui_Fitmap.py ps.sub( menu_settings, self.menuSettings ) ##DND: class MainFrame ps.sub( toggle_selection_menu_item, self.toggleSelectionMenuItem ) ##DND: class MainFrame ps.sub( toggle_purge_menu_item, self.TogglePurgeMenuItem ) ##DND: class MainFrame ## call the big one - the big chief, the big cheese: ## This eventually draws all the Fitmaps - giving the middle have a width. ps.pub( update_font_view ) #DND: It's in gui_Middle.py under class FontViewPanel self.splitter.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGED, self.onSize) #Give splitter an event (not splitter2) weird. # Force splitter2 to the correct position. self.splitter2.SetSashPosition( -fpsys.config.rightSash, redraw=False ) self.Layout() ## A nasty looking line to call the SortOutTheDamnImages function ## This is to draw the right icons depending on the params from cli. self.panelTargetPogChooser.pogTargetlist.SortOutTheDamnImages(False) def OnAccelKey(self,evt): ps.pub( left_or_right_key_pressed, evt ) #fwd this business on-to a func in gui_Middle.py def toggleSelectionMenuItem(self, onoff): #HIG says to leave top menu alone and only toggle sub-items. self.MENUSELECTION.Enable(301,onoff[0]) self.MENUSELECTION.Enable(302,onoff[0]) def onSize( self, evt ): """ The splitter has been moved. Don't ask me why splitter and not splitter2 is the one we have to use. Go figure. """ ps.pub( update_font_view ) # starts a chain of calls. def GetSashesPos( self, args=None ): ## For saving/restoring the sashes to where we bloody left them :\ return ( self.splitter.GetSashPosition(), self.panelTargetPogChooser.GetClientSize()[0]) def StatusbarPrint(self, args): self.sb.Report(args[0]) def MessageBox(self, args): dlg = wx.MessageDialog(self, args[0] , _("Warning"), wx.OK | wx.ICON_INFORMATION) dlg.ShowModal() dlg.Destroy() def ErrorBox(self, args): dlg = wx.MessageDialog(self, args[0], _("Error"), wx.OK | wx.ICON_ERROR) dlg.ShowModal() dlg.Destroy() def ErrorAbort(self, args): self.ErrorBox(args) #Pass it along to be displayed self.endApp() def onHandleESC(self, e) : print strings.done self.endApp() def endApp(self) : """ Save app's vital statistics and exit. See the end of start.py where it's actually saved. """ fpsys.config.pos = self.GetPositionTuple() ## Dec 2007 - I was using the wrong func and the ## main window kept getting smaller! fpsys.config.size = self.GetSizeTuple() fpsys.config.leftSash, fpsys.config.rightSash = self.GetSashesPos() ##June 2009 - fetch and record the value of the recurse folders checkbox. fpsys.config.recurseFolders = app.GetTopWindow().nb.recurseFolders.GetValue() self.Destroy() def menuSettings(self, e): lastnuminpage, lastpoints, lasttext = fpsys.config.numinpage ,fpsys.config.text, fpsys.config.points dlg = dialogues.DialogSettings(self) val = dlg.ShowModal() if val == wx.ID_OK: ## Did anything change? num = int(dlg.inputPageLen.GetValue()) points = int(dlg.inputPointSize.GetValue()) txt = dlg.inputSampleString.GetValue() ignoreAdjust = dlg.chkAdjust.GetValue() #Sept 2009 if (num, txt, points) != (lastnuminpage, lastpoints, lasttext): fpsys.config.numinpage = int(num) fpsys.config.points = int(points) if len(txt) > 0: fpsys.config.text = txt fpsys.config.ignore_adjustments = ignoreAdjust #Sept 2009 fpsys.config.CMC.SET_CURRENT_APPNAME( dlg.CHOSEN_CHARACTER_MAP) # Oct 2009 ## Now to refresh things: ## Sept 2009 : size change means we need new values for fitmaps ps.pub( reset_top_left_adjustments ) ##DND : In ScrolledFontView ps.pub( update_font_view ) dlg.Destroy() def menuAbout(self, e): dlg =dialogues.DialogAbout(self) val = dlg.ShowModal() dlg.Destroy() def menuHelp(self, e): dlg = dialogues.DialogHelp(self, size=(800, 600)) val = dlg.ShowModal() dlg.Destroy() def menuCheckFonts( self, e ): """ Added Jan 18 2008 User can visit suspicious directories with this tool to gather a list of fonts that kill the app. They will be marked as such and hereafter be safe to use. """ ## Set startdir to the one our own dircontrol is in if fpsys.state.viewpattern == "F": startdir = fpsys.state.viewobject.path else: ##Let's get it from the config object startdir = fpsys.config.lastdir dlg = dialogues.DialogCheckFonts( self, startdir ) val = dlg.ShowModal() dlg.Destroy() def menuSelectionALL(self,e): if not fpsys.state.cantick: return # Can't tick if this is False. fpsys.state.numticks=0 vo=fpsys.state.filteredViewObject # We want to select what is FILTERED for fi in vo: if not fi.inactive: fi.ticked=True fpsys.state.numticks += 1 ## Now update the view ps.pub( update_font_view ) def menuSelectionNONE(self,e): fpsys.state.numticks=0 vo=fpsys.state.viewobject # We *REALLY* mean select NONE. So ignore filter. for fi in vo: if not fi.inactive: fi.ticked=False ## Now update the view ps.pub( update_font_view ) def TogglePurgeMenuItem(self, vis): vis=vis[0] self.MENUPURGE.Enable(103,vis) def menuPurgePog(self,e): ##The menu item only becomes active for Pogs that are not installed, ##so we can purge without further tests: pogname = fpsys.state.viewobject.name dlg = wx.MessageDialog(self,_("Do you want to purge %s?\n\nPurging means all the fonts in the pog\nthat are not pointing to actual files\nwill be removed from this pog.") % pogname, _("Purge font?"), wx.YES_NO | wx.ICON_INFORMATION ) if dlg.ShowModal() == wx.ID_YES: ## pog.purge() Raises ## PogEmpty ## PogInstalled try: fpsys.state.viewobject.purge() except(fontybugs.PogEmpty, fontybugs.PogInstalled),e: ps.pub(show_error, unicode( e )) ps.pub(print_to_status_bar, _("%s has not been purged.") % pogname) return ## Update GUI ps.pub(print_to_status_bar, _("%s has been purged.") % pogname) ps.pub(update_font_view) ##http://wiki.wxpython.org/Widget%20Inspection%20Tool ## Use ctrl+alt+i to open it. #import wx.lib.mixins.inspection ## Start the main frame and then show it. class App(wx.App ):#, wx.lib.mixins.inspection.InspectionMixin) : def OnInit(self): #self.Init() # initialize the inspection tool ## Initial dialogue to inform user about their potential fate: if not "unicode" in wx.PlatformInfo: wx.MessageBox(_("I am sorry, but Unicode is not supported by this installation of wxPython. Fonty Python relies on Unicode and will simply not work without it.\n\nPlease fetch and install the Unicode version of python-wxgtk."), caption=_("SORRY: UNICODE MUST BE SUPPORTED"), style=wx.OK | wx.ICON_EXCLAMATION ) raise SystemExit bmp=wx.Image(fpsys.mythingsdir + "splash.png",wx.BITMAP_TYPE_PNG).ConvertToBitmap() ss=wx.SplashScreen( bmp, wx.SPLASH_CENTRE_ON_SCREEN, 1, None, -1) ## Oct 2009 ## this is the only place I can get the system font family fpsys.DFAM = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT).GetFamily() frame = MainFrame(None, _("Fonty Python: bring out your fonts!")) self.SetTopWindow(frame) frame.Show(True) ss.Close() return True ## app app = App(0) ## start app.MainLoop() fontypython-0.4.4/CHANGELOG0000644000175000017500000002234711742276621014030 0ustar donndonnChangelist ========== 11 June 2009 1. Changed many button events to wx.EVT_BUTTON for better behaviour ) 2. Fixed Bug 2 (wxgui) -- The Tab->Folder->Last Directory->Show Fonts bug. 3. Changed cli, fontcontrol, strings and wxgui to allow recursive folders. 12 June 2009 1. Adding a Search Assistant panel. It's full of junk from the wxDemo at the moment. 2. Added/Edited ROADMAP after reading email from Michael. 3. Removed Select All button. RIP bad idea :) 4. Added Selection menu and it's sub-items. Wired-them up to the remains of the Select Button code. 5. Fixed the PogChooser issue betwixt source and target. 6. Split-off most of wxgui.py classes into their own gui_xxx.py modules. Trying to make it simpler. We now have gui_Left, gui_Middle and gui_Right for the main sections. 13 June 2009 1. Continued the refactoring. Moved functions to where they made more sense. Cut down on chains of calls. 2. Got rid of shadow functions. At last! 3. Put refs to locale stuff into the new modules, BUT HAVE NOT TESTED i18n yet. HELP! 4. Improved the pubsub a tiny little bit. Also removed the return value -- it was not being used. 5. Fixed strings GPL message. It loads it from the COPYING file. 6. Hacking a search bar together from a combo box and some spare bits :) 14 June 1. Got the search combo box working a little. History is added etc. 16 June 1. Fixed the bug where the first fitmap in the fontview would draw at an odd y value. 2. Fixed the persistent InfoFontItem issue. Now it goes away when it should. 18 June 1. Many visual fixes. Re-factored the drawing code in Fitmap. 2. Many little fixes like toggle selection menu and multi-selection on/off in the lists. 19 June 1. Gave up on the fancy search dream. FontTools and Panose confuse me horribly. Michael can't help dev at the moment, so it's all back to square one. I remarked-out the assistant panel. 2. I got the left and right arrow keys to step through the list - like the buttons do. 3. I (think I) fixed the ESC key to work from anywhere. 20 June 1. Cleaning-up files etc. Lot's of little zipzap commits. Yesterday I merged the branch back into the trunk. 2. Caught an encode and decode problem in Folder.__init__. Had to jump through the usual unicode hoops to fix it. Hope it is fixed now... 3. Added the licence header to a bunch of files it was missing from. 4. Small fixes to README regarding i18n. 5. Fixing some unicode errors and error dialog boxes. 6. Trying to repair the "lost focus" bug when the main button is clicked -- so far no dice. 22 June 1. Rigged the main button so that focus is not lost on click. It's a hack, but what the heck. 26 June 1. Main button focus issue has a hack-fix 2. Delete multiple pogs at once from the gui. 3. Fixed the help text. Changed the app screenshot. 4. Moved the Purge function out to the File menu. It now applies to the VIEW POG selected. 26 June 1. Added a test to prevent fonts re-drawing when a new target Pog is clicked. 2. Added help about the Purge menu item. 26 June 1. Reversed decision to not redraw the target Pog. There are too many subtleties involved for the hammer-and-nail approach I took and I just don't have time to be subtle now. So, it will redraw when you choose another target Pog. Tough. 27 June 1. Changed left/right arrow to pageup/pagedown. Michael Hoeft warned of the damage to editing the search term. 2. Improving the splash image. 27 June 1. Fixed ref to page up/down keys in help. 28 June 1. Upon reflection, the arrow keys are easier than page up/down. So, I added CTRL as a modifier. Now it's ctrl+left/right to step through the pages. (Help updated too.) 29 June 1. Repaired the .desktop file to comply with HIG. 30 June 1. Changed selection menu item toggling system. Recently read a little Gnome HIG :) 1 July 1. Changed logo in help, about and splash. 2. Altered setup.py to remove MANIFEST file if it's there. Unless it's removed, setup.py sdist will potentially miss new files. 6 July 2009 1. Fixed a problem with setup.py that was making ~/.fontypython folder (and as root too). That folder now only gets made when the app is run for the first time, not during setup. Thanks to Pietro for catching this one. 7 July 1. Pietro sent us an Italian .po file. I did "make mos" and I hope that was right. 2. Removed some _() stuff from CORNER CASE error messages. 3. Redacted pofiles/README file somewhat. 24 July 1. A bug was caught by Michael Hoeft - the combo box (for search field) requires wxPython 2.8 -- So we had to shift a few things around. After a false start, I have created version 0.4.1 and am about to upload to the ftp site. 15 Sept 2009 1. Fixed a bug where fonts that are already installed would refuse to install again. It ignores OSError 17 now. 2. Added zip function -- zip all fonts in a pog(s) for easy distribution. 3. Moved to vers 0.4.2 16 Sept 1. Removed irritating message dialogs from zip function. 2. Removed pofiles directory from MANIFEST.in so they do not go into the tarball 3. There is a weird bug in the zip files -- when you unzip one there are odd files that want renaming... Not sure what this is yet. 4. Changed File menu to Tools menu. 5. Added error catch and report to zip. 6. Improved directory dialogue for zip. 7. Fixed help file and image. 18 Sept Added reference counting to fonts that are shared/common among pogs: When a pog is uninstalled *and* another installed pog has the same font(s), those fonts are left installed. 19 Sept 1. A long day of tidying-up and abstracting the unicode/str stuff. 2. Gone a long way to a standard error approach. Still have some loose ends. 21 Sept 1. Adding icons for the various font items that are bad in some way. 2. Tweaking colours and effects to look better 3. Trying to get the widths of fitems to fit the middle panel. Kind of working, but not on first run. 22 Sept 1. Got a workaround for fitem widths going. 2. Improved the rendering of fitems under various conditions. 3. Removed fatfont. 22 Sept 1. Changed button on Check fonts form to 'Close' -- makes more sense now. 24 Sept 1. Major update of help file and graphics. 2. Trying to fancy-up the info label in the font-view. So far no luck. 3. Got the label going! Made a custom control. 25 Sept 1. Improved the drawing of fitmaps and gradients. Still have some precalcing of colours to do. 2. Tweaked the images and icons. 26 Sept 1. Added a sunken border to font view -- better visual containment I think. 27 Sept More gui polishing done. Strings changed -- PO files will be broken :( 28 Sept 1. Seems PO files are quite robust -- the strings are marked as 'fuzzy' and should still translate fairly well. 2. Today I will make a 'release' branch on the SVN and get the tarball for 0.4.2 going. 28 Sept : Feedback from Kartik 1. Removed the Version tag from .desktop file -- it's not required. 2. Removed the .png from the icon key in .desktop file -- it's not wanted. 3. Some confusion as to whether fonty will run 100% on Python 2.5, I developed this year on 2.6 4. Version bumped to 0.4.2.1 29 Sept 1. Working on a way to scan the font images and remove that leading blank space on certain fonts. Done, and included an override in settings dialog. 30 Sept 1. Spent the *ENTIRE* day fighting the damn splitter and sizers. Not really sure why or how, but I got it working okay. I also don't really know what broke from last version! 1 Oct 2009 1. Renamed 'fp' script to 'start_fontypython' - had to edit a bunch of files. 1.1 It turns out that fonty has been running without the segfault catcher all along. This should be remedied as of now. Backported fix to 0.4.2.x as well. 2. Taking-over the maintenance of the man page. I will leave it in the root of the tarball and Kartik will deal with it from there. Backported to 0.4.2.x 2 Oct 1. Spot changes. Made label above font views look better. 2. Started adding threading so that Fonty can spawn gucharmap or kfontview on a given fitmap in the view. 3 Oct 1. Fixed a bug in Delete Pogs -- reported by Michael Hoeft. Backported to 0.4.2.2 as well. 2. Adding an 'Voodoo' tab to Settings dialogue to house the charmap choice and the font adjustment checkbox. Wired it all up and it works! 4 Oct 1. Built a button to spawn the character-map app. Nice rollover and all. 2. Updated the help. 3. Created three buttons Bold, Italic and Regular for quick filtering. 4. Updated man page 5 Oct 1. Segfault dialogue suddenly started causing segfaults of its own... Sheesh. I had to remove a box sizer to get it to work. 2. Fixed bug in character map viewer code. 3. Small repair to BIR toggles. 11 Oct 1. Fixed a config startup bug - whatever charmaps are found, the first in the list is now taken as the default else None. 2. Made the default size 800x600 with left sash 200. 3. Made custom icons for the dir control. 4. New screenshot for the help file. 5. Tweaked zip name to xxxx.fonts.zip so it's obvious what it contains. 6. Adding the design files (Inkscape stuff) to the trunk so that others can use them. 7. "fixed" another wee bug in charmap default choice.I hope... 12 Oct 1. Made a new module to better deal with the charmap viewer wiring. 2. Removed the bitmap toggle buttons for B I R : they sucked. Normal toggle buttons will be used until wxpython can get bitmap buttons right. 13 Oct 1. Removed the -t --text= comand-line option. It was totally useless. 2. Fixed the strings.py file to reflect 1. 3. Fixed the man page too. fontypython-0.4.4/COPYING0000644000175000017500000010451311742276621013645 0ustar donndonn GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . fontypython-0.4.4/MANIFEST.in0000644000175000017500000000040511742276621014343 0ustar donndonninclude fontypython start_fontypython README COPYING CHANGELOG fontypython.png fontypython.desktop fontypython.1 MANIFEST.in recursive-include fontypythonmodules/things * recursive-include fontypythonmodules/locale * recursive-include fontypythonmodules/help * fontypython-0.4.4/README0000644000175000017500000001241011742276621013464 0ustar donndonnFonty Python Copyright (C) 2006,2007,2008,2009 Donn.C.Ingle donn.ingle@gmail.com Fonty Python comes with ABSOLUTELY NO WARRANTY; for details see the COPYING file. This is free software, and you are welcome to redistribute it under certain conditions; see the COPYING file for details. NB: Remove the old version BEFORE you install FP. ============== You can find the path by: locate fontypythonmodules If that does not work, then you must update your locate database: As root run: locate -u Go make coffee.Then run the locate command above again. This will give you a directory something like: /usr/lib/python2.5/site-packages/fontypythonmodules Use your root account to remove that folder: sudo rm -fr /usr/lib/python2.5/site-packages/fontypythonmodules (Be *very* careful what you type!) You should be good to go now. How to install ============== Please see the end of this file if your install fails, there are certain files that FP relies upon. I assume you have extracted the "tarball" already. Change to the directory it creates. As the root user enter this command: python setup.py install If you are on Ubuntu/Kubuntu/Xubuntu/Debian etc: sudo python setup.py install This will create a program called 'fontypython' Alternative installation ======================== Move the entire extracted folder to a folder that is in your PATH, like ~/bin Make a link to the fontypython script like this: (for e.g.) tar -s ~/bin/fontypython-x.x.x/fontypython . Make it executable: chmod u+x fontypython Now you should be good to go. If it does not work, try closing your console and starting it again. Running the program =================== To get started: fontypython -h For more info: fontypython -e Please read the help ( -h or Help menu in app ). Troubleshooting the installation ================================ Fonty Python depends on several other libraries: ( These are minimum version numbers ) 1. python2.4 to python2.6 (Not python3) 2. python-dev (odd one this. See notes below) 3. python-imaging 4. python-wxgtk2.6 or greater. Items 1 and 3 are usually pre-installed on Gnu\Linux distros. Item 2 is a new twist. I am not sure why it's required for FP (yes - I don't know everything :)) but some users have had problems and installing python2.4-dev fixed them. (replace 2.4 with the actual version of python you are using.) On *buntu: sudo apt-get install python2.4-dev If you cannot install item 2 - try the alternative installation instructions above. Item 4 may be installed, or it may be in your distro's main repository.To install item 4, try the following: On *buntu/Debian: apt-cache search python-wxgtk Find the latest version in the list, then: sudo apt-get install python-wxgtkX.Y (replacing X.Y with the results of your search) On distro X: *Please send me your experiences and I'll fill this in* After this has installed, try to run fontypython again. If you still do not come right, then I advise you to go to the following web sites for help directly from the horse's mouth: http://wxpython.org http://www.pythonware.com/products/pil/index.htm LOCALIZATION TIPS ================= Make sure your LANG variable is set properly. To run under a locale, do something like this: LANG=en_ZA.utf8 ./fontypython You can find your locales by: locale -a If localization is not working it could be that there is no translation for your language yet, it can also be a problem with missing packages in your distro. This is what I installed on my system (Kubuntu 7.10 as of December 2007) while I was developing: language-support-fr language-support-en language-pack-gnome-fr (*) (*) This one is VERY important, it has many stock translations for GTK. Without it you likely not see buttons and widgets in the right language. Substitute your language code as you please. TRANSLATION TIPS ================ If you want to help translate, please contact us via the fontypython list: fontypython@googlegroups.com I have included the pot files that I have. Look at fontypythonmodules/pofiles/README (Translation stuff is messy. Headers are all wrong and versions all over the place.) CHANGELOG ================ Jan 22 2008 : FP version 0.3.6 * Fixed another font bug (0 width). * Bad wxImage badfont catch - draws a yellow block like a segfont. * Made the Check Font dialog work a lot better. feedback & better layout. * Updated the po/mo files, but no new translating has been done. Jan 20 2008 : FP version 0.3.5 * Added a .desktop file and an icon - changes to setup.py Jan 18 2008 : FP version 0.3.4 * Did a lot of locale/unicode work to support LANG=C * Added a tool to 'check' fonts - marks segfaulters * Added long command-line options * Repairs to help file * Many bugs fixed, new ones created :) Jan 10 2008 : FP version 0.3.3 * Fixed setup.py bug - should install properly now. * Tweaked some gui things - like spacing. * Added a clear button for the filter. * Major overhaul of the Type1 code in fontcontrol. Jan 4 2008 : FP version 0.3.1 * Fixed img height/width bugs in help file. It scrolls smoothly now. * Fixed startup bug when last folder viewed no longer has any fonts. * Fixed some text in strings. * Improved the setup.py system to use i18n, strings and fpversion modules. * Added Italian translation (Thanks to Pietro Battiston) Please send me reports about your experiences with Fonty Python. Donn,2007,2008,2009. fontypython-0.4.4/fontypython0000755000175000017500000000643711742276621015147 0ustar donndonn#!/usr/bin/env python ## Fonty Python Copyright (C) 2006,2007,2008,2009 Donn.C.Ingle ## Contact: donn.ingle@gmail.com - I hope this email lasts. ## ## This file is part of Fonty Python. ## Fonty Python 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. ## ## Fonty Python 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 Fonty Python. If not, see . """ Dec 2007 This wraps start_fontypython and catches the segfaults that kill it. A window displays the situation and gives the user some hope. """ import subprocess, sys, os ## find the directory from where THIS script ## is actually being run. root = __file__ if os.path.islink(root): root = os.path.realpath(root) fontyroot = os.path.dirname(os.path.abspath(root)) import fontypythonmodules.i18n as i18n ## Get the dir to run this from: #root = os.path.dirname(sys.argv[0]) # note: # this returns /usr/bin when we run from an installed # version of fonty. # Since I am testing from my dev directory, and sometimes # make a link in /usr/bin to fake things: # (sudo ln -s `pwd`/fontypython /usr/bin/fontypython) # I want the actual site-root where fontypythonmodules/ is # so I will use fontyroot from above ##os.chdir( fontyroot ) # note: # Not changing dir anymore because this makes relative # directory stuff like: # fontypython . # not work properly. User should be able to open a view # on the current directory. # Thus: # Point to the absolute path of the 'start_fontypython' script. c1 = [os.path.join(fontyroot,'start_fontypython') ] ## Append any args for arg in sys.argv[1:]: c1.append( arg ) p1 = subprocess.call( c1 ) if p1 == 0: print #print _("Thanks for trying Fonty Python!") ## retired 28 May 2009 elif p1 == 1: print #Skip this line else all cli errors also print this: _("Mysterious Bad Stuff happened. Fonty failed. Let us know.") else: # err code -11 #print "ERROR CODE:", p1 ## This actually works! import sys, os, locale import fontypythonmodules.pathcontrol as PC import wx, fontypythonmodules.dialogues as D ## Setup wxPython to access translations : enables the stock buttons. localedir = "fontypythonmodules/locales" langid = wx.LANGUAGE_DEFAULT mylocale = wx.Locale( langid ) iPC = PC.PathControl() def getSegfaulter(): """ What was the last font to segfault PIL? """ paf = os.path.join( iPC.appPath(),"lastFontBeforeSegfault") culprit = None try: f = open( paf, "r" ) culprit = f.readline()[:-1] f.close() except: raise return culprit ## Start the App and then show the Segfault dialog. class App(wx.App) : def OnInit(self) : culprit = getSegfaulter() #print culprit dlg = D.SegfaultDialog(None, culprit) val = dlg.ShowModal() if val == wx.ID_OK: print _("Please restart Fonty Python after you have moved:\"%s\" to some other place.") % culprit dlg.Destroy() return True app = App(0) app.MainLoop() fontypython-0.4.4/fontypython.10000644000175000017500000000616511742276621015301 0ustar donndonn.TH "FONTYPYTHON" 1 "2009-09-28" "" "" .SH NAME fontypython \- Find, view and manage font files of all kinds. .SH SYNOPSIS .B fontypython [\fIOPTIONS\fR]... [\fIVIEW\fR]... [\fITARGET\fR]... .SH DESCRIPTION .B fontypython is a GUI utility written in Python and WxPython that will help you do font stuff on GNU/Linux system. You can quickly view and filter arbitrary* TTF, TTC, OTF or Type1 font files and then gather them together into 'Pogs' which can be .B installed or removed as needed. In this way you control which fonts are installed on a per-project basis. If you have .B gucharmap or .B kfontview installed, (there is an option in Settings to choose which one) you can view any font's character maps etc. *Arbitrary means you can .B see and/or use .B any fonts in a local directory (or a mount). They .B do not need to be installed on your system. .PP .SH OPTIONS .TP \fB VIEW A place where fonts are. A Pog or a folder someplace. .TP \fB TARGET A "Pog". A place to keep those fonts (just references to them). .TP \fB OPTIONS Below are the various command-line options. You don't need to use them, but they are handy. The program will run as a GUI if you only invoke 'fontypython'. .TP \fB\-e\fR, \fB\-\-examples\fR Show some %$@#$ examples! .TP \fB\-l\fR, \fB\-\-list\fR List the names of all the Pogs. .TP \fB\-i\fR Pog, \fB\-\-install\fR=\fIPog\fR Install the fonts in this Pog to your fonts folder. .TP \fB\-u\fR Pog, \fB\-\-uninstall\fR=\fIPog\fR Uninstall the fonts in this Pog. .TP \fB\-p\fR Pog, \fB\-\-purge\fR=\fIPog\fR Purge the Pog of font files that are no longer really there. .TP \fB\-s\fR num, \fB\-\-size\fR=\fInum\fR Set a new default point size. .TP \fB\-n\fR num, \fB\-\-number\fR=\fInum\fR Set a new default for how many fonts to view at one go. Don't overdo this. .TP \fB\-c\fR folder \fB\-\-check\fR=\fIfolder\fR Check for bad fonts that crash the program. It will recurse through sub-folders. This will build a file: ~/.fontypython/segfonts After using this tool you should be able to browse safely. (The reason it's not done by default is that it's very slow.) NOTE: The fonts that crash the program are probably still perfectly good and can be used in other apps. .TP \fB\-a\fR folder Pog, \fB\-\-all\fR=\fIfolder Pog\fR Puts all fonts in this folder into the Pog. If the Pog already exists, it will add only *new* fonts, this means fonts are not repeated in that Pog. .TP \fB\-A\fR folder Pog, \fB\-\-all\-recurse=\fIfolder Pog\fR Puts all fonts in this folder and *all* sub-folders into the Pog. Rest same as \-a. .TP \fB\-z\fR Pog, \fB\-\-zip=\fIPog\fR All the fonts inside Pog will be zipped and the zipfile will be named after the Pog. The file will be placed in the current directory. .TP \fB\-\-version\fR Show program's version number and exit. .TP \fB\-h\fR, \fB\-\-help\fR Show help message and exit. .SH SEE ALSO .BR Homepage: .SH AUTHOR fontypython was written by Donn.C.Ingle . .PP This manual page was updated by Donn Ingle in October 2009. It was originally written by Kartik Mistry , for the Debian project (but may be used by others). fontypython-0.4.4/fontypython.desktop0000644000175000017500000000067511742276621016612 0ustar donndonn[Desktop Entry] Name=Fonty Python Font Manager GenericName=Font Manager Comment=View and temporarily install all kinds of fonts. Comment[fr]=Fonty Python est aussi approprié pour visionner vos fichiers TTF où qu'ils soient sur votre ordinateur Comment[it]=Vedi e installa temporaneamente tutti i tipi di font Type=Application Categories=Graphics; Exec=fontypython TryExec=fontypython Terminal=false StartupNotify=true Icon=fontypython fontypython-0.4.4/fontypython.png0000644000175000017500000000452711742276621015725 0ustar donndonnPNG  IHDR@@iqsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<IDATx[lg;s98!CBN4 q DAېIb7LcZ/Vq47ckס @ڎ%@(k!8''q;w8 gL+>}}^[\y'_u3? \,-^MU'V_uKcRʔ*N^Wl,&ۑd%d;ll-y.,ՐӢV?Ilã8]+HAN^Ӣ@æ6lg`؎mCkN׌d;O L^WֺjKߏcjn޹ˬ˅B͍;? ՒgГoгHYqy>o_τP+4TT[Ifz;v9=)3Z a;z~Y:-E94VXr77aA`Gc[IQ(hkkѣ\|>$[7n\;8gdȘwSV\ޝ{fLj7^7HU=0g||䛇׃n+;݇]l(+a W~=JM+ӘfΝ;͍:ƙsK;37~DW j֯ ?.ih4i79x 8_O]?⚙e&d{(Sn9rǏjUWW/97in!=UME骐b͛0dsI~yBl]uO݆Хt4VW` ߏm-s !`&DQWo--HER"! 9HSP+A%i2XDKKKqi4JJJs4:> N]r"TY?:S USJWfn'`_JsAUҵDa.xޘZj+i| 9'IKQ,ܢ . @ZEA^--ۇ^:0DgoTc4Ԭ+6(zŵ&cߖɎmק DueXc`I \rE#c0ʛ=6iQE :-cG|>^*ɑF#&ɘ L&cht,dd2 ssX,LNNJr$ @O@c*uZ(  '\Fkk$'@EK_H H7|IX%D"dfdPQQAH)(.*g@ 㙟1Fk ͆*- QYï41 E:{mLK*r4 Cf%VCz7KrJ)Vs#^ל90hӶI^NANp O H*_PnGdtg)P53*e B&*%9Y].U*;?,<}L3Έ+q$@TYYt$%7'eM|iydOqG{$EokB;F1"(6zi~=!. OHPY/]jLנLYC{{;(5*`x`virŨO0PqmB)3#R 韛Ůf֮2ᚙ彿_7"$@TSSXZNQ((.ȧf}51'Ϟd+,!2J%yzVP¼LMx:m$: (ȧ-)\ w142Ne 2%R\Դ~A\(!di2HKOFc+tO|xp2;ff|r~:($pb߿Dley@qbqH}}=S!,|&&&X,1.//'#=]R/ @L!Wŵkb@c*᝜ `2!B\ h4^o[e8BI* :qKGd(({]V^sgG_%d;ll@%d|g9@1۽E|1,6\!ڒIENDB`fontypython-0.4.4/setup.py0000644000175000017500000001143411742276621014323 0ustar donndonn#!/usr/bin/env python ## Fonty Python Copyright (C) 2006,2007,2008,2009 Donn.C.Ingle ## Contact: donn.ingle@gmail.com - I hope this email lasts. ## ## This file is part of Fonty Python. ## Fonty Python 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. ## ## Fonty Python 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 Fonty Python. If not, see . import fontypythonmodules.i18n import fontypythonmodules.sanitycheck import fontypythonmodules.fpversion import os, sys, glob, fnmatch from distutils.core import setup, Extension import distutils.command.install_data ## Code borrowed from wxPython's setup and config files ## Thanks to Robin Dunn for the suggestion. ## I am not 100% sure what's going on, but it works! def opj(*args): path = os.path.join(*args) return os.path.normpath(path) # Specializations of some distutils command classes class wx_smart_install_data(distutils.command.install_data.install_data): """need to change self.install_dir to the actual library dir""" def run(self): install_cmd = self.get_finalized_command('install') self.install_dir = getattr(install_cmd, 'install_lib') return distutils.command.install_data.install_data.run(self) def find_data_files(srcdir, *wildcards, **kw): # get a list of all files under the srcdir matching wildcards, # returned in a format to be used for install_data ## A list of partials within a filename that would disqualify it ## from appearing in the tarball. badnames=[".pyc","~","no_",".svn","CVS",".old"] def walk_helper(arg, dirname, files): BL=[ bad for bad in badnames if bad in dirname ] L=len( BL ) if L > 0: # There is a bad string in the dirname, so we skip it return names = [] lst, wildcards = arg for wc in wildcards: wc_name = opj(dirname, wc) for f in files: filename = opj(dirname, f) ## This hairy looking line excludes the filename ## if any part of one of badnames is in it: L=len([bad for bad in badnames if bad in filename]) if L == 0: if fnmatch.fnmatch(filename, wc_name) and not os.path.isdir(filename): names.append(filename) if names: lst.append( (dirname, names ) ) file_list = [] recursive = kw.get('recursive', True) if recursive: os.path.walk(srcdir, walk_helper, (file_list, wildcards)) else: walk_helper((file_list, wildcards), srcdir, [os.path.basename(f) for f in glob.glob(opj(srcdir, '*'))]) return file_list ## Remove the MANIFEST file, if there. try: os.remove("MANIFEST") print "MANIFEST removed" except: print "No MANIFEST to remove." try: os.remove("PKG-INFO") except: pass ## This is a list of files to install, and where: ## Make sure the MANIFEST.in file points to all the right ## directories too. files = find_data_files('fontypythonmodules/', '*.*') ## Jan 20 2008 - Add an icon and .desktop file ## Unsure about the absolute path to /usr/share ## but this works on my system. files.append( ('/usr/share/pixmaps',['fontypython.png']) ) files.append( ('/usr/share/applications',['fontypython.desktop']) ) ## files.append( ('/usr/share/man/man1',['fontypython.1']) ) # leave this up to Kartik to handle. files.append( ('fontypythonmodules/',['COPYING']) ) # on setup.py install this puts COPYING into fontypythonmodules setup(name = "fontypython", version = fontypythonmodules.fpversion.version, description = fontypythonmodules.strings.description, author = "Donn.C.Ingle", author_email = fontypythonmodules.strings.contact, license = "GNU GPLv3", url = "https://savannah.nongnu.org/projects/fontypython/", packages = ['fontypythonmodules'], data_files = files, ## Borrowed from wxPython too: ## Causes the data_files to be installed into the modules directory. ## Override some of the default distutils command classes with my own. cmdclass = { 'install_data': wx_smart_install_data }, #'fontypython' and 'start_fontypython' are in the root. scripts = ["fontypython", "start_fontypython"], long_description = fontypythonmodules.strings.long_description, classifiers=[ 'Development Status :: 4 - Beta', 'Environment :: X11 Applications :: GTK', 'Intended Audience :: End Users/Desktop', 'Intended Audience :: Developers', 'License :: OSI Approved :: GNU General Public License (GPL)', 'Operating System :: POSIX :: Linux', 'Programming Language :: Python', 'Topic :: Desktop Environment', 'Topic :: Text Processing :: Fonts' ] ) fontypython-0.4.4/start_fontypython0000755000175000017500000000207511742276621016356 0ustar donndonn#!/usr/bin/env python ## Fonty Python Copyright (C) 2006,2007,2008,2009 Donn.C.Ingle ## Contact: donn.ingle@gmail.com - I hope this email lasts. ## ## This file is part of Fonty Python. ## Fonty Python 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. ## ## Fonty Python 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 Fonty Python. If not, see . import fontypythonmodules.i18n import os ## Just clear up some sad facts: if os.name != "posix": sys.exit(_("Sorry, only Gnu/Linux is supported at the moment.")) ## start the show! import fontypythonmodules.start fontypython-0.4.4/PKG-INFO0000644000175000017500000000400411742300067013671 0ustar donndonnMetadata-Version: 1.0 Name: fontypython Version: 0.4.4 Summary: Fonty Python - view and manage all kinds of fonts on Gnu/Linux Home-page: https://savannah.nongnu.org/projects/fontypython/ Author: Donn.C.Ingle Author-email: email: donn.ingle@gmail.com License: GNU GPLv3 Description: Manage your fonts on Gnu/Linux. NEWS : We now support TTF, OTF, Type1 (PFB, PFA) and TTC fonts. Many designers have collections of font files in big directory structures or on other media. Fonty Python will let you gather your fonts and structure them into collections -- or what I call "Pogs" -- a place to keep tyPOGraphy. Well, why not? Your fonts never move from where they are (so don't worry). All that happens is that you select fonts visually and place their names into a Pog, then you install or uninstall Pogs as you need them. No copies of your fonts are made, only links to the original files are used to install the fonts. For example, you might have a Pog called "logos" into which you place all the fonts you have of company logos. After that, when you need to work with those logos, you simply install the 'logos' Pog and start your design app! FP is also great for just looking at fonts wherever they are on your computer, without having to install them system-wide. Fonty Python Copyright (C) 2006, 2007, 2008, 2009 Donn.C.Ingle email: donn.ingle@gmail.com Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: Environment :: X11 Applications :: GTK Classifier: Intended Audience :: End Users/Desktop Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: GNU General Public License (GPL) Classifier: Operating System :: POSIX :: Linux Classifier: Programming Language :: Python Classifier: Topic :: Desktop Environment Classifier: Topic :: Text Processing :: Fonts