diff -Nru pybik-0.5/AUTHORS pybik-1.0.1/AUTHORS --- pybik-0.5/AUTHORS 2011-06-28 05:38:09.000000000 +0000 +++ pybik-1.0.1/AUTHORS 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ -B. Clausius - is the main author and maintainer of this package. - -This package is derived from GNUbik 2.3. -Authors of GNUbik: - -John Mark Darrington - is the main author and maintainer of GNUbik. - -Dale Mellor - diff -Nru pybik-0.5/HACKING pybik-1.0.1/HACKING --- pybik-0.5/HACKING 2011-06-28 05:42:29.000000000 +0000 +++ pybik-1.0.1/HACKING 1970-01-01 00:00:00.000000000 +0000 @@ -1,8 +0,0 @@ -Development versions of Pybik are available through a Bazaar repository. - -The Barzaar release represents work in progress and is not guaranteed -to compile on your machine or be functional in any manner. - -The latest development version of Pybik can be retrieved using: - bzr branch lp:pybik - diff -Nru pybik-0.5/INSTALL pybik-1.0.1/INSTALL --- pybik-0.5/INSTALL 2011-07-06 07:43:56.000000000 +0000 +++ pybik-1.0.1/INSTALL 2012-10-26 02:03:51.000000000 +0000 @@ -1,53 +1,77 @@ +Installation Instructions for Pybik 1.0 +======================================= -= Installation Instructions = +If Pybik is available for your distribution, you should install Pybik with a +package manager. Otherwise see the following installation instructions. -Please make sure you satisfy Pybik's dependencies: - * Python 2.7 - * Python bindings for GTK+: pygtk >= 2.16 - * pyopengl - * python-numpy - For building extension module (optional [2]): - * cython or pyrex [1] - * development files for python, mesa - For building translation files (optional): - * gettext - * intltool +Installation from Ubuntu PPA +============================ + +For Ubuntu the latest release is available in the Pybik Personal Package Archive (PPA) +. Add `ppa:barcc/pybik` to your system's +software sources (with the Ubuntu Software-Center). +You can also do this in a terminal: + sudo add-apt-repository ppa:barcc/pybik + sudo apt-get update + sudo apt-get install pybik -[1] The project is currently moving from pyrex to cython, - the support for pyrex may be removed sometime. -[2] Without the extension module Pybik runs with poor performance +Run from source archive +======================= -== Ubuntu == +Please use the latest source from the official download site +. -For Ubuntu Pybik is also available in a PPA. +Requirements +------------ + +Please make sure you satisfy Pybik's dependencies: + * Python 2.7 + * Qt4 and Python bindings for Qt4 (PySide) + You need at least the thee modules + * qtcore, qtgui and qtopengl + * Python bindings for OpenGL (pyopengl) + * python-numpy +For building the extension modules [1]: + * C-compiler (gcc) + * development files for python + * mesa development files + * gettext + * intltool + * cython (>= 0.14.1) + * pyside-tools + * help2man -You can use the Ubuntu Software-Center and add ppa:barcc/pybik to your -system's Software Sources. Just install the package pybik and do not care -about the dependencies, it will be resolved automatically. +[1] Without the extension modules Pybik runs with poor performance. -You can also do this in a Terminal: - sudo add-apt-repository ppa:barcc/pybik - sudo apt-get install pybik +Build +----- +Extract the archive, switch to the created directory in a terminal and enter: + ./build_local.sh -== Source directory == +To run Pybik you can use the command in the same directory + ./pybik -Pybik should run fine directly from source directory. -To build the extension module, manpage and translation files, run: - ./build_local.sh +System-wide installation +======================== +This installation method is intended primarily for packagers. Pybik comes +with a full featured `setup.py` installation script. To find out more, run: + ./setup.py --help -== System-wide installation == -To install properly, run: +VCS and Daily Builds +==================== - ./setup.py install +Development happens with the Bazaar version control system. +Location: +You can get the latest revision with: + bzr branch lp:pybik -See --help for an overview of the available options; e.g. --prefix to -install to a custom base directory, and --without-gettext to avoid -installing natural language support files. +Daily build for Ubuntu are provided in the PPA `ppa:barcc/daily-build` + diff -Nru pybik-0.5/MANIFEST.in pybik-1.0.1/MANIFEST.in --- pybik-0.5/MANIFEST.in 2011-11-28 22:26:54.000000000 +0000 +++ pybik-1.0.1/MANIFEST.in 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ -include AUTHORS COPYING HACKING INSTALL NEWS README THANKS -include pybik -include build_local.sh - -include pybiklib/*.pxd - -recursive-include data *.py *.in *.png *.jpg *.ui *.desktop* -recursive-include po *.po *.in -recursive-include tools *.py - diff -Nru pybik-0.5/NEWS pybik-1.0.1/NEWS --- pybik-0.5/NEWS 2012-01-05 23:01:34.000000000 +0000 +++ pybik-1.0.1/NEWS 2013-02-01 09:16:50.000000000 +0000 @@ -1,3 +1,19 @@ +Pybik 1.0.1: + + * Minor improvements and bugfixes + * Updated translations + +Pybik 1.0: + + * Improved user interface. + * Added Towers and Bricks (non cubic puzzles). + * Added an option to show the back faces. + * The cube can be manipulated with the keyboard. + * Animation is faster and rendering more beautiful. + * Added more pretty patterns. + * Added a new solver. + * Added new translations. + Pybik 0.5: * New solutions: diff -Nru pybik-0.5/PKG-INFO pybik-1.0.1/PKG-INFO --- pybik-0.5/PKG-INFO 1970-01-01 00:00:00.000000000 +0000 +++ pybik-1.0.1/PKG-INFO 2013-02-02 21:45:29.000000000 +0000 @@ -0,0 +1,10 @@ +Metadata-Version: 1.0 +Name: pybik +Version: 1.0.1 +Summary: 3D Rubik's cube game +Home-page: https://launchpad.net/pybik/ +Author: B. Clausius +Author-email: barcc@gmx.de +License: GNU GPL v3 +Description: Pybik is an interactive, graphical, single player puzzle about the cube invented by Ernő Rubik. Besides the cube the program can handle towers and bricks (non cubic puzzles). Pybik also has solvers, pretty patterns and a collection of various moves. The cube can be manipulated with the mouse or keyboard. You can change the colors or images on the faces of the cube. +Platform: UNKNOWN diff -Nru pybik-0.5/README pybik-1.0.1/README --- pybik-0.5/README 2011-06-28 05:42:29.000000000 +0000 +++ pybik-1.0.1/README 2013-02-02 21:45:29.000000000 +0000 @@ -1,19 +1,60 @@ -This is the Pybik distribution. -Pybik is a 3D interactive graphics -puzzle. It renders an image of a magic cube -(similar to a rubik cube) and you attempt to solve it. +About Pybik 1.0.1 +================= +Pybik is an interactive, graphical, single player puzzle about the cube +invented by Ernő Rubik. Besides the cube the program can handle towers and +bricks (non cubic puzzles). Pybik also has solvers, pretty patterns and a +collection of various moves. The cube can be manipulated with the mouse or +keyboard. You can change the colors or images on the faces of the cube. -See the file INSTALL for installation instructions. +Author: B. Clausius +License: GNU GPL v3 +Project page: -Reporting Bugs --------------- +Installation +============ -If you find any bugs in pybik, or even just have a suggestion -for an improvement to the game then please submit a bug report -by using the web-based interface at +If Pybik is available for your distribution, you should install Pybik with a +package manager. Otherwise see the file INSTALL for installation instructions. -https://bugs.launchpad.net/pybik + +Feedback +======== + +If you find any bugs in Pybik or have a suggestion for an improvement then +please submit a bug report [1]. In the latter case you can mark the bug report +as "Wishlist". + +[1] + + +Translation +=========== + +Translations are managed by the Launchpad translation group [1]. If you want +help to translate Pybik to your language you can do it through the web +interface [2]. Read more about "Translating with Launchpad" [3] and "Starting +to translate" [4]. + +[1] +[2] +[3] +[4] + + +License +======= + +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 . diff -Nru pybik-0.5/build_local.sh pybik-1.0.1/build_local.sh --- pybik-0.5/build_local.sh 2011-07-06 02:58:06.000000000 +0000 +++ pybik-1.0.1/build_local.sh 2012-12-13 20:38:14.000000000 +0000 @@ -1,3 +1,5 @@ #!/bin/sh -./setup.py build_ext --inplace build_i18n build_man +./setup.py build --inplace --parallel=auto "$@" +./tools/create_docs.py README + diff -Nru pybik-0.5/copyright pybik-1.0.1/copyright --- pybik-0.5/copyright 1970-01-01 00:00:00.000000000 +0000 +++ pybik-1.0.1/copyright 2013-02-02 21:45:29.000000000 +0000 @@ -0,0 +1,70 @@ +Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: pybik +Upstream-Contact: B. Clausius +Source: https://launchpad.net/pybik/+download +Comment: + Originally this package was derived from GNUbik 2.3 + and ported from C to Python. + Authors of GNUbik: + * John Mark Darrington + is the main author and maintainer of GNUbik. + * Dale Mellor + +Files: * +Copyright: 2009-2013 B. Clausius +License: GPL-3+ + +Files: data/ui/images/BEAMED?EIGHTH?NOTES.png + data/ui/images/ATOM?SYMBOL.png + data/ui/images/SNOWFLAKE.png + data/ui/images/WHITE?SUN?WITH?RAYS.png +Copyright: 2002-2010 Free Software Foundation + 2012 B. Clausius +License: GPL-3+ +Comment: Images created from font FreeSerif: + U+266B BEAMED EIGHTH NOTES + U+269B ATOM SYMBOL + U+2744 SNOWFLAKE + Image created from font FreeMono: + U+263C WHITE SUN WITH RAYS + +Files: data/ui/images/SHAMROCK.png + data/ui/images/SKULL?AND?CROSSBONES.png + data/ui/images/PEACE?SYMBOL.png + data/ui/images/YIN?YANG.png + data/ui/images/BLACK?SMILING?FACE.png + data/ui/images/WHITE?SMILING?FACE.png +Copyright: DejaVu Authors + 2012 B. Clausius +License: public-domain + The DejaVu fonts are a font family based on the Vera Fonts. + License of DejaVu (http://dejavu-fonts.org/wiki/Main_Page): + Fonts are © Bitstream (…). DejaVu changes are in public domain. …. + Glyphs imported from Arev fonts are © Tavmjung Bah (…). + . + The used symbols where added in version 2.4 as stated by DejaVu in the file + status.txt and therefore are in the public domain. +Comment: Images were created from font DejaVu-Sans-Oblique: + U+2618 SHAMROCK + U+2620 SKULL AND CROSSBONES + U+262E PEACE SYMBOL + U+262F YIN YANG + U+263A WHITE SMILING FACE + U+263B BLACK SMILING FACE + +License: GPL-3+ + 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 . + . + The full text of the GPL is distributed in + the original source archive in the file COPYING. diff -Nru pybik-0.5/data/GPL-3 pybik-1.0.1/data/GPL-3 --- pybik-0.5/data/GPL-3 1970-01-01 00:00:00.000000000 +0000 +++ pybik-1.0.1/data/GPL-3 2011-06-28 05:38:09.000000000 +0000 @@ -0,0 +1,674 @@ + 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 +. diff -Nru pybik-0.5/data/applications/pybik.desktop pybik-1.0.1/data/applications/pybik.desktop --- pybik-0.5/data/applications/pybik.desktop 2011-07-07 02:12:39.000000000 +0000 +++ pybik-1.0.1/data/applications/pybik.desktop 2013-01-31 20:35:26.000000000 +0000 @@ -1,12 +1,31 @@ [Desktop Entry] Name=Pybik Name[de]=Pybik -Comment=The magic cube -Comment[de]=Der Zauberwürfel +Name[en_GB]=Pybik +Name[es]=Pybik +Name[fr]=Pybik +Name[gl]=Pybik +Name[he]=Pybik +Name[ky]=Pybik +Name[ms]=Pybik +Name[pt_BR]=Pybik +Name[uk]=Pybik +Comment=3D Rubik's cube game +Comment[de]=Ein 3D-Zauberwürfelspiel +Comment[en_GB]=3D Rubik's cube game +Comment[es]=Juego del cubo de Rubik en 3D +Comment[fr]=Jeu de Rubik's cube en 3D +Comment[gl]=Xogo do cubo de Rubik en 3D +Comment[he]=משחק קוביה הונגרית תלת־ממדי +Comment[ms]=Permainan kiub Rubrik 3D +Comment[pt_BR]=Jogo 3D do cubo de Rubik +Comment[uk]=Тривимірний кубик Рубіка TryExec=pybik Exec=pybik Icon=pybik Type=Application -Categories=GNOME;GTK;Game; +Categories=Game;LogicGame; +# Add whatever keywords you want in your language, separated by semicolons. These keywords are used when searching for applications in dashes, etc. (Unity, GNOME Shell) +Keywords=rubik;cube;puzzle;magic; StartupNotify=true X-Ubuntu-Gettext-Domain=pybik diff -Nru pybik-0.5/data/applications/pybik.desktop.in pybik-1.0.1/data/applications/pybik.desktop.in --- pybik-0.5/data/applications/pybik.desktop.in 2011-06-28 05:38:09.000000000 +0000 +++ pybik-1.0.1/data/applications/pybik.desktop.in 2013-01-31 13:24:49.000000000 +0000 @@ -1,10 +1,12 @@ [Desktop Entry] _Name=Pybik -_Comment=The magic cube +_Comment=3D Rubik's cube game TryExec=pybik Exec=pybik Icon=pybik Type=Application -Categories=GNOME;GTK;Game; +Categories=Game;LogicGame; +# Add whatever keywords you want in your language, separated by semicolons. These keywords are used when searching for applications in dashes, etc. (Unity, GNOME Shell) +_Keywords=rubik;cube;puzzle;magic; StartupNotify=true X-Ubuntu-Gettext-Domain=pybik Binary files /tmp/NykpzDcWhX/pybik-0.5/data/pixmaps/screenshot.png and /tmp/gD0eBO7MB2/pybik-1.0.1/data/pixmaps/screenshot.png differ diff -Nru pybik-0.5/data/plugins/01-challenges.algorithm pybik-1.0.1/data/plugins/01-challenges.algorithm --- pybik-0.5/data/plugins/01-challenges.algorithm 1970-01-01 00:00:00.000000000 +0000 +++ pybik-1.0.1/data/plugins/01-challenges.algorithm 2012-11-08 16:36:30.000000000 +0000 @@ -0,0 +1,51 @@ +# Copyright © 2012, B. Clausius +# +# 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 . + +File-Version: 1.1 +Model: * + +Path: /Challenges/Solve random cube +Module: challenges random + +Path: /Challenges/Solve in 1 move +Module: challenges random1 + +Path: /Challenges/Solve in 2 moves +Module: challenges random2 + +Path: /Challenges/Solve in 3 moves +Module: challenges random3 + +Path: /Challenges/Solve in 4 moves +Module: challenges random4 + +Path: /Challenges/Solve in 5 moves +Module: challenges random5 + +Path: /Challenges/Solve in 6 moves +Module: challenges random6 + +Path: /Challenges/Solve in 7 moves +Module: challenges random7 + +Path: /Challenges/Solve in 8 moves +Module: challenges random8 + +Path: /Challenges/Solve in 9 moves +Module: challenges random9 + +Path: /Challenges/Solve in 10 moves +Module: challenges random10 + diff -Nru pybik-0.5/data/plugins/10-spiegel.algorithm pybik-1.0.1/data/plugins/10-spiegel.algorithm --- pybik-0.5/data/plugins/10-spiegel.algorithm 1970-01-01 00:00:00.000000000 +0000 +++ pybik-1.0.1/data/plugins/10-spiegel.algorithm 2012-12-12 11:14:20.000000000 +0000 @@ -0,0 +1,160 @@ +# Copyright © 2011-2012, B. Clausius +# +# 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 . + +File-Version: 1.1 +Model: Cube 3 +Ref-Blocks: f l u b r d + +################################ +# Solution: pos, block, moves +# 1. position on the cube, e.g. "rf" for the front-right edge or "ufr" for +# the uppper-front-right corner. The order does not matter, "ufr" is equal to "fur". +# Multiple blocks are separated by spaces. +# 2. The block at the position. The order matters and depends on the first field. +# The number of blocks must be the same as in field 1. +# "fr|fl": "fr" or "fl" is allowed at the position +# "!fru": every block except "fru" is allowed at the position +# "*fru": a block in any rotation state of "fru" is allowed at the position (fru, ruf, ufr) +# "!*fru": every block except all "fru" rotations is allowed at the position +# "f?u": "?" can be every face +# 3. The moves that should be applied to the cube. + +# Spiegel is the name of a solution method +Path: /Solvers/Spiegel +Depends: /Solvers/Spiegel/Bottom corner orient + +Path: /Solvers/Spiegel/Top edges +Solution: + df=df dl=dl db=db dr=dr dfl=dfl dlb=dlb dbr=dbr drf=drf fr=fr rb=rb bl=bl lf=lf, @@solved + uf=uf ur=ur ub=ub ul=ul, @@solved + # + rf=uf, f- + df=uf, f-f- + fr=uf, u2fu2- + fu=uf, fu2fu2- + fd=uf, dl2d-l2- + # + lf=uf, f + fl=uf, u2-f-u2 + # + dr=*uf, d- + dl=*uf, d + db=*uf, dd + # + br=uf, u2f-u2- + rb=uf, u2u2fu2u2 + bl=uf, u2-fu2 + lb=uf, u2u2f-u2u2 + # + ur=*uf, r + ub=*uf, b + ul=*uf, l + # + , U + +Path: /Solvers/Spiegel/Top corners +Depends: /Solvers/Spiegel/Top edges +Solution: + df=df dl=dl db=db dr=dr dfl=dfl dlb=dlb dbr=dbr drf=drf fr=fr rb=rb bl=bl lf=lf, @@solved + ufr=ufr urb=urb ubl=ubl ulf=ulf, @@solved + # + fld=ruf, r-dr + fld=ufr, ddfd-f- + #fld=fru, f-dffd-f- + fld=fru, dr-drfd-d-f- + # + rfd=*fru, d- + brd=*fru, dd + lbd=*fru, d + # + fru=!fru fru=*fru, r-d-r + rbu=*fru, b-d-d-b + blu=*fru, bdb- + lfu=*fru, f-df + , U + +Path: /Solvers/Spiegel/Middle slice +Depends: /Solvers/Spiegel/Top corners +Solution: + fr=fr rb=rb bl=bl lf=lf, @@solved + fd=fr, d-r-drdfd-f- + fd=fl, dld-l-d-f-df + # + rd=fr|fl, d- + bd=fr|fl, dd + ld=fr|fl, d + # + fd=*?d rd=*?d bd=*?d ld=*?d fr=!fr, d-r-drdfd-f- + fd=*?d rd=*?d bd=*?d ld=*?d fl=!fl, dld-l-d-f-df + , U + +Path: /Solvers/Spiegel/Bottom edge place +Depends: /Solvers/Spiegel/Middle slice +Solution: + uf=uf ur=ur ub=ub ul=ul ufr=ufr urb=urb ubl=ubl ulf=ulf df=*df dl=*dl db=*db dr=*dr, @@solved + uf=uf ur=ur ub=ub ul=ul ufr=ufr urb=urb ubl=ubl ulf=ulf, FF + # + uf=*uf ur=*ur ub=*ub ul=*ul, @@solved + uf=!*uf ur=!*ur ub=!*ub ul=!*ul, u + ul=*uf ur=*ur, ufrur-u-f- + uf=*ul ub=*ub, ufrur-u-f- + uf=*ub ub=*uf, ufrur-u-f- + , U + +Path: /Solvers/Spiegel/Bottom edge orient +Depends: /Solvers/Spiegel/Bottom edge place +Solution: + uf=uf ur=ur ub=ub ul=ul ufr=ufr urb=urb ubl=ubl ulf=ulf df=df dl=dl db=db dr=dr, @@solved + uf=uf ur=ur ub=ub ul=ul ufr=ufr urb=urb ubl=ubl ulf=ulf, FF + # + uf=uf ur=ur ub=ub ul=ul, @@solved + ur=?u, rd2rd2rd2rd2 + # + ub=?u, u + uf=?u, u- + ul=?u, uu + # + uf=ul, u + uf=ur, u- + uf=ub, uu + +Path: /Solvers/Spiegel/Bottom corner place +Depends: /Solvers/Spiegel/Bottom edge orient +Solution: + uf=uf ur=ur ub=ub ul=ul ufr=ufr urb=urb ubl=ubl ulf=ulf df=df dl=dl db=db dr=dr dfl=*dfl dlb=*dlb dbr=*dbr drf=*drf, @@solved + uf=uf ur=ur ub=ub ul=ul ufr=ufr urb=urb ubl=ubl ulf=ulf, FF + # + ufr=*ufr urb=*urb ubl=*ubl ulf=*ulf, @@solved + ufl=!*ufl ufr=!*ufr ubl=!*ubl ubr=!*ubr, fdffddffd-f-ufdffddffd-f-u- + ubl=*ubl ufl=!*ufl, fdffddffd-f-ufdffddffd-f-u- + , U + +Path: /Solvers/Spiegel/Bottom corner orient +Depends: /Solvers/Spiegel/Bottom corner place +Solution: + uf=uf ur=ur ub=ub ul=ul ufr=ufr urb=urb ubl=ubl ulf=ulf df=df dl=dl db=db dr=dr dfl=dfl dlb=dlb dbr=dbr drf=drf, @@solved + uf=uf ur=ur ub=ub ul=ul ufr=ufr urb=urb ubl=ubl ulf=ulf, FF + # + ufr=ufr urb=urb ubl=ubl ulf=ulf, @@solved + ufr=!ufr ufr=!urb ufr=!ubl ufr=!ulf, rf-r-frf-r-f + # + urb=!ufr urb=!urb urb=!ubl urb=!ulf, u + ulf=!ufr ulf=!urb ulf=!ubl ulf=!ulf, u- + ubl=!ufr ubl=!urb ubl=!ubl ubl=!ulf, uu + # + uf=ul, u + uf=ur, u- + uf=ub, uu + diff -Nru pybik-0.5/data/plugins/11-spiegel-improved.algorithm pybik-1.0.1/data/plugins/11-spiegel-improved.algorithm --- pybik-0.5/data/plugins/11-spiegel-improved.algorithm 1970-01-01 00:00:00.000000000 +0000 +++ pybik-1.0.1/data/plugins/11-spiegel-improved.algorithm 2012-12-12 12:01:29.000000000 +0000 @@ -0,0 +1,232 @@ +# Copyright © 2011-2012, B. Clausius +# +# 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 . + +File-Version: 1.1 +Model: Cube 3 +Ref-Blocks: f l u b r d + +################################ +# Solution: pos, block, moves +# 1. position on the cube, e.g. "rf" for the front-right edge or "ufr" for +# the uppper-front-right corner. The order does not matter, "ufr" is equal to "fur". +# Multiple blocks are separated by spaces. +# 2. The block at the position. The order matters and depends on the first field. +# The number of blocks must be the same as in field 1. +# "fr|fl": "fr" or "fl" is allowed at the position +# "!fru": every block except "fru" is allowed at the position +# "*fru": a block in any rotation state of "fru" is allowed at the position (fru, ruf, ufr) +# "!*fru": every block except all "fru" rotations is allowed at the position +# "f?u": "?" can be every face +# 3. The moves that should be applied to the cube. + +# Spiegel is the name of a solution method +Path: /Solvers/Spiegel improved +Depends: /Solvers/Spiegel improved/Bottom corner orient + +Path: /Solvers/Spiegel improved/Top edges +Solution: + df=df dl=dl db=db dr=dr dfl=dfl dlb=dlb dbr=dbr drf=drf fr=fr rb=rb bl=bl lf=lf, @@solved + uf=uf ur=ur ub=ub ul=ul, @@solved + # Initial orientation of the top slice + ur=uf ub=!ub ul=!ul, u + uf=!uf ub=ur ul=!ul, u + uf=!uf ur=!ur ul=ub, u + uf=ul ur=!ur ub=!ub, u + ur=!ur ub=!ub ul=uf, u- + uf=ur ub=!ub ul=!ul, u- + uf=!uf ur=ub ul=!ul, u- + uf=!uf ur=!ur ub=ul, u- + ur=!ur ub=uf ul=!ul, uu + uf=!uf ub=!ub ul=ur, uu + uf=ub ur=!ur ul=!ul, uu + uf=!uf ur=ul ub=!ub, uu + # uf is on top slice + fu=uf, fu-ru + ur=*uf, r- + ub=*uf, b + ul=*uf, l + # uf is on middle slice + fr=fu, f- + fr=uf, u-ru + fl=fu, f + fl=uf, ul-u- + br=fu, uubuu + br=uf, u-r-u + bl=fu, uub-uu + bl=uf, ulu- + # uf is on bottom slice + fd=fu, ff + fd=uf, f-u-ru + dr=uf, d-ff + dr=fu, rf-r- + dl=uf, dff + dl=fu, l-fl + db=uf, ddff + db=fu, u-d-ruf- + # next edge + ur=!ur, U + ul=!ul, U- + ub=!ub, UU + +Path: /Solvers/Spiegel improved/Top corners +Depends: /Solvers/Spiegel improved/Top edges +Solution: + df=df dl=dl db=db dr=dr dfl=dfl dlb=dlb dbr=dbr drf=drf fr=fr rb=rb bl=bl lf=lf, @@solved + ufr=ufr urb=urb ubl=ubl ulf=ulf, @@solved + # corner is one of front bottom + frd=fur, r-d-r + frd=rfu, fd-f-r-ddr + frd=urf, fdf- + fld=ruf, r-dr + fld=fru, f-rfr-fd-f- + fld=ufr, d + # corner is one of back bottom + brd=fru, d- + brd=ufr, fd-f- + brd=ruf, d- + lbd=fru, fdf-r-d-r + lbd=ufr, fddf- + lbd=ruf, d + # corner rotated + #fru=fru, + fru=ufr, r-dr + fru=ruf, fd-f- + # corner is one of upper front + flu=rfu, ldl- + flu=urf, ld-l- + flu=fur, lr-dl-r + # corner is one of upper back + bru=rfu, b-d-b + bru=urf, fb-d-f-b + bru=fur, rdrrddr + blu=fru, l-r-ddrl + blu=ufr, l-dlr-ddr + blu=ruf, l-fddf-l + # Next corner + bru=!bru, U + flu=!flu, U- + blu=!blu, UU + +Path: /Solvers/Spiegel improved/Middle slice +Depends: /Solvers/Spiegel improved/Top corners +Solution: + fr=fr rb=rb bl=bl lf=lf, @@solved + # Move edges from the bottom slice + fd=fr, d- + rd=fr, dd + bd=fr, d + ld=fr, r-drdfd-f- + fd=fl, d + rd=fl, ld-l-d-f-df + bd=fl, d- + ld=fl, dd + # Next edge + fd=rf|rb, U + rd=rf|rb, U + bd=rf|rb, U + ld=rf|rb, U + fd=lb|lf, U- + rd=lb|lf, U- + bd=lb|lf, U- + ld=lb|lf, U- + fd=br|bl, UU + rd=br|bl, UU + bd=br|bl, UU + ld=br|bl, UU + # If all above fails, move a wrong edge to the bottom slice + fd=*?d rd=*?d bd=*?d ld=*?d fr=!fr, r-drdfd-f- + fd=*?d rd=*?d bd=*?d ld=*?d fl=!fl, ld-l-d-f-df + br=!br, U + bl=!bl, U- + +Path: /Solvers/Spiegel improved/Bottom edge place +Depends: /Solvers/Spiegel improved/Middle slice +Solution: + uf=uf ur=ur ub=ub ul=ul ufr=ufr urb=urb ubl=ubl ulf=ulf df=*df dl=*dl db=*db dr=*dr, @@solved + uf=uf ur=ur ub=ub ul=ul ufr=ufr urb=urb ubl=ubl ulf=ulf, FF + # + uf=*uf ur=*ur ub=*ub ul=*ul, @@solved + # Move the bottom slice is enough + #uf=*uf ur=*ur ub=*ub ul=*ul, + uf=*ul ur=*uf ub=*ur ul=*ub, u + uf=*ub ur=*ul ub=*uf ul=*ur, uu + uf=*ur ur=*ub ub=*ul ul=*uf, u- + # Swap two edges is enough + uf=*ul ur=*ur ub=*ub ul=*uf, ufrur-u-f- + uf=*uf ur=*ul ub=*ur ul=*ub, uufrur-u-f- + uf=*ub ur=*uf ub=*ul ul=*ur, u-frur-u-f- + uf=*ur ur=*ub ub=*uf ul=*ul, frur-u-f- + # More than two edges needs to be swapped + uf=*ul ur=*ub ub=*ur ul=*uf, u-frur-u-f- + uf=*uf ur=*ul ub=*ub ul=*ur, frur-u-f- + uf=*ur ur=*uf ub=*ul ul=*ub, ufrur-u-f- + uf=*ub ur=*ur ub=*uf ul=*ul, uufrur-u-f- + # + , U + +#TODO: Modify the previous paragraph so that this is not necessary +Path: /Solvers/Spiegel improved/Bottom edge orient +Depends: /Solvers/Spiegel improved/Bottom edge place +Solution: + uf=uf ur=ur ub=ub ul=ul ufr=ufr urb=urb ubl=ubl ulf=ulf df=df dl=dl db=db dr=dr, @@solved + uf=uf ur=ur ub=ub ul=ul ufr=ufr urb=urb ubl=ubl ulf=ulf, FF + # + uf=uf ur=ur ub=ub ul=ul, @@solved + # Turn edge + ur=?u, rd2rd2rd2rd2 + # Proceed to the next edge + ub=?u, u + uf=?u, u- + ul=?u, uu + # Done, only turn back the bottom slice + uf=ul, u + uf=ur, u- + uf=ub, uu + +Path: /Solvers/Spiegel improved/Bottom corner place +Depends: /Solvers/Spiegel improved/Bottom edge orient +Solution: + uf=uf ur=ur ub=ub ul=ul ufr=ufr urb=urb ubl=ubl ulf=ulf df=df dl=dl db=db dr=dr dfl=*dfl dlb=*dlb dbr=*dbr drf=*drf, @@solved + uf=uf ur=ur ub=ub ul=ul ufr=ufr urb=urb ubl=ubl ulf=ulf, FF + # + ufr=*ufr urb=*urb ubl=*ubl ulf=*ulf, @@solved + ufl=*urf urf=*ulb ulb=*ufl ubr=*ubr, fdffddffd-f-u-fdffddffd-f-u + ufl=*ubr urf=*ufl ulb=*ulb ubr=*urf, fdffddffd-f-ufdffddffd-f-u- + ufl=*urf urf=*ufl ulb=*ubr ubr=*ulb, fdffddffd-f-uufdffddffd-f-uu + ufl=*ubr urf=*ulb ulb=*urf ubr=*ufl, fdffddffd-f-ufdffddffd-f-u- + # + , U + +Path: /Solvers/Spiegel improved/Bottom corner orient +Depends: /Solvers/Spiegel improved/Bottom corner place +Solution: + uf=uf ur=ur ub=ub ul=ul ufr=ufr urb=urb ubl=ubl ulf=ulf df=df dl=dl db=db dr=dr dfl=dfl dlb=dlb dbr=dbr drf=drf, @@solved + uf=uf ur=ur ub=ub ul=ul ufr=ufr urb=urb ubl=ubl ulf=ulf, FF + # + ufr=ufr urb=urb ubl=ubl ulf=ulf, @@solved + # Turn corner + ufr=?u?, rf-r-frf-r-f + ufr=??u, f-rfr-f-rfr- + # Proceed to the next corner + urb=!u?? fr=!fr, u + ulf=!u?? fr=!fr, u- + ubl=!u?? fr=!fr, uu + # Done, only turn back the bottom slice + uf=ul ufr=u?? urb=u?? ulf=u?? ubl=u??, u + uf=ur ufr=u?? urb=u?? ulf=u?? ubl=u??, u- + uf=ub ufr=u?? urb=u?? ulf=u?? ubl=u??, uu + # + , U + diff -Nru pybik-0.5/data/plugins/12-lbl-leyan.algorithm pybik-1.0.1/data/plugins/12-lbl-leyan.algorithm --- pybik-0.5/data/plugins/12-lbl-leyan.algorithm 1970-01-01 00:00:00.000000000 +0000 +++ pybik-1.0.1/data/plugins/12-lbl-leyan.algorithm 2012-12-13 16:45:58.000000000 +0000 @@ -0,0 +1,194 @@ +# Copyright © 2012, B. Clausius +# +# 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 . + +File-Version: 1.1 +Model: Cube 3 +Ref-Blocks: f l u b r d + +Depends: /Solvers/Layer Method (Leyan Lo)/Bottom edge place +# Leyan Lo is the inventor of the solution method +Path: /Solvers/Layer Method (Leyan Lo) + +Path: /Solvers/Layer Method (Leyan Lo)/Top edges +Solution: + df=df dl=dl db=db dr=dr dfl=dfl dlb=dlb dbr=dbr drf=drf fr=fr rb=rb bl=bl lf=lf, @@solved + uf=uf ur=ur ub=ub ul=ul, @@solved + # + rf=uf, f- + df=uf, f-f- + fr=uf, u2fu2- + fu=uf, fu2fu2- + fd=uf, dl2d-l2- + # + lf=uf, f + fl=uf, u2-f-u2 + # + dr=*uf, d- + dl=*uf, d + db=*uf, dd + # + br=uf, u2f-u2- + rb=uf, u2u2fu2u2 + bl=uf, u2-fu2 + lb=uf, u2u2f-u2u2 + # + ur=*uf, r + ub=*uf, b + ul=*uf, l + # + , U + +Depends: /Solvers/Layer Method (Leyan Lo)/Top edges +Path: /Solvers/Layer Method (Leyan Lo)/Top corners +Solution: + df=df dl=dl db=db dr=dr dfl=dfl dlb=dlb dbr=dbr drf=drf fr=fr rb=rb bl=bl lf=lf, @@solved + ufr=ufr urb=urb ubl=ubl ulf=ulf, @@solved + # + fld=ruf, r-dr + fld=ufr, ddfd-f- + #fld=fru, f-dffd-f- + fld=fru, dr-drfd-d-f- + # + rfd=*fru, d- + brd=*fru, dd + lbd=*fru, d + # + fru=!fru fru=*fru, r-d-r + rbu=*fru, b-d-d-b + blu=*fru, bdb- + lfu=*fru, f-df + , U + +Depends: /Solvers/Layer Method (Leyan Lo)/Top corners +Path: /Solvers/Layer Method (Leyan Lo)/Middle slice +Solution: + fr=fr rb=rb bl=bl lf=lf, @@solved + # solve front-right edge + fd=fr, d-r-drdfd-f- + rd=rf, dfd-f-d-r-dr + # prepare front-right edge for solving + fd=rf, d + rd=fr, d- + bd=rf|fr, d- + ld=rf|fr, d + # + fd=*?d rd=*?d bd=*?d ld=*?d fr=!fr, d-r-drdfd-f- + , U + +Depends: /Solvers/Layer Method (Leyan Lo)/Middle slice +Path: /Solvers/Layer Method (Leyan Lo)/Bottom edge orient +Solution: + uf=uf ur=ur ub=ub ul=ul ufr=ufr urb=urb ubl=ubl ulf=ulf df=d? dl=d? db=d? dr=d?, @@solved + uf=uf ur=ur ub=ub ul=ul ufr=ufr urb=urb ubl=ubl ulf=ulf, FF + # + uf=u? ur=u? ub=u? ul=u?, @@solved + ub=u? ul=u? uf=?u ur=?u, furu-r-f- + ur=u? ul=u? uf=?u ub=?u, frur-u-f- + uf=?u ur=?u ub=?u ul=?u, furu-r-f- + # + ul=u? uf=u? ur=?u ub=?u, U + uf=u? ur=u? ub=?u ul=?u, UU + ur=u? ub=u? ul=?u uf=?u, U- + # + uf=u? ub=u? ur=?u ul=?u, U + +Depends: /Solvers/Layer Method (Leyan Lo)/Bottom edge orient +Path: /Solvers/Layer Method (Leyan Lo)/Bottom corner place +Solution: + uf=uf ur=ur ub=ub ul=ul ufr=ufr urb=urb ubl=ubl ulf=ulf dfr=*dfr drb=*drb dbl=*dbl dlf=*dlf, @@solved + uf=uf ur=ur ub=ub ul=ul ufr=ufr urb=urb ubl=ubl ulf=ulf, FF + # solved (1/24) + ufr=*ufr urb=*urb ubl=*ubl ulf=*ulf, @@solved + # two adjacent corners need to be swapped (6/24) + ulf=*ufr ufr=*ulf, U- + ufr=*urb urb=*ufr, lu-r-ul-u-ruu + urb=*ubl ubl=*urb, U + ubl=*ulf ulf=*ubl, UU + # two diagonal corners need to be swapped (3/24) + ufr=*ubl ubl=*ufr, u + urb=*ulf ulf=*urb, u- + # rotate 3 corners ccw (4/16), four corners need to be moved ccw (1/16), rotate crosswise (2/16) + ufr=*urb, u- + ubl=*ulf, u- + # rotate 3 corners cw (4/16), four corners need to be moved cw (1/16), rotate crosswise (2/16) + ufr=*ulf, u + ubl=*urb, u + +Depends: /Solvers/Layer Method (Leyan Lo)/Bottom corner place +Path: /Solvers/Layer Method (Leyan Lo)/Bottom corner orient +Solution: + uf=uf ur=ur ub=ub ul=ul ufr=ufr urb=urb ubl=ubl ulf=ulf dfr=dfr drb=drb dbl=dbl dlf=dlf, @@solved + uf=uf ur=ur ub=ub ul=ul ufr=ufr urb=urb ubl=ubl ulf=ulf, FF + # + ufr=ufr urb=urb ubl=ubl ulf=ulf, @@solved + # + lub=lub rub=bru luf=flu ruf=ufr, r-u-ru-r-uuruu + ful=ful bul=lbu fur=rfu bur=urb, U + bur=bur fur=rfu bul=lbu ful=ulf, U- + ruf=ruf luf=flu rub=bru lub=ubl, UU + # + ful=ful lub=blu rub=ubr ruf=fru, rur-uruur-uu + ruf=ruf ful=lfu bul=ulb bur=rbu, U + lub=lub bur=rbu fur=urf ful=lfu, U- + bur=bur ruf=fru luf=ufl lub=blu, UU + # + bul=ulb bur=urb ful=ful fur=fur, r-u-ru-r-uuruu + luf=ufl lub=ubl ruf=ruf rub=rub, U + rub=ubr ruf=ufr lub=lub luf=luf, U- + fur=urf ful=ulf bur=bur bul=bul, UU + # + ful=ulf bul=ulb fur=fur bur=bur, rur-uruur-uu + ruf=ufr luf=ufl rub=rub lub=lub, U + lub=ubl rub=ubr luf=luf ruf=ruf, U- + bur=urb fur=urf bul=bul ful=ful, UU + # + rub=ubr luf=flu ruf=ruf lub=lub, rur-uruur-uu + bul=ulb fur=rfu bur=bur ful=ful, U + fur=urf bul=lbu ful=ful bur=bur, U- + luf=ufl rub=bru lub=lub ruf=ruf, UU + # + lub=ubl rub=bru luf=ufl ruf=fru, r-u-ru-r-uuruu + ful=ulf bul=lbu fur=urf bur=rbu, U + bur=urb fur=rfu bul=ulb ful=lfu, U- + ruf=ufr luf=flu rub=ubr lub=blu, UU + # + lub=ubl rub=ubr luf=ufl ruf=ufr, r-u-ru-r-uuruu + lub=blu rub=bru luf=flu ruf=fru, U + +Depends: /Solvers/Layer Method (Leyan Lo)/Bottom corner orient +Path: /Solvers/Layer Method (Leyan Lo)/Bottom edge place +Solution: + uf=uf ur=ur ub=ub ul=ul ufr=ufr urb=urb ubl=ubl ulf=ulf df=df dr=dr db=db dl=dl, @@solved + uf=uf ur=ur ub=ub ul=ul ufr=ufr urb=urb ubl=ubl ulf=ulf, FF + # solved (1/12) + uf=uf ur=ur ub=ub ul=ul, @@solved + # rotate 3 edges clockwise (4/12) + uf=ub ub=ur ru=fu ul=ul, rrufb-rrf-burr + ur=ul ul=ub bu=ru uf=uf, U + ul=ur ur=uf fu=lu ub=ub, U- + ub=uf uf=ul lu=bu ur=ur, UU + # rotate 3 edges counterclockwise (4/12) + ru=bu uf=ur ub=uf ul=ul, rru-fb-rrf-bu-rr + bu=lu ur=ub ul=ur uf=uf, U + fu=ru ul=uf ur=ul ub=ub, U- + lu=fu ub=ul uf=ub ur=ur, UU + # swap pairwise opposite edges, (1/12) + uf=ub ru=lu lu=ru ub=uf, rrufb-rrf-burr + # swap pairwise adjacent edges, (2/12) + ru=bu uf=ul ub=ur lu=fu, rrufb-rrf-burr + bu=lu ur=uf ul=ub fu=ru, rrufb-rrf-burr + + + diff -Nru pybik-0.5/data/plugins/20-2x2x2.algorithm pybik-1.0.1/data/plugins/20-2x2x2.algorithm --- pybik-0.5/data/plugins/20-2x2x2.algorithm 1970-01-01 00:00:00.000000000 +0000 +++ pybik-1.0.1/data/plugins/20-2x2x2.algorithm 2012-11-08 16:36:36.000000000 +0000 @@ -0,0 +1,77 @@ +# Copyright © 2011-2012, B. Clausius +# +# 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 . + +File-Version: 1.1 +Model: Cube 2 + +Path: /Solvers/2×2×2 +Depends: /Solvers/2×2×2/Bottom corner orient + +Path: /Solvers/2×2×2/Top slice +Ref-Blocks: flu +Solution: + ufr=ufr urb=urb ubl=ubl ulf=ulf, @@solved + fld=?uf, r-dr + fld=uf?, ddfd-f- + #fld=f?u, f-dffd-f- + fld=f?u, dr-drfd-d-f- + # + rfd=*f?u, d- + brd=*f?u, dd + lbd=*f?u, d + # + fru=!f?u fru=*f?u, r-d-r + rbu=*f?u, b-d-d-b + blu=*f?u, bdb- + lfu=*f?u, f-df + , U + +Path: /Solvers/2×2×2/Bottom corner place +Depends: /Solvers/2×2×2/Top slice +Ref-Blocks: flu bru +Solution: + dfl=*dfl dlb=*dlb dbr=*dbr drf=*drf, @@solved + dfl=*drf drf=*dfl, r-d-rfdf-r-drdd + dfl=*dbr drf=*dlb, dd + dfl=*drf drf=*dbr, d + dfl=*dlb drf=*dfl, d- + dfl=*dfl dbr=*dbr, d + , U + +Path: @Solvers/2×2×2/Bottom corner orient +Depends: /Solvers/2×2×2/Bottom corner place +Ref-Blocks: flu bru +Solution: + flu=flu rfu=rfu bru=bru lbu=lbu dfl=ldf, lf-l-flf-l-f + flu=flu rfu=rfu bru=bru lbu=lbu dfl=fld, f-lfl-f-lfl- + , @@solved + +Path: /Solvers/2×2×2/Bottom corner orient +Depends: @Solvers/2×2×2/Bottom corner orient +Ref-Blocks: dfl +Solution: + ufl=ufl dfl=dfl dlb=dlb dbr=dbr drf=drf, @@solved + # rotate corner + dfl=dfl dfr=frd, d-lf-l-flf-l-f + dfl=dfl dfr=rdf, d-f-lfl-f-lfl- + dfl=dfl dbl=bld, dlf-l-flf-l-f + dfl=dfl dbl=ldb, df-lfl-f-lfl- + dfl=dfl dbr=brd, ddf-lfl-f-lfl- + dfl=dfl dbr=rdb, ddlf-l-flf-l-f + # move solved bottom slice + ufl=urf, d- + ufl=ubr, dd + ufl=ulb, d + diff -Nru pybik-0.5/data/plugins/80-pretty-patterns.algorithm pybik-1.0.1/data/plugins/80-pretty-patterns.algorithm --- pybik-0.5/data/plugins/80-pretty-patterns.algorithm 1970-01-01 00:00:00.000000000 +0000 +++ pybik-1.0.1/data/plugins/80-pretty-patterns.algorithm 2012-12-12 13:47:07.000000000 +0000 @@ -0,0 +1,143 @@ +# Copyright © 2012, B. Clausius +# +# 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 . + +File-Version: 1.1 + +Path: /Pretty patterns/Stripes +Model: Brick k m n with k % 2 == n % 2 == 1 and m % 2 == 0 +Module: pretty_patterns play_stripes_Brick_nnn_2 + +Path: /Pretty patterns/Stripes +Model: Brick m n 1 with m % 4 == 1 and n % 2 == 1 +Module: pretty_patterns play_stripes_Brick_nn1_4 + +Path: /Pretty patterns/Stripes +Model: Brick 1 n m with m % 4 == 1 and n % 2 == 1 +Module: pretty_patterns play_stripes_Brick_1nn_4 + +Path: /Pretty patterns/Stripes +Model: Cube n with n % 2 == 0 +Module: pretty_patterns play_stripes_Cube_nnn_2 + +Path: /Pretty patterns/Stripes +Model: Tower k n with k % 2 == 0 + Brick k m n with k % 2 == 0 and n % 2 == 0 +Module: pretty_patterns play_stripes_TowerBrick_nnn_2 + +Path: /Pretty patterns/Stripes +Model: Cube 3 +Moves: rrffllrrffll + +Path: /Pretty patterns/Stripes +Model: Tower 3 n + Brick 3 m 3 +Moves: rflrfl + +Path: /Pretty patterns/Criss-Cross +Model: Cube +Moves: rruullrruurr + +Path: /Pretty patterns/Criss-Cross +Model: Tower +Moves: ruulruur + +Path: /Pretty patterns/Fried Eggs +Model: Cube n with n>=3 +Moves: l2-f2-l2f2 + +Path: /Pretty patterns/Big Fried Eggs +Model: Cube +Moves: rl-fb-ud-rl- + +Path: /Pretty patterns/4 Fried Eggs +Model: Cube n with n>=3 +Moves: l2l2u2l2l2u2- + +Path: /Pretty patterns/Chessboard +Model: Cube n with n % 2 == 1 + Tower w h with w % 2 == 1 + Brick w h d with w % 2 + h % 2 + d % 2 >= 2 +Module: pretty_patterns play_chessboard + +Path: /Pretty patterns/Cross +Model: Cube +Moves: u-ffuul-rffuufflr-u- + +Path: /Pretty patterns/Zig Zag +Model: Cube +Moves: rlfbrlfbrlfb + +# T is the shape formed by the cube labels +Path: /Pretty patterns/T-Time +Model: Cube n with n%2 == 1 +Module: pretty_patterns play_t_time_Cube_odd + +Path: /Pretty patterns/T-Time +Model: Cube 4 +Moves: l2l2l3l3du-f2f2f3f3ud-l2l2l3l3duul2l2l3l3uul2l2l3l3d-l2l2l3l3uu + +Path: /Pretty patterns/T-Time +Model: Cube n with n%2 == 0 +Module: pretty_patterns play_t_time_Cube_even + +Path: /Pretty patterns/T-Time +Model: Tower m×n with m%2 == 1 +Module: pretty_patterns play_t_time_Tower_odd + +Path: /Pretty patterns/T-Time +Model: Tower m×n with n == 4 +Moves: l4l5du-f4f5ud-l4l5duul4l5uul4l5d-l4l5uu + +Path: /Pretty patterns/T-Time +Model: Tower m×n with m%2 == 0 +Module: pretty_patterns play_t_time_Tower_even + +# C is the shape formed by the cube labels +Path: /Pretty patterns/C +Model: Cube +Moves: uullr-b-rru-r-drfflr-fdlluu + +Path: /Pretty patterns/Cube in a Cube +Model: Cube +Moves: uur-ufu-r-uflfl-u-rfu-ru- + +Path: /Pretty patterns/Striped Cube in a Cube +Model: Cube +Moves: d-fd-lbddffurb-urrfd-rfuu + +Path: /Pretty patterns/Six Square Cuboids +Model: Cube +Moves: ffdffddllullu-llbddrr + +Path: /Pretty patterns/Superflip +Model: Cube +Moves: urrfbrbbruulbbru-d-rrfr-lbbuuff + +Path: /Pretty patterns/Superflip easy +Model: Cube +Moves: l2ul2ul2ul2uLDl2ul2ul2ul2uLDl2ul2ul2ul2uLD + +Path: /Pretty patterns/Green Mamba +Model: Cube +Moves: rdrfr-f-bdr-u-b-udd + +Path: /Pretty patterns/Anaconda +Model: Cube +Moves: lbbdrb-fd-l-rd-uf-rru- + +Path: /Pretty patterns/Duck Feet +Model: Cube +Moves: rrdu-ld-llrbrrubur-f-d-fu- + diff -Nru pybik-0.5/data/plugins/90-library.algorithm pybik-1.0.1/data/plugins/90-library.algorithm --- pybik-0.5/data/plugins/90-library.algorithm 1970-01-01 00:00:00.000000000 +0000 +++ pybik-1.0.1/data/plugins/90-library.algorithm 2012-12-12 13:59:40.000000000 +0000 @@ -0,0 +1,52 @@ +# Copyright © 2012, B. Clausius +# +# 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 . + +File-Version: 1.1 +Model: Cube 3 +Ref-Blocks: f l u b r d + +Path: /Library/Middle Layer/Front to Right +Moves: d-r-drdfd-f- + +Path: /Library/Middle Layer/Front to Left +Moves: dld-l-d-f-df + +Path: /Library/Last Layer/Swap Edges +Moves: dfldl-d-f- + +Path: /Library/Last Layer/Flip Edges +Moves: lu2lu2lu2lu2 + +Path: /Library/Last Layer/Swap Corners +Moves: fuffuuffu-f- + +Path: /Library/Last Layer/Rotate Corners +Moves: lf-l-flf-l-f + +Path: /Library/Rotate Center/2×Up +Moves: urluur-l-urluur-l- + +Path: /Library/Rotate Center/Up and Front +Moves: ufu-d-ffl-rfbuf-b-lr-ffd + +Path: /Library/Rotate Center/Up and Down +Moves: urlf2f2r-l-u-rlf2f2r-l- + +Path: /Library/Misc/Back without Back +Moves: rrllffrruurrllddllf-rrllffrruurrllddllff + +Path: /Library/Misc/2×Back without Back +Moves: rrdduullffrrdduull + diff -Nru pybik-0.5/data/plugins/challenges.py pybik-1.0.1/data/plugins/challenges.py --- pybik-0.5/data/plugins/challenges.py 1970-01-01 00:00:00.000000000 +0000 +++ pybik-1.0.1/data/plugins/challenges.py 2012-10-15 19:31:30.000000000 +0000 @@ -0,0 +1,31 @@ +#-*- coding:utf-8 -*- + +# Copyright © 2009-2012 B. Clausius +# +# 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 . + +from __future__ import print_function, division, unicode_literals + +random = lambda game: game.random() +random1 = lambda game: game.random(1) +random2 = lambda game: game.random(2) +random3 = lambda game: game.random(3) +random4 = lambda game: game.random(4) +random5 = lambda game: game.random(5) +random6 = lambda game: game.random(6) +random7 = lambda game: game.random(7) +random8 = lambda game: game.random(8) +random9 = lambda game: game.random(9) +random10 = lambda game: game.random(10) + diff -Nru pybik-0.5/data/plugins/pretty_patterns.py pybik-1.0.1/data/plugins/pretty_patterns.py --- pybik-0.5/data/plugins/pretty_patterns.py 1970-01-01 00:00:00.000000000 +0000 +++ pybik-1.0.1/data/plugins/pretty_patterns.py 2012-12-05 12:34:13.000000000 +0000 @@ -0,0 +1,105 @@ +#-*- coding:utf-8 -*- + +# Copyright © 2009-2012 B. Clausius +# +# 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 . + +# pylint: disable=C0321 +from __future__ import print_function, division, unicode_literals + + +def play_stripes_Brick_nnn_2(game): + size = game.current_state.model.sizes + for unused_j in 0, 1: + for i in xrange(size[1]-1, size[1]//2-1, -1): game.add_moves([(1, i, 0)]) + for i in xrange(1, size[0], 2): game.add_moves([(0, i, 0)]) + for i in xrange(1, size[2], 2): game.add_moves([(2, i, 0)]) + +def play_stripes_Brick_nn1_4(game): + size = game.current_state.model.sizes + for i in xrange(1, size[0], 2): game.add_moves([(0, i, 0)]) + for i in xrange(size[1]-1, size[1]//2, -1): game.add_moves([(1, i, 0)]) + for i in xrange(1, size[0] // 2, 2): game.add_moves([(0, i, 0)]) + game.add_moves([(1, size[1]//2, 0)]) + for i in xrange(size[0]//2+1, size[0], 2): game.add_moves([(0, i, 0)]) + for i in xrange(size[1]-1, size[1]//2-1, -1): game.add_moves([(1, i, 0)]) + +def play_stripes_Brick_1nn_4(game): + size = game.current_state.model.sizes + for i in xrange(1, size[2], 2): game.add_moves([(2, i, 0)]) + for i in xrange(size[1]-1, size[1]//2, -1): game.add_moves([(1, i, 0)]) + for i in xrange(1, size[2] // 2, 2): game.add_moves([(2, i, 0)]) + game.add_moves([(1, size[1]//2, 0)]) + for i in xrange(size[2]//2+1, size[2], 2): game.add_moves([(2, i, 0)]) + for i in xrange(size[1]-1, size[1]//2-1, -1): game.add_moves([(1, i, 0)]) + +def play_stripes_Cube_nnn_2(game): + size = game.current_state.model.sizes + for i in xrange(0, size[0], 2): game.add_moves([(0, i, 0)] * 2) + for i in xrange(0, size[2], 2): game.add_moves([(2, i, 0)] * 2) + for i in xrange(0, size[0], 2): game.add_moves([(0, i, 0)] * 2) + +def play_stripes_TowerBrick_nnn_2(game): + size = game.current_state.model.sizes + for i in xrange(0, size[0], 2): game.add_moves([(0, i, 0)]) + for i in xrange(0, size[2], 2): game.add_moves([(2, i, 0)]) + for i in xrange(0, size[0], 2): game.add_moves([(0, i, 0)]) + +def play_chessboard(game): + model = game.current_state.model + size = model.sizes + symmetry = [int(180 // s) for s in model.symmetry] + + # Moves are 3-Tuples (axis, slice, dir) axis=0,1,2 slice=0,...,size-1 dir=0,1 + if size[0] % 2 == size[1] % 2 == 1: + moves = [(0, i, 0) for i in xrange(1, size[0], 2)] + moves += [(1, i, 0) for i in xrange(1, size[1], 2)] + moves += [(2, i, 0) for i in xrange(1, size[2], 2)] + elif size[1] % 2 == size[2] % 2 == 1: + moves = [(1, i, 0) for i in xrange(1, size[1], 2)] + moves += [(2, i, 0) for i in xrange(1, size[2], 2)] + moves += [(0, i, 0) for i in xrange(1, size[0], 2)] + elif size[2] % 2 == size[0] % 2 == 1: + moves = [(2, i, 0) for i in xrange(1, size[2], 2)] + moves += [(0, i, 0) for i in xrange(1, size[0], 2)] + moves += [(1, i, 0) for i in xrange(1, size[1], 2)] + for move in moves: + game.add_moves([move] * symmetry[move[0]]) + +def play_t_time_Cube_odd(game): + size = game.current_state.model.sizes + ll = 'l{0}l{0}'.format(size[0] // 2 + 1) + ff = 'f{0}f{0}'.format(size[0] // 2 + 1) + game.add_flubrd("{0}du-{1}ud-{0}duu{0}uu{0}d-{0}uu".format(ll, ff)) + +def play_t_time_Cube_even(game): + size = game.current_state.model.sizes + ll = 'l{0}l{0}l{1}l{1}'.format(size[0] // 2, size[0] // 2 + 1) + ff = 'f{0}f{0}f{1}f{1}'.format(size[0] // 2, size[0] // 2 + 1) + game.add_flubrd("{0}dd2u-u2-{1}uu2d-d2-{0}dd2uuu2u2{0}uuu2u2{0}d-d2-{0}uuu2u2".format(ll, ff)) + +def play_t_time_Tower_odd(game): + size = game.current_state.model.sizes + ll = 'l{0}'.format(size[0] // 2 + 1) + ff = 'f{0}'.format(size[0] // 2 + 1) + game.add_flubrd("{0}du-{1}ud-{0}duu{0}uu{0}d-{0}uu".format(ll, ff)) + +def play_t_time_Tower_even(game): + size = game.current_state.model.sizes + ll = 'l{0}l{1}'.format(size[0] // 2, size[0] // 2 + 1) + ff = 'f{0}f{1}'.format(size[0] // 2, size[0] // 2 + 1) + game.add_flubrd("{0}dd2u-u2-{1}uu2d-d2-{0}dd2uuu2u2{0}uuu2u2{0}d-d2-{0}uuu2u2".format(ll, ff)) + + + diff -Nru pybik-0.5/data/scripts/10-spiegel.script pybik-1.0.1/data/scripts/10-spiegel.script --- pybik-0.5/data/scripts/10-spiegel.script 2012-01-06 16:46:24.000000000 +0000 +++ pybik-1.0.1/data/scripts/10-spiegel.script 1970-01-01 00:00:00.000000000 +0000 @@ -1,129 +0,0 @@ -File-Version: 1.0 -Copyright: 2011-2012, B. Clausius -Model: Cube 3 -Ref-Blocks: f l u b r d - -################################ -# Solution: pos, block, moves -# 1. position on the cube, e.g. "rf" for the front-right edge or "ufr" for -# the uppper-front-right corner. The order does not matter, "ufr" is equal to "fur". -# Multiple blocks are separated by spaces. -# 2. The block at the position. The order matters and depends on the first field. -# The number of blocks must be the same as in field 1. -# "fr|fl": "fr" or "fl" is allowed at the position -# "!fru": every block except "fru" is allowed at the position -# "*fru": a block in any rotation state of "fru" is allowed at the position (fru, ruf, ufr) -# "!*fru": every block except all "fru" rotations is allowed at the position -# "f?u": "?" can be every face -# 3. The moves that should be applied to the cube. - -Path: /Solvers/Spiegel -Depends: /Solvers/Spiegel/Bottom corner orient - -Path: /Solvers/Spiegel/Top edges -Solution: - uf=uf ur=ur ub=ub ul=ul, @@solved - rf=uf, f- - df=uf, f-f- - fr=uf, u2fu2- - fu=uf, fu2fu2- - fd=uf, dl2d-l2- - # - lf=uf, f - fl=uf, u2-f-u2 - # - dr=*uf, d- - dl=*uf, d - db=*uf, dd - # - br=uf, u2f-u2- - rb=uf, u2u2fu2u2 - bl=uf, u2-fu2 - lb=uf, u2u2f-u2u2 - # - ur=*uf, r - ub=*uf, b - ul=*uf, l - # - , U - -Path: /Solvers/Spiegel/Top corners -Depends: /Solvers/Spiegel/Top edges -Solution: - ufr=ufr urb=urb ubl=ubl ulf=ulf, @@solved - fld=ruf, r-dr - fld=ufr, ddfd-f- - #fld=fru, f-dffd-f- - fld=fru, dr-drfd-d-f- - # - rfd=*fru, d- - brd=*fru, dd - lbd=*fru, d - # - fru=!fru fru=*fru, r-d-r - rbu=*fru, b-d-d-b - blu=*fru, bdb- - lfu=*fru, f-df - , U - -Path: /Solvers/Spiegel/Middle slice -Depends: /Solvers/Spiegel/Top corners -Solution: - fr=fr rb=rb bl=bl lf=lf, @@solved - fd=fr, d-r-drdfd-f- - fd=fl, dld-l-d-f-df - # - rd=fr|fl, d- - bd=fr|fl, dd - ld=fr|fl, d - # - fd=*?d rd=*?d bd=*?d ld=*?d fr=!fr, d-r-drdfd-f- - fd=*?d rd=*?d bd=*?d ld=*?d fl=!fl, dld-l-d-f-df - , U - -Path: /Solvers/Spiegel/Bottom edge place -Depends: /Solvers/Spiegel/Middle slice -Solution: - df=*df dl=*dl db=*db dr=*dr, @@solved - df=!*df dl=!*dl db=!*db dr=!*dr, d - dr=*df dl=*dl, dfldl-d-f- - df=*dr db=*db, dfldl-d-f- - df=*db db=*df, dfldl-d-f- - , U - -Path: /Solvers/Spiegel/Bottom edge orient -Depends: /Solvers/Spiegel/Bottom edge place -Solution: - df=df dl=dl db=db dr=dr, @@solved - dl=?d, lu2lu2lu2lu2 - # - db=?d, d - df=?d, d- - dr=?d, dd - # - df=dr, d - df=dl, d- - df=db, dd - -Path: /Solvers/Spiegel/Bottom corner place -Depends: /Solvers/Spiegel/Bottom edge orient -Solution: - dfl=*dfl dlb=*dlb dbr=*dbr drf=*drf, @@solved - dfr=!*dfr dfl=!*dfl dbr=!*dbr dbl=!*dbl, fuffuuffu-f-dfuffuuffu-f-d- - dbr=*dbr dfr=!*dfr, fuffuuffu-f-dfuffuuffu-f-d- - , U - -Path: /Solvers/Spiegel/Bottom corner orient -Depends: /Solvers/Spiegel/Bottom corner place -Solution: - dfl=dfl dlb=dlb dbr=dbr drf=drf, @@solved - dfl=!dfl dfl=!dlb dfl=!dbr dfl=!drf, lf-l-flf-l-f - # - dlb=!dfl dlb=!dlb dlb=!dbr dlb=!drf, d - drf=!dfl drf=!dlb drf=!dbr drf=!drf, d- - dbr=!dfl dbr=!dlb dbr=!dbr dbr=!drf, dd - # - df=dr, d - df=dl, d- - df=db, dd - diff -Nru pybik-0.5/data/scripts/11-spiegel-improved.script pybik-1.0.1/data/scripts/11-spiegel-improved.script --- pybik-0.5/data/scripts/11-spiegel-improved.script 2011-12-22 11:49:48.000000000 +0000 +++ pybik-1.0.1/data/scripts/11-spiegel-improved.script 1970-01-01 00:00:00.000000000 +0000 @@ -1,203 +0,0 @@ -File-Version: 1.0 -Copyright: 2011, B. Clausius -Model: Cube 3 -Ref-Blocks: f l u b r d - -################################ -# Solution: pos, block, moves -# 1. position on the cube, e.g. "rf" for the front-right edge or "ufr" for -# the uppper-front-right corner. The order does not matter, "ufr" is equal to "fur". -# Multiple blocks are separated by spaces. -# 2. The block at the position. The order matters and depends on the first field. -# The number of blocks must be the same as in field 1. -# "fr|fl": "fr" or "fl" is allowed at the position -# "!fru": every block except "fru" is allowed at the position -# "*fru": a block in any rotation state of "fru" is allowed at the position (fru, ruf, ufr) -# "!*fru": every block except all "fru" rotations is allowed at the position -# "f?u": "?" can be every face -# 3. The moves that should be applied to the cube. - -Path: /Solvers/Spiegel improved -Depends: /Solvers/Spiegel improved/Bottom corner orient - -Path: /Solvers/Spiegel improved/Top edges -Solution: - uf=uf ur=ur ub=ub ul=ul, @@solved - # Initial orientation of the top slice - ur=uf ub=!ub ul=!ul, u - uf=!uf ub=ur ul=!ul, u - uf=!uf ur=!ur ul=ub, u - uf=ul ur=!ur ub=!ub, u - ur=!ur ub=!ub ul=uf, u- - uf=ur ub=!ub ul=!ul, u- - uf=!uf ur=ub ul=!ul, u- - uf=!uf ur=!ur ub=ul, u- - ur=!ur ub=uf ul=!ul, uu - uf=!uf ub=!ub ul=ur, uu - uf=ub ur=!ur ul=!ul, uu - uf=!uf ur=ul ub=!ub, uu - # uf is on top slice - fu=uf, fu-ru - ur=*uf, r- - ub=*uf, b - ul=*uf, l - # uf is on middle slice - fr=fu, f- - fr=uf, u-ru - fl=fu, f - fl=uf, ul-u- - br=fu, uubuu - br=uf, u-r-u - bl=fu, uub-uu - bl=uf, ulu- - # uf is on bottom slice - fd=fu, ff - fd=uf, f-u-ru - dr=uf, d-ff - dr=fu, rf-r- - dl=uf, dff - dl=fu, l-fl - db=uf, ddff - db=fu, u-d-ruf- - # next edge - ur=!ur, U - ul=!ul, U- - ub=!ub, UU - -Path: /Solvers/Spiegel improved/Top corners -Depends: /Solvers/Spiegel improved/Top edges -Solution: - ufr=ufr urb=urb ubl=ubl ulf=ulf, @@solved - # corner is one of front bottom - frd=fur, r-d-r - frd=rfu, fd-f-r-ddr - frd=urf, fdf- - fld=ruf, r-dr - fld=fru, f-rfr-fd-f- - fld=ufr, d - # corner is one of back bottom - brd=fru, d- - brd=ufr, fd-f- - brd=ruf, d- - lbd=fru, fdf-r-d-r - lbd=ufr, fddf- - lbd=ruf, d - # corner rotated - #fru=fru, - fru=ufr, r-dr - fru=ruf, fd-f- - # corner is one of upper front - flu=rfu, ldl- - flu=urf, ld-l- - flu=fur, lr-dl-r - # corner is one of upper back - bru=rfu, b-d-b - bru=urf, fb-d-f-b - bru=fur, rdrrddr - blu=fru, l-r-ddrl - blu=ufr, l-dlr-ddr - blu=ruf, l-fddf-l - # Next corner - bru=!bru, U - flu=!flu, U- - blu=!blu, UU - -Path: /Solvers/Spiegel improved/Middle slice -Depends: /Solvers/Spiegel improved/Top corners -Solution: - fr=fr rb=rb bl=bl lf=lf, @@solved - # Move edges from the bottom slice - fd=fr, d- - rd=fr, dd - bd=fr, d - ld=fr, r-drdfd-f- - fd=fl, d - rd=fl, ld-l-d-f-df - bd=fl, d- - ld=fl, dd - # Next edge - fd=rf|rb, U - rd=rf|rb, U - bd=rf|rb, U - ld=rf|rb, U - fd=lb|lf, U- - rd=lb|lf, U- - bd=lb|lf, U- - ld=lb|lf, U- - fd=br|bl, UU - rd=br|bl, UU - bd=br|bl, UU - ld=br|bl, UU - # If all above fails, move a wrong edge to the bottom slice - fd=*?d rd=*?d bd=*?d ld=*?d fr=!fr, r-drdfd-f- - fd=*?d rd=*?d bd=*?d ld=*?d fl=!fl, ld-l-d-f-df - br=!br, U - bl=!bl, U- - -Path: /Solvers/Spiegel improved/Bottom edge place -Depends: /Solvers/Spiegel improved/Middle slice -Solution: - df=*df dl=*dl db=*db dr=*dr, @@solved - # Move the bottom slice is enough - #df=*df dl=*dl db=*db dr=*dr, #flbr - df=*dr dl=*df db=*dl dr=*db, d #rflb - df=*db dl=*dr db=*df dr=*dl, dd #brfl - df=*dl dl=*db db=*dr dr=*df, d- #lbrf - # Swap two edges is enough - df=*dr dl=*dl db=*db dr=*df, dfldl-d-f- #lfbr flrb fblr rlbf - df=*df dl=*dr db=*dl dr=*db, ddfldl-d-f- #rlfb bflr rfbl frlb - df=*db dl=*df db=*dr dr=*dl, d-fldl-d-f- #brlf rbfl lrfb bfrl - df=*dl dl=*db db=*df dr=*dr, fldl-d-f- #fbrl lrbf blrf lbfr - # More than two edges needs to be swapped - df=*dr dl=*db db=*dl dr=*df, d-fldl-d-f- #rblf - df=*df dl=*dr db=*db dr=*dl, fldl-d-f- #frbl - df=*dl dl=*df db=*dr dr=*db, dfldl-d-f- #lfrb - df=*db dl=*dl db=*df dr=*dr, ddfldl-d-f- #blfr - # - , U - -#TODO: Modify the previous paragraph so that this is not necessary -Path: /Solvers/Spiegel improved/Bottom edge orient -Depends: /Solvers/Spiegel improved/Bottom edge place -Solution: - df=df dl=dl db=db dr=dr, @@solved - # Turn edge - dl=?d, lu2lu2lu2lu2 - # Proceed to the next edge - db=?d, d - df=?d, d- - dr=?d, dd - # Done, only turn back the bottom slice - df=dr, d - df=dl, d- - df=db, dd - -Path: /Solvers/Spiegel improved/Bottom corner place -Depends: /Solvers/Spiegel improved/Bottom edge orient -Solution: - dfl=*dfl dlb=*dlb dbr=*dbr drf=*drf, @@solved - dfr=*dlf dlf=*drb drb=*dfr dbl=*dbl, fuffuuffu-f-d-fuffuuffu-f-d - dfr=*dbl dlf=*dfr drb=*drb dbl=*dlf, fuffuuffu-f-dfuffuuffu-f-d- - dfr=*dlf dlf=*dfr drb=*dbl dbl=*drb, fuffuuffu-f-ddfuffuuffu-f-dd - dfr=*dbl dlf=*drb drb=*dlf dbl=*dfr, fuffuuffu-f-dfuffuuffu-f-d- - # - , U - -Path: /Solvers/Spiegel improved/Bottom corner orient -Depends: /Solvers/Spiegel improved/Bottom corner place -Solution: - dfl=dfl dlb=dlb dbr=dbr drf=drf, @@solved - # Turn corner - dfl=?d?, lf-l-flf-l-f - dfl=??d, f-lfl-f-lfl- - # Proceed to the next corner - dlb=!d?? fl=!fl, d - drf=!d?? fl=!fl, d- - dbr=!d?? fl=!fl, dd - # Done, only turn back the bottom slice - df=dr dfl=d?? dlb=d?? drf=d?? dbr=d??, d - df=dl dfl=d?? dlb=d?? drf=d?? dbr=d??, d- - df=db dfl=d?? dlb=d?? drf=d?? dbr=d??, dd - # - , U - diff -Nru pybik-0.5/data/scripts/15-mellor_solve.py pybik-1.0.1/data/scripts/15-mellor_solve.py --- pybik-0.5/data/scripts/15-mellor_solve.py 2011-12-22 17:29:18.000000000 +0000 +++ pybik-1.0.1/data/scripts/15-mellor_solve.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,383 +0,0 @@ -#-*- coding:utf-8 -*- - -# Copyright © 2009, 2011 B. Clausius -# -# 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 . - - -# Ported from GNUbik -# Original filename: mellor-solve.scm -# Original copyright and license: 2004 Dale Mellor, GPL3+ - - -import pybikplugin as plugin - -# Alist with fbdurl strings to identify elements as the key, and -# face and index as the value. -symbolic_mapping = { - 'ulf': (0, 0), 'ufl': (0, 0), 'ul': (0, 1), 'ulb': (0, 2), 'ubl': (0, 2), - 'uf': (0, 3), 'u': (0, 4), 'ub': (0, 5), - 'urf': (0, 6), 'ufr': (0, 6), 'ur': (0, 7), 'urb': (0, 8), 'ubr': (0, 8), - - 'dlf': (1, 0), 'dfl': (1, 0), 'dl': (1, 1), 'dlb': (1, 2), 'dbl': (1, 2), - 'df': (1, 3), 'd': (1, 4), 'db': (1, 5), - 'drf': (1, 6), 'dfr': (1, 6), 'dr': (1, 7), 'drb': (1, 8), 'dbr': (1, 8), - - 'luf': (2, 0), 'lfu': (2, 0), 'lu': (2, 1), 'lub': (2, 2), 'lbu': (2, 2), - 'lf': (2, 3), 'l': (2, 4), 'lb': (2, 5), - 'ldf': (2, 6), 'lfd': (2, 6), 'ld': (2, 7), 'ldb': (2, 8), 'lbd': (2, 8), - - 'ruf': (3, 0), 'rfu': (3, 0), 'ru': (3, 1), 'rub': (3, 2), 'rbu': (3, 2), - 'rf': (3, 3), 'r': (3, 4), 'rb': (3, 5), - 'rdf': (3, 6), 'rfd': (3, 6), 'rd': (3, 7), 'rdb': (3, 8), 'rbd': (3, 8), - - 'ful': (4, 0), 'flu': (4, 0), 'fu': (4, 1), 'fur': (4, 2), 'fru': (4, 2), - 'fl': (4, 3), 'f': (4, 4), 'fr': (4, 5), - 'fdl': (4, 6), 'fld': (4, 6), 'fd': (4, 7), 'fdr': (4, 8), 'frd': (4, 8), - - 'bul': (5, 0), 'blu': (5, 0), 'bu': (5, 1), 'bur': (5, 2), 'bru': (5, 2), - 'bl': (5, 3), 'b': (5, 4), 'br': (5, 5), - 'bdl': (5, 6), 'bld': (5, 6), 'bd': (5, 7), 'bdr': (5, 8), 'brd': (5, 8), - } - - -def get_color_symbolic(cube, symbol): - face, index = symbolic_mapping[symbol] - return cube.faces[face][index] - -def rotated_flubrd_symbol(s, turns): - for j in xrange(turns): - s = ({'l': 'f', 'f': 'r', 'r': 'b', 'b': 'l'}.get(c,c) for c in s) - return ''.join(s) - - -# Wrapper around get_color_symbolic which applies the cube rotation first -def lookup_color(cube, turns, s): - return get_color_symbolic(cube, rotated_flubrd_symbol(s, turns)) - - - -# This takes a string consisting of multiple moves, each one represented by two -# letters, e.g. "f+" -def do_moves(cube, turns, moves): - while moves: - symbol = rotated_flubrd_symbol(moves[0:2], turns) - move = { 'f': (0, 0, 0), 'f+': (0, 0, 0), 'f ': (0, 0, 0), 'f-': (0, 0, 1), - 'b': (0, 2, 1), 'b+': (0, 2, 1), 'b ': (0, 2, 1), 'b-': (0, 2, 0), - 'l': (1, 0, 0), 'l+': (1, 0, 0), 'l ': (1, 0, 0), 'l-': (1, 0, 1), - 'r': (1, 2, 1), 'r+': (1, 2, 1), 'r ': (1, 2, 1), 'r-': (1, 2, 0), - 'u': (2, 0, 0), 'u+': (2, 0, 0), 'u ': (2, 0, 0), 'u-': (2, 0, 1), - 'd': (2, 2, 1), 'd+': (2, 2, 1), 'd ': (2, 2, 1), 'd-': (2, 2, 0), - }[symbol] - - cube._rotate_slice(*move) - plugin.rotate_animated([move]) - moves = moves[2:] - - -# Think about fixing the uf block, but then apply the algorithms with the cube -# symbolically rotated four times. Look for the required block in all possible -# locations, and when it is found lookup the moves that are needed to bring it -# to uf, without upsetting any of the other top edges. -def mellor_top_edge_solve(cube): - moves = [ - ('fu', 'f-u+l-u-'), - - ('ur', 'r-u-r+u+'), - ('ru', 'r-f-'), - ('ub', 'b-u-u-b+u-u-'), - ('bu', 'b-u-r-u+'), - ('ul', 'l+u+l-u-'), - ('lu', 'l+f+'), - - ('rf', 'f-'), - ('fr', 'u-r+u+'), - ('rb', 'r+r+f-r-r-'), - ('br', 'u-r-u+'), - ('lb', 'l+l+f+l-l-'), - ('bl', 'u+l+u-'), - ('lf', 'f+'), - ('fl', 'u+l-u-'), - - ('df', 'f+f+'), - ('fd', 'd+r+f-r-'), - ('dr', 'd-f+f+'), - ('rd', 'r+f-r-'), - ('db', 'd+d+f+f+'), - ('bd', 'd-r+f-r-'), - ('dl', 'd+f+f+'), - ('ld', 'l-f+l+'), - ] - for turns in xrange(4): - u = lookup_color(cube, turns, 'u') - f = lookup_color(cube, turns, 'f') - for symbol, move in moves: - if (u == lookup_color(cube, turns, symbol) and - f == lookup_color(cube, turns, symbol[::-1])): - do_moves(cube, turns, move) - break - - -# Concentrate on getting the block ufr correct, but then apply the procedure to -# all four sides of the cube. Look for the correct block in all locations, and -# then lookup the moves required to get it to ufr. -def mellor_top_corner_solve(cube): - moves = [ ('rfd', 'r-d-r+'), - ('fld', 'd+r-d-r+'), - ('lbd', 'f+d-d-f-'), - ('brd', 'f+d-f-'), - - ('fdr', 'f+d+f-'), - ('rdb', 'd-f+d+f-'), - ('bdl', 'r-d-d-r+'), - ('ldf', 'r-d+r+'), - - ('drf', 'r-d+r+f+d-d-f-'), - ('dfl', 'd+r-d+r+f+d-d-f-'), - ('dlb', 'd-d-r-d+r+f+d-d-f-'), - ('dbr', 'd-r-d+r+f+d-d-f-'), - - ('fru', 'f+d-d-f-r-d-d-r+'), - ('ruf', 'r-d-d-r+f+d-d-f-'), - ('urb', 'b-d-d-b+r-d+r+'), - ('rbu', 'r+d+r-r-d-d-r+'), - ('bur', 'f+b-d-f-b+'), - ('ubl', 'b+d-b-r-d-d-r+'), - ('blu', 'b+r-d-d-r+b-'), - ('lub', 'l-f+d-d-f-l+'), - ('ulf', 'l+d-l-r-d+r+'), - ('lfu', 'l+r-d+r+l-'), - ('ful', 'f-d-f+f+d-d-f-'), - ] - for turns in xrange(4): - top_color = lookup_color(cube, turns, 'u') - front_color = lookup_color(cube, turns, 'f') - right_color = lookup_color(cube, turns, 'r') - for symbol, move in moves: - if ( lookup_color(cube, turns, symbol) == top_color and - lookup_color(cube, turns, (symbol*2)[1:4]) == front_color and - lookup_color(cube, turns, (symbol*2)[2:5]) == right_color): - do_moves(cube, turns, move) - break - - -# Consider the fr block. If the block is to be found in the bottom slice, get -# it into one of two `starting positions' (either fd or rd) and then move it up -# into fr by looping back. If the piece is not found here, it must be in one of -# the other middle edge positions; for now we just check if we are holding a -# middle edge block at fr and if so we drop it to the bottom slice, so that a -# repeat of the algorithm will eventually put it in its correct place, and by -# the time the repeat comes around our own block will hopefully have been -# dropped down. -def mellor_middle_slice_solve(cube): - for i in xrange(3): - for turns in xrange(4): - front_color = lookup_color(cube, turns, 'f') - right_color = lookup_color(cube, turns, 'r') - while True: - if (lookup_color(cube, turns, 'fd') == front_color and - lookup_color(cube, turns, 'df') == right_color): - do_moves(cube, turns, 'd-r-d+r+d+f+d-f-') - break - elif (lookup_color(cube, turns, 'df') == front_color and - lookup_color(cube, turns, 'fd') == right_color): - do_moves(cube, turns, 'd+') - elif (lookup_color(cube, turns, 'rd') == right_color and - lookup_color(cube, turns, 'dr') == front_color): - do_moves(cube, turns, 'd+f+d-f-d-r-d+r+') - break - elif (lookup_color(cube, turns, 'dr') == right_color and - lookup_color(cube, turns, 'rd') == front_color): - do_moves(cube, turns, 'd-') - elif (lookup_color(cube, turns, 'ld') == front_color and - lookup_color(cube, turns, 'dl') == right_color): - do_moves(cube, turns, 'd+') - elif (lookup_color(cube, turns, 'dl') == front_color and - lookup_color(cube, turns, 'ld') == right_color): - do_moves(cube, turns, 'd+d+') - elif (lookup_color(cube, turns, 'bd') == front_color and - lookup_color(cube, turns, 'db') == right_color): - do_moves(cube, turns, 'd+d+') - elif (lookup_color(cube, turns, 'db') == front_color and - lookup_color(cube, turns, 'bd') == right_color): - do_moves(cube, turns, 'd-') - - elif (lookup_color(cube, turns, 'fr') == front_color and - lookup_color(cube, turns, 'rf') == right_color): - break - else: - bottom_color = lookup_color(cube, turns, 'd') - if (lookup_color(cube, turns, 'fr') != bottom_color and - lookup_color(cube, turns, 'rf') != bottom_color): - do_moves(cube, turns, 'd+f+d-f-d-r-d+r+') - else: - # not found retry in the next round - break - - - -# Procedure which answers the question, `Is the fdr block located in the right -# place (regardless of orientation)?' -def placed_fdr_q(cube, turns): - return ( - (1 << lookup_color(cube, turns, 'fdr')) + - (1 << lookup_color(cube, turns, 'dfr')) + - (1 << lookup_color(cube, turns, 'rdf')) - ) == ( - (1 << lookup_color(cube, turns, 'f')) + - (1 << lookup_color(cube, turns, 'd')) + - (1 << lookup_color(cube, turns, 'r')) - ) - - -# We look at all the bottom corners, and set a bit in a bit-mask when one is in -# the right place. There are six patterns to look for: four in which two -# adjacent blocks are out of place, and two in which diagonal blocks are out of -# place. When we find one of these, we apply a symbolic rotation to the cube so -# that the missing pieces are in set positions, and then apply appriopriate set -# moves. Otherwise, either all the pieces are already in place, or else we just -# shift the bottom slice around and loop until we find a pattern. -def mellor_bottom_corner_place(cube): - fix_2 = 'r-d-r+f+d+f-r-d+r+d-d-' - fix_d = 'r-d-r+f+d-d-f-r-d+r+d-' - while True: - a = 0 - for turns in xrange(4): - if placed_fdr_q(cube, turns): - a += 1 << turns - if a == 3: do_moves(cube, 3, fix_2) - elif a == 6: do_moves(cube, 0, fix_2) - elif a == 12: do_moves(cube, 1, fix_2) - elif a == 9: do_moves(cube, 2, fix_2) - elif a == 5: do_moves(cube, 1, fix_d) - elif a == 10: do_moves(cube, 0, fix_d) - elif a == 15: pass - else: - do_moves(cube, 0, 'd+') - continue - break - - -# Very similar methodology to the above; look for patterns of blocks with the -# right orientation, and then apply set-piece moves (depending on whether three -# or two pieces are out of position). In all cases, we loop until we have a -# solution because sometimes it takes more than one effort to get things -# correct (we could go for a more intelligent approach than this...) -def mellor_bottom_corner_orient(cube): - base_color = get_color_symbolic(cube, 'd') - fix_2 = 'f-f-r-d+r+f+d+f-u-f+d-f-r-d-r+u+f-f-' - fix_3 = 'r-d-r+d-r-d-d-r+d-d-' - while True: - a = 0 - for turns in xrange(4): - if lookup_color(cube, turns, 'dfr') == base_color: - a += 1 << turns - if a == 0: do_moves(cube, 0, fix_3) - elif a == 8: do_moves(cube, 0, fix_3) - elif a == 1: do_moves(cube, 1, fix_3) - elif a == 2: do_moves(cube, 2, fix_3) - elif a == 4: do_moves(cube, 3, fix_3) - elif a == 6: do_moves(cube, 0, fix_2) - elif a == 12: do_moves(cube, 1, fix_2) - elif a == 9: do_moves(cube, 2, fix_2) - elif a == 3: do_moves(cube, 3, fix_2) - elif a in (5, 10): do_moves(cube, 3, fix_2) - else: - break - - -# Almost the same again; look at the pattern of correctly placed bottom edges, -# and apply set-piece moves to a logically rotated cube so that the pieces are -# in a certain pattern which we can solve. Again, it might take several efforts -# to get this right, so we loop until a solution is found (again we could do -# better than this if we tried!) -def mellor_bottom_edge_place(cube): - fix = 'r+l-f+r-l+d-d-r+l-f+r-l+' - while True: - a = 0 - for turns in xrange(4): - side_color = lookup_color(cube, turns, 'f') - if (lookup_color(cube, turns, 'fd') == side_color or - lookup_color(cube, turns, 'df') == side_color): - a += 1 << turns - if a == 0: do_moves(cube, 3, fix) - elif a == 1: do_moves(cube, 0, fix) - elif a == 2: do_moves(cube, 1, fix) - elif a == 4: do_moves(cube, 2, fix) - elif a == 8: do_moves(cube, 3, fix) - else: - break - - -# A similar approach again, but looking for patterns and applying moves to get -# the bottom edges in the correct orientation. -def mellor_bottom_edge_orient(cube): - base_color = get_color_symbolic(cube, 'd') - fix_adjacent = 'f-f-r-r-r-u-d+b-b-u-u-d-d-f-u-f+u-u-d-d-b+b+u+d-r+u+r-r-f-f-' - fix_opposite = 'r-r-l-l-r-u-d+b-b-u-u-d-d-f-u-u-f+u-u-d-d-b-b-u+d-r+u-u-r-r-l-l-' - while True: - a = 0 - for turns in xrange(4): - if lookup_color(cube, turns, 'df') == base_color: - a += 1 << turns - if a == 0: - do_moves(cube, 3, fix_opposite) - continue - elif a == 3: do_moves(cube, 2, fix_adjacent) - elif a == 6: do_moves(cube, 3, fix_adjacent) - elif a == 12: do_moves(cube, 0, fix_adjacent) - elif a == 9: do_moves(cube, 1, fix_adjacent) - elif a == 5: do_moves(cube, 0, fix_opposite) - elif a == 10: do_moves(cube, 1, fix_opposite) - break - - -# Apply all the various stages for fixing a cube in order, but allow the user -# to specify when to stop. -def mellor_solve (stage): - cube = plugin.cube_state() - if cube.dimension != 3: - plugin.error_dialog(_('This script only works on 3x3x3 cubes.')) - return - stage_list = [mellor_top_edge_solve, - mellor_top_corner_solve, - mellor_middle_slice_solve, - mellor_bottom_corner_place, - mellor_bottom_corner_orient, - mellor_bottom_edge_place, - mellor_bottom_edge_orient] - - for i in xrange(stage): - stage_list[i](cube) - - -N_ = lambda t: t - -# Provide plenty of menu entries to give the user some control over the solving -# algorithm (he may want to perform part of the solution himself!) -for path, func in [ - ((N_('Solvers'), - # Translators: "Mellor" is the name of the original Author of the algorithm for this solution - N_('Mellor (3x3)')), lambda: mellor_solve(7)), - (('Solvers', 'Mellor (3x3)' ,N_('Top edges')), lambda: mellor_solve(1)), - (('Solvers', 'Mellor (3x3)' ,N_('Top slice')), lambda: mellor_solve(2)), - (('Solvers', 'Mellor (3x3)' ,N_('Middle slice')), lambda: mellor_solve(3)), - (('Solvers', 'Mellor (3x3)' ,N_('Bottom corner place')), lambda: mellor_solve(4)), - (('Solvers', 'Mellor (3x3)' ,N_('Bottom corner orient')),lambda: mellor_solve(5)), - (('Solvers', 'Mellor (3x3)' ,N_('Bottom edge place')), lambda: mellor_solve(6)), - (('Solvers', 'Mellor (3x3)' ,N_('Bottom edge orient')), lambda: mellor_solve(7)), - ]: - plugin.register_script(path, func) - - diff -Nru pybik-0.5/data/scripts/20-2x2x2.script pybik-1.0.1/data/scripts/20-2x2x2.script --- pybik-0.5/data/scripts/20-2x2x2.script 2011-12-23 21:19:31.000000000 +0000 +++ pybik-1.0.1/data/scripts/20-2x2x2.script 1970-01-01 00:00:00.000000000 +0000 @@ -1,63 +0,0 @@ -File-Version: 1.0 -Copyright: 2011, B. Clausius -Model: Cube 2 - -Path: /Solvers/2×2×2 -Depends: /Solvers/2×2×2/Bottom corner orient - -Path: /Solvers/2×2×2/Top slice -Ref-Blocks: flu -Solution: - ufr=ufr urb=urb ubl=ubl ulf=ulf, @@solved - fld=?uf, r-dr - fld=uf?, ddfd-f- - #fld=f?u, f-dffd-f- - fld=f?u, dr-drfd-d-f- - # - rfd=*f?u, d- - brd=*f?u, dd - lbd=*f?u, d - # - fru=!f?u fru=*f?u, r-d-r - rbu=*f?u, b-d-d-b - blu=*f?u, bdb- - lfu=*f?u, f-df - , U - -Path: /Solvers/2×2×2/Bottom corner place -Depends: /Solvers/2×2×2/Top slice -Ref-Blocks: flu bru -Solution: - dfl=*dfl dlb=*dlb dbr=*dbr drf=*drf, @@solved - dfl=*drf drf=*dfl, r-d-rfdf-r-drdd - dfl=*dbr drf=*dlb, dd - dfl=*drf drf=*dbr, d - dfl=*dlb drf=*dfl, d- - dfl=*dfl dbr=*dbr, d - , U - -Path: @Solvers/2×2×2/Bottom corner orient -Depends: /Solvers/2×2×2/Bottom corner place -Ref-Blocks: flu bru -Solution: - flu=flu rfu=rfu bru=bru lbu=lbu dfl=ldf, lf-l-flf-l-f - flu=flu rfu=rfu bru=bru lbu=lbu dfl=fld, f-lfl-f-lfl- - , @@solved - -Path: /Solvers/2×2×2/Bottom corner orient -Depends: @Solvers/2×2×2/Bottom corner orient -Ref-Blocks: dfl -Solution: - ufl=ufl dfl=dfl dlb=dlb dbr=dbr drf=drf, @@solved - # rotate corner - dfl=dfl dfr=frd, d-lf-l-flf-l-f - dfl=dfl dfr=rdf, d-f-lfl-f-lfl- - dfl=dfl dbl=bld, dlf-l-flf-l-f - dfl=dfl dbl=ldb, df-lfl-f-lfl- - dfl=dfl dbr=brd, ddf-lfl-f-lfl- - dfl=dfl dbr=rdb, ddlf-l-flf-l-f - # move solved bottom slice - ufl=urf, d- - ufl=ubr, dd - ufl=ulb, d - diff -Nru pybik-0.5/data/scripts/80-pretty_patterns.py pybik-1.0.1/data/scripts/80-pretty_patterns.py --- pybik-0.5/data/scripts/80-pretty_patterns.py 2011-12-22 17:44:23.000000000 +0000 +++ pybik-1.0.1/data/scripts/80-pretty_patterns.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,68 +0,0 @@ -#-*- coding:utf-8 -*- - -# Copyright © 2009-2011 B. Clausius -# -# 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 . - -import pybikplugin as plugin - -def play_chessboard_odd(): - size = plugin.cube_state().dimension - # Moves are 3-Tuples (axis, slice, dir) axis=0,1,2 slice=0,...,size-1 dir=0,1 - moves = [(0, i, 0) for i in xrange(1,size,2)] - moves += [(1, i, 0) for i in xrange(1,size,2)] - moves += [(2, i, 0) for i in xrange(1,size,2)] - moves = [moves[i//2] for i in range(2*len(moves))] - plugin.rotate_animated(moves) - -def play_chessboard_even(): - size = plugin.cube_state().dimension - moves = [(0, i, 0) for i in xrange(0,size,2)] - moves += [(1, i, 0) for i in xrange(0,size,2)] - moves += [(2, i, 0) for i in xrange(0,size,2)] - moves += [(1, i, 0) for i in xrange(0,size,2)] - moves = [moves[i//2] for i in range(2*len(moves))] - plugin.rotate_animated(moves) - -def play_pattern(pattern, min_size): - size = plugin.cube_state().dimension - if size < min_size: - plugin.error_dialog( - ngettext('This pretty pattern only works on cubes\nwith at least {count} slice.', - 'This pretty pattern only works on cubes\nwith at least {count} slices.', - min_size).format(count=min_size)) - else: - plugin.rotate_flubrd(pattern, size) - -N_ = lambda t: t - -def item_path(name): - return N_('Pretty patterns'), name -def item(name, pattern, min_size): - return item_path(name), lambda: play_pattern(pattern, min_size) - -for path, func in [ - item(N_('Stripes'), "rrbbllrrbbll", 1), - item(N_('Criss-Cross'), "rruullrruurr", 1), - item(N_('Fried Eggs'), "l2-f2-l2f2", 2), - item(N_('Fried Eggs v2'), "rl-fb-ud-rl-", 1), - item(N_('4 Fried Eggs'), "l2l2u2l2l2u2-", 2), - (item_path(N_('Chessboard odd')), play_chessboard_odd), - (item_path(N_('Chessboard even')), play_chessboard_even), - item(N_('Zig Zag'), "rlfbrlfbrlfb", 1), - item(N_('T-Time'), "l2l2u2l2l2u2-l2l2duul2l2uul2l2d-l2l2uu", 2), - #"rr2r2ll2l2ff2f2bb2b2 rr2r2ll2l2ff2f2bb2b2 rr2r2ll2l2ff2f2bb2b2 rr2r2ll2l2ff2f2bb2b2 rr2r2ll2l2ff2f2bb2b2 rr2r2ll2l2ff2f2bb2b2" - ]: - plugin.register_script(path, func) - diff -Nru pybik-0.5/data/scripts/90-rand.py pybik-1.0.1/data/scripts/90-rand.py --- pybik-0.5/data/scripts/90-rand.py 2011-12-22 23:27:05.000000000 +0000 +++ pybik-1.0.1/data/scripts/90-rand.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,53 +0,0 @@ -#-*- coding:utf-8 -*- - -# Copyright © 2009-2011 B. Clausius -# -# 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 . - - -# Ported from GNUbik -# Original filename: rand.scm -# Original copyright and license: 2004 Dale Mellor, GPL3+ - - -import pybikplugin as plugin - -# Procedure which generates a list of lists of three random items, and sends it -# to gnubik-rotate-animated. The three random components are the face number -# (0, 1 or 2), the slice number (-(size-1), ..., size-3, size-1), and the -# direction to turn the slice (0 or 1). -def randomize(num): - size = plugin.cube_state().dimension - moves = [(plugin.random(3), plugin.random(size), plugin.random(2)) for i in xrange(num)] - plugin.rotate_animated(moves) - - -N_ = lambda t: t - -def items(s): - return N_('Randomize'), s - -for path, func in [ - (items(N_('1 Move')), lambda: randomize(1)), - (items(N_('2 Moves')), lambda: randomize(2)), - (items(N_('3 Moves')), lambda: randomize(3)), - (items(N_('4 Moves')), lambda: randomize(4)), - (items(N_('5 Moves')), lambda: randomize(5)), - (items(N_('6 Moves')), lambda: randomize(6)), - (items(N_('7 Moves')), lambda: randomize(7)), - (items(N_('8 Moves')), lambda: randomize(8)), - (items(N_('50 Moves')),lambda: (randomize(50), plugin.run_moves())), - ]: - plugin.register_script(path, func) - diff -Nru pybik-0.5/data/ui/about.ui pybik-1.0.1/data/ui/about.ui --- pybik-0.5/data/ui/about.ui 1970-01-01 00:00:00.000000000 +0000 +++ pybik-1.0.1/data/ui/about.ui 2012-10-24 12:40:42.000000000 +0000 @@ -0,0 +1,237 @@ + + + AboutDialog + + + Qt::ApplicationModal + + + About Pybik + + + + + + + + icon + + + Qt::AlignCenter + + + + + + + + + + + + 1 + 0 + + + + + 16 + 75 + true + + + + appname + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 1 + 0 + + + + version + + + + + + + + + + + + + 0 + + + + About + + + + + + description + + + true + + + + + + + copyright + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + website + + + true + + + + + + + + Feedback + + + + + + Qt::RichText + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + true + + + + + + + + Translation + + + + + + Qt::RichText + + + true + + + true + + + + + + + + License + + + + + + true + + + false + + + false + + + + + + + QTextEdit::NoWrap + + + false + + + true + + + + + text_license_short + text_license_short + text_license_full + + + + + + + QDialogButtonBox::Close + + + + + + + + + buttonBox + accepted() + AboutDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + AboutDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + Binary files /tmp/NykpzDcWhX/pybik-0.5/data/ui/images/ATOM SYMBOL.png and /tmp/gD0eBO7MB2/pybik-1.0.1/data/ui/images/ATOM SYMBOL.png differ Binary files /tmp/NykpzDcWhX/pybik-0.5/data/ui/images/BEAMED EIGHTH NOTES.png and /tmp/gD0eBO7MB2/pybik-1.0.1/data/ui/images/BEAMED EIGHTH NOTES.png differ Binary files /tmp/NykpzDcWhX/pybik-0.5/data/ui/images/BLACK SMILING FACE.png and /tmp/gD0eBO7MB2/pybik-1.0.1/data/ui/images/BLACK SMILING FACE.png differ Binary files /tmp/NykpzDcWhX/pybik-0.5/data/ui/images/PEACE SYMBOL.png and /tmp/gD0eBO7MB2/pybik-1.0.1/data/ui/images/PEACE SYMBOL.png differ Binary files /tmp/NykpzDcWhX/pybik-0.5/data/ui/images/SHAMROCK.png and /tmp/gD0eBO7MB2/pybik-1.0.1/data/ui/images/SHAMROCK.png differ Binary files /tmp/NykpzDcWhX/pybik-0.5/data/ui/images/SKULL AND CROSSBONES.png and /tmp/gD0eBO7MB2/pybik-1.0.1/data/ui/images/SKULL AND CROSSBONES.png differ Binary files /tmp/NykpzDcWhX/pybik-0.5/data/ui/images/SNOWFLAKE.png and /tmp/gD0eBO7MB2/pybik-1.0.1/data/ui/images/SNOWFLAKE.png differ Binary files /tmp/NykpzDcWhX/pybik-0.5/data/ui/images/WHITE SMILING FACE.png and /tmp/gD0eBO7MB2/pybik-1.0.1/data/ui/images/WHITE SMILING FACE.png differ Binary files /tmp/NykpzDcWhX/pybik-0.5/data/ui/images/WHITE SUN WITH RAYS.png and /tmp/gD0eBO7MB2/pybik-1.0.1/data/ui/images/WHITE SUN WITH RAYS.png differ Binary files /tmp/NykpzDcWhX/pybik-0.5/data/ui/images/YIN YANG.png and /tmp/gD0eBO7MB2/pybik-1.0.1/data/ui/images/YIN YANG.png differ Binary files /tmp/NykpzDcWhX/pybik-0.5/data/ui/images/diagonal-lines.png and /tmp/gD0eBO7MB2/pybik-1.0.1/data/ui/images/diagonal-lines.png differ Binary files /tmp/NykpzDcWhX/pybik-0.5/data/ui/images/squares.png and /tmp/gD0eBO7MB2/pybik-1.0.1/data/ui/images/squares.png differ diff -Nru pybik-0.5/data/ui/main.ui pybik-1.0.1/data/ui/main.ui --- pybik-0.5/data/ui/main.ui 1970-01-01 00:00:00.000000000 +0000 +++ pybik-1.0.1/data/ui/main.ui 2012-12-12 10:56:39.000000000 +0000 @@ -0,0 +1,370 @@ + + + MainWindow + + + Pybik + + + + + 6 + + + 0 + + + + + 0 + + + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + 0 + + + 0 + + + + 0 + + + 0 + + + + + Qt::NoFocus + + + + + + true + + + + + + + false + + + + + + + Qt::NoFocus + + + + + + true + + + + + + + + + + Qt::Horizontal + + + + + 0 + + + + + + + 0 + + + 0 + + + + + PushButton + + + true + + + + + + + QFrame::NoFrame + + + QAbstractItemView::NoEditTriggers + + + true + + + true + + + true + + + + + + + + + + + + + + + &Game + + + + + + + + + + &Edit + + + + + + + + + + + + + + + + + + + + + + + &View + + + + + + + + &Help + + + + + + + + + + + + Pybik Toolbar + + + TopToolBarArea + + + false + + + + + &New Random + + + Ctrl+N + + + + + Ne&w Solved + + + Ctrl+Shift+N + + + + + &Quit + + + Ctrl+Q + + + + + &Select Model … + + + + + &Set as Initial State + + + + + &Reset Rotation + + + + + &Invert Moves + + + + + Reload Plugins + + + + + &Preferences … + + + + + true + + + true + + + &Toolbar + + + + + true + + + true + + + &Status Bar + + + + + &Info … + + + + + Rewind + + + Go to the previous mark (or the beginning) of the sequence of moves + + + + + Previous + + + Make one step backwards + + + + + Stop + + + Stop running the sequence of moves + + + + + Play + + + Run forward through the sequence of moves + + + + + Next + + + Make one step forwards + + + + + Forward + + + Go to the next mark (or the end) of the sequence of moves + + + + + Add Mark + + + Mark the current place in the sequence of moves + + + + + Remove Mark + + + Remove the mark at the current place in the sequence of moves + + + + + true + + + true + + + &Edit Bar + + + + + Normalize Cube Rotations + + + + + + diff -Nru pybik-0.5/data/ui/menu.ui pybik-1.0.1/data/ui/menu.ui --- pybik-0.5/data/ui/menu.ui 2012-01-05 16:11:48.000000000 +0000 +++ pybik-1.0.1/data/ui/menu.ui 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff -Nru pybik-0.5/data/ui/model.ui pybik-1.0.1/data/ui/model.ui --- pybik-0.5/data/ui/model.ui 1970-01-01 00:00:00.000000000 +0000 +++ pybik-1.0.1/data/ui/model.ui 2012-12-14 23:53:25.000000000 +0000 @@ -0,0 +1,142 @@ + + + DialogSelectModel + + + Qt::NonModal + + + Select Model + + + + + + + + + + + + 1 + 0 + + + + 1 + + + 10 + + + + + + + Size: + + + + + + + Height: + + + + + + + + 1 + 0 + + + + 1 + + + 10 + + + + + + + Depth: + + + + + + + + 1 + 0 + + + + 1 + + + 10 + + + + + + + + + solved + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + DialogSelectModel + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + DialogSelectModel + reject() + + + 316 + 260 + + + 286 + 274 + + + + + Binary files /tmp/NykpzDcWhX/pybik-0.5/data/ui/mouse_ccw.png and /tmp/gD0eBO7MB2/pybik-1.0.1/data/ui/mouse_ccw.png differ diff -Nru pybik-0.5/data/ui/preferences.ui pybik-1.0.1/data/ui/preferences.ui --- pybik-0.5/data/ui/preferences.ui 1970-01-01 00:00:00.000000000 +0000 +++ pybik-1.0.1/data/ui/preferences.ui 2012-12-12 13:29:07.000000000 +0000 @@ -0,0 +1,493 @@ + + + DialogPreferences + + + Preferences + + + + + + 0 + + + + Graphic + + + + + + Animation Speed: + + + + + + + 1 + + + 100 + + + Qt::Horizontal + + + QSlider::TicksBelow + + + 0 + + + + + + + + + + + + + + Lighting + + + + + + + + + + + + + + Mirror Distance: + + + + + + + + 0 + 0 + + + + 0.100000000000000 + + + + + + + + + + + + + + Qt::Horizontal + + + + + + + Antialiasing + + + + + + + + + + + + + + Hardware: + + + 20 + + + + + + + + + + Software: + + + 20 + + + + + + + + 0 + 0 + + + + + + + + <html><head/><body><p><span style=" color:#aa0000;">The program needs to be restarted for the changes to take effect.</span></p></body></html> + + + true + + + + + + + Qt::Vertical + + + + 20 + 108 + + + + + + + + + Mouse + + + + + + + + + + 96 + 96 + + + + + + + + + 1 + 0 + + + + Four directions + + + + + + + + + + + 96 + 96 + + + + + + + + + 1 + 0 + + + + Simplified, +right button inverts move + + + true + + + + + + + + Keys + + + + + + true + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Add + + + Add + + + Qt::ToolButtonIconOnly + + + + + + + Remove + + + Remove + + + Qt::ToolButtonIconOnly + + + + + + + Reset + + + Reset + + + Qt::ToolButtonIconOnly + + + + + + + + + + Appearance + + + + + + + 0 + 0 + + + + Qt::ScrollBarAlwaysOff + + + QAbstractItemView::NoEditTriggers + + + Qt::ElideNone + + + true + + + + + + + Color: + + + + + + + + 0 + 0 + + + + Color + + + + + + + + + + + + + + Image File: + + + + + + + + 0 + 0 + + + + + 32 + 32 + + + + + + + + + + + + + + + + 0 + 0 + + + + Tiled + + + + + + + + 0 + 0 + + + + Mosaic + + + + + + + Background: + + + + + + + + 0 + 0 + + + + Color + + + + + + + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Close + + + + + + + + + buttonBox + accepted() + DialogPreferences + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + DialogPreferences + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff -Nru pybik-0.5/data/ui/pybik.ui pybik-1.0.1/data/ui/pybik.ui --- pybik-0.5/data/ui/pybik.ui 2012-01-05 16:03:36.000000000 +0000 +++ pybik-1.0.1/data/ui/pybik.ui 1970-01-01 00:00:00.000000000 +0000 @@ -1,1157 +0,0 @@ - - - - - - - _Game - - - - - _Edit - - - - - _View - - - - - _Help - - - - - _New random - New random cube - gtk-new - - - - - - - New _solved - New solved cube - - - - - - - gtk-quit - - - - - - gtk-preferences - - - - - - gtk-select-color - - - - - - gtk-about - - - - - - _Play Toolbar - Play Toolbar - True - - - - - - _Status Bar - Status Bar - True - - - - - - _Set as initial state - - - - - - _Reload scripts - - - - - - _Dynamic script selection - - - - - - Rese_t rotation - - - - - - _Invert moves - - - - - - - - Go to the previous mark (or the beginning) of the sequence of moves - gtk-media-rewind - - - - - - - Make one step backwards - gtk-media-previous - - - - - - Stop running the sequence of moves - gtk-media-stop - - - - - - Run forward through the sequence of moves - gtk-media-play - - - - - - Make one step forwards - gtk-media-next - - - - - - Go to the next mark (or the end) of the sequence of moves - gtk-media-forward - - - - - - - Add mark - Mark the current place in the sequence of moves - gtk-add - - - - - - Remove mark - Remove the mark at the current place in the sequence of moves - gtk-remove - - - - - - 100 - 3 - 1 - 10 - - - 1 - 10 - 1 - 1 - 1 - - - False - 5 - Color selector - True - dialog - True - True - - - True - False - vertical - 2 - - - True - False - end - - - gtk-close - True - True - True - False - True - - - False - False - 0 - - - - - False - True - end - 0 - - - - - True - False - 6 - 5 - 6 - 6 - - - True - True - False - False - False - False - - - - - - 5 - - - - - True - True - True - False - Select a color - #000000000000 - - - 3 - 4 - GTK_FILL - - - - - True - False - 0 - Color: - - - 1 - 2 - GTK_FILL - - - - - True - False - 0 - Pattern: - - - 1 - 2 - 1 - 2 - GTK_FILL - - - - - True - False - 0 - Image File: - - - 1 - 2 - 2 - 3 - GTK_FILL - - - - - _Mosaic - True - True - False - Place a copy of the image across -the entire face of the cube - False - True - True - True - radiobutton_tile - - - 2 - 4 - 4 - 5 - - - - - _Tiled - True - True - False - Place a copy of the image -on each block - False - True - True - - - 2 - 4 - 3 - 4 - - - - - True - False - Use an image file on the cube face - Select image file - 14 - - - 2 - 4 - 2 - 3 - - - - - True - False - 3 - 0 - - - 3 - 4 - 1 - 2 - - - - - - True - False - queue - none - - - - - - 2 - 3 - 2 - - - - - True - True - True - False - - - - - True - False - gtk-clear - - - ClearFaceColor - - - - - - - 4 - 5 - GTK_FILL - - - - - True - True - True - False - - - - - True - False - gtk-clear - - - ClearPattern - - - - - - - 4 - 5 - 1 - 2 - GTK_FILL - - - - - True - True - True - False - - - - - True - False - gtk-clear - - - ClearImageFile - - - - - - - 4 - 5 - 2 - 3 - GTK_FILL - - - - - True - False - Background: - - - 1 - 2 - 5 - 6 - - - - - True - True - True - False - - - - 3 - 4 - 5 - 6 - - - - - True - True - True - False - - - - - True - False - gtk-clear - - - - - 4 - 5 - 5 - 6 - - - - - - - - - - - - - - - - - - - - - - - True - True - 1 - - - - - - button5 - - - - False - 5 - Preferences - True - dialog - True - True - - - True - False - vertical - 2 - - - True - False - end - - - gtk-close - True - True - True - False - True - - - False - False - 0 - - - - - False - True - end - 0 - - - - - True - True - - - True - False - 4 - 3 - 6 - 6 - - - 180 - True - True - adjustment1 - True - 0 - - - AnimSpeed - - - - - 2 - 2 - 3 - - - - - - Lighting - True - True - False - Makes the cube appear illuminated - False - True - - - 2 - 3 - 4 - - - - - - True - True - Sets the number of blocks in each side - False - False - adjustment2 - True - - - SpinButtonSize - - - - - 1 - 2 - GTK_FILL - - - - - - True - False - 0 - Animation: - - - 2 - 1 - 2 - GTK_FILL - - - - - - True - False - 0 - Size: - - - GTK_FILL - - - - - - True - True - True - False - - - - - True - False - - gtk-clear - - - ClearAnimspeed - - - - - - - 2 - 3 - 2 - 3 - GTK_FILL - GTK_FILL - - - - - True - True - True - False - - - - - True - False - gtk-clear - - - ClearSize - - - - - - - 2 - 3 - GTK_FILL - GTK_FILL - - - - - True - True - True - False - - - - - True - False - gtk-clear - - - ClearLighting - - - - - - - 2 - 3 - 3 - 4 - GTK_FILL - GTK_FILL - - - - - - - - False - - - - - True - False - General - - - False - - - - - True - False - 2 - 2 - 3 - 6 - - - Four directions - True - True - False - False - 0 - right - True - True - - - - - Simplified, -right button -inverts move - True - True - False - False - 0 - right - True - True - radiobutton_quad - - - 1 - - - - - True - False - mousemode-quad.png - - - 1 - 2 - - - - - True - False - mousemode-ext.png - - - 1 - 2 - 1 - 2 - - - - - 1 - - - - - True - False - Mouse - - - 1 - False - - - - - True - True - 1 - - - - - - button1 - - - - - - - - - - - - - - - - - - False - Pybik - 480 - 360 - - - True - False - - - - - - True - True - Displays the sequence of moves - - gtk-execute - gtk-clear - Apply the sequence of moves to the cube - Clear the sequence of moves - - - - EntryFormula - - - - - - - False - True - 1 - - - - - True - True - 400 - - - True - False - - - True - False - - - True - False - action_rewind - True - - - False - True - - - - - True - False - action_previous - True - - - False - True - - - - - True - False - action_stop - True - - - False - True - - - - - True - False - action_play - True - - - False - True - - - - - True - False - action_next - True - - - False - True - - - - - True - False - action_forward - True - - - False - True - - - - - True - False - False - - - False - - - - - True - False - action_add_mark - True - - - False - True - - - - - True - False - action_remove_mark - True - - - False - True - - - - - False - True - 0 - - - - - 300 - 300 - True - True - - - True - True - 1 - - - - - True - False - - - - - True - True - - - 200 - True - True - False - 0 - True - - - TreeviewScripts - - - - - - - - - - False - False - - - - - True - True - 2 - - - - - True - False - 2 - - - StatusbarMain - - - - - False - True - 3 - - - - - - diff -Nru pybik-0.5/debian/changelog pybik-1.0.1/debian/changelog --- pybik-0.5/debian/changelog 2012-01-06 17:43:38.000000000 +0000 +++ pybik-1.0.1/debian/changelog 2013-02-02 21:42:49.000000000 +0000 @@ -1,41 +1,91 @@ +pybik (1.0.1-0~ppa1) quantal; urgency=low + + * New release + + Minor improvements and bugfixes + * Updated Build-Depends: pyside-tools -> python-qt4 + * Updated Depends: PyQt4 as an alternative to PySide + + -- B. Clausius Sat, 02 Feb 2013 22:42:49 +0100 + +pybik (1.0-0~ppa2) quantal; urgency=low + + * New release + * Improved user interface. + * Added Towers and Bricks (non cubic puzzles). + * Added an option to show the back faces. + * The cube can be manipulated with the keyboard. + * Animation is faster and rendering more beautiful. + * Added more pretty patterns. + * Added a new solver. + * Added new translations. + * Update debhelper dependency and compat to 9 + * Update Standards-Version to 3.9.3, no changes needed + * debian/copyright: update Format URL for final copyright format 1.0 + * Update (Build-)Depends for transitions: + + GTK2/GConf -> Qt4 (PySide) + + GtkGlExt -> QtOpenGL (PySide) + * Changed source package format from 3.0 (native) to 3.0 (quilt) + + -- B. Clausius Tue, 08 Jan 2013 12:32:51 +0100 + pybik (0.5) oneiric; urgency=low * New release + * New solutions: + - Spiegel improved + - Solution for the 2×2×2 Cube + * New file format for solutions + * Improved mouse control + - Mouse button with control key rotates the whole cube + - Right button moves in the opposite direction + * Changeable background color -- B. Clausius Fri, 06 Jan 2012 18:43:38 +0100 pybik (0.4.2) oneiric; urgency=low - * New Release + * New bugfix release -- B. Clausius Mon, 28 Nov 2011 23:25:18 +0100 pybik (0.4.1) oneiric; urgency=low - * New Release + * New bugfix release -- B. Clausius Tue, 15 Nov 2011 08:30:12 +0100 pybik (0.4) natty; urgency=low - * New upstream release + * New release + This release does not contain many new features. Most of the changes + took place under the hood. A new solution (Spiegel) has been added. -- B. Clausius Wed, 06 Jul 2011 11:36:08 +0200 pybik (0.3) karmic; urgency=low - * New upstream release + * New release + * Text field to edit moves in a notation similar to Singmaster's + * The state of the cube and the moves are now stored between sessions + * Some sequences for pretty patterns in the sidebar -- B. Clausius Wed, 16 Dec 2009 21:22:14 +0100 pybik (0.2) jaunty; urgency=low - * New upstream release + * New release + * Preferences are stored with GConf + * UI Improvements and bugfixes -- B. Clausius Sat, 22 Aug 2009 13:49:21 +0200 pybik (0.1.1) jaunty; urgency=low - * Initial release + * Initial Ubuntu PPA release + * New in Pybik 0.1: + * Port from gnubik-2.3 to Python + * Sidebar for Actions + * Redesigned color dialog + * Improvements in cube rendering -- B. Clausius Tue, 18 Aug 2009 10:40:47 +0200 diff -Nru pybik-0.5/debian/compat pybik-1.0.1/debian/compat --- pybik-0.5/debian/compat 2011-06-28 05:49:43.000000000 +0000 +++ pybik-1.0.1/debian/compat 2012-10-29 13:43:43.000000000 +0000 @@ -1 +1 @@ -7 +9 diff -Nru pybik-0.5/debian/control pybik-1.0.1/debian/control --- pybik-0.5/debian/control 2011-12-26 05:11:06.000000000 +0000 +++ pybik-1.0.1/debian/control 2013-02-02 21:45:31.000000000 +0000 @@ -2,28 +2,49 @@ Section: games Priority: optional Maintainer: B. Clausius -Build-Depends: - debhelper (>= 7.0.50~), - intltool, - cython (>= 0.11.2), - python-all-dev (>= 2.7), - libgl1-mesa-dev, - libglu1-mesa-dev -Standards-Version: 3.9.2 +Build-Depends: debhelper (>= 9), + cython (>= 0.14.1), + python-all-dev (>= 2.7), + libgl1-mesa-dev, + libglu1-mesa-dev, + python-numpy, + intltool, + python-qt4, + help2man, +Standards-Version: 3.9.3 X-Python-Version: >= 2.7 -Homepage: https://launchpad.net/pybik +Homepage: https://launchpad.net/pybik/ Package: pybik -Architecture: any -Depends: ${shlibs:Depends}, ${python:Depends}, ${misc:Depends}, - python-gobject, - python-gtk2, - python-gtkglext1, - python-opengl, - python-numpy, - python-gconf +Architecture: all +Depends: ${python:Depends}, ${misc:Depends}, + python-pyside.qtcore | python-qt4, + python-pyside.qtgui | python-qt4, + python-pyside.qtopengl | python-qt4-gl, + python-numpy, + pybik-bin (>= ${source:Version}), + pybik-bin (<< ${source:Version}.1~) +Suggests: python-opengl, + gconf2 Description: 3D Rubik's cube game - Pybik is an interactive, graphical, single player puzzle. - This program renders an image of a cube, like that invented - by Erno Rubik. You have to manipulate the cube using the mouse. When each - face shows only one color, the game is solved. + Pybik is an interactive, graphical, single player puzzle about the cube + invented by Ernő Rubik. Besides the cube the program can handle towers and + bricks (non cubic puzzles). Pybik also has solvers, pretty patterns and a + collection of various moves. The cube can be manipulated with the mouse or + keyboard. You can change the colors or images on the faces of the cube. + +Package: pybik-bin +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, + python-numpy, +Recommends: pybik +Replaces: pybik (<< ${source:Version}) +Breaks: pybik (<< ${source:Version}) +Description: 3D Rubik's cube game - binary files + Pybik is an interactive, graphical, single player puzzle about the cube + invented by Ernő Rubik. Besides the cube the program can handle towers and + bricks (non cubic puzzles). Pybik also has solvers, pretty patterns and a + collection of various moves. The cube can be manipulated with the mouse or + keyboard. You can change the colors or images on the faces of the cube. + . + This package contains the architecture dependent files for Pybik. diff -Nru pybik-0.5/debian/control.in pybik-1.0.1/debian/control.in --- pybik-0.5/debian/control.in 1970-01-01 00:00:00.000000000 +0000 +++ pybik-1.0.1/debian/control.in 2013-02-01 09:34:36.000000000 +0000 @@ -0,0 +1,42 @@ +Source: pybik +Section: games +Priority: optional +Maintainer: @@AUTHOR@@ <@@CONTACT_EMAIL@@> +Build-Depends: debhelper (>= 9), + cython (>= 0.14.1), + python-all-dev (>= 2.7), + libgl1-mesa-dev, + libglu1-mesa-dev, + python-numpy, + intltool, + python-qt4, + help2man, +Standards-Version: 3.9.3 +X-Python-Version: >= 2.7 +Homepage: @@WEBSITE@@ + +Package: pybik +Architecture: all +Depends: ${python:Depends}, ${misc:Depends}, + python-pyside.qtcore | python-qt4, + python-pyside.qtgui | python-qt4, + python-pyside.qtopengl | python-qt4-gl, + python-numpy, + pybik-bin (>= ${source:Version}), + pybik-bin (<< ${source:Version}.1~) +Suggests: python-opengl, + gconf2 +Description: @@SHORT_DESCRIPTION@@ + @@LONG_DESCRIPTION@@ + +Package: pybik-bin +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, + python-numpy, +Recommends: pybik +Replaces: pybik (<< ${source:Version}) +Breaks: pybik (<< ${source:Version}) +Description: @@SHORT_DESCRIPTION@@ - binary files + @@LONG_DESCRIPTION@@ + . + This package contains the architecture dependent files for Pybik. diff -Nru pybik-0.5/debian/copyright pybik-1.0.1/debian/copyright --- pybik-0.5/debian/copyright 2012-01-06 16:32:25.000000000 +0000 +++ pybik-1.0.1/debian/copyright 2013-01-07 16:36:04.000000000 +0000 @@ -1,4 +1,4 @@ -Format: http://dep.debian.net/deps/dep5 +Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: pybik Upstream-Contact: B. Clausius Source: https://launchpad.net/pybik/+download @@ -11,7 +11,47 @@ * Dale Mellor Files: * -Copyright: 2009-2012 B. Clausius +Copyright: 2009-2013 B. Clausius +License: GPL-3+ + +Files: data/ui/images/BEAMED?EIGHTH?NOTES.png + data/ui/images/ATOM?SYMBOL.png + data/ui/images/SNOWFLAKE.png + data/ui/images/WHITE?SUN?WITH?RAYS.png +Copyright: 2002-2010 Free Software Foundation + 2012 B. Clausius +License: GPL-3+ +Comment: Images created from font FreeSerif: + U+266B BEAMED EIGHTH NOTES + U+269B ATOM SYMBOL + U+2744 SNOWFLAKE + Image created from font FreeMono: + U+263C WHITE SUN WITH RAYS + +Files: data/ui/images/SHAMROCK.png + data/ui/images/SKULL?AND?CROSSBONES.png + data/ui/images/PEACE?SYMBOL.png + data/ui/images/YIN?YANG.png + data/ui/images/BLACK?SMILING?FACE.png + data/ui/images/WHITE?SMILING?FACE.png +Copyright: DejaVu Authors + 2012 B. Clausius +License: public-domain + The DejaVu fonts are a font family based on the Vera Fonts. + License of DejaVu (http://dejavu-fonts.org/wiki/Main_Page): + Fonts are © Bitstream (…). DejaVu changes are in public domain. …. + Glyphs imported from Arev fonts are © Tavmjung Bah (…). + . + The used symbols where added in version 2.4 as stated by DejaVu in the file + status.txt and therefore are in the public domain. +Comment: Images were created from font DejaVu-Sans-Oblique: + U+2618 SHAMROCK + U+2620 SKULL AND CROSSBONES + U+262E PEACE SYMBOL + U+262F YIN YANG + U+263A WHITE SMILING FACE + U+263B BLACK SMILING FACE + License: GPL-3+ 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 diff -Nru pybik-0.5/debian/docs pybik-1.0.1/debian/docs --- pybik-0.5/debian/docs 2011-06-28 05:50:53.000000000 +0000 +++ pybik-1.0.1/debian/docs 2012-10-26 03:33:32.000000000 +0000 @@ -1 +1 @@ -README +debian/README diff -Nru pybik-0.5/debian/links pybik-1.0.1/debian/links --- pybik-0.5/debian/links 2011-11-27 22:42:43.000000000 +0000 +++ pybik-1.0.1/debian/links 2012-10-26 17:51:48.000000000 +0000 @@ -1 +1,2 @@ usr/lib/pybik/pybik usr/games/pybik +usr/share/common-licenses/GPL-3 usr/share/pybik/GPL-3 diff -Nru pybik-0.5/debian/pybik-bin.install pybik-1.0.1/debian/pybik-bin.install --- pybik-0.5/debian/pybik-bin.install 1970-01-01 00:00:00.000000000 +0000 +++ pybik-1.0.1/debian/pybik-bin.install 2012-11-29 05:32:53.000000000 +0000 @@ -0,0 +1 @@ +usr/lib/pybik/pybiklib/*.so diff -Nru pybik-0.5/debian/pybik.install pybik-1.0.1/debian/pybik.install --- pybik-0.5/debian/pybik.install 1970-01-01 00:00:00.000000000 +0000 +++ pybik-1.0.1/debian/pybik.install 2012-12-14 10:40:56.000000000 +0000 @@ -0,0 +1,5 @@ +usr/share/ +usr/lib/pybik/pybik +usr/lib/pybik/pybiklib/ui/ +usr/lib/pybik/pybiklib/*.py +usr/lib/pybik/*.egg-info diff -Nru pybik-0.5/debian/pybik.lintian-overrides pybik-1.0.1/debian/pybik.lintian-overrides --- pybik-0.5/debian/pybik.lintian-overrides 1970-01-01 00:00:00.000000000 +0000 +++ pybik-1.0.1/debian/pybik.lintian-overrides 2013-01-06 18:32:26.000000000 +0000 @@ -0,0 +1 @@ +pybik: package-contains-broken-symlink usr/share/pybik/GPL-3 ../common-licenses/GPL-3 diff -Nru pybik-0.5/debian/rules pybik-1.0.1/debian/rules --- pybik-0.5/debian/rules 2011-11-28 01:48:54.000000000 +0000 +++ pybik-1.0.1/debian/rules 2013-01-31 10:17:11.000000000 +0000 @@ -1,7 +1,38 @@ #!/usr/bin/make -f +#export DH_VERBOSE=1 + +ifneq (,$(filter parallel=%,$(DEB_BUILD_OPTIONS))) + NUMJOBS = $(patsubst parallel=%,%,$(filter parallel=%,$(DEB_BUILD_OPTIONS))) +else + NUMJOBS = auto +endif + %: dh $@ --with python2 -override_dh_auto_install: - dh_auto_install -- --install-scripts=/usr/lib/pybik --install-lib=/usr/lib/pybik +override_dh_clean: + python -B debian/tools/control.py + rm -f debian/README + dh_clean + +override_dh_auto_build-arch: + dh_auto_build -- --arch-only + +override_dh_auto_build-indep: + python tools/create_docs.py --skip-install README=debian/README + dh_auto_build -- --parallel=$(NUMJOBS) --indep-only --pyqt4 + +override_dh_auto_install-arch: + dh_auto_install -- --install-lib=/usr/lib/pybik \ + --arch-only + +override_dh_auto_install-indep: + dh_auto_install -- --install-scripts=/usr/lib/pybik \ + --install-lib=/usr/lib/pybik \ + --data-dir=/usr/share \ + --indep-only + +get-orig-source: + ./setup.py sdist --dist-dir=. --debian-names + diff -Nru pybik-0.5/debian/source/format pybik-1.0.1/debian/source/format --- pybik-0.5/debian/source/format 2013-02-16 17:48:32.046465740 +0000 +++ pybik-1.0.1/debian/source/format 2013-02-16 17:48:32.226466783 +0000 @@ -1 +1 @@ -3.0 (native) +3.0 (quilt) diff -Nru pybik-0.5/debian/tools/control.py pybik-1.0.1/debian/tools/control.py --- pybik-0.5/debian/tools/control.py 1970-01-01 00:00:00.000000000 +0000 +++ pybik-1.0.1/debian/tools/control.py 2012-12-12 03:03:37.000000000 +0000 @@ -0,0 +1,41 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright © 2012 B. Clausius +# +# 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 . + +from __future__ import print_function, division, unicode_literals + +import sys +sys.path.insert(0, '.') + +from pybiklib import config +from tools import create_docs + +def main(): + text = create_docs.read_utf8('debian/control.in') + text = text.replace('@@AUTHOR@@', config.AUTHOR) + text = text.replace('@@CONTACT_EMAIL@@', config.CONTACT_EMAIL) + text = text.replace('@@WEBSITE@@', config.WEBSITE) + text = text.replace('@@SHORT_DESCRIPTION@@', config.SHORT_DESCRIPTION) + description = create_docs.wrap(config.LONG_DESCRIPTION, sep='\n ') + text = text.replace('@@LONG_DESCRIPTION@@', description) + create_docs.write_utf8('debian/control', text) + + +if __name__ == '__main__': + main() + + diff -Nru pybik-0.5/debian/watch pybik-1.0.1/debian/watch --- pybik-0.5/debian/watch 1970-01-01 00:00:00.000000000 +0000 +++ pybik-1.0.1/debian/watch 2012-10-26 00:55:54.000000000 +0000 @@ -0,0 +1 @@ +# see debian/rules diff -Nru pybik-0.5/merge-po.sh pybik-1.0.1/merge-po.sh --- pybik-0.5/merge-po.sh 2011-11-13 23:01:39.000000000 +0000 +++ pybik-1.0.1/merge-po.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,4 +0,0 @@ -#!/bin/bash - -./setup.py build_i18n --merge-po - diff -Nru pybik-0.5/po/POTFILES.in pybik-1.0.1/po/POTFILES.in --- pybik-0.5/po/POTFILES.in 2012-01-04 14:06:55.000000000 +0000 +++ pybik-1.0.1/po/POTFILES.in 2012-10-31 23:11:44.000000000 +0000 @@ -1,29 +1,34 @@ pybiklib/application.py pybiklib/config.py -pybiklib/confstore.py -pybiklib/cube.py -pybiklib/cube_form.py +pybiklib/cubestate.py pybiklib/debug.py -pybiklib/dialogcolors.py pybiklib/dialogs.py -pybiklib/drwBlock.py +pybiklib/drawingarea.py +pybiklib/gamestate.py pybiklib/glarea.py -pybiklib/glarea_common.py +pybiklib/gldraw.py pybiklib/main.py -pybiklib/move_queue.py +pybiklib/model.py +pybiklib/moves.py pybiklib/plugins.py pybiklib/pybik.py -pybiklib/state.py +pybiklib/settings.py pybiklib/textures.py -[type: gettext/glade]data/ui/pybik.ui -data/scripts/10-spiegel.script.py -data/scripts/11-spiegel-improved.script.py -data/scripts/15-mellor_solve.py -data/scripts/20-2x2x2.script.py -data/scripts/80-pretty_patterns.py -data/scripts/90-rand.py +pybiklib/ui/about.py +pybiklib/ui/main.py +pybiklib/ui/model.py +pybiklib/ui/preferences.py + data/applications/pybik.desktop.in -tools/create_manpage.py +data/plugins/01-challenges.algorithm.py +data/plugins/10-spiegel.algorithm.py +data/plugins/11-spiegel-improved.algorithm.py +data/plugins/12-lbl-leyan.algorithm.py +data/plugins/20-2x2x2.algorithm.py +data/plugins/80-pretty-patterns.algorithm.py +data/plugins/90-library.algorithm.py +data/plugins/challenges.py +data/plugins/pretty_patterns.py diff -Nru pybik-0.5/po/de.po pybik-1.0.1/po/de.po --- pybik-0.5/po/de.po 2012-01-06 17:38:54.000000000 +0000 +++ pybik-1.0.1/po/de.po 2013-02-01 20:18:02.000000000 +0000 @@ -1,80 +1,109 @@ # German translation for pybik -# Copyright (C) 2009-2011 B. Clausius +# Copyright (C) 2009-2012 B. Clausius # This file is distributed under the same license as the pybik package. -# B. Clausius , 2009. +# B. Clausius , 2009-2012. # msgid "" msgstr "" "Project-Id-Version: pybik\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-01-06 18:15+0100\n" -"PO-Revision-Date: 2012-01-04 15:38+0000\n" -"Last-Translator: B Clausius \n" +"Report-Msgid-Bugs-To: https://bugs.launchpad.net/pybik/+filebug\n" +"POT-Creation-Date: 2013-01-31 14:25+0100\n" +"PO-Revision-Date: 2012-12-15 00:22+0000\n" +"Last-Translator: B Clausius \n" "Language-Team: German\n" +"Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-01-05 05:46+0000\n" -"X-Generator: Launchpad (build 14625)\n" -"Language: \n" - -#: ../pybiklib/application.py:140 -msgid "Name" -msgstr "Name" +"X-Launchpad-Export-Date: 2012-12-16 04:59+0000\n" +"X-Generator: Launchpad (build 16372)\n" -#: ../pybiklib/application.py:420 -msgid "not solved" -msgstr "ungelöst" +#: ../pybiklib/application.py:304 +msgid "Press the Esc key to exit Edit Mode" +msgstr "Drücken Sie die Esc-Taste, um den Edit-Modus zu beenden" -#: ../pybiklib/application.py:420 -msgid "solved" -msgstr "gelöst" - -#: ../pybiklib/application.py:424 +#. substitution for {move_text} in statusbar text +#: ../pybiklib/application.py:313 msgid "{current} / {total} move" msgid_plural "{current} / {total} moves" msgstr[0] "{current} / {total} Zug" msgstr[1] "{current} / {total} Züge" -#: ../pybiklib/config.py:41 ../pybiklib/config.py:42 +#. substitution for {solved_text} in statusbar text +#: ../pybiklib/application.py:317 ../pybiklib/ui/model.py:82 +msgid "solved" +msgstr "gelöst" + +#: ../pybiklib/application.py:317 +msgid "not solved" +msgstr "ungelöst" + +#. statusbar text +#: ../pybiklib/application.py:320 +msgid "{model_text}, {move_text}, {solved_text}" +msgstr "{model_text}, {move_text}, {solved_text}" + +#: ../pybiklib/application.py:353 +msgid "Congratulations, you have solved the puzzle!" +msgstr "Glückwunsch, Sie haben das Puzzle gelöst!" + +#: ../pybiklib/config.py:30 ../pybiklib/ui/main.py:194 #: ../data/applications/pybik.desktop.in.h:1 msgid "Pybik" msgstr "Pybik" -#: ../pybiklib/config.py:43 -msgid "Pybik is a 3 dimensional magic cube game." -msgstr "Pybik ist ein 3-dimensionales Zauberwürfelspiel." - -#: ../pybiklib/config.py:44 -msgid "Pybik web site" -msgstr "Pybik Web-Seite" +#: ../pybiklib/config.py:59 ../data/applications/pybik.desktop.in.h:2 +msgid "3D Rubik's cube game" +msgstr "Ein 3D-Zauberwürfelspiel" -#: ../pybiklib/config.py:47 +#: ../pybiklib/config.py:61 msgid "" -"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." +"Pybik is an interactive, graphical, single player puzzle about the cube " +"invented by Ernő Rubik. Besides the cube the program can handle towers and " +"bricks (non cubic puzzles). Pybik also has solvers, pretty patterns and a " +"collection of various moves. The cube can be manipulated with the mouse or " +"keyboard. You can change the colors or images on the faces of the cube." msgstr "" -"Dieses Programm ist freie Software. Sie können es unter den Bedingungen der " -"GNU General Public License, wie von der Free Software Foundation " -"veröffentlicht, weitergeben und/oder modifizieren, entweder gemäß Version 3 " -"der Lizenz oder (nach Ihrer Option) jeder späteren Version." +"Pybik ist ein interaktives, grafisches, Ein-Personen-Puzzle mit dem " +"Zauberwürfel, der von Ernő Rubik erfunden wurde. Neben dem Würfel kann das " +"Programm auch Türme und Ziegel (nicht-kubische Puzzle) darstellen. Pybik hat " +"auch Lösungsalgorithmen, Muster und eine Sammlung verschiedener " +"interessanter Züge. Man kann den Würfel mit der Maus oder der Tastatur " +"drehen. Man kann die Farben des Würfels ändern und Bilder auf die " +"Würfelseiten legen." -#: ../pybiklib/config.py:52 +#: ../pybiklib/config.py:69 msgid "" +"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.\n" +"\n" "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." msgstr "" +"Dieses Programm ist freie Software. Sie können es unter den Bedingungen der " +"GNU General Public License, wie von der Free Software Foundation " +"veröffentlicht, weitergeben und/oder modifizieren, entweder gemäß Version 3 " +"der Lizenz oder (nach Ihrer Option) jeder späteren Version.\n" +"\n" "Die Veröffentlichung dieses Programms erfolgt in der Hoffnung, dass es Ihnen " "von Nutzen sein wird, aber OHNE IRGENDEINE GARANTIE, sogar ohne die " "implizite Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN " "BESTIMMTEN ZWECK. Details finden Sie in der GNU General Public License." -#: ../pybiklib/config.py:57 +#: ../pybiklib/config.py:79 +msgid "" +"Read the full text of the GNU General Public " +"License<|> or see ." +msgstr "" +"Lesen sie den vollständigen Text der GNU General " +"Public License<|> oder siehe ." + +#: ../pybiklib/config.py:82 msgid "" "You should have received a copy of the GNU General Public License along with " "this program. If not, see ." @@ -82,538 +111,803 @@ "Sie sollten ein Exemplar der GNU General Public License zusammen mit diesem " "Programm erhalten haben. Falls nicht, siehe ." -#: ../pybiklib/dialogcolors.py:91 +#: ../pybiklib/config.py:88 +msgid "" +"If you find any bugs in Pybik or have a suggestion for an improvement then " +"please submit a <{CONTACT_FILEBUG}|>bug report<|>. In the latter case you " +"can mark the bug report as \"Wishlist\"." +msgstr "" +"Wenn Sie irgendwelche Fehler in Pybik gefunden haben oder einen " +"Verbesserungsvorschlag haben, erstellen Sie bitte einen <{CONTACT_FILEBUG}|" +">Fehlerbericht<|>. Im letzteren Fall können Sie den Fehlerbericht als " +"„Wishlist“ markieren." + +#: ../pybiklib/config.py:94 +msgid "" +"Translations are managed by the Launchpad translation group<|>.\n" +"\n" +"If you want help to translate Pybik to your language you can do it through " +"the web interface<|>.\n" +"\n" +"Read more about \"Translating with " +"Launchpad\"<|> and \"Starting to translate\"<|>." +msgstr "" +"Übersetzungen werden von der Launchpad Übersetzer-Gruppe<|> gemacht.\n" +"\n" +"Wenn Sie bei der Übersetzung von Pybik helfen wollen, können Sie das über " +"die Web-Oberfläche<|> tun.\n" +"\n" +"Lesen Sie mehr über „Translating " +"with Launchpad“<|> und „Starting to translate“<|>." + +#: ../pybiklib/dialogs.py:168 +msgid "Press a key …" +msgstr "Drücken Sie eine Taste …" + +#: ../pybiklib/dialogs.py:296 +msgid "plain" +msgstr "einfarbig" + +#: ../pybiklib/dialogs.py:301 +msgid "select …" +msgstr "Auswählen …" + +#: ../pybiklib/dialogs.py:313 msgid "Up" msgstr "Oben" -#: ../pybiklib/dialogcolors.py:91 +#: ../pybiklib/dialogs.py:313 msgid "Down" msgstr "Unten" -#: ../pybiklib/dialogcolors.py:91 +#: ../pybiklib/dialogs.py:313 msgid "Left" msgstr "Links" -#: ../pybiklib/dialogcolors.py:91 +#: ../pybiklib/dialogs.py:313 msgid "Right" msgstr "Rechts" -#: ../pybiklib/dialogcolors.py:91 +#: ../pybiklib/dialogs.py:313 msgid "Front" msgstr "Vorne" -#: ../pybiklib/dialogcolors.py:91 +#: ../pybiklib/dialogs.py:313 msgid "Back" msgstr "Hinten" -#: ../pybiklib/dialogcolors.py:103 -msgid "Face" -msgstr "Seite" - -#: ../pybiklib/dialogcolors.py:118 -msgid "plain" -msgstr "einfarbig" - -#: ../pybiklib/dialogs.py:100 -msgid "" -"The Dimension of the cube has changed.\n" -"Start cube with new settings?" -msgstr "" -"Die Größe des Würfels wurde geändert.\n" -"Soll der Würfel mit den neuen Einstellungen neu gestartet werden?" - -#: ../pybiklib/glarea.py:624 -msgid "Cannot create image from file {filename}: {error}" -msgstr "" -"Erstellung eines Bildes aus der Datei {filename} ist nicht möglich: {error}" - -#. Translators: Strings from file main.py are visible only on the commandline and/or in the man-page -#: ../pybiklib/main.py:32 -msgid "usage: " -msgstr "Benutzung: " - -#: ../pybiklib/main.py:33 -msgid "optional arguments" -msgstr "optionale Argumente" - -#: ../pybiklib/main.py:149 -msgid "Show help message and exit" -msgstr "Zeigt eine Hilfenachricht an und endet dann" +#: ../pybiklib/dialogs.py:331 +msgid "Move" +msgstr "Zug" + +#: ../pybiklib/dialogs.py:332 +msgid "Key" +msgstr "Taste" + +#: ../pybiklib/dialogs.py:486 +msgid "Open Image" +msgstr "Ein Bild öffnen" -#: ../pybiklib/main.py:151 -msgid "Show version number and exit" -msgstr "Zeigt die Versionsnummer an und endet dann" - -#: ../pybiklib/main.py:153 -msgid "Start with the cube already solved" -msgstr "Starte mit einem gelösten Würfel" - -#: ../pybiklib/main.py:155 -msgid "Start with a N x N x N sized cube" -msgstr "Starte mit einem N x N x N großen Würfel" - -#: ../pybiklib/main.py:157 -msgid "Show N intermediate positions in animations" -msgstr "N Zwischenschritte in Animationen" +#: ../pybiklib/dialogs.py:536 ../pybiklib/ui/model.py:79 +msgid "Size:" +msgstr "Größe:" -#: ../pybiklib/main.py:159 -msgid "Use python module for rendering (very slow)" -msgstr "Benutze das Python-Modul zur Darstellung (sehr langsam)" +#: ../pybiklib/dialogs.py:536 +msgid "Basis:" +msgstr "Basis:" + +#: ../pybiklib/dialogs.py:536 +msgid "Width:" +msgstr "Breite:" + +#: ../pybiklib/dialogs.py:565 +msgid "Canceling operation, please wait" +msgstr "Der Vorgang wird abgebrochen, bitte warten" + +#: ../pybiklib/dialogs.py:621 +msgid "Pybik project website" +msgstr "Pybik Projekt-Webseite" -#: ../pybiklib/main.py:161 +#: ../pybiklib/main.py:287 msgid "" -"Enable debug output, D is an integer or a comma-separated list of [{0}]" +"An error occurred while reading the settings:\n" +"{error_message}" msgstr "" -"Debug-Ausgaben aktivieren, D ist eine Zahl oder eine durch Kommas getrennte " -"Liste von [{0}]..." +"Beim Lesen der Einstellungen ist ein Fehler aufgetreten:\n" +"{error_message}" -#: ../pybiklib/main.py:178 -msgid "debug level out of range: {0}" -msgstr "Debug-Level außerhalb des zulässigen Bereichs: {0}" +#: ../pybiklib/model.py:214 +msgid "Brick" +msgstr "Ziegel" + +#: ../pybiklib/model.py:215 +msgid "{0}×{1}×{2}-Brick" +msgstr "{0}×{1}×{2}-Ziegel" + +#: ../pybiklib/model.py:835 +msgid "Tower" +msgstr "Turm" + +#: ../pybiklib/model.py:836 +msgid "{0}×{1}-Tower" +msgstr "{0}×{1}-Turm" + +#: ../pybiklib/model.py:850 +msgid "Cube" +msgstr "Würfel" + +#: ../pybiklib/model.py:851 +msgid "{0}×{0}×{0}-Cube" +msgstr "{0}×{0}×{0}-Würfel" + +#: ../pybiklib/plugins.py:92 +msgid "This algorithm does not work for any model.\n" +msgstr "Dieses Algorithmus funktioniert für kein Modell.\n" + +#: ../pybiklib/plugins.py:94 ../pybiklib/plugins.py:97 +msgid "This algorithm only works for:\n" +msgstr "Dieser Algorithmus funktioniert nur für:\n" -#: ../pybiklib/main.py:186 -msgid "unknown debug option: {0}" -msgstr "unbekannte Debug-Option: {0}" +#: ../pybiklib/settings.py:256 +msgid "Settings can not be written to file: {error_message}" +msgstr "" +"Die Einstellungen können nicht in die Datei geschrieben werden: " +"{error_message}" -#: ../pybiklib/plugins.py:276 -msgid "This script only works for:" -msgstr "Dieses Skript funktioniert nur für:" +#: ../pybiklib/ui/about.py:131 +msgid "About Pybik" +msgstr "Über Pybik" + +#: ../pybiklib/ui/about.py:132 +msgid "About" +msgstr "Über" + +#: ../pybiklib/ui/about.py:133 +msgid "Feedback" +msgstr "Rückmeldung" + +#: ../pybiklib/ui/about.py:134 +msgid "Translation" +msgstr "Übersetzung" + +#: ../pybiklib/ui/about.py:135 +msgid "License" +msgstr "Lizenz" + +#: ../pybiklib/ui/main.py:195 +msgid "&Game" +msgstr "&Spiel" + +#: ../pybiklib/ui/main.py:196 +msgid "&Edit" +msgstr "&Bearbeiten" + +#: ../pybiklib/ui/main.py:197 +msgid "&View" +msgstr "&Ansicht" + +#: ../pybiklib/ui/main.py:198 +msgid "&Help" +msgstr "&Hilfe" + +#: ../pybiklib/ui/main.py:199 +msgid "Pybik Toolbar" +msgstr "Pybik Werkzeugleiste" + +#: ../pybiklib/ui/main.py:200 +msgid "&New Random" +msgstr "&Neu, zufällig" + +#: ../pybiklib/ui/main.py:201 +msgid "Ne&w Solved" +msgstr "Ne&u, gelöst" + +#: ../pybiklib/ui/main.py:202 +msgid "&Quit" +msgstr "&Beenden" + +#: ../pybiklib/ui/main.py:203 +msgid "&Select Model …" +msgstr "Modell aus&wählen …" + +#: ../pybiklib/ui/main.py:204 +msgid "&Set as Initial State" +msgstr "Als &Ausgangszustand festlegen" + +#: ../pybiklib/ui/main.py:205 +msgid "&Reset Rotation" +msgstr "&Rotation zurücksetzen" + +#: ../pybiklib/ui/main.py:206 +msgid "&Invert Moves" +msgstr "Züge &invertieren" + +#: ../pybiklib/ui/main.py:207 +msgid "Reload Plugins" +msgstr "Plugins neu laden" + +#: ../pybiklib/ui/main.py:208 +msgid "&Preferences …" +msgstr "&Einstellungen …" + +#: ../pybiklib/ui/main.py:209 +msgid "&Toolbar" +msgstr "&Werkzeugleiste" + +#: ../pybiklib/ui/main.py:210 +msgid "&Status Bar" +msgstr "&Statusleiste" + +#: ../pybiklib/ui/main.py:211 +msgid "&Info …" +msgstr "&Info …" + +#: ../pybiklib/ui/main.py:212 +msgid "Rewind" +msgstr "Zurückspulen" -#: ../pybiklib/textures.py:177 -msgid "Pixbuf has wrong number of channels" -msgstr "Die Bilddaten haben eine falsche Anzahl an Kanälen." +#: ../pybiklib/ui/main.py:213 +msgid "Go to the previous mark (or the beginning) of the sequence of moves" +msgstr "Gehe zur vorherigen Markierung (oder dem Anfang) der Zugabfolge" -#: ../pybiklib/textures.py:180 -msgid "Pixbuf has unknown color space: {0}" -msgstr "Die Bilddaten verwenden einen unbekannten Farbraum: {0}" +#: ../pybiklib/ui/main.py:214 +msgid "Previous" +msgstr "Zurück" -#: ../data/ui/pybik.ui.h:1 -msgid "Add mark" -msgstr "Markierung einfügen" +#: ../pybiklib/ui/main.py:215 +msgid "Make one step backwards" +msgstr "Einen Schritt zurücknehmen" -#: ../data/ui/pybik.ui.h:2 -msgid "Animation:" -msgstr "Animation:" +#: ../pybiklib/ui/main.py:216 +msgid "Stop" +msgstr "Stopp" -#: ../data/ui/pybik.ui.h:3 -msgid "Background:" -msgstr "Hintergrund:" +#: ../pybiklib/ui/main.py:217 +msgid "Stop running the sequence of moves" +msgstr "Abspielen der Zugabfolge beenden" -#: ../data/ui/pybik.ui.h:4 -msgid "Color selector" -msgstr "Farbauswahl" +#: ../pybiklib/ui/main.py:218 +msgid "Play" +msgstr "Abspielen" -#: ../data/ui/pybik.ui.h:5 -msgid "Color:" -msgstr "Farbe:" +#: ../pybiklib/ui/main.py:219 +msgid "Run forward through the sequence of moves" +msgstr "Laufe vorwärts durch die Zugabfolge" -#: ../data/ui/pybik.ui.h:6 -msgid "Displays the sequence of moves" -msgstr "Anzeige der Zugabfolge" +#: ../pybiklib/ui/main.py:220 +msgid "Next" +msgstr "Weiter" -#: ../data/ui/pybik.ui.h:7 -msgid "Four directions" -msgstr "Vier Richtungen" +#: ../pybiklib/ui/main.py:221 +msgid "Make one step forwards" +msgstr "Einen Schritt weiter" -#: ../data/ui/pybik.ui.h:8 -msgid "General" -msgstr "Allgemein" +#: ../pybiklib/ui/main.py:222 +msgid "Forward" +msgstr "Vorspulen" -#: ../data/ui/pybik.ui.h:9 +#: ../pybiklib/ui/main.py:223 msgid "Go to the next mark (or the end) of the sequence of moves" msgstr "Gehe zur nächsten Markierung (oder dem Ende) der Zugabfolge" -#: ../data/ui/pybik.ui.h:10 -msgid "Go to the previous mark (or the beginning) of the sequence of moves" -msgstr "Gehe zur vorherigen Markierung (oder dem Anfang) der Zugabfolge" - -#: ../data/ui/pybik.ui.h:11 -msgid "Image File:" -msgstr "Bildauswahl:" - -#: ../data/ui/pybik.ui.h:12 -msgid "Lighting" -msgstr "Beleuchtung" - -#: ../data/ui/pybik.ui.h:13 -msgid "Make one step backwards" -msgstr "Einen Schritt zurücknehmen" - -#: ../data/ui/pybik.ui.h:14 -msgid "Make one step forwards" -msgstr "Einen Schritt weiter" - -#: ../data/ui/pybik.ui.h:15 -msgid "Makes the cube appear illuminated" -msgstr "Lässt den Würfel beleuchtet aussehen" +#: ../pybiklib/ui/main.py:224 +msgid "Add Mark" +msgstr "Markierung einfügen" -#: ../data/ui/pybik.ui.h:16 +#: ../pybiklib/ui/main.py:225 msgid "Mark the current place in the sequence of moves" msgstr "Markiere die aktuelle Stelle in der Zugabfolge" -#: ../data/ui/pybik.ui.h:17 -msgid "Mouse" -msgstr "Maus" +#: ../pybiklib/ui/main.py:226 +msgid "Remove Mark" +msgstr "Markierung entfernen" -#: ../data/ui/pybik.ui.h:18 -msgid "New _solved" -msgstr "Neu, gelö_st" - -#: ../data/ui/pybik.ui.h:19 -msgid "New random cube" -msgstr "Neuer zufälliger Würfel" - -#: ../data/ui/pybik.ui.h:20 -msgid "New solved cube" -msgstr "Neuer gelöster Würfel" - -#: ../data/ui/pybik.ui.h:21 -msgid "Pattern:" -msgstr "Muster:" +#: ../pybiklib/ui/main.py:227 +msgid "Remove the mark at the current place in the sequence of moves" +msgstr "Markierung an der aktuellen Stelle in der Zugabfolge entfernen" -#: ../data/ui/pybik.ui.h:22 -msgid "" -"Place a copy of the image\n" -"on each block" -msgstr "" -"Projiziere das Bild auf jeden Block\n" -"des Würfels" +#: ../pybiklib/ui/main.py:228 +msgid "&Edit Bar" +msgstr "&Bearbeiten-Leiste" -#: ../data/ui/pybik.ui.h:24 -msgid "" -"Place a copy of the image across\n" -"the entire face of the cube" -msgstr "" -"Projiziere das Bild auf die\n" -"gesamte Seite des Würfel" +#: ../pybiklib/ui/main.py:229 +msgid "Normalize Cube Rotations" +msgstr "Würfeldrehungen normalisieren" -#: ../data/ui/pybik.ui.h:26 -msgid "Play Toolbar" -msgstr "Abspielen-Werkzeugleiste" +#: ../pybiklib/ui/model.py:78 +msgid "Select Model" +msgstr "Ein Modell wählen" -#: ../data/ui/pybik.ui.h:27 +#: ../pybiklib/ui/model.py:80 +msgid "Height:" +msgstr "Höhe:" + +#: ../pybiklib/ui/model.py:81 +msgid "Depth:" +msgstr "Tiefe:" + +#: ../pybiklib/ui/preferences.py:252 msgid "Preferences" msgstr "Einstellungen" -#: ../data/ui/pybik.ui.h:28 -msgid "Remove mark" -msgstr "Markierung entfernen" +#: ../pybiklib/ui/preferences.py:253 +msgid "Animation Speed:" +msgstr "Animationsgeschwindigkeit:" -#: ../data/ui/pybik.ui.h:29 -msgid "Remove the mark at the current place in the sequence of moves" -msgstr "Markiere an der aktuellen Stelle in der Zugabfolge entfernen" +#: ../pybiklib/ui/preferences.py:254 +msgid "Lighting" +msgstr "Beleuchtung" -#: ../data/ui/pybik.ui.h:30 -msgid "Rese_t rotation" -msgstr "_Rotation zurücksetzen" +#: ../pybiklib/ui/preferences.py:255 +msgid "Mirror Distance:" +msgstr "Spiegel-Abstand:" + +#: ../pybiklib/ui/preferences.py:256 +msgid "Antialiasing" +msgstr "Antialiasing" + +#: ../pybiklib/ui/preferences.py:257 +msgid "Hardware:" +msgstr "Hardware:" + +#: ../pybiklib/ui/preferences.py:258 +msgid "Software:" +msgstr "Software:" -#: ../data/ui/pybik.ui.h:31 -msgid "Run forward through the sequence of moves" -msgstr "Laufe vorwärts durch die Zugabfolge" +#: ../pybiklib/ui/preferences.py:259 +msgid "" +"

The program needs to " +"be restarted for the changes to take effect.

" +msgstr "" +"

Das Programm muss neu " +"gestartet werden, damit die Änderungen wirksam werden.

" + +#: ../pybiklib/ui/preferences.py:260 +msgid "Graphic" +msgstr "Grafik" -#: ../data/ui/pybik.ui.h:32 -msgid "Select a color" -msgstr "Wähle eine Farbe" - -#: ../data/ui/pybik.ui.h:33 -msgid "Select image file" -msgstr "Auswahl einer Bilddatei" - -#: ../data/ui/pybik.ui.h:34 -msgid "Sets the number of blocks in each side" -msgstr "Ändert die Anzahl der Blöcke je Seite" +#: ../pybiklib/ui/preferences.py:261 +msgid "Four directions" +msgstr "Vier Richtungen" -#: ../data/ui/pybik.ui.h:35 +#: ../pybiklib/ui/preferences.py:262 msgid "" "Simplified,\n" -"right button\n" -"inverts move" +"right button inverts move" msgstr "" "Vereinfacht,\n" -"die rechte Taste\n" -"invertiert den Zug" +"die rechte Taste invertiert den Zug" -#: ../data/ui/pybik.ui.h:38 -msgid "Size:" -msgstr "Größe:" +#: ../pybiklib/ui/preferences.py:263 +msgid "Mouse" +msgstr "Maus" -#: ../data/ui/pybik.ui.h:39 -msgid "Status Bar" -msgstr "Status-Werkzeugleiste" +#: ../pybiklib/ui/preferences.py:264 ../pybiklib/ui/preferences.py:265 +msgid "Add" +msgstr "Hinzufügen" + +#: ../pybiklib/ui/preferences.py:266 ../pybiklib/ui/preferences.py:267 +msgid "Remove" +msgstr "Entfernen" + +#: ../pybiklib/ui/preferences.py:268 ../pybiklib/ui/preferences.py:269 +msgid "Reset" +msgstr "Zurücksetzen" + +#: ../pybiklib/ui/preferences.py:270 +msgid "Keys" +msgstr "Tasten" -#: ../data/ui/pybik.ui.h:40 -msgid "Stop running the sequence of moves" -msgstr "Abspielen der Zugabfolge beenden" +#: ../pybiklib/ui/preferences.py:271 +msgid "Color:" +msgstr "Farbe:" + +#: ../pybiklib/ui/preferences.py:272 +msgid "Image File:" +msgstr "Bildauswahl:" + +#: ../pybiklib/ui/preferences.py:273 +msgid "Tiled" +msgstr "Gekachelt" + +#: ../pybiklib/ui/preferences.py:274 +msgid "Mosaic" +msgstr "Mosaik" -#: ../data/ui/pybik.ui.h:41 -msgid "Use an image file on the cube face" -msgstr "Benutze ein Bild für die Würfeloberfläche" - -#: ../data/ui/pybik.ui.h:42 -msgid "_Dynamic script selection" -msgstr "Skriptauswahl _dynamisch" - -#: ../data/ui/pybik.ui.h:43 -msgid "_Edit" -msgstr "_Bearbeiten" - -#: ../data/ui/pybik.ui.h:44 -msgid "_Game" -msgstr "_Spiel" - -#: ../data/ui/pybik.ui.h:45 -msgid "_Help" -msgstr "_Hilfe" - -#: ../data/ui/pybik.ui.h:46 -msgid "_Invert moves" -msgstr "Züge _invertieren" - -#: ../data/ui/pybik.ui.h:47 -msgid "_Mosaic" -msgstr "_Mosaik" - -#: ../data/ui/pybik.ui.h:48 -msgid "_New random" -msgstr "_Neu, zufällig" - -#: ../data/ui/pybik.ui.h:49 -msgid "_Play Toolbar" -msgstr "_Abspielen-Werkzeugleiste" - -#: ../data/ui/pybik.ui.h:50 -msgid "_Reload scripts" -msgstr "Skripte neu _laden" - -#: ../data/ui/pybik.ui.h:51 -msgid "_Set as initial state" -msgstr "Als _Ausgangszustand festlegen" - -#: ../data/ui/pybik.ui.h:52 -msgid "_Status Bar" -msgstr "_Status-Werkzeugleiste" - -#: ../data/ui/pybik.ui.h:53 -msgid "_Tiled" -msgstr "Ge_kachelt" - -#: ../data/ui/pybik.ui.h:54 -msgid "_View" -msgstr "_Ansicht" - -#: ../data/scripts/10-spiegel.script.py:20 -#: ../data/scripts/10-spiegel.script.py:23 -#: ../data/scripts/10-spiegel.script.py:50 -#: ../data/scripts/10-spiegel.script.py:69 -#: ../data/scripts/10-spiegel.script.py:84 -#: ../data/scripts/10-spiegel.script.py:94 -#: ../data/scripts/10-spiegel.script.py:108 -#: ../data/scripts/10-spiegel.script.py:116 -#: ../data/scripts/11-spiegel-improved.script.py:20 -#: ../data/scripts/11-spiegel-improved.script.py:23 -#: ../data/scripts/11-spiegel-improved.script.py:67 -#: ../data/scripts/11-spiegel-improved.script.py:105 -#: ../data/scripts/11-spiegel-improved.script.py:137 -#: ../data/scripts/11-spiegel-improved.script.py:160 -#: ../data/scripts/11-spiegel-improved.script.py:175 -#: ../data/scripts/11-spiegel-improved.script.py:186 -#: ../data/scripts/15-mellor_solve.py:370 ../data/scripts/20-2x2x2.script.py:5 -#: ../data/scripts/20-2x2x2.script.py:8 ../data/scripts/20-2x2x2.script.py:27 -#: ../data/scripts/20-2x2x2.script.py:47 +#: ../pybiklib/ui/preferences.py:275 +msgid "Background:" +msgstr "Hintergrund:" + +#: ../pybiklib/ui/preferences.py:276 +msgid "Appearance" +msgstr "Aussehen" + +#. Add whatever keywords you want in your language, separated by semicolons. These keywords are used when searching for applications in dashes, etc. (Unity, GNOME Shell) +#: ../data/applications/pybik.desktop.in.h:4 +msgid "rubik;cube;puzzle;magic;" +msgstr "rubik;würfel;puzzle;zauberwürfel;" + +#: ../data/plugins/01-challenges.algorithm.py:19 +#: ../data/plugins/01-challenges.algorithm.py:22 +#: ../data/plugins/01-challenges.algorithm.py:25 +#: ../data/plugins/01-challenges.algorithm.py:28 +#: ../data/plugins/01-challenges.algorithm.py:31 +#: ../data/plugins/01-challenges.algorithm.py:34 +#: ../data/plugins/01-challenges.algorithm.py:37 +#: ../data/plugins/01-challenges.algorithm.py:40 +#: ../data/plugins/01-challenges.algorithm.py:43 +#: ../data/plugins/01-challenges.algorithm.py:46 +#: ../data/plugins/01-challenges.algorithm.py:49 +msgid "Challenges" +msgstr "Herausforderungen" + +#: ../data/plugins/01-challenges.algorithm.py:20 +msgid "Solve random cube" +msgstr "Zufälligen Würfel lösen" + +#: ../data/plugins/01-challenges.algorithm.py:23 +msgid "Solve in 1 move" +msgstr "In einem Zug lösen" + +#: ../data/plugins/01-challenges.algorithm.py:26 +msgid "Solve in 2 moves" +msgstr "In 2 Zügen lösen" + +#: ../data/plugins/01-challenges.algorithm.py:29 +msgid "Solve in 3 moves" +msgstr "In 3 Zügen lösen" + +#: ../data/plugins/01-challenges.algorithm.py:32 +msgid "Solve in 4 moves" +msgstr "In 4 Zügen lösen" + +#: ../data/plugins/01-challenges.algorithm.py:35 +msgid "Solve in 5 moves" +msgstr "In 5 Zügen lösen" + +#: ../data/plugins/01-challenges.algorithm.py:38 +msgid "Solve in 6 moves" +msgstr "In 6 Zügen lösen" + +#: ../data/plugins/01-challenges.algorithm.py:41 +msgid "Solve in 7 moves" +msgstr "In 7 Zügen lösen" + +#: ../data/plugins/01-challenges.algorithm.py:44 +msgid "Solve in 8 moves" +msgstr "In 8 Zügen lösen" + +#: ../data/plugins/01-challenges.algorithm.py:47 +msgid "Solve in 9 moves" +msgstr "In 9 Zügen lösen" + +#: ../data/plugins/01-challenges.algorithm.py:50 +msgid "Solve in 10 moves" +msgstr "In 10 Zügen lösen" + +#: ../data/plugins/10-spiegel.algorithm.py:35 +#: ../data/plugins/10-spiegel.algorithm.py:38 +#: ../data/plugins/10-spiegel.algorithm.py:67 +#: ../data/plugins/10-spiegel.algorithm.py:88 +#: ../data/plugins/10-spiegel.algorithm.py:103 +#: ../data/plugins/10-spiegel.algorithm.py:116 +#: ../data/plugins/10-spiegel.algorithm.py:133 +#: ../data/plugins/10-spiegel.algorithm.py:144 +#: ../data/plugins/11-spiegel-improved.algorithm.py:35 +#: ../data/plugins/11-spiegel-improved.algorithm.py:38 +#: ../data/plugins/11-spiegel-improved.algorithm.py:83 +#: ../data/plugins/11-spiegel-improved.algorithm.py:122 +#: ../data/plugins/11-spiegel-improved.algorithm.py:154 +#: ../data/plugins/11-spiegel-improved.algorithm.py:180 +#: ../data/plugins/11-spiegel-improved.algorithm.py:198 +#: ../data/plugins/11-spiegel-improved.algorithm.py:212 +#: ../data/plugins/12-lbl-leyan.algorithm.py:22 +#: ../data/plugins/12-lbl-leyan.algorithm.py:25 +#: ../data/plugins/12-lbl-leyan.algorithm.py:54 +#: ../data/plugins/12-lbl-leyan.algorithm.py:75 +#: ../data/plugins/12-lbl-leyan.algorithm.py:91 +#: ../data/plugins/12-lbl-leyan.algorithm.py:108 +#: ../data/plugins/12-lbl-leyan.algorithm.py:130 +#: ../data/plugins/12-lbl-leyan.algorithm.py:171 +#: ../data/plugins/20-2x2x2.algorithm.py:19 +#: ../data/plugins/20-2x2x2.algorithm.py:22 +#: ../data/plugins/20-2x2x2.algorithm.py:41 +#: ../data/plugins/20-2x2x2.algorithm.py:61 msgid "Solvers" msgstr "Lösungen" -#: ../data/scripts/10-spiegel.script.py:20 -#: ../data/scripts/10-spiegel.script.py:23 -#: ../data/scripts/10-spiegel.script.py:50 -#: ../data/scripts/10-spiegel.script.py:69 -#: ../data/scripts/10-spiegel.script.py:84 -#: ../data/scripts/10-spiegel.script.py:94 -#: ../data/scripts/10-spiegel.script.py:108 -#: ../data/scripts/10-spiegel.script.py:116 +#. Spiegel is the name of a solution method +#: ../data/plugins/10-spiegel.algorithm.py:37 +#: ../data/plugins/10-spiegel.algorithm.py:39 +#: ../data/plugins/10-spiegel.algorithm.py:68 +#: ../data/plugins/10-spiegel.algorithm.py:89 +#: ../data/plugins/10-spiegel.algorithm.py:104 +#: ../data/plugins/10-spiegel.algorithm.py:117 +#: ../data/plugins/10-spiegel.algorithm.py:134 +#: ../data/plugins/10-spiegel.algorithm.py:145 msgid "Spiegel" msgstr "Spiegel" -#: ../data/scripts/10-spiegel.script.py:23 -#: ../data/scripts/11-spiegel-improved.script.py:23 -#: ../data/scripts/15-mellor_solve.py:373 +#: ../data/plugins/10-spiegel.algorithm.py:40 +#: ../data/plugins/11-spiegel-improved.algorithm.py:40 +#: ../data/plugins/12-lbl-leyan.algorithm.py:27 msgid "Top edges" msgstr "Obere Kanten" -#: ../data/scripts/10-spiegel.script.py:50 -#: ../data/scripts/11-spiegel-improved.script.py:67 +#: ../data/plugins/10-spiegel.algorithm.py:69 +#: ../data/plugins/11-spiegel-improved.algorithm.py:85 +#: ../data/plugins/12-lbl-leyan.algorithm.py:56 msgid "Top corners" msgstr "Obere Ecken" -#: ../data/scripts/10-spiegel.script.py:69 -#: ../data/scripts/11-spiegel-improved.script.py:105 -#: ../data/scripts/15-mellor_solve.py:375 +#: ../data/plugins/10-spiegel.algorithm.py:90 +#: ../data/plugins/11-spiegel-improved.algorithm.py:124 +#: ../data/plugins/12-lbl-leyan.algorithm.py:77 msgid "Middle slice" msgstr "Mittlere Schicht" -#: ../data/scripts/10-spiegel.script.py:84 -#: ../data/scripts/11-spiegel-improved.script.py:137 -#: ../data/scripts/15-mellor_solve.py:378 +#: ../data/plugins/10-spiegel.algorithm.py:105 +#: ../data/plugins/11-spiegel-improved.algorithm.py:156 +#: ../data/plugins/12-lbl-leyan.algorithm.py:173 msgid "Bottom edge place" msgstr "Untere Kanten platzieren" -#: ../data/scripts/10-spiegel.script.py:94 -#: ../data/scripts/11-spiegel-improved.script.py:160 -#: ../data/scripts/15-mellor_solve.py:379 +#: ../data/plugins/10-spiegel.algorithm.py:118 +#: ../data/plugins/11-spiegel-improved.algorithm.py:182 +#: ../data/plugins/12-lbl-leyan.algorithm.py:93 msgid "Bottom edge orient" msgstr "Untere Kanten ausrichten" -#: ../data/scripts/10-spiegel.script.py:108 -#: ../data/scripts/11-spiegel-improved.script.py:175 -#: ../data/scripts/15-mellor_solve.py:376 -#: ../data/scripts/20-2x2x2.script.py:27 +#: ../data/plugins/10-spiegel.algorithm.py:135 +#: ../data/plugins/11-spiegel-improved.algorithm.py:200 +#: ../data/plugins/12-lbl-leyan.algorithm.py:110 +#: ../data/plugins/20-2x2x2.algorithm.py:43 msgid "Bottom corner place" msgstr "Untere Ecken platzieren" -#: ../data/scripts/10-spiegel.script.py:116 -#: ../data/scripts/11-spiegel-improved.script.py:186 -#: ../data/scripts/15-mellor_solve.py:377 -#: ../data/scripts/20-2x2x2.script.py:47 +#: ../data/plugins/10-spiegel.algorithm.py:146 +#: ../data/plugins/11-spiegel-improved.algorithm.py:214 +#: ../data/plugins/12-lbl-leyan.algorithm.py:132 +#: ../data/plugins/20-2x2x2.algorithm.py:63 msgid "Bottom corner orient" msgstr "Untere Ecken ausrichten" -#: ../data/scripts/11-spiegel-improved.script.py:20 -#: ../data/scripts/11-spiegel-improved.script.py:23 -#: ../data/scripts/11-spiegel-improved.script.py:67 -#: ../data/scripts/11-spiegel-improved.script.py:105 -#: ../data/scripts/11-spiegel-improved.script.py:137 -#: ../data/scripts/11-spiegel-improved.script.py:160 -#: ../data/scripts/11-spiegel-improved.script.py:175 -#: ../data/scripts/11-spiegel-improved.script.py:186 +#. Spiegel is the name of a solution method +#: ../data/plugins/11-spiegel-improved.algorithm.py:37 +#: ../data/plugins/11-spiegel-improved.algorithm.py:39 +#: ../data/plugins/11-spiegel-improved.algorithm.py:84 +#: ../data/plugins/11-spiegel-improved.algorithm.py:123 +#: ../data/plugins/11-spiegel-improved.algorithm.py:155 +#: ../data/plugins/11-spiegel-improved.algorithm.py:181 +#: ../data/plugins/11-spiegel-improved.algorithm.py:199 +#: ../data/plugins/11-spiegel-improved.algorithm.py:213 msgid "Spiegel improved" msgstr "Spiegel verbessert" -#: ../data/scripts/15-mellor_solve.py:351 -msgid "This script only works on 3x3x3 cubes." -msgstr "Dieses Skript funktioniert nur für 3x3x3 Würfel." - -# -#. Translators: "Mellor" is the name of the original Author of the algorithm for this solution -#: ../data/scripts/15-mellor_solve.py:372 -msgid "Mellor (3x3)" -msgstr "Mellor (3x3)" - -#: ../data/scripts/15-mellor_solve.py:374 ../data/scripts/20-2x2x2.script.py:8 -msgid "Top slice" -msgstr "Obere Schicht" - -#: ../data/scripts/20-2x2x2.script.py:5 ../data/scripts/20-2x2x2.script.py:8 -#: ../data/scripts/20-2x2x2.script.py:27 ../data/scripts/20-2x2x2.script.py:47 +#. Leyan Lo is the inventor of the solution method +#: ../data/plugins/12-lbl-leyan.algorithm.py:24 +#: ../data/plugins/12-lbl-leyan.algorithm.py:26 +#: ../data/plugins/12-lbl-leyan.algorithm.py:55 +#: ../data/plugins/12-lbl-leyan.algorithm.py:76 +#: ../data/plugins/12-lbl-leyan.algorithm.py:92 +#: ../data/plugins/12-lbl-leyan.algorithm.py:109 +#: ../data/plugins/12-lbl-leyan.algorithm.py:131 +#: ../data/plugins/12-lbl-leyan.algorithm.py:172 +msgid "Layer Method (Leyan Lo)" +msgstr "Schichten-Methode (Leyan Lo)" + +#: ../data/plugins/20-2x2x2.algorithm.py:20 +#: ../data/plugins/20-2x2x2.algorithm.py:23 +#: ../data/plugins/20-2x2x2.algorithm.py:42 +#: ../data/plugins/20-2x2x2.algorithm.py:62 msgid "2×2×2" msgstr "2×2×2" -#: ../data/scripts/80-pretty_patterns.py:42 -msgid "" -"This pretty pattern only works on cubes\n" -"with at least {count} slice." -msgid_plural "" -"This pretty pattern only works on cubes\n" -"with at least {count} slices." -msgstr[0] "" -"Dieses Muster funktioniert nur bei Würfeln\n" -"mit mindestens {count} Scheibe." -msgstr[1] "" -"Dieses Muster funktioniert nur bei Würfeln\n" -"mit mindestens {count} Scheiben." +#: ../data/plugins/20-2x2x2.algorithm.py:24 +msgid "Top slice" +msgstr "Obere Schicht" -#: ../data/scripts/80-pretty_patterns.py:51 +#: ../data/plugins/80-pretty-patterns.algorithm.py:18 +#: ../data/plugins/80-pretty-patterns.algorithm.py:22 +#: ../data/plugins/80-pretty-patterns.algorithm.py:26 +#: ../data/plugins/80-pretty-patterns.algorithm.py:30 +#: ../data/plugins/80-pretty-patterns.algorithm.py:34 +#: ../data/plugins/80-pretty-patterns.algorithm.py:39 +#: ../data/plugins/80-pretty-patterns.algorithm.py:43 +#: ../data/plugins/80-pretty-patterns.algorithm.py:48 +#: ../data/plugins/80-pretty-patterns.algorithm.py:52 +#: ../data/plugins/80-pretty-patterns.algorithm.py:56 +#: ../data/plugins/80-pretty-patterns.algorithm.py:60 +#: ../data/plugins/80-pretty-patterns.algorithm.py:64 +#: ../data/plugins/80-pretty-patterns.algorithm.py:68 +#: ../data/plugins/80-pretty-patterns.algorithm.py:74 +#: ../data/plugins/80-pretty-patterns.algorithm.py:78 +#: ../data/plugins/80-pretty-patterns.algorithm.py:83 +#: ../data/plugins/80-pretty-patterns.algorithm.py:87 +#: ../data/plugins/80-pretty-patterns.algorithm.py:91 +#: ../data/plugins/80-pretty-patterns.algorithm.py:95 +#: ../data/plugins/80-pretty-patterns.algorithm.py:99 +#: ../data/plugins/80-pretty-patterns.algorithm.py:103 +#: ../data/plugins/80-pretty-patterns.algorithm.py:108 +#: ../data/plugins/80-pretty-patterns.algorithm.py:112 +#: ../data/plugins/80-pretty-patterns.algorithm.py:116 +#: ../data/plugins/80-pretty-patterns.algorithm.py:120 +#: ../data/plugins/80-pretty-patterns.algorithm.py:124 +#: ../data/plugins/80-pretty-patterns.algorithm.py:128 +#: ../data/plugins/80-pretty-patterns.algorithm.py:132 +#: ../data/plugins/80-pretty-patterns.algorithm.py:136 +#: ../data/plugins/80-pretty-patterns.algorithm.py:140 msgid "Pretty patterns" msgstr "Muster" -#: ../data/scripts/80-pretty_patterns.py:56 +#: ../data/plugins/80-pretty-patterns.algorithm.py:19 +#: ../data/plugins/80-pretty-patterns.algorithm.py:23 +#: ../data/plugins/80-pretty-patterns.algorithm.py:27 +#: ../data/plugins/80-pretty-patterns.algorithm.py:31 +#: ../data/plugins/80-pretty-patterns.algorithm.py:35 +#: ../data/plugins/80-pretty-patterns.algorithm.py:40 +#: ../data/plugins/80-pretty-patterns.algorithm.py:44 msgid "Stripes" msgstr "Streifen" -#: ../data/scripts/80-pretty_patterns.py:57 +#: ../data/plugins/80-pretty-patterns.algorithm.py:49 +#: ../data/plugins/80-pretty-patterns.algorithm.py:53 msgid "Criss-Cross" msgstr "Kreuz und Quer" -#: ../data/scripts/80-pretty_patterns.py:58 +#: ../data/plugins/80-pretty-patterns.algorithm.py:57 msgid "Fried Eggs" msgstr "Spiegeleier" -#: ../data/scripts/80-pretty_patterns.py:59 -msgid "Fried Eggs v2" -msgstr "Spiegeleier v2" +#: ../data/plugins/80-pretty-patterns.algorithm.py:61 +msgid "Big Fried Eggs" +msgstr "Große Spiegeleier" -#: ../data/scripts/80-pretty_patterns.py:60 +#: ../data/plugins/80-pretty-patterns.algorithm.py:65 msgid "4 Fried Eggs" msgstr "4 Spiegeleier" -#: ../data/scripts/80-pretty_patterns.py:61 -msgid "Chessboard odd" -msgstr "Schachbrett ungerade" - -#: ../data/scripts/80-pretty_patterns.py:62 -msgid "Chessboard even" -msgstr "Schachbrett gerade" +#: ../data/plugins/80-pretty-patterns.algorithm.py:69 +msgid "Chessboard" +msgstr "Schachbrett" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:75 +msgid "Cross" +msgstr "Kreuz" -#: ../data/scripts/80-pretty_patterns.py:63 +#: ../data/plugins/80-pretty-patterns.algorithm.py:79 msgid "Zig Zag" msgstr "Zick Zack" -#: ../data/scripts/80-pretty_patterns.py:64 +#. T is the shape formed by the cube labels +#: ../data/plugins/80-pretty-patterns.algorithm.py:85 +#: ../data/plugins/80-pretty-patterns.algorithm.py:88 +#: ../data/plugins/80-pretty-patterns.algorithm.py:92 +#: ../data/plugins/80-pretty-patterns.algorithm.py:96 +#: ../data/plugins/80-pretty-patterns.algorithm.py:100 +#: ../data/plugins/80-pretty-patterns.algorithm.py:104 msgid "T-Time" msgstr "T-Time" -#: ../data/scripts/90-rand.py:39 -msgid "Randomize" -msgstr "Zufällig" - -#: ../data/scripts/90-rand.py:42 -msgid "1 Move" -msgstr "1 Zug" - -#: ../data/scripts/90-rand.py:43 -msgid "2 Moves" -msgstr "2 Züge" - -#: ../data/scripts/90-rand.py:44 -msgid "3 Moves" -msgstr "3 Züge" - -#: ../data/scripts/90-rand.py:45 -msgid "4 Moves" -msgstr "4 Züge" - -#: ../data/scripts/90-rand.py:46 -msgid "5 Moves" -msgstr "5 Züge" - -#: ../data/scripts/90-rand.py:47 -msgid "6 Moves" -msgstr "6 Züge" - -#: ../data/scripts/90-rand.py:48 -msgid "7 Moves" -msgstr "7 Züge" - -#: ../data/scripts/90-rand.py:49 -msgid "8 Moves" -msgstr "8 Züge" - -#: ../data/scripts/90-rand.py:50 -msgid "50 Moves" -msgstr "50 Züge" - -#: ../data/applications/pybik.desktop.in.h:2 -msgid "The magic cube" -msgstr "Der Zauberwürfel" - -#. Translators: Strings from file create_manpage.py are visible only in the man-page -#: ../tools/create_manpage.py:71 -msgid "NAME" -msgstr "NAME" - -#: ../tools/create_manpage.py:74 -msgid "SYNOPSIS" -msgstr "SYNTAX" - -#: ../tools/create_manpage.py:76 -msgid "OPTIONS" -msgstr "OPTIONEN" +#. C is the shape formed by the cube labels +#: ../data/plugins/80-pretty-patterns.algorithm.py:110 +msgid "C" +msgstr "C" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:113 +msgid "Cube in a Cube" +msgstr "Würfel im Würfel" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:117 +msgid "Striped Cube in a Cube" +msgstr "gestreifter Würfel im Würfel" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:121 +msgid "Six Square Cuboids" +msgstr "Sechs quadratische Quader" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:125 +msgid "Superflip" +msgstr "Superflip" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:129 +msgid "Superflip easy" +msgstr "Superflip einfach" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:133 +msgid "Green Mamba" +msgstr "Grüne Mamba" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:137 +msgid "Anaconda" +msgstr "Anakonda" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:141 +msgid "Duck Feet" +msgstr "Entenfüße" + +#: ../data/plugins/90-library.algorithm.py:20 +#: ../data/plugins/90-library.algorithm.py:23 +#: ../data/plugins/90-library.algorithm.py:26 +#: ../data/plugins/90-library.algorithm.py:29 +#: ../data/plugins/90-library.algorithm.py:32 +#: ../data/plugins/90-library.algorithm.py:35 +#: ../data/plugins/90-library.algorithm.py:38 +#: ../data/plugins/90-library.algorithm.py:41 +#: ../data/plugins/90-library.algorithm.py:44 +#: ../data/plugins/90-library.algorithm.py:47 +#: ../data/plugins/90-library.algorithm.py:50 +msgid "Library" +msgstr "Sammlung" + +#: ../data/plugins/90-library.algorithm.py:21 +#: ../data/plugins/90-library.algorithm.py:24 +msgid "Middle Layer" +msgstr "Mittlere Schicht" + +#: ../data/plugins/90-library.algorithm.py:22 +msgid "Front to Right" +msgstr "Vorne nach Rechts" + +#: ../data/plugins/90-library.algorithm.py:25 +msgid "Front to Left" +msgstr "Vorne nach Links" + +#: ../data/plugins/90-library.algorithm.py:27 +#: ../data/plugins/90-library.algorithm.py:30 +#: ../data/plugins/90-library.algorithm.py:33 +#: ../data/plugins/90-library.algorithm.py:36 +msgid "Last Layer" +msgstr "Letzte Schicht" + +#: ../data/plugins/90-library.algorithm.py:28 +msgid "Swap Edges" +msgstr "Tausche Kanten" + +#: ../data/plugins/90-library.algorithm.py:31 +msgid "Flip Edges" +msgstr "Kanten kippen" + +#: ../data/plugins/90-library.algorithm.py:34 +msgid "Swap Corners" +msgstr "Ecken vertauschen" + +#: ../data/plugins/90-library.algorithm.py:37 +msgid "Rotate Corners" +msgstr "Ecken drehen" + +#: ../data/plugins/90-library.algorithm.py:39 +#: ../data/plugins/90-library.algorithm.py:42 +#: ../data/plugins/90-library.algorithm.py:45 +msgid "Rotate Center" +msgstr "Zentrum drehen" + +#: ../data/plugins/90-library.algorithm.py:40 +msgid "2×Up" +msgstr "2×Oben" + +#: ../data/plugins/90-library.algorithm.py:43 +msgid "Up and Front" +msgstr "Oben und Vorne" + +#: ../data/plugins/90-library.algorithm.py:46 +msgid "Up and Down" +msgstr "Oben und Unten" + +#: ../data/plugins/90-library.algorithm.py:48 +#: ../data/plugins/90-library.algorithm.py:51 +msgid "Misc" +msgstr "Verschiedenes" + +#: ../data/plugins/90-library.algorithm.py:49 +msgid "Back without Back" +msgstr "Hinten ohne Hinten" + +#: ../data/plugins/90-library.algorithm.py:52 +msgid "2×Back without Back" +msgstr "2×Hinten ohne Hinten" diff -Nru pybik-0.5/po/en_GB.po pybik-1.0.1/po/en_GB.po --- pybik-0.5/po/en_GB.po 2012-01-06 17:19:35.000000000 +0000 +++ pybik-1.0.1/po/en_GB.po 2013-02-01 20:18:02.000000000 +0000 @@ -6,587 +6,898 @@ msgid "" msgstr "" "Project-Id-Version: pybik\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-01-06 18:15+0100\n" -"PO-Revision-Date: 2011-06-22 12:01+0000\n" -"Last-Translator: B Clausius \n" +"Report-Msgid-Bugs-To: https://bugs.launchpad.net/pybik/+filebug\n" +"POT-Creation-Date: 2013-01-31 14:25+0100\n" +"PO-Revision-Date: 2013-01-15 18:58+0000\n" +"Last-Translator: Andi Chandler \n" "Language-Team: \n" +"Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Launchpad-Export-Date: 2012-01-05 05:46+0000\n" -"X-Generator: Launchpad (build 14625)\n" -"Language: \n" +"X-Launchpad-Export-Date: 2013-01-16 04:47+0000\n" +"X-Generator: Launchpad (build 16420)\n" -#: ../pybiklib/application.py:140 -msgid "Name" -msgstr "" +#: ../pybiklib/application.py:304 +msgid "Press the Esc key to exit Edit Mode" +msgstr "Press the Esc key to exit Edit Mode" -#: ../pybiklib/application.py:420 -msgid "not solved" -msgstr "" +#. substitution for {move_text} in statusbar text +#: ../pybiklib/application.py:313 +msgid "{current} / {total} move" +msgid_plural "{current} / {total} moves" +msgstr[0] "{current} / {total} move" +msgstr[1] "{current} / {total} moves" -#: ../pybiklib/application.py:420 +#. substitution for {solved_text} in statusbar text +#: ../pybiklib/application.py:317 ../pybiklib/ui/model.py:82 msgid "solved" -msgstr "" +msgstr "solved" -#: ../pybiklib/application.py:424 -msgid "{current} / {total} move" -msgid_plural "{current} / {total} moves" -msgstr[0] "" -msgstr[1] "" +#: ../pybiklib/application.py:317 +msgid "not solved" +msgstr "not solved" + +#. statusbar text +#: ../pybiklib/application.py:320 +msgid "{model_text}, {move_text}, {solved_text}" +msgstr "{model_text}, {move_text}, {solved_text}" + +#: ../pybiklib/application.py:353 +msgid "Congratulations, you have solved the puzzle!" +msgstr "Congratulations, you have solved the puzzle!" -#: ../pybiklib/config.py:41 ../pybiklib/config.py:42 +#: ../pybiklib/config.py:30 ../pybiklib/ui/main.py:194 #: ../data/applications/pybik.desktop.in.h:1 msgid "Pybik" -msgstr "" +msgstr "Pybik" -#: ../pybiklib/config.py:43 -msgid "Pybik is a 3 dimensional magic cube game." -msgstr "" +#: ../pybiklib/config.py:59 ../data/applications/pybik.desktop.in.h:2 +msgid "3D Rubik's cube game" +msgstr "3D Rubik's cube game" -#: ../pybiklib/config.py:44 -msgid "Pybik web site" -msgstr "" +#: ../pybiklib/config.py:61 +msgid "" +"Pybik is an interactive, graphical, single player puzzle about the cube " +"invented by Ernő Rubik. Besides the cube the program can handle towers and " +"bricks (non cubic puzzles). Pybik also has solvers, pretty patterns and a " +"collection of various moves. The cube can be manipulated with the mouse or " +"keyboard. You can change the colors or images on the faces of the cube." +msgstr "" +"Pybik is an interactive, graphical, single player puzzle about the cube " +"invented by Ernő Rubik. Besides the cube the program can handle towers and " +"bricks (non cubic puzzles). Pybik also has solvers, pretty patterns and a " +"collection of various moves. The cube can be manipulated with the mouse or " +"keyboard. You can change the colours or images on the faces of the cube." -#: ../pybiklib/config.py:47 +#: ../pybiklib/config.py:69 msgid "" "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." -msgstr "" - -#: ../pybiklib/config.py:52 -msgid "" +"any later version.\n" +"\n" "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." msgstr "" +"This program is free software: you can redistribute it and/or modify it " +"under the terms of the GNU General Public Licence as published by the Free " +"Software Foundation, either version 3 of the Licence, or (at your option) " +"any later version.\n" +"\n" +"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 Licence for " +"more details." + +#: ../pybiklib/config.py:79 +msgid "" +"Read the full text of the GNU General Public " +"License<|> or see ." +msgstr "" +"Read the full text of the GNU General Public " +"Licence<|> or see ." -#: ../pybiklib/config.py:57 +#: ../pybiklib/config.py:82 msgid "" "You should have received a copy of the GNU General Public License along with " "this program. If not, see ." msgstr "" +"You should have received a copy of the GNU General Public Licence along with " +"this program. If not, see ." + +#: ../pybiklib/config.py:88 +msgid "" +"If you find any bugs in Pybik or have a suggestion for an improvement then " +"please submit a <{CONTACT_FILEBUG}|>bug report<|>. In the latter case you " +"can mark the bug report as \"Wishlist\"." +msgstr "" +"If you find any bugs in Pybik or have a suggestion for an improvement then " +"please submit a <{CONTACT_FILEBUG}|>bug report<|>. In the latter case you " +"can mark the bug report as \"Wishlist\"." -#: ../pybiklib/dialogcolors.py:91 +#: ../pybiklib/config.py:94 +msgid "" +"Translations are managed by the Launchpad translation group<|>.\n" +"\n" +"If you want help to translate Pybik to your language you can do it through " +"the web interface<|>.\n" +"\n" +"Read more about \"Translating with " +"Launchpad\"<|> and \"Starting to translate\"<|>." +msgstr "" +"Translations are managed by the Launchpad translation group<|>.\n" +"\n" +"If you want help to translate Pybik to your language you can do it through " +"the web interface<|>.\n" +"\n" +"Read more about \"Translating with " +"Launchpad\"<|> and \"Starting to translate\"<|>." + +#: ../pybiklib/dialogs.py:168 +msgid "Press a key …" +msgstr "Press a key …" + +#: ../pybiklib/dialogs.py:296 +msgid "plain" +msgstr "plain" + +#: ../pybiklib/dialogs.py:301 +msgid "select …" +msgstr "select …" + +#: ../pybiklib/dialogs.py:313 msgid "Up" -msgstr "" +msgstr "Up" -#: ../pybiklib/dialogcolors.py:91 +#: ../pybiklib/dialogs.py:313 msgid "Down" -msgstr "" +msgstr "Down" -#: ../pybiklib/dialogcolors.py:91 +#: ../pybiklib/dialogs.py:313 msgid "Left" -msgstr "" +msgstr "Left" -#: ../pybiklib/dialogcolors.py:91 +#: ../pybiklib/dialogs.py:313 msgid "Right" -msgstr "" +msgstr "Right" -#: ../pybiklib/dialogcolors.py:91 +#: ../pybiklib/dialogs.py:313 msgid "Front" -msgstr "" +msgstr "Front" -#: ../pybiklib/dialogcolors.py:91 +#: ../pybiklib/dialogs.py:313 msgid "Back" -msgstr "" +msgstr "Back" -#: ../pybiklib/dialogcolors.py:103 -msgid "Face" -msgstr "" +#: ../pybiklib/dialogs.py:331 +msgid "Move" +msgstr "Move" -#: ../pybiklib/dialogcolors.py:118 -msgid "plain" +#: ../pybiklib/dialogs.py:332 +msgid "Key" +msgstr "Key" + +#: ../pybiklib/dialogs.py:486 +msgid "Open Image" +msgstr "Open Image" + +#: ../pybiklib/dialogs.py:536 ../pybiklib/ui/model.py:79 +msgid "Size:" +msgstr "Size:" + +#: ../pybiklib/dialogs.py:536 +msgid "Basis:" msgstr "" -#: ../pybiklib/dialogs.py:100 +#: ../pybiklib/dialogs.py:536 +msgid "Width:" +msgstr "Width:" + +#: ../pybiklib/dialogs.py:565 +msgid "Canceling operation, please wait" +msgstr "Canceling operation, please wait" + +#: ../pybiklib/dialogs.py:621 +msgid "Pybik project website" +msgstr "Pybik project website" + +#: ../pybiklib/main.py:287 msgid "" -"The Dimension of the cube has changed.\n" -"Start cube with new settings?" +"An error occurred while reading the settings:\n" +"{error_message}" msgstr "" +"An error occurred while reading the settings:\n" +"{error_message}" -#: ../pybiklib/glarea.py:624 -msgid "Cannot create image from file {filename}: {error}" -msgstr "" +#: ../pybiklib/model.py:214 +msgid "Brick" +msgstr "Brick" -#. Translators: Strings from file main.py are visible only on the commandline and/or in the man-page -#: ../pybiklib/main.py:32 -msgid "usage: " -msgstr "" +#: ../pybiklib/model.py:215 +msgid "{0}×{1}×{2}-Brick" +msgstr "{0}×{1}×{2}-Brick" -#: ../pybiklib/main.py:33 -msgid "optional arguments" -msgstr "" +#: ../pybiklib/model.py:835 +msgid "Tower" +msgstr "Tower" -#: ../pybiklib/main.py:149 -msgid "Show help message and exit" -msgstr "" +#: ../pybiklib/model.py:836 +msgid "{0}×{1}-Tower" +msgstr "{0}×{1}-Tower" -#: ../pybiklib/main.py:151 -msgid "Show version number and exit" -msgstr "" +#: ../pybiklib/model.py:850 +msgid "Cube" +msgstr "Cube" -#: ../pybiklib/main.py:153 -msgid "Start with the cube already solved" -msgstr "" +#: ../pybiklib/model.py:851 +msgid "{0}×{0}×{0}-Cube" +msgstr "{0}×{0}×{0}-Cube" + +#: ../pybiklib/plugins.py:92 +msgid "This algorithm does not work for any model.\n" +msgstr "This algorithm does not work for any model.\n" + +#: ../pybiklib/plugins.py:94 ../pybiklib/plugins.py:97 +msgid "This algorithm only works for:\n" +msgstr "This algorithm only works for:\n" -#: ../pybiklib/main.py:155 -msgid "Start with a N x N x N sized cube" +#: ../pybiklib/settings.py:256 +msgid "Settings can not be written to file: {error_message}" +msgstr "Settings can not be written to file: {error_message}" + +#: ../pybiklib/ui/about.py:131 +msgid "About Pybik" +msgstr "About Pybik" + +#: ../pybiklib/ui/about.py:132 +msgid "About" +msgstr "About" + +#: ../pybiklib/ui/about.py:133 +msgid "Feedback" +msgstr "Feedback" + +#: ../pybiklib/ui/about.py:134 +msgid "Translation" +msgstr "Translation" + +#: ../pybiklib/ui/about.py:135 +msgid "License" +msgstr "Licence" + +#: ../pybiklib/ui/main.py:195 +msgid "&Game" +msgstr "&Game" + +#: ../pybiklib/ui/main.py:196 +msgid "&Edit" +msgstr "&Edit" + +#: ../pybiklib/ui/main.py:197 +msgid "&View" msgstr "" -#: ../pybiklib/main.py:157 -msgid "Show N intermediate positions in animations" +#: ../pybiklib/ui/main.py:198 +msgid "&Help" msgstr "" -#: ../pybiklib/main.py:159 -msgid "Use python module for rendering (very slow)" +#: ../pybiklib/ui/main.py:199 +msgid "Pybik Toolbar" +msgstr "Pybik Toolbar" + +#: ../pybiklib/ui/main.py:200 +msgid "&New Random" +msgstr "&New Random" + +#: ../pybiklib/ui/main.py:201 +msgid "Ne&w Solved" +msgstr "Ne&w Solved" + +#: ../pybiklib/ui/main.py:202 +msgid "&Quit" +msgstr "&Quit" + +#: ../pybiklib/ui/main.py:203 +msgid "&Select Model …" +msgstr "&Select Model …" + +#: ../pybiklib/ui/main.py:204 +msgid "&Set as Initial State" +msgstr "&Set as Initial State" + +#: ../pybiklib/ui/main.py:205 +msgid "&Reset Rotation" +msgstr "&Reset Rotation" + +#: ../pybiklib/ui/main.py:206 +msgid "&Invert Moves" msgstr "" -#: ../pybiklib/main.py:161 -msgid "" -"Enable debug output, D is an integer or a comma-separated list of [{0}]" +#: ../pybiklib/ui/main.py:207 +msgid "Reload Plugins" +msgstr "Reload Plug-ins" + +#: ../pybiklib/ui/main.py:208 +msgid "&Preferences …" +msgstr "&Preferences …" + +#: ../pybiklib/ui/main.py:209 +msgid "&Toolbar" +msgstr "&Toolbar" + +#: ../pybiklib/ui/main.py:210 +msgid "&Status Bar" +msgstr "&Status Bar" + +#: ../pybiklib/ui/main.py:211 +msgid "&Info …" +msgstr "&Info …" + +#: ../pybiklib/ui/main.py:212 +msgid "Rewind" msgstr "" -#: ../pybiklib/main.py:178 -msgid "debug level out of range: {0}" +#: ../pybiklib/ui/main.py:213 +msgid "Go to the previous mark (or the beginning) of the sequence of moves" msgstr "" -#: ../pybiklib/main.py:186 -msgid "unknown debug option: {0}" +#: ../pybiklib/ui/main.py:214 +msgid "Previous" msgstr "" -#: ../pybiklib/plugins.py:276 -msgid "This script only works for:" +#: ../pybiklib/ui/main.py:215 +msgid "Make one step backwards" msgstr "" -#: ../pybiklib/textures.py:177 -msgid "Pixbuf has wrong number of channels" +#: ../pybiklib/ui/main.py:216 +msgid "Stop" msgstr "" -#: ../pybiklib/textures.py:180 -msgid "Pixbuf has unknown color space: {0}" -msgstr "Pixbuf has unknown colour space: {0}" +#: ../pybiklib/ui/main.py:217 +msgid "Stop running the sequence of moves" +msgstr "" -#: ../data/ui/pybik.ui.h:1 -msgid "Add mark" +#: ../pybiklib/ui/main.py:218 +msgid "Play" msgstr "" -#: ../data/ui/pybik.ui.h:2 -msgid "Animation:" +#: ../pybiklib/ui/main.py:219 +msgid "Run forward through the sequence of moves" msgstr "" -#: ../data/ui/pybik.ui.h:3 -msgid "Background:" +#: ../pybiklib/ui/main.py:220 +msgid "Next" msgstr "" -#: ../data/ui/pybik.ui.h:4 -msgid "Color selector" -msgstr "Colour selector" +#: ../pybiklib/ui/main.py:221 +msgid "Make one step forwards" +msgstr "" -#: ../data/ui/pybik.ui.h:5 -msgid "Color:" -msgstr "Colour:" +#: ../pybiklib/ui/main.py:222 +msgid "Forward" +msgstr "" -#: ../data/ui/pybik.ui.h:6 -msgid "Displays the sequence of moves" +#: ../pybiklib/ui/main.py:223 +msgid "Go to the next mark (or the end) of the sequence of moves" msgstr "" -#: ../data/ui/pybik.ui.h:7 -msgid "Four directions" +#: ../pybiklib/ui/main.py:224 +msgid "Add Mark" msgstr "" -#: ../data/ui/pybik.ui.h:8 -msgid "General" +#: ../pybiklib/ui/main.py:225 +msgid "Mark the current place in the sequence of moves" msgstr "" -#: ../data/ui/pybik.ui.h:9 -msgid "Go to the next mark (or the end) of the sequence of moves" +#: ../pybiklib/ui/main.py:226 +msgid "Remove Mark" msgstr "" -#: ../data/ui/pybik.ui.h:10 -msgid "Go to the previous mark (or the beginning) of the sequence of moves" +#: ../pybiklib/ui/main.py:227 +msgid "Remove the mark at the current place in the sequence of moves" msgstr "" -#: ../data/ui/pybik.ui.h:11 -msgid "Image File:" +#: ../pybiklib/ui/main.py:228 +msgid "&Edit Bar" msgstr "" -#: ../data/ui/pybik.ui.h:12 -msgid "Lighting" +#: ../pybiklib/ui/main.py:229 +msgid "Normalize Cube Rotations" msgstr "" -#: ../data/ui/pybik.ui.h:13 -msgid "Make one step backwards" +#: ../pybiklib/ui/model.py:78 +msgid "Select Model" msgstr "" -#: ../data/ui/pybik.ui.h:14 -msgid "Make one step forwards" +#: ../pybiklib/ui/model.py:80 +msgid "Height:" msgstr "" -#: ../data/ui/pybik.ui.h:15 -msgid "Makes the cube appear illuminated" +#: ../pybiklib/ui/model.py:81 +msgid "Depth:" msgstr "" -#: ../data/ui/pybik.ui.h:16 -msgid "Mark the current place in the sequence of moves" +#: ../pybiklib/ui/preferences.py:252 +msgid "Preferences" msgstr "" -#: ../data/ui/pybik.ui.h:17 -msgid "Mouse" +#: ../pybiklib/ui/preferences.py:253 +msgid "Animation Speed:" msgstr "" -#: ../data/ui/pybik.ui.h:18 -msgid "New _solved" +#: ../pybiklib/ui/preferences.py:254 +msgid "Lighting" msgstr "" -#: ../data/ui/pybik.ui.h:19 -msgid "New random cube" +#: ../pybiklib/ui/preferences.py:255 +msgid "Mirror Distance:" msgstr "" -#: ../data/ui/pybik.ui.h:20 -msgid "New solved cube" +#: ../pybiklib/ui/preferences.py:256 +msgid "Antialiasing" msgstr "" -#: ../data/ui/pybik.ui.h:21 -msgid "Pattern:" +#: ../pybiklib/ui/preferences.py:257 +msgid "Hardware:" msgstr "" -#: ../data/ui/pybik.ui.h:22 -msgid "" -"Place a copy of the image\n" -"on each block" +#: ../pybiklib/ui/preferences.py:258 +msgid "Software:" msgstr "" -#: ../data/ui/pybik.ui.h:24 +#: ../pybiklib/ui/preferences.py:259 msgid "" -"Place a copy of the image across\n" -"the entire face of the cube" +"

The program needs to " +"be restarted for the changes to take effect.

" msgstr "" -#: ../data/ui/pybik.ui.h:26 -msgid "Play Toolbar" +#: ../pybiklib/ui/preferences.py:260 +msgid "Graphic" msgstr "" -#: ../data/ui/pybik.ui.h:27 -msgid "Preferences" +#: ../pybiklib/ui/preferences.py:261 +msgid "Four directions" msgstr "" -#: ../data/ui/pybik.ui.h:28 -msgid "Remove mark" +#: ../pybiklib/ui/preferences.py:262 +msgid "" +"Simplified,\n" +"right button inverts move" msgstr "" -#: ../data/ui/pybik.ui.h:29 -msgid "Remove the mark at the current place in the sequence of moves" +#: ../pybiklib/ui/preferences.py:263 +msgid "Mouse" msgstr "" -#: ../data/ui/pybik.ui.h:30 -msgid "Rese_t rotation" +#: ../pybiklib/ui/preferences.py:264 ../pybiklib/ui/preferences.py:265 +msgid "Add" msgstr "" -#: ../data/ui/pybik.ui.h:31 -msgid "Run forward through the sequence of moves" +#: ../pybiklib/ui/preferences.py:266 ../pybiklib/ui/preferences.py:267 +msgid "Remove" msgstr "" -#: ../data/ui/pybik.ui.h:32 -msgid "Select a color" -msgstr "Select a colour" - -#: ../data/ui/pybik.ui.h:33 -msgid "Select image file" +#: ../pybiklib/ui/preferences.py:268 ../pybiklib/ui/preferences.py:269 +msgid "Reset" msgstr "" -#: ../data/ui/pybik.ui.h:34 -msgid "Sets the number of blocks in each side" +#: ../pybiklib/ui/preferences.py:270 +msgid "Keys" msgstr "" -#: ../data/ui/pybik.ui.h:35 -msgid "" -"Simplified,\n" -"right button\n" -"inverts move" +#: ../pybiklib/ui/preferences.py:271 +msgid "Color:" +msgstr "Colour:" + +#: ../pybiklib/ui/preferences.py:272 +msgid "Image File:" msgstr "" -#: ../data/ui/pybik.ui.h:38 -msgid "Size:" +#: ../pybiklib/ui/preferences.py:273 +msgid "Tiled" msgstr "" -#: ../data/ui/pybik.ui.h:39 -msgid "Status Bar" +#: ../pybiklib/ui/preferences.py:274 +msgid "Mosaic" msgstr "" -#: ../data/ui/pybik.ui.h:40 -msgid "Stop running the sequence of moves" +#: ../pybiklib/ui/preferences.py:275 +msgid "Background:" msgstr "" -#: ../data/ui/pybik.ui.h:41 -msgid "Use an image file on the cube face" +#: ../pybiklib/ui/preferences.py:276 +msgid "Appearance" msgstr "" -#: ../data/ui/pybik.ui.h:42 -msgid "_Dynamic script selection" +#. Add whatever keywords you want in your language, separated by semicolons. These keywords are used when searching for applications in dashes, etc. (Unity, GNOME Shell) +#: ../data/applications/pybik.desktop.in.h:4 +msgid "rubik;cube;puzzle;magic;" msgstr "" -#: ../data/ui/pybik.ui.h:43 -msgid "_Edit" +#: ../data/plugins/01-challenges.algorithm.py:19 +#: ../data/plugins/01-challenges.algorithm.py:22 +#: ../data/plugins/01-challenges.algorithm.py:25 +#: ../data/plugins/01-challenges.algorithm.py:28 +#: ../data/plugins/01-challenges.algorithm.py:31 +#: ../data/plugins/01-challenges.algorithm.py:34 +#: ../data/plugins/01-challenges.algorithm.py:37 +#: ../data/plugins/01-challenges.algorithm.py:40 +#: ../data/plugins/01-challenges.algorithm.py:43 +#: ../data/plugins/01-challenges.algorithm.py:46 +#: ../data/plugins/01-challenges.algorithm.py:49 +msgid "Challenges" msgstr "" -#: ../data/ui/pybik.ui.h:44 -msgid "_Game" +#: ../data/plugins/01-challenges.algorithm.py:20 +msgid "Solve random cube" msgstr "" -#: ../data/ui/pybik.ui.h:45 -msgid "_Help" +#: ../data/plugins/01-challenges.algorithm.py:23 +msgid "Solve in 1 move" msgstr "" -#: ../data/ui/pybik.ui.h:46 -msgid "_Invert moves" +#: ../data/plugins/01-challenges.algorithm.py:26 +msgid "Solve in 2 moves" msgstr "" -#: ../data/ui/pybik.ui.h:47 -msgid "_Mosaic" +#: ../data/plugins/01-challenges.algorithm.py:29 +msgid "Solve in 3 moves" msgstr "" -#: ../data/ui/pybik.ui.h:48 -msgid "_New random" +#: ../data/plugins/01-challenges.algorithm.py:32 +msgid "Solve in 4 moves" msgstr "" -#: ../data/ui/pybik.ui.h:49 -msgid "_Play Toolbar" +#: ../data/plugins/01-challenges.algorithm.py:35 +msgid "Solve in 5 moves" msgstr "" -#: ../data/ui/pybik.ui.h:50 -msgid "_Reload scripts" +#: ../data/plugins/01-challenges.algorithm.py:38 +msgid "Solve in 6 moves" msgstr "" -#: ../data/ui/pybik.ui.h:51 -msgid "_Set as initial state" +#: ../data/plugins/01-challenges.algorithm.py:41 +msgid "Solve in 7 moves" msgstr "" -#: ../data/ui/pybik.ui.h:52 -msgid "_Status Bar" +#: ../data/plugins/01-challenges.algorithm.py:44 +msgid "Solve in 8 moves" msgstr "" -#: ../data/ui/pybik.ui.h:53 -msgid "_Tiled" +#: ../data/plugins/01-challenges.algorithm.py:47 +msgid "Solve in 9 moves" msgstr "" -#: ../data/ui/pybik.ui.h:54 -msgid "_View" +#: ../data/plugins/01-challenges.algorithm.py:50 +msgid "Solve in 10 moves" msgstr "" -#: ../data/scripts/10-spiegel.script.py:20 -#: ../data/scripts/10-spiegel.script.py:23 -#: ../data/scripts/10-spiegel.script.py:50 -#: ../data/scripts/10-spiegel.script.py:69 -#: ../data/scripts/10-spiegel.script.py:84 -#: ../data/scripts/10-spiegel.script.py:94 -#: ../data/scripts/10-spiegel.script.py:108 -#: ../data/scripts/10-spiegel.script.py:116 -#: ../data/scripts/11-spiegel-improved.script.py:20 -#: ../data/scripts/11-spiegel-improved.script.py:23 -#: ../data/scripts/11-spiegel-improved.script.py:67 -#: ../data/scripts/11-spiegel-improved.script.py:105 -#: ../data/scripts/11-spiegel-improved.script.py:137 -#: ../data/scripts/11-spiegel-improved.script.py:160 -#: ../data/scripts/11-spiegel-improved.script.py:175 -#: ../data/scripts/11-spiegel-improved.script.py:186 -#: ../data/scripts/15-mellor_solve.py:370 ../data/scripts/20-2x2x2.script.py:5 -#: ../data/scripts/20-2x2x2.script.py:8 ../data/scripts/20-2x2x2.script.py:27 -#: ../data/scripts/20-2x2x2.script.py:47 +#: ../data/plugins/10-spiegel.algorithm.py:35 +#: ../data/plugins/10-spiegel.algorithm.py:38 +#: ../data/plugins/10-spiegel.algorithm.py:67 +#: ../data/plugins/10-spiegel.algorithm.py:88 +#: ../data/plugins/10-spiegel.algorithm.py:103 +#: ../data/plugins/10-spiegel.algorithm.py:116 +#: ../data/plugins/10-spiegel.algorithm.py:133 +#: ../data/plugins/10-spiegel.algorithm.py:144 +#: ../data/plugins/11-spiegel-improved.algorithm.py:35 +#: ../data/plugins/11-spiegel-improved.algorithm.py:38 +#: ../data/plugins/11-spiegel-improved.algorithm.py:83 +#: ../data/plugins/11-spiegel-improved.algorithm.py:122 +#: ../data/plugins/11-spiegel-improved.algorithm.py:154 +#: ../data/plugins/11-spiegel-improved.algorithm.py:180 +#: ../data/plugins/11-spiegel-improved.algorithm.py:198 +#: ../data/plugins/11-spiegel-improved.algorithm.py:212 +#: ../data/plugins/12-lbl-leyan.algorithm.py:22 +#: ../data/plugins/12-lbl-leyan.algorithm.py:25 +#: ../data/plugins/12-lbl-leyan.algorithm.py:54 +#: ../data/plugins/12-lbl-leyan.algorithm.py:75 +#: ../data/plugins/12-lbl-leyan.algorithm.py:91 +#: ../data/plugins/12-lbl-leyan.algorithm.py:108 +#: ../data/plugins/12-lbl-leyan.algorithm.py:130 +#: ../data/plugins/12-lbl-leyan.algorithm.py:171 +#: ../data/plugins/20-2x2x2.algorithm.py:19 +#: ../data/plugins/20-2x2x2.algorithm.py:22 +#: ../data/plugins/20-2x2x2.algorithm.py:41 +#: ../data/plugins/20-2x2x2.algorithm.py:61 msgid "Solvers" msgstr "" -#: ../data/scripts/10-spiegel.script.py:20 -#: ../data/scripts/10-spiegel.script.py:23 -#: ../data/scripts/10-spiegel.script.py:50 -#: ../data/scripts/10-spiegel.script.py:69 -#: ../data/scripts/10-spiegel.script.py:84 -#: ../data/scripts/10-spiegel.script.py:94 -#: ../data/scripts/10-spiegel.script.py:108 -#: ../data/scripts/10-spiegel.script.py:116 +#. Spiegel is the name of a solution method +#: ../data/plugins/10-spiegel.algorithm.py:37 +#: ../data/plugins/10-spiegel.algorithm.py:39 +#: ../data/plugins/10-spiegel.algorithm.py:68 +#: ../data/plugins/10-spiegel.algorithm.py:89 +#: ../data/plugins/10-spiegel.algorithm.py:104 +#: ../data/plugins/10-spiegel.algorithm.py:117 +#: ../data/plugins/10-spiegel.algorithm.py:134 +#: ../data/plugins/10-spiegel.algorithm.py:145 msgid "Spiegel" msgstr "" -#: ../data/scripts/10-spiegel.script.py:23 -#: ../data/scripts/11-spiegel-improved.script.py:23 -#: ../data/scripts/15-mellor_solve.py:373 +#: ../data/plugins/10-spiegel.algorithm.py:40 +#: ../data/plugins/11-spiegel-improved.algorithm.py:40 +#: ../data/plugins/12-lbl-leyan.algorithm.py:27 msgid "Top edges" msgstr "" -#: ../data/scripts/10-spiegel.script.py:50 -#: ../data/scripts/11-spiegel-improved.script.py:67 +#: ../data/plugins/10-spiegel.algorithm.py:69 +#: ../data/plugins/11-spiegel-improved.algorithm.py:85 +#: ../data/plugins/12-lbl-leyan.algorithm.py:56 msgid "Top corners" msgstr "" -#: ../data/scripts/10-spiegel.script.py:69 -#: ../data/scripts/11-spiegel-improved.script.py:105 -#: ../data/scripts/15-mellor_solve.py:375 +#: ../data/plugins/10-spiegel.algorithm.py:90 +#: ../data/plugins/11-spiegel-improved.algorithm.py:124 +#: ../data/plugins/12-lbl-leyan.algorithm.py:77 msgid "Middle slice" msgstr "" -#: ../data/scripts/10-spiegel.script.py:84 -#: ../data/scripts/11-spiegel-improved.script.py:137 -#: ../data/scripts/15-mellor_solve.py:378 +#: ../data/plugins/10-spiegel.algorithm.py:105 +#: ../data/plugins/11-spiegel-improved.algorithm.py:156 +#: ../data/plugins/12-lbl-leyan.algorithm.py:173 msgid "Bottom edge place" msgstr "" -#: ../data/scripts/10-spiegel.script.py:94 -#: ../data/scripts/11-spiegel-improved.script.py:160 -#: ../data/scripts/15-mellor_solve.py:379 +#: ../data/plugins/10-spiegel.algorithm.py:118 +#: ../data/plugins/11-spiegel-improved.algorithm.py:182 +#: ../data/plugins/12-lbl-leyan.algorithm.py:93 msgid "Bottom edge orient" msgstr "" -#: ../data/scripts/10-spiegel.script.py:108 -#: ../data/scripts/11-spiegel-improved.script.py:175 -#: ../data/scripts/15-mellor_solve.py:376 -#: ../data/scripts/20-2x2x2.script.py:27 +#: ../data/plugins/10-spiegel.algorithm.py:135 +#: ../data/plugins/11-spiegel-improved.algorithm.py:200 +#: ../data/plugins/12-lbl-leyan.algorithm.py:110 +#: ../data/plugins/20-2x2x2.algorithm.py:43 msgid "Bottom corner place" msgstr "" -#: ../data/scripts/10-spiegel.script.py:116 -#: ../data/scripts/11-spiegel-improved.script.py:186 -#: ../data/scripts/15-mellor_solve.py:377 -#: ../data/scripts/20-2x2x2.script.py:47 +#: ../data/plugins/10-spiegel.algorithm.py:146 +#: ../data/plugins/11-spiegel-improved.algorithm.py:214 +#: ../data/plugins/12-lbl-leyan.algorithm.py:132 +#: ../data/plugins/20-2x2x2.algorithm.py:63 msgid "Bottom corner orient" msgstr "" -#: ../data/scripts/11-spiegel-improved.script.py:20 -#: ../data/scripts/11-spiegel-improved.script.py:23 -#: ../data/scripts/11-spiegel-improved.script.py:67 -#: ../data/scripts/11-spiegel-improved.script.py:105 -#: ../data/scripts/11-spiegel-improved.script.py:137 -#: ../data/scripts/11-spiegel-improved.script.py:160 -#: ../data/scripts/11-spiegel-improved.script.py:175 -#: ../data/scripts/11-spiegel-improved.script.py:186 +#. Spiegel is the name of a solution method +#: ../data/plugins/11-spiegel-improved.algorithm.py:37 +#: ../data/plugins/11-spiegel-improved.algorithm.py:39 +#: ../data/plugins/11-spiegel-improved.algorithm.py:84 +#: ../data/plugins/11-spiegel-improved.algorithm.py:123 +#: ../data/plugins/11-spiegel-improved.algorithm.py:155 +#: ../data/plugins/11-spiegel-improved.algorithm.py:181 +#: ../data/plugins/11-spiegel-improved.algorithm.py:199 +#: ../data/plugins/11-spiegel-improved.algorithm.py:213 msgid "Spiegel improved" msgstr "" -#: ../data/scripts/15-mellor_solve.py:351 -msgid "This script only works on 3x3x3 cubes." -msgstr "" - -#. Translators: "Mellor" is the name of the original Author of the algorithm for this solution -#: ../data/scripts/15-mellor_solve.py:372 -msgid "Mellor (3x3)" +#. Leyan Lo is the inventor of the solution method +#: ../data/plugins/12-lbl-leyan.algorithm.py:24 +#: ../data/plugins/12-lbl-leyan.algorithm.py:26 +#: ../data/plugins/12-lbl-leyan.algorithm.py:55 +#: ../data/plugins/12-lbl-leyan.algorithm.py:76 +#: ../data/plugins/12-lbl-leyan.algorithm.py:92 +#: ../data/plugins/12-lbl-leyan.algorithm.py:109 +#: ../data/plugins/12-lbl-leyan.algorithm.py:131 +#: ../data/plugins/12-lbl-leyan.algorithm.py:172 +msgid "Layer Method (Leyan Lo)" +msgstr "" + +#: ../data/plugins/20-2x2x2.algorithm.py:20 +#: ../data/plugins/20-2x2x2.algorithm.py:23 +#: ../data/plugins/20-2x2x2.algorithm.py:42 +#: ../data/plugins/20-2x2x2.algorithm.py:62 +msgid "2×2×2" msgstr "" -#: ../data/scripts/15-mellor_solve.py:374 ../data/scripts/20-2x2x2.script.py:8 +#: ../data/plugins/20-2x2x2.algorithm.py:24 msgid "Top slice" msgstr "" -#: ../data/scripts/20-2x2x2.script.py:5 ../data/scripts/20-2x2x2.script.py:8 -#: ../data/scripts/20-2x2x2.script.py:27 ../data/scripts/20-2x2x2.script.py:47 -msgid "2×2×2" -msgstr "" - -#: ../data/scripts/80-pretty_patterns.py:42 -msgid "" -"This pretty pattern only works on cubes\n" -"with at least {count} slice." -msgid_plural "" -"This pretty pattern only works on cubes\n" -"with at least {count} slices." -msgstr[0] "" -msgstr[1] "" - -#: ../data/scripts/80-pretty_patterns.py:51 +#: ../data/plugins/80-pretty-patterns.algorithm.py:18 +#: ../data/plugins/80-pretty-patterns.algorithm.py:22 +#: ../data/plugins/80-pretty-patterns.algorithm.py:26 +#: ../data/plugins/80-pretty-patterns.algorithm.py:30 +#: ../data/plugins/80-pretty-patterns.algorithm.py:34 +#: ../data/plugins/80-pretty-patterns.algorithm.py:39 +#: ../data/plugins/80-pretty-patterns.algorithm.py:43 +#: ../data/plugins/80-pretty-patterns.algorithm.py:48 +#: ../data/plugins/80-pretty-patterns.algorithm.py:52 +#: ../data/plugins/80-pretty-patterns.algorithm.py:56 +#: ../data/plugins/80-pretty-patterns.algorithm.py:60 +#: ../data/plugins/80-pretty-patterns.algorithm.py:64 +#: ../data/plugins/80-pretty-patterns.algorithm.py:68 +#: ../data/plugins/80-pretty-patterns.algorithm.py:74 +#: ../data/plugins/80-pretty-patterns.algorithm.py:78 +#: ../data/plugins/80-pretty-patterns.algorithm.py:83 +#: ../data/plugins/80-pretty-patterns.algorithm.py:87 +#: ../data/plugins/80-pretty-patterns.algorithm.py:91 +#: ../data/plugins/80-pretty-patterns.algorithm.py:95 +#: ../data/plugins/80-pretty-patterns.algorithm.py:99 +#: ../data/plugins/80-pretty-patterns.algorithm.py:103 +#: ../data/plugins/80-pretty-patterns.algorithm.py:108 +#: ../data/plugins/80-pretty-patterns.algorithm.py:112 +#: ../data/plugins/80-pretty-patterns.algorithm.py:116 +#: ../data/plugins/80-pretty-patterns.algorithm.py:120 +#: ../data/plugins/80-pretty-patterns.algorithm.py:124 +#: ../data/plugins/80-pretty-patterns.algorithm.py:128 +#: ../data/plugins/80-pretty-patterns.algorithm.py:132 +#: ../data/plugins/80-pretty-patterns.algorithm.py:136 +#: ../data/plugins/80-pretty-patterns.algorithm.py:140 msgid "Pretty patterns" msgstr "" -#: ../data/scripts/80-pretty_patterns.py:56 +#: ../data/plugins/80-pretty-patterns.algorithm.py:19 +#: ../data/plugins/80-pretty-patterns.algorithm.py:23 +#: ../data/plugins/80-pretty-patterns.algorithm.py:27 +#: ../data/plugins/80-pretty-patterns.algorithm.py:31 +#: ../data/plugins/80-pretty-patterns.algorithm.py:35 +#: ../data/plugins/80-pretty-patterns.algorithm.py:40 +#: ../data/plugins/80-pretty-patterns.algorithm.py:44 msgid "Stripes" msgstr "" -#: ../data/scripts/80-pretty_patterns.py:57 +#: ../data/plugins/80-pretty-patterns.algorithm.py:49 +#: ../data/plugins/80-pretty-patterns.algorithm.py:53 msgid "Criss-Cross" msgstr "" -#: ../data/scripts/80-pretty_patterns.py:58 +#: ../data/plugins/80-pretty-patterns.algorithm.py:57 msgid "Fried Eggs" msgstr "" -#: ../data/scripts/80-pretty_patterns.py:59 -msgid "Fried Eggs v2" +#: ../data/plugins/80-pretty-patterns.algorithm.py:61 +msgid "Big Fried Eggs" msgstr "" -#: ../data/scripts/80-pretty_patterns.py:60 +#: ../data/plugins/80-pretty-patterns.algorithm.py:65 msgid "4 Fried Eggs" msgstr "" -#: ../data/scripts/80-pretty_patterns.py:61 -msgid "Chessboard odd" +#: ../data/plugins/80-pretty-patterns.algorithm.py:69 +msgid "Chessboard" msgstr "" -#: ../data/scripts/80-pretty_patterns.py:62 -msgid "Chessboard even" +#: ../data/plugins/80-pretty-patterns.algorithm.py:75 +msgid "Cross" msgstr "" -#: ../data/scripts/80-pretty_patterns.py:63 +#: ../data/plugins/80-pretty-patterns.algorithm.py:79 msgid "Zig Zag" msgstr "" -#: ../data/scripts/80-pretty_patterns.py:64 +#. T is the shape formed by the cube labels +#: ../data/plugins/80-pretty-patterns.algorithm.py:85 +#: ../data/plugins/80-pretty-patterns.algorithm.py:88 +#: ../data/plugins/80-pretty-patterns.algorithm.py:92 +#: ../data/plugins/80-pretty-patterns.algorithm.py:96 +#: ../data/plugins/80-pretty-patterns.algorithm.py:100 +#: ../data/plugins/80-pretty-patterns.algorithm.py:104 msgid "T-Time" msgstr "" -#: ../data/scripts/90-rand.py:39 -msgid "Randomize" +#. C is the shape formed by the cube labels +#: ../data/plugins/80-pretty-patterns.algorithm.py:110 +msgid "C" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:113 +msgid "Cube in a Cube" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:117 +msgid "Striped Cube in a Cube" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:121 +msgid "Six Square Cuboids" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:125 +msgid "Superflip" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:129 +msgid "Superflip easy" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:133 +msgid "Green Mamba" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:137 +msgid "Anaconda" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:141 +msgid "Duck Feet" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:20 +#: ../data/plugins/90-library.algorithm.py:23 +#: ../data/plugins/90-library.algorithm.py:26 +#: ../data/plugins/90-library.algorithm.py:29 +#: ../data/plugins/90-library.algorithm.py:32 +#: ../data/plugins/90-library.algorithm.py:35 +#: ../data/plugins/90-library.algorithm.py:38 +#: ../data/plugins/90-library.algorithm.py:41 +#: ../data/plugins/90-library.algorithm.py:44 +#: ../data/plugins/90-library.algorithm.py:47 +#: ../data/plugins/90-library.algorithm.py:50 +msgid "Library" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:21 +#: ../data/plugins/90-library.algorithm.py:24 +msgid "Middle Layer" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:22 +msgid "Front to Right" msgstr "" -#: ../data/scripts/90-rand.py:42 -msgid "1 Move" +#: ../data/plugins/90-library.algorithm.py:25 +msgid "Front to Left" msgstr "" -#: ../data/scripts/90-rand.py:43 -msgid "2 Moves" +#: ../data/plugins/90-library.algorithm.py:27 +#: ../data/plugins/90-library.algorithm.py:30 +#: ../data/plugins/90-library.algorithm.py:33 +#: ../data/plugins/90-library.algorithm.py:36 +msgid "Last Layer" msgstr "" -#: ../data/scripts/90-rand.py:44 -msgid "3 Moves" +#: ../data/plugins/90-library.algorithm.py:28 +msgid "Swap Edges" msgstr "" -#: ../data/scripts/90-rand.py:45 -msgid "4 Moves" +#: ../data/plugins/90-library.algorithm.py:31 +msgid "Flip Edges" msgstr "" -#: ../data/scripts/90-rand.py:46 -msgid "5 Moves" +#: ../data/plugins/90-library.algorithm.py:34 +msgid "Swap Corners" msgstr "" -#: ../data/scripts/90-rand.py:47 -msgid "6 Moves" +#: ../data/plugins/90-library.algorithm.py:37 +msgid "Rotate Corners" msgstr "" -#: ../data/scripts/90-rand.py:48 -msgid "7 Moves" +#: ../data/plugins/90-library.algorithm.py:39 +#: ../data/plugins/90-library.algorithm.py:42 +#: ../data/plugins/90-library.algorithm.py:45 +msgid "Rotate Center" msgstr "" -#: ../data/scripts/90-rand.py:49 -msgid "8 Moves" +#: ../data/plugins/90-library.algorithm.py:40 +msgid "2×Up" msgstr "" -#: ../data/scripts/90-rand.py:50 -msgid "50 Moves" +#: ../data/plugins/90-library.algorithm.py:43 +msgid "Up and Front" msgstr "" -#: ../data/applications/pybik.desktop.in.h:2 -msgid "The magic cube" +#: ../data/plugins/90-library.algorithm.py:46 +msgid "Up and Down" msgstr "" -#. Translators: Strings from file create_manpage.py are visible only in the man-page -#: ../tools/create_manpage.py:71 -msgid "NAME" +#: ../data/plugins/90-library.algorithm.py:48 +#: ../data/plugins/90-library.algorithm.py:51 +msgid "Misc" msgstr "" -#: ../tools/create_manpage.py:74 -msgid "SYNOPSIS" +#: ../data/plugins/90-library.algorithm.py:49 +msgid "Back without Back" msgstr "" -#: ../tools/create_manpage.py:76 -msgid "OPTIONS" +#: ../data/plugins/90-library.algorithm.py:52 +msgid "2×Back without Back" msgstr "" diff -Nru pybik-0.5/po/es.po pybik-1.0.1/po/es.po --- pybik-0.5/po/es.po 1970-01-01 00:00:00.000000000 +0000 +++ pybik-1.0.1/po/es.po 2013-02-01 20:18:02.000000000 +0000 @@ -0,0 +1,881 @@ +# Spanish translation for pybik +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the pybik package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: pybik\n" +"Report-Msgid-Bugs-To: https://bugs.launchpad.net/pybik/+filebug\n" +"POT-Creation-Date: 2013-01-31 14:25+0100\n" +"PO-Revision-Date: 2013-01-13 06:46+0000\n" +"Last-Translator: Adolfo Jayme Barrientos \n" +"Language-Team: Spanish \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Launchpad-Export-Date: 2013-01-14 04:40+0000\n" +"X-Generator: Launchpad (build 16420)\n" + +#: ../pybiklib/application.py:304 +msgid "Press the Esc key to exit Edit Mode" +msgstr "Oprima la tecla Esc para salir del modo de edición" + +#. substitution for {move_text} in statusbar text +#: ../pybiklib/application.py:313 +msgid "{current} / {total} move" +msgid_plural "{current} / {total} moves" +msgstr[0] "" +msgstr[1] "" + +#. substitution for {solved_text} in statusbar text +#: ../pybiklib/application.py:317 ../pybiklib/ui/model.py:82 +msgid "solved" +msgstr "resuelto" + +#: ../pybiklib/application.py:317 +msgid "not solved" +msgstr "sin resolver" + +#. statusbar text +#: ../pybiklib/application.py:320 +msgid "{model_text}, {move_text}, {solved_text}" +msgstr "{model_text}, {move_text}, {solved_text}" + +#: ../pybiklib/application.py:353 +msgid "Congratulations, you have solved the puzzle!" +msgstr "¡Felicidades, ha resuelto el rompecabezas!" + +#: ../pybiklib/config.py:30 ../pybiklib/ui/main.py:194 +#: ../data/applications/pybik.desktop.in.h:1 +msgid "Pybik" +msgstr "Pybik" + +#: ../pybiklib/config.py:59 ../data/applications/pybik.desktop.in.h:2 +msgid "3D Rubik's cube game" +msgstr "Juego del cubo de Rubik en 3D" + +#: ../pybiklib/config.py:61 +msgid "" +"Pybik is an interactive, graphical, single player puzzle about the cube " +"invented by Ernő Rubik. Besides the cube the program can handle towers and " +"bricks (non cubic puzzles). Pybik also has solvers, pretty patterns and a " +"collection of various moves. The cube can be manipulated with the mouse or " +"keyboard. You can change the colors or images on the faces of the cube." +msgstr "" + +#: ../pybiklib/config.py:69 +msgid "" +"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.\n" +"\n" +"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." +msgstr "" + +#: ../pybiklib/config.py:79 +msgid "" +"Read the full text of the GNU General Public " +"License<|> or see ." +msgstr "" +"Lea el texto completo de la Licencia Pública " +"General de GNU<|> o consulte ." + +#: ../pybiklib/config.py:82 +msgid "" +"You should have received a copy of the GNU General Public License along with " +"this program. If not, see ." +msgstr "" +"Debería haber recibido una copia de la Licencia Pública General GNU junto " +"con este programa. De no ser así, visite ." + +#: ../pybiklib/config.py:88 +msgid "" +"If you find any bugs in Pybik or have a suggestion for an improvement then " +"please submit a <{CONTACT_FILEBUG}|>bug report<|>. In the latter case you " +"can mark the bug report as \"Wishlist\"." +msgstr "" + +#: ../pybiklib/config.py:94 +msgid "" +"Translations are managed by the " +"Launchpad " +"translation group<|>.\n" +"\n" +"If you want help to translate Pybik to your language you can do it through " +"the web interface<|>.\n" +"\n" +"Read more about \"Translating with " +"Launchpad\"<|> and " +"\"Starting to " +"translate\"<|>." +msgstr "" + +#: ../pybiklib/dialogs.py:168 +msgid "Press a key …" +msgstr "Oprima una tecla…" + +#: ../pybiklib/dialogs.py:296 +msgid "plain" +msgstr "plano" + +#: ../pybiklib/dialogs.py:301 +msgid "select …" +msgstr "seleccionar…" + +#: ../pybiklib/dialogs.py:313 +msgid "Up" +msgstr "Arriba" + +#: ../pybiklib/dialogs.py:313 +msgid "Down" +msgstr "Abajo" + +#: ../pybiklib/dialogs.py:313 +msgid "Left" +msgstr "Izquierda" + +#: ../pybiklib/dialogs.py:313 +msgid "Right" +msgstr "Derecha" + +#: ../pybiklib/dialogs.py:313 +msgid "Front" +msgstr "Anverso" + +#: ../pybiklib/dialogs.py:313 +msgid "Back" +msgstr "Reverso" + +#: ../pybiklib/dialogs.py:331 +msgid "Move" +msgstr "Mover" + +#: ../pybiklib/dialogs.py:332 +msgid "Key" +msgstr "Clave" + +#: ../pybiklib/dialogs.py:486 +msgid "Open Image" +msgstr "Abrir imagen" + +#: ../pybiklib/dialogs.py:536 ../pybiklib/ui/model.py:79 +msgid "Size:" +msgstr "Tamaño:" + +#: ../pybiklib/dialogs.py:536 +msgid "Basis:" +msgstr "Base:" + +#: ../pybiklib/dialogs.py:536 +msgid "Width:" +msgstr "Anchura:" + +#: ../pybiklib/dialogs.py:565 +msgid "Canceling operation, please wait" +msgstr "Cancelando la operación, espere un momento" + +#: ../pybiklib/dialogs.py:621 +msgid "Pybik project website" +msgstr "Sitio web del proyecto Pybik" + +#: ../pybiklib/main.py:287 +msgid "" +"An error occurred while reading the settings:\n" +"{error_message}" +msgstr "" +"Ocurrió un error mientras se leían las configuraciones:\n" +"{error_message}" + +#: ../pybiklib/model.py:214 +msgid "Brick" +msgstr "Ladrillo" + +#: ../pybiklib/model.py:215 +msgid "{0}×{1}×{2}-Brick" +msgstr "" + +#: ../pybiklib/model.py:835 +msgid "Tower" +msgstr "Torre" + +#: ../pybiklib/model.py:836 +msgid "{0}×{1}-Tower" +msgstr "" + +#: ../pybiklib/model.py:850 +msgid "Cube" +msgstr "Cubo" + +#: ../pybiklib/model.py:851 +msgid "{0}×{0}×{0}-Cube" +msgstr "" + +#: ../pybiklib/plugins.py:92 +msgid "This algorithm does not work for any model.\n" +msgstr "Este algoritmo no funciona para cualquier modelo.\n" + +#: ../pybiklib/plugins.py:94 ../pybiklib/plugins.py:97 +msgid "This algorithm only works for:\n" +msgstr "Este algoritmo sólo funciona para:\n" + +#: ../pybiklib/settings.py:256 +msgid "Settings can not be written to file: {error_message}" +msgstr "" +"Las configuraciones no pueden ser leídas para el archivo: {error_message}" + +#: ../pybiklib/ui/about.py:131 +msgid "About Pybik" +msgstr "Acerca de Pybik" + +#: ../pybiklib/ui/about.py:132 +msgid "About" +msgstr "Acerca de" + +#: ../pybiklib/ui/about.py:133 +msgid "Feedback" +msgstr "Sugerencias" + +#: ../pybiklib/ui/about.py:134 +msgid "Translation" +msgstr "Traducción" + +#: ../pybiklib/ui/about.py:135 +msgid "License" +msgstr "Licencia" + +#: ../pybiklib/ui/main.py:195 +msgid "&Game" +msgstr "&Juego" + +#: ../pybiklib/ui/main.py:196 +msgid "&Edit" +msgstr "&Editar" + +#: ../pybiklib/ui/main.py:197 +msgid "&View" +msgstr "&Ver" + +#: ../pybiklib/ui/main.py:198 +msgid "&Help" +msgstr "Ay&uda" + +#: ../pybiklib/ui/main.py:199 +msgid "Pybik Toolbar" +msgstr "Barra de herramientas de Pybik" + +#: ../pybiklib/ui/main.py:200 +msgid "&New Random" +msgstr "" + +#: ../pybiklib/ui/main.py:201 +msgid "Ne&w Solved" +msgstr "" + +#: ../pybiklib/ui/main.py:202 +msgid "&Quit" +msgstr "&Salir" + +#: ../pybiklib/ui/main.py:203 +msgid "&Select Model …" +msgstr "" + +#: ../pybiklib/ui/main.py:204 +msgid "&Set as Initial State" +msgstr "" + +#: ../pybiklib/ui/main.py:205 +msgid "&Reset Rotation" +msgstr "" + +#: ../pybiklib/ui/main.py:206 +msgid "&Invert Moves" +msgstr "" + +#: ../pybiklib/ui/main.py:207 +msgid "Reload Plugins" +msgstr "Recargar complementos" + +#: ../pybiklib/ui/main.py:208 +msgid "&Preferences …" +msgstr "&Preferencias…" + +#: ../pybiklib/ui/main.py:209 +msgid "&Toolbar" +msgstr "&Barra de herramientas" + +#: ../pybiklib/ui/main.py:210 +msgid "&Status Bar" +msgstr "Barra de e&stado" + +#: ../pybiklib/ui/main.py:211 +msgid "&Info …" +msgstr "" + +#: ../pybiklib/ui/main.py:212 +msgid "Rewind" +msgstr "Retroceder" + +#: ../pybiklib/ui/main.py:213 +msgid "Go to the previous mark (or the beginning) of the sequence of moves" +msgstr "" + +#: ../pybiklib/ui/main.py:214 +msgid "Previous" +msgstr "Anterior" + +#: ../pybiklib/ui/main.py:215 +msgid "Make one step backwards" +msgstr "" + +#: ../pybiklib/ui/main.py:216 +msgid "Stop" +msgstr "Detener" + +#: ../pybiklib/ui/main.py:217 +msgid "Stop running the sequence of moves" +msgstr "" + +#: ../pybiklib/ui/main.py:218 +msgid "Play" +msgstr "Reproducir" + +#: ../pybiklib/ui/main.py:219 +msgid "Run forward through the sequence of moves" +msgstr "" + +#: ../pybiklib/ui/main.py:220 +msgid "Next" +msgstr "Siguiente" + +#: ../pybiklib/ui/main.py:221 +msgid "Make one step forwards" +msgstr "" + +#: ../pybiklib/ui/main.py:222 +msgid "Forward" +msgstr "Avanzar" + +#: ../pybiklib/ui/main.py:223 +msgid "Go to the next mark (or the end) of the sequence of moves" +msgstr "" + +#: ../pybiklib/ui/main.py:224 +msgid "Add Mark" +msgstr "Añadir marca" + +#: ../pybiklib/ui/main.py:225 +msgid "Mark the current place in the sequence of moves" +msgstr "" + +#: ../pybiklib/ui/main.py:226 +msgid "Remove Mark" +msgstr "Quitar marca" + +#: ../pybiklib/ui/main.py:227 +msgid "Remove the mark at the current place in the sequence of moves" +msgstr "" + +#: ../pybiklib/ui/main.py:228 +msgid "&Edit Bar" +msgstr "" + +#: ../pybiklib/ui/main.py:229 +msgid "Normalize Cube Rotations" +msgstr "" + +#: ../pybiklib/ui/model.py:78 +msgid "Select Model" +msgstr "Seleccionar modelo" + +#: ../pybiklib/ui/model.py:80 +msgid "Height:" +msgstr "Altura:" + +#: ../pybiklib/ui/model.py:81 +msgid "Depth:" +msgstr "Profundidad:" + +#: ../pybiklib/ui/preferences.py:252 +msgid "Preferences" +msgstr "Preferencias" + +#: ../pybiklib/ui/preferences.py:253 +msgid "Animation Speed:" +msgstr "Velocidad de la animación:" + +#: ../pybiklib/ui/preferences.py:254 +msgid "Lighting" +msgstr "Iluminación" + +#: ../pybiklib/ui/preferences.py:255 +msgid "Mirror Distance:" +msgstr "Distancia de espejo:" + +#: ../pybiklib/ui/preferences.py:256 +msgid "Antialiasing" +msgstr "Suavizado" + +#: ../pybiklib/ui/preferences.py:257 +msgid "Hardware:" +msgstr "Hardware:" + +#: ../pybiklib/ui/preferences.py:258 +msgid "Software:" +msgstr "Software:" + +#: ../pybiklib/ui/preferences.py:259 +msgid "" +"

The program needs to " +"be restarted for the changes to take effect.

" +msgstr "" +"

Necesita reiniciar el " +"programa para que los cambios surtan efecto.

" + +#: ../pybiklib/ui/preferences.py:260 +msgid "Graphic" +msgstr "Gráfico" + +#: ../pybiklib/ui/preferences.py:261 +msgid "Four directions" +msgstr "Cuatro direcciones" + +#: ../pybiklib/ui/preferences.py:262 +msgid "" +"Simplified,\n" +"right button inverts move" +msgstr "" + +#: ../pybiklib/ui/preferences.py:263 +msgid "Mouse" +msgstr "Ratón" + +#: ../pybiklib/ui/preferences.py:264 ../pybiklib/ui/preferences.py:265 +msgid "Add" +msgstr "Añadir" + +#: ../pybiklib/ui/preferences.py:266 ../pybiklib/ui/preferences.py:267 +msgid "Remove" +msgstr "Quitar" + +#: ../pybiklib/ui/preferences.py:268 ../pybiklib/ui/preferences.py:269 +msgid "Reset" +msgstr "Restablecer" + +#: ../pybiklib/ui/preferences.py:270 +msgid "Keys" +msgstr "Teclas" + +#: ../pybiklib/ui/preferences.py:271 +msgid "Color:" +msgstr "Color:" + +#: ../pybiklib/ui/preferences.py:272 +msgid "Image File:" +msgstr "Archivo de imagen:" + +#: ../pybiklib/ui/preferences.py:273 +msgid "Tiled" +msgstr "En mosaico" + +#: ../pybiklib/ui/preferences.py:274 +msgid "Mosaic" +msgstr "Mosaico" + +#: ../pybiklib/ui/preferences.py:275 +msgid "Background:" +msgstr "Fondo:" + +#: ../pybiklib/ui/preferences.py:276 +msgid "Appearance" +msgstr "Apariencia" + +#. Add whatever keywords you want in your language, separated by semicolons. These keywords are used when searching for applications in dashes, etc. (Unity, GNOME Shell) +#: ../data/applications/pybik.desktop.in.h:4 +msgid "rubik;cube;puzzle;magic;" +msgstr "" + +#: ../data/plugins/01-challenges.algorithm.py:19 +#: ../data/plugins/01-challenges.algorithm.py:22 +#: ../data/plugins/01-challenges.algorithm.py:25 +#: ../data/plugins/01-challenges.algorithm.py:28 +#: ../data/plugins/01-challenges.algorithm.py:31 +#: ../data/plugins/01-challenges.algorithm.py:34 +#: ../data/plugins/01-challenges.algorithm.py:37 +#: ../data/plugins/01-challenges.algorithm.py:40 +#: ../data/plugins/01-challenges.algorithm.py:43 +#: ../data/plugins/01-challenges.algorithm.py:46 +#: ../data/plugins/01-challenges.algorithm.py:49 +msgid "Challenges" +msgstr "" + +#: ../data/plugins/01-challenges.algorithm.py:20 +msgid "Solve random cube" +msgstr "" + +#: ../data/plugins/01-challenges.algorithm.py:23 +msgid "Solve in 1 move" +msgstr "" + +#: ../data/plugins/01-challenges.algorithm.py:26 +msgid "Solve in 2 moves" +msgstr "Resolver en 2 movimientos" + +#: ../data/plugins/01-challenges.algorithm.py:29 +msgid "Solve in 3 moves" +msgstr "Resolver en 3 movimientos" + +#: ../data/plugins/01-challenges.algorithm.py:32 +msgid "Solve in 4 moves" +msgstr "Resolver en 4 movimientos" + +#: ../data/plugins/01-challenges.algorithm.py:35 +msgid "Solve in 5 moves" +msgstr "Resolver en 5 movimientos" + +#: ../data/plugins/01-challenges.algorithm.py:38 +msgid "Solve in 6 moves" +msgstr "Resolver en 6 movimientos" + +#: ../data/plugins/01-challenges.algorithm.py:41 +msgid "Solve in 7 moves" +msgstr "Resolver en 7 movimientos" + +#: ../data/plugins/01-challenges.algorithm.py:44 +msgid "Solve in 8 moves" +msgstr "Resolver en 8 movimientos" + +#: ../data/plugins/01-challenges.algorithm.py:47 +msgid "Solve in 9 moves" +msgstr "Resolver en 9 movimientos" + +#: ../data/plugins/01-challenges.algorithm.py:50 +msgid "Solve in 10 moves" +msgstr "Resolver en 10 movimientos" + +#: ../data/plugins/10-spiegel.algorithm.py:35 +#: ../data/plugins/10-spiegel.algorithm.py:38 +#: ../data/plugins/10-spiegel.algorithm.py:67 +#: ../data/plugins/10-spiegel.algorithm.py:88 +#: ../data/plugins/10-spiegel.algorithm.py:103 +#: ../data/plugins/10-spiegel.algorithm.py:116 +#: ../data/plugins/10-spiegel.algorithm.py:133 +#: ../data/plugins/10-spiegel.algorithm.py:144 +#: ../data/plugins/11-spiegel-improved.algorithm.py:35 +#: ../data/plugins/11-spiegel-improved.algorithm.py:38 +#: ../data/plugins/11-spiegel-improved.algorithm.py:83 +#: ../data/plugins/11-spiegel-improved.algorithm.py:122 +#: ../data/plugins/11-spiegel-improved.algorithm.py:154 +#: ../data/plugins/11-spiegel-improved.algorithm.py:180 +#: ../data/plugins/11-spiegel-improved.algorithm.py:198 +#: ../data/plugins/11-spiegel-improved.algorithm.py:212 +#: ../data/plugins/12-lbl-leyan.algorithm.py:22 +#: ../data/plugins/12-lbl-leyan.algorithm.py:25 +#: ../data/plugins/12-lbl-leyan.algorithm.py:54 +#: ../data/plugins/12-lbl-leyan.algorithm.py:75 +#: ../data/plugins/12-lbl-leyan.algorithm.py:91 +#: ../data/plugins/12-lbl-leyan.algorithm.py:108 +#: ../data/plugins/12-lbl-leyan.algorithm.py:130 +#: ../data/plugins/12-lbl-leyan.algorithm.py:171 +#: ../data/plugins/20-2x2x2.algorithm.py:19 +#: ../data/plugins/20-2x2x2.algorithm.py:22 +#: ../data/plugins/20-2x2x2.algorithm.py:41 +#: ../data/plugins/20-2x2x2.algorithm.py:61 +msgid "Solvers" +msgstr "Solucionadores" + +#. Spiegel is the name of a solution method +#: ../data/plugins/10-spiegel.algorithm.py:37 +#: ../data/plugins/10-spiegel.algorithm.py:39 +#: ../data/plugins/10-spiegel.algorithm.py:68 +#: ../data/plugins/10-spiegel.algorithm.py:89 +#: ../data/plugins/10-spiegel.algorithm.py:104 +#: ../data/plugins/10-spiegel.algorithm.py:117 +#: ../data/plugins/10-spiegel.algorithm.py:134 +#: ../data/plugins/10-spiegel.algorithm.py:145 +msgid "Spiegel" +msgstr "Spiegel" + +#: ../data/plugins/10-spiegel.algorithm.py:40 +#: ../data/plugins/11-spiegel-improved.algorithm.py:40 +#: ../data/plugins/12-lbl-leyan.algorithm.py:27 +msgid "Top edges" +msgstr "" + +#: ../data/plugins/10-spiegel.algorithm.py:69 +#: ../data/plugins/11-spiegel-improved.algorithm.py:85 +#: ../data/plugins/12-lbl-leyan.algorithm.py:56 +msgid "Top corners" +msgstr "" + +#: ../data/plugins/10-spiegel.algorithm.py:90 +#: ../data/plugins/11-spiegel-improved.algorithm.py:124 +#: ../data/plugins/12-lbl-leyan.algorithm.py:77 +msgid "Middle slice" +msgstr "" + +#: ../data/plugins/10-spiegel.algorithm.py:105 +#: ../data/plugins/11-spiegel-improved.algorithm.py:156 +#: ../data/plugins/12-lbl-leyan.algorithm.py:173 +msgid "Bottom edge place" +msgstr "" + +#: ../data/plugins/10-spiegel.algorithm.py:118 +#: ../data/plugins/11-spiegel-improved.algorithm.py:182 +#: ../data/plugins/12-lbl-leyan.algorithm.py:93 +msgid "Bottom edge orient" +msgstr "" + +#: ../data/plugins/10-spiegel.algorithm.py:135 +#: ../data/plugins/11-spiegel-improved.algorithm.py:200 +#: ../data/plugins/12-lbl-leyan.algorithm.py:110 +#: ../data/plugins/20-2x2x2.algorithm.py:43 +msgid "Bottom corner place" +msgstr "" + +#: ../data/plugins/10-spiegel.algorithm.py:146 +#: ../data/plugins/11-spiegel-improved.algorithm.py:214 +#: ../data/plugins/12-lbl-leyan.algorithm.py:132 +#: ../data/plugins/20-2x2x2.algorithm.py:63 +msgid "Bottom corner orient" +msgstr "" + +#. Spiegel is the name of a solution method +#: ../data/plugins/11-spiegel-improved.algorithm.py:37 +#: ../data/plugins/11-spiegel-improved.algorithm.py:39 +#: ../data/plugins/11-spiegel-improved.algorithm.py:84 +#: ../data/plugins/11-spiegel-improved.algorithm.py:123 +#: ../data/plugins/11-spiegel-improved.algorithm.py:155 +#: ../data/plugins/11-spiegel-improved.algorithm.py:181 +#: ../data/plugins/11-spiegel-improved.algorithm.py:199 +#: ../data/plugins/11-spiegel-improved.algorithm.py:213 +msgid "Spiegel improved" +msgstr "Spiegel mejorado" + +#. Leyan Lo is the inventor of the solution method +#: ../data/plugins/12-lbl-leyan.algorithm.py:24 +#: ../data/plugins/12-lbl-leyan.algorithm.py:26 +#: ../data/plugins/12-lbl-leyan.algorithm.py:55 +#: ../data/plugins/12-lbl-leyan.algorithm.py:76 +#: ../data/plugins/12-lbl-leyan.algorithm.py:92 +#: ../data/plugins/12-lbl-leyan.algorithm.py:109 +#: ../data/plugins/12-lbl-leyan.algorithm.py:131 +#: ../data/plugins/12-lbl-leyan.algorithm.py:172 +msgid "Layer Method (Leyan Lo)" +msgstr "" + +#: ../data/plugins/20-2x2x2.algorithm.py:20 +#: ../data/plugins/20-2x2x2.algorithm.py:23 +#: ../data/plugins/20-2x2x2.algorithm.py:42 +#: ../data/plugins/20-2x2x2.algorithm.py:62 +msgid "2×2×2" +msgstr "2×2×2" + +#: ../data/plugins/20-2x2x2.algorithm.py:24 +msgid "Top slice" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:18 +#: ../data/plugins/80-pretty-patterns.algorithm.py:22 +#: ../data/plugins/80-pretty-patterns.algorithm.py:26 +#: ../data/plugins/80-pretty-patterns.algorithm.py:30 +#: ../data/plugins/80-pretty-patterns.algorithm.py:34 +#: ../data/plugins/80-pretty-patterns.algorithm.py:39 +#: ../data/plugins/80-pretty-patterns.algorithm.py:43 +#: ../data/plugins/80-pretty-patterns.algorithm.py:48 +#: ../data/plugins/80-pretty-patterns.algorithm.py:52 +#: ../data/plugins/80-pretty-patterns.algorithm.py:56 +#: ../data/plugins/80-pretty-patterns.algorithm.py:60 +#: ../data/plugins/80-pretty-patterns.algorithm.py:64 +#: ../data/plugins/80-pretty-patterns.algorithm.py:68 +#: ../data/plugins/80-pretty-patterns.algorithm.py:74 +#: ../data/plugins/80-pretty-patterns.algorithm.py:78 +#: ../data/plugins/80-pretty-patterns.algorithm.py:83 +#: ../data/plugins/80-pretty-patterns.algorithm.py:87 +#: ../data/plugins/80-pretty-patterns.algorithm.py:91 +#: ../data/plugins/80-pretty-patterns.algorithm.py:95 +#: ../data/plugins/80-pretty-patterns.algorithm.py:99 +#: ../data/plugins/80-pretty-patterns.algorithm.py:103 +#: ../data/plugins/80-pretty-patterns.algorithm.py:108 +#: ../data/plugins/80-pretty-patterns.algorithm.py:112 +#: ../data/plugins/80-pretty-patterns.algorithm.py:116 +#: ../data/plugins/80-pretty-patterns.algorithm.py:120 +#: ../data/plugins/80-pretty-patterns.algorithm.py:124 +#: ../data/plugins/80-pretty-patterns.algorithm.py:128 +#: ../data/plugins/80-pretty-patterns.algorithm.py:132 +#: ../data/plugins/80-pretty-patterns.algorithm.py:136 +#: ../data/plugins/80-pretty-patterns.algorithm.py:140 +msgid "Pretty patterns" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:19 +#: ../data/plugins/80-pretty-patterns.algorithm.py:23 +#: ../data/plugins/80-pretty-patterns.algorithm.py:27 +#: ../data/plugins/80-pretty-patterns.algorithm.py:31 +#: ../data/plugins/80-pretty-patterns.algorithm.py:35 +#: ../data/plugins/80-pretty-patterns.algorithm.py:40 +#: ../data/plugins/80-pretty-patterns.algorithm.py:44 +msgid "Stripes" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:49 +#: ../data/plugins/80-pretty-patterns.algorithm.py:53 +msgid "Criss-Cross" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:57 +msgid "Fried Eggs" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:61 +msgid "Big Fried Eggs" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:65 +msgid "4 Fried Eggs" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:69 +msgid "Chessboard" +msgstr "Tablero de ajedrez" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:75 +msgid "Cross" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:79 +msgid "Zig Zag" +msgstr "Zig Zag" + +#. T is the shape formed by the cube labels +#: ../data/plugins/80-pretty-patterns.algorithm.py:85 +#: ../data/plugins/80-pretty-patterns.algorithm.py:88 +#: ../data/plugins/80-pretty-patterns.algorithm.py:92 +#: ../data/plugins/80-pretty-patterns.algorithm.py:96 +#: ../data/plugins/80-pretty-patterns.algorithm.py:100 +#: ../data/plugins/80-pretty-patterns.algorithm.py:104 +msgid "T-Time" +msgstr "" + +#. C is the shape formed by the cube labels +#: ../data/plugins/80-pretty-patterns.algorithm.py:110 +msgid "C" +msgstr "C" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:113 +msgid "Cube in a Cube" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:117 +msgid "Striped Cube in a Cube" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:121 +msgid "Six Square Cuboids" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:125 +msgid "Superflip" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:129 +msgid "Superflip easy" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:133 +msgid "Green Mamba" +msgstr "Mamba verde" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:137 +msgid "Anaconda" +msgstr "Anaconda" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:141 +msgid "Duck Feet" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:20 +#: ../data/plugins/90-library.algorithm.py:23 +#: ../data/plugins/90-library.algorithm.py:26 +#: ../data/plugins/90-library.algorithm.py:29 +#: ../data/plugins/90-library.algorithm.py:32 +#: ../data/plugins/90-library.algorithm.py:35 +#: ../data/plugins/90-library.algorithm.py:38 +#: ../data/plugins/90-library.algorithm.py:41 +#: ../data/plugins/90-library.algorithm.py:44 +#: ../data/plugins/90-library.algorithm.py:47 +#: ../data/plugins/90-library.algorithm.py:50 +msgid "Library" +msgstr "Biblioteca" + +#: ../data/plugins/90-library.algorithm.py:21 +#: ../data/plugins/90-library.algorithm.py:24 +msgid "Middle Layer" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:22 +msgid "Front to Right" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:25 +msgid "Front to Left" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:27 +#: ../data/plugins/90-library.algorithm.py:30 +#: ../data/plugins/90-library.algorithm.py:33 +#: ../data/plugins/90-library.algorithm.py:36 +msgid "Last Layer" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:28 +msgid "Swap Edges" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:31 +msgid "Flip Edges" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:34 +msgid "Swap Corners" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:37 +msgid "Rotate Corners" +msgstr "Girar esquinas" + +#: ../data/plugins/90-library.algorithm.py:39 +#: ../data/plugins/90-library.algorithm.py:42 +#: ../data/plugins/90-library.algorithm.py:45 +msgid "Rotate Center" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:40 +msgid "2×Up" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:43 +msgid "Up and Front" +msgstr "Arriba y adelante" + +#: ../data/plugins/90-library.algorithm.py:46 +msgid "Up and Down" +msgstr "Arriba y abajo" + +#: ../data/plugins/90-library.algorithm.py:48 +#: ../data/plugins/90-library.algorithm.py:51 +msgid "Misc" +msgstr "Varios" + +#: ../data/plugins/90-library.algorithm.py:49 +msgid "Back without Back" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:52 +msgid "2×Back without Back" +msgstr "" diff -Nru pybik-0.5/po/fr.po pybik-1.0.1/po/fr.po --- pybik-0.5/po/fr.po 1970-01-01 00:00:00.000000000 +0000 +++ pybik-1.0.1/po/fr.po 2013-02-01 20:18:02.000000000 +0000 @@ -0,0 +1,887 @@ +# French translation for pybik +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the pybik package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: pybik\n" +"Report-Msgid-Bugs-To: https://bugs.launchpad.net/pybik/+filebug\n" +"POT-Creation-Date: 2013-01-31 14:25+0100\n" +"PO-Revision-Date: 2013-01-08 12:53+0000\n" +"Last-Translator: Aurélien Ribeiro \n" +"Language-Team: French \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Launchpad-Export-Date: 2013-01-09 05:14+0000\n" +"X-Generator: Launchpad (build 16412)\n" + +#: ../pybiklib/application.py:304 +msgid "Press the Esc key to exit Edit Mode" +msgstr "Appuyez sur la touche Échap pour quitter le mode Édition" + +#. substitution for {move_text} in statusbar text +#: ../pybiklib/application.py:313 +msgid "{current} / {total} move" +msgid_plural "{current} / {total} moves" +msgstr[0] "{current} / {total} mouvement" +msgstr[1] "{current} / {total} mouvements" + +#. substitution for {solved_text} in statusbar text +#: ../pybiklib/application.py:317 ../pybiklib/ui/model.py:82 +msgid "solved" +msgstr "résolu" + +#: ../pybiklib/application.py:317 +msgid "not solved" +msgstr "non résolu" + +#. statusbar text +#: ../pybiklib/application.py:320 +msgid "{model_text}, {move_text}, {solved_text}" +msgstr "{model_text}, {move_text}, {solved_text}" + +#: ../pybiklib/application.py:353 +msgid "Congratulations, you have solved the puzzle!" +msgstr "Félicitations, vous avez résolu le casse-tête !" + +#: ../pybiklib/config.py:30 ../pybiklib/ui/main.py:194 +#: ../data/applications/pybik.desktop.in.h:1 +msgid "Pybik" +msgstr "Pybik" + +#: ../pybiklib/config.py:59 ../data/applications/pybik.desktop.in.h:2 +msgid "3D Rubik's cube game" +msgstr "Jeu de Rubik's cube en 3D" + +#: ../pybiklib/config.py:61 +msgid "" +"Pybik is an interactive, graphical, single player puzzle about the cube " +"invented by Ernő Rubik. Besides the cube the program can handle towers and " +"bricks (non cubic puzzles). Pybik also has solvers, pretty patterns and a " +"collection of various moves. The cube can be manipulated with the mouse or " +"keyboard. You can change the colors or images on the faces of the cube." +msgstr "" + +#: ../pybiklib/config.py:69 +msgid "" +"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.\n" +"\n" +"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." +msgstr "" + +#: ../pybiklib/config.py:79 +msgid "" +"Read the full text of the GNU General Public " +"License<|> or see ." +msgstr "" +"Veuillez lire le texte intégral de lalicence " +"publique générale GNU<|> ou aller sur ." + +#: ../pybiklib/config.py:82 +msgid "" +"You should have received a copy of the GNU General Public License along with " +"this program. If not, see ." +msgstr "" +"Vous devriez avoir reçu une copie de la « GNU General Public License » avec " +"ce programme. Sinon, voir ." + +#: ../pybiklib/config.py:88 +msgid "" +"If you find any bugs in Pybik or have a suggestion for an improvement then " +"please submit a <{CONTACT_FILEBUG}|>bug report<|>. In the latter case you " +"can mark the bug report as \"Wishlist\"." +msgstr "" +"Si vous trouvez des bogues dans Pybik ou si vous souhaitez suggérer une " +"amélioration, veuillez déposer un <{CONTACT_FILEBUG}|>rapport de bogue<|>. " +"Dans le dernier cas, vous pouvez marquer le rapport de bogue comme " +"« Wishlist »." + +#: ../pybiklib/config.py:94 +msgid "" +"Translations are managed by the " +"Launchpad " +"translation group<|>.\n" +"\n" +"If you want help to translate Pybik to your language you can do it through " +"the web interface<|>.\n" +"\n" +"Read more about \"Translating with " +"Launchpad\"<|> and " +"\"Starting to " +"translate\"<|>." +msgstr "" + +#: ../pybiklib/dialogs.py:168 +msgid "Press a key …" +msgstr "Appuyez sur une touche…" + +#: ../pybiklib/dialogs.py:296 +msgid "plain" +msgstr "" + +#: ../pybiklib/dialogs.py:301 +msgid "select …" +msgstr "" + +#: ../pybiklib/dialogs.py:313 +msgid "Up" +msgstr "" + +#: ../pybiklib/dialogs.py:313 +msgid "Down" +msgstr "" + +#: ../pybiklib/dialogs.py:313 +msgid "Left" +msgstr "" + +#: ../pybiklib/dialogs.py:313 +msgid "Right" +msgstr "" + +#: ../pybiklib/dialogs.py:313 +msgid "Front" +msgstr "" + +#: ../pybiklib/dialogs.py:313 +msgid "Back" +msgstr "" + +#: ../pybiklib/dialogs.py:331 +msgid "Move" +msgstr "Mouvement" + +#: ../pybiklib/dialogs.py:332 +msgid "Key" +msgstr "" + +#: ../pybiklib/dialogs.py:486 +msgid "Open Image" +msgstr "" + +#: ../pybiklib/dialogs.py:536 ../pybiklib/ui/model.py:79 +msgid "Size:" +msgstr "" + +#: ../pybiklib/dialogs.py:536 +msgid "Basis:" +msgstr "Principe de base :" + +#: ../pybiklib/dialogs.py:536 +msgid "Width:" +msgstr "" + +#: ../pybiklib/dialogs.py:565 +msgid "Canceling operation, please wait" +msgstr "" + +#: ../pybiklib/dialogs.py:621 +msgid "Pybik project website" +msgstr "" + +#: ../pybiklib/main.py:287 +msgid "" +"An error occurred while reading the settings:\n" +"{error_message}" +msgstr "" + +#: ../pybiklib/model.py:214 +msgid "Brick" +msgstr "" + +#: ../pybiklib/model.py:215 +msgid "{0}×{1}×{2}-Brick" +msgstr "" + +#: ../pybiklib/model.py:835 +msgid "Tower" +msgstr "" + +#: ../pybiklib/model.py:836 +msgid "{0}×{1}-Tower" +msgstr "" + +#: ../pybiklib/model.py:850 +msgid "Cube" +msgstr "" + +#: ../pybiklib/model.py:851 +msgid "{0}×{0}×{0}-Cube" +msgstr "" + +#: ../pybiklib/plugins.py:92 +msgid "This algorithm does not work for any model.\n" +msgstr "Cet algorithme ne fonctionne pas pour tous les modèles.\n" + +#: ../pybiklib/plugins.py:94 ../pybiklib/plugins.py:97 +msgid "This algorithm only works for:\n" +msgstr "Cet algorithme fonctionne seulement pour :\n" + +#: ../pybiklib/settings.py:256 +msgid "Settings can not be written to file: {error_message}" +msgstr "" + +#: ../pybiklib/ui/about.py:131 +msgid "About Pybik" +msgstr "À propos de Pybik" + +#: ../pybiklib/ui/about.py:132 +msgid "About" +msgstr "" + +#: ../pybiklib/ui/about.py:133 +msgid "Feedback" +msgstr "" + +#: ../pybiklib/ui/about.py:134 +msgid "Translation" +msgstr "" + +#: ../pybiklib/ui/about.py:135 +msgid "License" +msgstr "" + +#: ../pybiklib/ui/main.py:195 +msgid "&Game" +msgstr "" + +#: ../pybiklib/ui/main.py:196 +msgid "&Edit" +msgstr "" + +#: ../pybiklib/ui/main.py:197 +msgid "&View" +msgstr "" + +#: ../pybiklib/ui/main.py:198 +msgid "&Help" +msgstr "" + +#: ../pybiklib/ui/main.py:199 +msgid "Pybik Toolbar" +msgstr "Barre d'outils Pybik" + +#: ../pybiklib/ui/main.py:200 +msgid "&New Random" +msgstr "" + +#: ../pybiklib/ui/main.py:201 +msgid "Ne&w Solved" +msgstr "" + +#: ../pybiklib/ui/main.py:202 +msgid "&Quit" +msgstr "" + +#: ../pybiklib/ui/main.py:203 +msgid "&Select Model …" +msgstr "" + +#: ../pybiklib/ui/main.py:204 +msgid "&Set as Initial State" +msgstr "" + +#: ../pybiklib/ui/main.py:205 +msgid "&Reset Rotation" +msgstr "" + +#: ../pybiklib/ui/main.py:206 +msgid "&Invert Moves" +msgstr "&Inverser les mouvements" + +#: ../pybiklib/ui/main.py:207 +msgid "Reload Plugins" +msgstr "Recharger les greffons" + +#: ../pybiklib/ui/main.py:208 +msgid "&Preferences …" +msgstr "&Préférences…" + +#: ../pybiklib/ui/main.py:209 +msgid "&Toolbar" +msgstr "" + +#: ../pybiklib/ui/main.py:210 +msgid "&Status Bar" +msgstr "" + +#: ../pybiklib/ui/main.py:211 +msgid "&Info …" +msgstr "&Info…" + +#: ../pybiklib/ui/main.py:212 +msgid "Rewind" +msgstr "" + +#: ../pybiklib/ui/main.py:213 +msgid "Go to the previous mark (or the beginning) of the sequence of moves" +msgstr "" +"Revenir à la marque précédente (ou au début) de la séquence de mouvements" + +#: ../pybiklib/ui/main.py:214 +msgid "Previous" +msgstr "" + +#: ../pybiklib/ui/main.py:215 +msgid "Make one step backwards" +msgstr "Revenir une étape en arrière" + +#: ../pybiklib/ui/main.py:216 +msgid "Stop" +msgstr "" + +#: ../pybiklib/ui/main.py:217 +msgid "Stop running the sequence of moves" +msgstr "Arrêter la séquence de mouvements" + +#: ../pybiklib/ui/main.py:218 +msgid "Play" +msgstr "Lire" + +#: ../pybiklib/ui/main.py:219 +msgid "Run forward through the sequence of moves" +msgstr "" + +#: ../pybiklib/ui/main.py:220 +msgid "Next" +msgstr "" + +#: ../pybiklib/ui/main.py:221 +msgid "Make one step forwards" +msgstr "" + +#: ../pybiklib/ui/main.py:222 +msgid "Forward" +msgstr "" + +#: ../pybiklib/ui/main.py:223 +msgid "Go to the next mark (or the end) of the sequence of moves" +msgstr "" +"Avancer à la marque suivante (ou à la fin) de la séquence de mouvements" + +#: ../pybiklib/ui/main.py:224 +msgid "Add Mark" +msgstr "Ajouter une marque" + +#: ../pybiklib/ui/main.py:225 +msgid "Mark the current place in the sequence of moves" +msgstr "Marquer la position actuelle dans la séquence de mouvements" + +#: ../pybiklib/ui/main.py:226 +msgid "Remove Mark" +msgstr "Supprimer une marque" + +#: ../pybiklib/ui/main.py:227 +msgid "Remove the mark at the current place in the sequence of moves" +msgstr "" +"Supprimer la marque de la position actuelle dans la séquence de mouvements" + +#: ../pybiklib/ui/main.py:228 +msgid "&Edit Bar" +msgstr "" + +#: ../pybiklib/ui/main.py:229 +msgid "Normalize Cube Rotations" +msgstr "" + +#: ../pybiklib/ui/model.py:78 +msgid "Select Model" +msgstr "Sélectionner le modèle" + +#: ../pybiklib/ui/model.py:80 +msgid "Height:" +msgstr "" + +#: ../pybiklib/ui/model.py:81 +msgid "Depth:" +msgstr "" + +#: ../pybiklib/ui/preferences.py:252 +msgid "Preferences" +msgstr "" + +#: ../pybiklib/ui/preferences.py:253 +msgid "Animation Speed:" +msgstr "" + +#: ../pybiklib/ui/preferences.py:254 +msgid "Lighting" +msgstr "" + +#: ../pybiklib/ui/preferences.py:255 +msgid "Mirror Distance:" +msgstr "" + +#: ../pybiklib/ui/preferences.py:256 +msgid "Antialiasing" +msgstr "" + +#: ../pybiklib/ui/preferences.py:257 +msgid "Hardware:" +msgstr "" + +#: ../pybiklib/ui/preferences.py:258 +msgid "Software:" +msgstr "Logiciel :" + +#: ../pybiklib/ui/preferences.py:259 +msgid "" +"

The program needs to " +"be restarted for the changes to take effect.

" +msgstr "" +"

Ce programme doit être " +"redémarré pour prendre en compte les changements.

" + +#: ../pybiklib/ui/preferences.py:260 +msgid "Graphic" +msgstr "" + +#: ../pybiklib/ui/preferences.py:261 +msgid "Four directions" +msgstr "Quatre directions" + +#: ../pybiklib/ui/preferences.py:262 +msgid "" +"Simplified,\n" +"right button inverts move" +msgstr "" +"Simplifié,\n" +"le bouton droit inverse les mouvements" + +#: ../pybiklib/ui/preferences.py:263 +msgid "Mouse" +msgstr "" + +#: ../pybiklib/ui/preferences.py:264 ../pybiklib/ui/preferences.py:265 +msgid "Add" +msgstr "" + +#: ../pybiklib/ui/preferences.py:266 ../pybiklib/ui/preferences.py:267 +msgid "Remove" +msgstr "" + +#: ../pybiklib/ui/preferences.py:268 ../pybiklib/ui/preferences.py:269 +msgid "Reset" +msgstr "" + +#: ../pybiklib/ui/preferences.py:270 +msgid "Keys" +msgstr "" + +#: ../pybiklib/ui/preferences.py:271 +msgid "Color:" +msgstr "" + +#: ../pybiklib/ui/preferences.py:272 +msgid "Image File:" +msgstr "Fichier image :" + +#: ../pybiklib/ui/preferences.py:273 +msgid "Tiled" +msgstr "" + +#: ../pybiklib/ui/preferences.py:274 +msgid "Mosaic" +msgstr "" + +#: ../pybiklib/ui/preferences.py:275 +msgid "Background:" +msgstr "" + +#: ../pybiklib/ui/preferences.py:276 +msgid "Appearance" +msgstr "" + +#. Add whatever keywords you want in your language, separated by semicolons. These keywords are used when searching for applications in dashes, etc. (Unity, GNOME Shell) +#: ../data/applications/pybik.desktop.in.h:4 +msgid "rubik;cube;puzzle;magic;" +msgstr "" + +#: ../data/plugins/01-challenges.algorithm.py:19 +#: ../data/plugins/01-challenges.algorithm.py:22 +#: ../data/plugins/01-challenges.algorithm.py:25 +#: ../data/plugins/01-challenges.algorithm.py:28 +#: ../data/plugins/01-challenges.algorithm.py:31 +#: ../data/plugins/01-challenges.algorithm.py:34 +#: ../data/plugins/01-challenges.algorithm.py:37 +#: ../data/plugins/01-challenges.algorithm.py:40 +#: ../data/plugins/01-challenges.algorithm.py:43 +#: ../data/plugins/01-challenges.algorithm.py:46 +#: ../data/plugins/01-challenges.algorithm.py:49 +msgid "Challenges" +msgstr "Défis" + +#: ../data/plugins/01-challenges.algorithm.py:20 +msgid "Solve random cube" +msgstr "" + +#: ../data/plugins/01-challenges.algorithm.py:23 +msgid "Solve in 1 move" +msgstr "Résoudre en 1 mouvement" + +#: ../data/plugins/01-challenges.algorithm.py:26 +msgid "Solve in 2 moves" +msgstr "Résoudre en 2 mouvements" + +#: ../data/plugins/01-challenges.algorithm.py:29 +msgid "Solve in 3 moves" +msgstr "Résoudre en 3 mouvements" + +#: ../data/plugins/01-challenges.algorithm.py:32 +msgid "Solve in 4 moves" +msgstr "Résoudre en 4 mouvements" + +#: ../data/plugins/01-challenges.algorithm.py:35 +msgid "Solve in 5 moves" +msgstr "Résoudre en 5 mouvements" + +#: ../data/plugins/01-challenges.algorithm.py:38 +msgid "Solve in 6 moves" +msgstr "Résoudre en 6 mouvements" + +#: ../data/plugins/01-challenges.algorithm.py:41 +msgid "Solve in 7 moves" +msgstr "Résoudre en 7 mouvements" + +#: ../data/plugins/01-challenges.algorithm.py:44 +msgid "Solve in 8 moves" +msgstr "Résoudre en 8 mouvements" + +#: ../data/plugins/01-challenges.algorithm.py:47 +msgid "Solve in 9 moves" +msgstr "Résoudre en 9 mouvements" + +#: ../data/plugins/01-challenges.algorithm.py:50 +msgid "Solve in 10 moves" +msgstr "Résoudre en 10 mouvements" + +#: ../data/plugins/10-spiegel.algorithm.py:35 +#: ../data/plugins/10-spiegel.algorithm.py:38 +#: ../data/plugins/10-spiegel.algorithm.py:67 +#: ../data/plugins/10-spiegel.algorithm.py:88 +#: ../data/plugins/10-spiegel.algorithm.py:103 +#: ../data/plugins/10-spiegel.algorithm.py:116 +#: ../data/plugins/10-spiegel.algorithm.py:133 +#: ../data/plugins/10-spiegel.algorithm.py:144 +#: ../data/plugins/11-spiegel-improved.algorithm.py:35 +#: ../data/plugins/11-spiegel-improved.algorithm.py:38 +#: ../data/plugins/11-spiegel-improved.algorithm.py:83 +#: ../data/plugins/11-spiegel-improved.algorithm.py:122 +#: ../data/plugins/11-spiegel-improved.algorithm.py:154 +#: ../data/plugins/11-spiegel-improved.algorithm.py:180 +#: ../data/plugins/11-spiegel-improved.algorithm.py:198 +#: ../data/plugins/11-spiegel-improved.algorithm.py:212 +#: ../data/plugins/12-lbl-leyan.algorithm.py:22 +#: ../data/plugins/12-lbl-leyan.algorithm.py:25 +#: ../data/plugins/12-lbl-leyan.algorithm.py:54 +#: ../data/plugins/12-lbl-leyan.algorithm.py:75 +#: ../data/plugins/12-lbl-leyan.algorithm.py:91 +#: ../data/plugins/12-lbl-leyan.algorithm.py:108 +#: ../data/plugins/12-lbl-leyan.algorithm.py:130 +#: ../data/plugins/12-lbl-leyan.algorithm.py:171 +#: ../data/plugins/20-2x2x2.algorithm.py:19 +#: ../data/plugins/20-2x2x2.algorithm.py:22 +#: ../data/plugins/20-2x2x2.algorithm.py:41 +#: ../data/plugins/20-2x2x2.algorithm.py:61 +msgid "Solvers" +msgstr "Solveurs" + +#. Spiegel is the name of a solution method +#: ../data/plugins/10-spiegel.algorithm.py:37 +#: ../data/plugins/10-spiegel.algorithm.py:39 +#: ../data/plugins/10-spiegel.algorithm.py:68 +#: ../data/plugins/10-spiegel.algorithm.py:89 +#: ../data/plugins/10-spiegel.algorithm.py:104 +#: ../data/plugins/10-spiegel.algorithm.py:117 +#: ../data/plugins/10-spiegel.algorithm.py:134 +#: ../data/plugins/10-spiegel.algorithm.py:145 +msgid "Spiegel" +msgstr "Spiegel" + +#: ../data/plugins/10-spiegel.algorithm.py:40 +#: ../data/plugins/11-spiegel-improved.algorithm.py:40 +#: ../data/plugins/12-lbl-leyan.algorithm.py:27 +msgid "Top edges" +msgstr "Bords supérieurs" + +#: ../data/plugins/10-spiegel.algorithm.py:69 +#: ../data/plugins/11-spiegel-improved.algorithm.py:85 +#: ../data/plugins/12-lbl-leyan.algorithm.py:56 +msgid "Top corners" +msgstr "Coins supérieurs" + +#: ../data/plugins/10-spiegel.algorithm.py:90 +#: ../data/plugins/11-spiegel-improved.algorithm.py:124 +#: ../data/plugins/12-lbl-leyan.algorithm.py:77 +msgid "Middle slice" +msgstr "" + +#: ../data/plugins/10-spiegel.algorithm.py:105 +#: ../data/plugins/11-spiegel-improved.algorithm.py:156 +#: ../data/plugins/12-lbl-leyan.algorithm.py:173 +msgid "Bottom edge place" +msgstr "" + +#: ../data/plugins/10-spiegel.algorithm.py:118 +#: ../data/plugins/11-spiegel-improved.algorithm.py:182 +#: ../data/plugins/12-lbl-leyan.algorithm.py:93 +msgid "Bottom edge orient" +msgstr "" + +#: ../data/plugins/10-spiegel.algorithm.py:135 +#: ../data/plugins/11-spiegel-improved.algorithm.py:200 +#: ../data/plugins/12-lbl-leyan.algorithm.py:110 +#: ../data/plugins/20-2x2x2.algorithm.py:43 +msgid "Bottom corner place" +msgstr "" + +#: ../data/plugins/10-spiegel.algorithm.py:146 +#: ../data/plugins/11-spiegel-improved.algorithm.py:214 +#: ../data/plugins/12-lbl-leyan.algorithm.py:132 +#: ../data/plugins/20-2x2x2.algorithm.py:63 +msgid "Bottom corner orient" +msgstr "" + +#. Spiegel is the name of a solution method +#: ../data/plugins/11-spiegel-improved.algorithm.py:37 +#: ../data/plugins/11-spiegel-improved.algorithm.py:39 +#: ../data/plugins/11-spiegel-improved.algorithm.py:84 +#: ../data/plugins/11-spiegel-improved.algorithm.py:123 +#: ../data/plugins/11-spiegel-improved.algorithm.py:155 +#: ../data/plugins/11-spiegel-improved.algorithm.py:181 +#: ../data/plugins/11-spiegel-improved.algorithm.py:199 +#: ../data/plugins/11-spiegel-improved.algorithm.py:213 +msgid "Spiegel improved" +msgstr "" + +#. Leyan Lo is the inventor of the solution method +#: ../data/plugins/12-lbl-leyan.algorithm.py:24 +#: ../data/plugins/12-lbl-leyan.algorithm.py:26 +#: ../data/plugins/12-lbl-leyan.algorithm.py:55 +#: ../data/plugins/12-lbl-leyan.algorithm.py:76 +#: ../data/plugins/12-lbl-leyan.algorithm.py:92 +#: ../data/plugins/12-lbl-leyan.algorithm.py:109 +#: ../data/plugins/12-lbl-leyan.algorithm.py:131 +#: ../data/plugins/12-lbl-leyan.algorithm.py:172 +msgid "Layer Method (Leyan Lo)" +msgstr "" + +#: ../data/plugins/20-2x2x2.algorithm.py:20 +#: ../data/plugins/20-2x2x2.algorithm.py:23 +#: ../data/plugins/20-2x2x2.algorithm.py:42 +#: ../data/plugins/20-2x2x2.algorithm.py:62 +msgid "2×2×2" +msgstr "" + +#: ../data/plugins/20-2x2x2.algorithm.py:24 +msgid "Top slice" +msgstr "Tranche supérieure" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:18 +#: ../data/plugins/80-pretty-patterns.algorithm.py:22 +#: ../data/plugins/80-pretty-patterns.algorithm.py:26 +#: ../data/plugins/80-pretty-patterns.algorithm.py:30 +#: ../data/plugins/80-pretty-patterns.algorithm.py:34 +#: ../data/plugins/80-pretty-patterns.algorithm.py:39 +#: ../data/plugins/80-pretty-patterns.algorithm.py:43 +#: ../data/plugins/80-pretty-patterns.algorithm.py:48 +#: ../data/plugins/80-pretty-patterns.algorithm.py:52 +#: ../data/plugins/80-pretty-patterns.algorithm.py:56 +#: ../data/plugins/80-pretty-patterns.algorithm.py:60 +#: ../data/plugins/80-pretty-patterns.algorithm.py:64 +#: ../data/plugins/80-pretty-patterns.algorithm.py:68 +#: ../data/plugins/80-pretty-patterns.algorithm.py:74 +#: ../data/plugins/80-pretty-patterns.algorithm.py:78 +#: ../data/plugins/80-pretty-patterns.algorithm.py:83 +#: ../data/plugins/80-pretty-patterns.algorithm.py:87 +#: ../data/plugins/80-pretty-patterns.algorithm.py:91 +#: ../data/plugins/80-pretty-patterns.algorithm.py:95 +#: ../data/plugins/80-pretty-patterns.algorithm.py:99 +#: ../data/plugins/80-pretty-patterns.algorithm.py:103 +#: ../data/plugins/80-pretty-patterns.algorithm.py:108 +#: ../data/plugins/80-pretty-patterns.algorithm.py:112 +#: ../data/plugins/80-pretty-patterns.algorithm.py:116 +#: ../data/plugins/80-pretty-patterns.algorithm.py:120 +#: ../data/plugins/80-pretty-patterns.algorithm.py:124 +#: ../data/plugins/80-pretty-patterns.algorithm.py:128 +#: ../data/plugins/80-pretty-patterns.algorithm.py:132 +#: ../data/plugins/80-pretty-patterns.algorithm.py:136 +#: ../data/plugins/80-pretty-patterns.algorithm.py:140 +msgid "Pretty patterns" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:19 +#: ../data/plugins/80-pretty-patterns.algorithm.py:23 +#: ../data/plugins/80-pretty-patterns.algorithm.py:27 +#: ../data/plugins/80-pretty-patterns.algorithm.py:31 +#: ../data/plugins/80-pretty-patterns.algorithm.py:35 +#: ../data/plugins/80-pretty-patterns.algorithm.py:40 +#: ../data/plugins/80-pretty-patterns.algorithm.py:44 +msgid "Stripes" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:49 +#: ../data/plugins/80-pretty-patterns.algorithm.py:53 +msgid "Criss-Cross" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:57 +msgid "Fried Eggs" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:61 +msgid "Big Fried Eggs" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:65 +msgid "4 Fried Eggs" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:69 +msgid "Chessboard" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:75 +msgid "Cross" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:79 +msgid "Zig Zag" +msgstr "" + +#. T is the shape formed by the cube labels +#: ../data/plugins/80-pretty-patterns.algorithm.py:85 +#: ../data/plugins/80-pretty-patterns.algorithm.py:88 +#: ../data/plugins/80-pretty-patterns.algorithm.py:92 +#: ../data/plugins/80-pretty-patterns.algorithm.py:96 +#: ../data/plugins/80-pretty-patterns.algorithm.py:100 +#: ../data/plugins/80-pretty-patterns.algorithm.py:104 +msgid "T-Time" +msgstr "" + +#. C is the shape formed by the cube labels +#: ../data/plugins/80-pretty-patterns.algorithm.py:110 +msgid "C" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:113 +msgid "Cube in a Cube" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:117 +msgid "Striped Cube in a Cube" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:121 +msgid "Six Square Cuboids" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:125 +msgid "Superflip" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:129 +msgid "Superflip easy" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:133 +msgid "Green Mamba" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:137 +msgid "Anaconda" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:141 +msgid "Duck Feet" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:20 +#: ../data/plugins/90-library.algorithm.py:23 +#: ../data/plugins/90-library.algorithm.py:26 +#: ../data/plugins/90-library.algorithm.py:29 +#: ../data/plugins/90-library.algorithm.py:32 +#: ../data/plugins/90-library.algorithm.py:35 +#: ../data/plugins/90-library.algorithm.py:38 +#: ../data/plugins/90-library.algorithm.py:41 +#: ../data/plugins/90-library.algorithm.py:44 +#: ../data/plugins/90-library.algorithm.py:47 +#: ../data/plugins/90-library.algorithm.py:50 +msgid "Library" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:21 +#: ../data/plugins/90-library.algorithm.py:24 +msgid "Middle Layer" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:22 +msgid "Front to Right" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:25 +msgid "Front to Left" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:27 +#: ../data/plugins/90-library.algorithm.py:30 +#: ../data/plugins/90-library.algorithm.py:33 +#: ../data/plugins/90-library.algorithm.py:36 +msgid "Last Layer" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:28 +msgid "Swap Edges" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:31 +msgid "Flip Edges" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:34 +msgid "Swap Corners" +msgstr "Échanger les coins" + +#: ../data/plugins/90-library.algorithm.py:37 +msgid "Rotate Corners" +msgstr "Pivoter les coins" + +#: ../data/plugins/90-library.algorithm.py:39 +#: ../data/plugins/90-library.algorithm.py:42 +#: ../data/plugins/90-library.algorithm.py:45 +msgid "Rotate Center" +msgstr "Pivoter le centre" + +#: ../data/plugins/90-library.algorithm.py:40 +msgid "2×Up" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:43 +msgid "Up and Front" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:46 +msgid "Up and Down" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:48 +#: ../data/plugins/90-library.algorithm.py:51 +msgid "Misc" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:49 +msgid "Back without Back" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:52 +msgid "2×Back without Back" +msgstr "" diff -Nru pybik-0.5/po/gl.po pybik-1.0.1/po/gl.po --- pybik-0.5/po/gl.po 1970-01-01 00:00:00.000000000 +0000 +++ pybik-1.0.1/po/gl.po 2013-02-01 20:18:02.000000000 +0000 @@ -0,0 +1,912 @@ +# Galician translation for pybik +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the pybik package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: pybik\n" +"Report-Msgid-Bugs-To: https://bugs.launchpad.net/pybik/+filebug\n" +"POT-Creation-Date: 2013-01-31 14:25+0100\n" +"PO-Revision-Date: 2012-12-20 10:28+0000\n" +"Last-Translator: Miguel Anxo Bouzada \n" +"Language-Team: Galician \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Launchpad-Export-Date: 2012-12-21 05:03+0000\n" +"X-Generator: Launchpad (build 16378)\n" + +#: ../pybiklib/application.py:304 +msgid "Press the Esc key to exit Edit Mode" +msgstr "Prema a tecla Esc para saír do modo de edición" + +#. substitution for {move_text} in statusbar text +#: ../pybiklib/application.py:313 +msgid "{current} / {total} move" +msgid_plural "{current} / {total} moves" +msgstr[0] "{current} / {total} movemento" +msgstr[1] "{current} / {total} movementos" + +#. substitution for {solved_text} in statusbar text +#: ../pybiklib/application.py:317 ../pybiklib/ui/model.py:82 +msgid "solved" +msgstr "resolto" + +#: ../pybiklib/application.py:317 +msgid "not solved" +msgstr "sen resolver" + +#. statusbar text +#: ../pybiklib/application.py:320 +msgid "{model_text}, {move_text}, {solved_text}" +msgstr "{model_text}, {move_text}, {solved_text}" + +#: ../pybiklib/application.py:353 +msgid "Congratulations, you have solved the puzzle!" +msgstr "Parabéns, resolveu o crebacabezas!" + +#: ../pybiklib/config.py:30 ../pybiklib/ui/main.py:194 +#: ../data/applications/pybik.desktop.in.h:1 +msgid "Pybik" +msgstr "Pybik" + +#: ../pybiklib/config.py:59 ../data/applications/pybik.desktop.in.h:2 +msgid "3D Rubik's cube game" +msgstr "Xogo do cubo de Rubik en 3D" + +#: ../pybiklib/config.py:61 +msgid "" +"Pybik is an interactive, graphical, single player puzzle about the cube " +"invented by Ernő Rubik. Besides the cube the program can handle towers and " +"bricks (non cubic puzzles). Pybik also has solvers, pretty patterns and a " +"collection of various moves. The cube can be manipulated with the mouse or " +"keyboard. You can change the colors or images on the faces of the cube." +msgstr "" +"Pybik é un crebacabezas gráfico e interactivo, baseado no cubo inventado por " +" Ernő Rubik. Ademais do cubo, o programa pode manexar torres e ladrillos " +"(crebacabezas que non son cúbicos). Pybik dispón tamén de solucionadores, " +"modelos agradábeis e unha colección de movementos. O cubo pode manipularse " +"co rato ou co teclado. Vostede pode cambiarlle as cores ou as imaxes nas " +"caras do cubo." + +#: ../pybiklib/config.py:69 +msgid "" +"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.\n" +"\n" +"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." +msgstr "" +"Este programa é software lbre: vostede pode redistribuílo e/pu modificalo " +"baixo os termos da Licenza Pública Xeral GNU, tal e como é publicada pola " +"Free Software Foundation, na súa versión 3, ou (á súa elección) segundo unha " +"versión posterior.\n" +"\n" +"Este programa distribúese agardando que sexa útil, mais SEN NINGUNHA " +"GARANTÍA, incluso sen a garantía expresa de COMERCIALIZACIÓN ou de " +"IDONEIDADE PARA UN PROPÓSITO PARTICULAR. Vexa a Licenza Pública Xeral GNU " +"para obter máis detalles." + +#: ../pybiklib/config.py:79 +msgid "" +"Read the full text of the GNU General Public " +"License<|> or see ." +msgstr "" +"Lea o texto completo da Licenza Pública Xeral de " +"GNU<|> ou olle ." + +#: ../pybiklib/config.py:82 +msgid "" +"You should have received a copy of the GNU General Public License along with " +"this program. If not, see ." +msgstr "" +"Debeu recibir unha copia da Licenza pública xeral GNU xunto con este " +"programa; en caso contrario, olle ." + +#: ../pybiklib/config.py:88 +msgid "" +"If you find any bugs in Pybik or have a suggestion for an improvement then " +"please submit a <{CONTACT_FILEBUG}|>bug report<|>. In the latter case you " +"can mark the bug report as \"Wishlist\"." +msgstr "" +"Se atopa algún erro no Pybik ou ten unha suxestión para melloralo, envíe un " +"<{CONTACT_FILEBUG}|>informe de erro<|>. Neste último caso se pode marcar o " +"informe de erro como «Wishlist» (Lista de desexos)." + +#: ../pybiklib/config.py:94 +msgid "" +"Translations are managed by the " +"Launchpad " +"translation group<|>.\n" +"\n" +"If you want help to translate Pybik to your language you can do it through " +"the web interface<|>.\n" +"\n" +"Read more about \"Translating with " +"Launchpad\"<|> and " +"\"Starting to " +"translate\"<|>." +msgstr "" +"As traducións son xestionadas polo " +"Grupo de " +"tradución de Launchpad<|>.\n" +"\n" +"Se quere axudar na tradución do Pybik ao seu idioma pode facelos na " +"interface web<|>.\n" +"\n" +"Bótelle unha ollada a \"Traducindo " +"co Launchpad\"<|> e " +"\"Comezar a " +"traducir\"<|>." + +#: ../pybiklib/dialogs.py:168 +msgid "Press a key …" +msgstr "Prema unha tecla…" + +#: ../pybiklib/dialogs.py:296 +msgid "plain" +msgstr "simple" + +#: ../pybiklib/dialogs.py:301 +msgid "select …" +msgstr "seleccionar..." + +#: ../pybiklib/dialogs.py:313 +msgid "Up" +msgstr "Arriba" + +#: ../pybiklib/dialogs.py:313 +msgid "Down" +msgstr "Abaixo" + +#: ../pybiklib/dialogs.py:313 +msgid "Left" +msgstr "Esquerda" + +#: ../pybiklib/dialogs.py:313 +msgid "Right" +msgstr "Dereita" + +#: ../pybiklib/dialogs.py:313 +msgid "Front" +msgstr "Adiante" + +#: ../pybiklib/dialogs.py:313 +msgid "Back" +msgstr "Atrás" + +#: ../pybiklib/dialogs.py:331 +msgid "Move" +msgstr "Mover" + +#: ../pybiklib/dialogs.py:332 +msgid "Key" +msgstr "Tecla" + +#: ../pybiklib/dialogs.py:486 +msgid "Open Image" +msgstr "Abrir a imaxe" + +#: ../pybiklib/dialogs.py:536 ../pybiklib/ui/model.py:79 +msgid "Size:" +msgstr "Tamaño:" + +#: ../pybiklib/dialogs.py:536 +msgid "Basis:" +msgstr "Base:" + +#: ../pybiklib/dialogs.py:536 +msgid "Width:" +msgstr "Largo:" + +#: ../pybiklib/dialogs.py:565 +msgid "Canceling operation, please wait" +msgstr "Cancelando a operación, agarde un chisco" + +#: ../pybiklib/dialogs.py:621 +msgid "Pybik project website" +msgstr "Páxina web do proxecto Pybik" + +#: ../pybiklib/main.py:287 +msgid "" +"An error occurred while reading the settings:\n" +"{error_message}" +msgstr "" +"Produciuse un erro ao ler a configuración:\n" +"{error_message}" + +#: ../pybiklib/model.py:214 +msgid "Brick" +msgstr "Ladrillo" + +#: ../pybiklib/model.py:215 +msgid "{0}×{1}×{2}-Brick" +msgstr "{0}×{1}×{2}-ladrillo" + +#: ../pybiklib/model.py:835 +msgid "Tower" +msgstr "Torre" + +#: ../pybiklib/model.py:836 +msgid "{0}×{1}-Tower" +msgstr "{0}×{1}-torre" + +#: ../pybiklib/model.py:850 +msgid "Cube" +msgstr "Cubo" + +#: ../pybiklib/model.py:851 +msgid "{0}×{0}×{0}-Cube" +msgstr "{0}×{0}×{0}-Cubo" + +#: ../pybiklib/plugins.py:92 +msgid "This algorithm does not work for any model.\n" +msgstr "Este algoritmo non funciona para calquera modelo.\n" + +#: ../pybiklib/plugins.py:94 ../pybiklib/plugins.py:97 +msgid "This algorithm only works for:\n" +msgstr "Este algoritmo só funciona para:\n" + +#: ../pybiklib/settings.py:256 +msgid "Settings can not be written to file: {error_message}" +msgstr "" +"Non foi posíbel gardar as configuracións no ficheiro: {error_message}" + +#: ../pybiklib/ui/about.py:131 +msgid "About Pybik" +msgstr "Sobre o Pybik" + +#: ../pybiklib/ui/about.py:132 +msgid "About" +msgstr "Sobre" + +#: ../pybiklib/ui/about.py:133 +msgid "Feedback" +msgstr "Comentarios" + +#: ../pybiklib/ui/about.py:134 +msgid "Translation" +msgstr "Tradución" + +#: ../pybiklib/ui/about.py:135 +msgid "License" +msgstr "Licenza" + +#: ../pybiklib/ui/main.py:195 +msgid "&Game" +msgstr "&Xogo" + +#: ../pybiklib/ui/main.py:196 +msgid "&Edit" +msgstr "&Editar" + +#: ../pybiklib/ui/main.py:197 +msgid "&View" +msgstr "&Ver" + +#: ../pybiklib/ui/main.py:198 +msgid "&Help" +msgstr "&Axuda" + +#: ../pybiklib/ui/main.py:199 +msgid "Pybik Toolbar" +msgstr "Barra de ferramentas do Pybik" + +#: ../pybiklib/ui/main.py:200 +msgid "&New Random" +msgstr "&Novo ao chou" + +#: ../pybiklib/ui/main.py:201 +msgid "Ne&w Solved" +msgstr "No&vo resolto" + +#: ../pybiklib/ui/main.py:202 +msgid "&Quit" +msgstr "&Saír" + +#: ../pybiklib/ui/main.py:203 +msgid "&Select Model …" +msgstr "&Seleccionar modelo..." + +#: ../pybiklib/ui/main.py:204 +msgid "&Set as Initial State" +msgstr "&Definir como estado inicial" + +#: ../pybiklib/ui/main.py:205 +msgid "&Reset Rotation" +msgstr "&Restabelecer a rotación" + +#: ../pybiklib/ui/main.py:206 +msgid "&Invert Moves" +msgstr "&Inverter os movementos" + +#: ../pybiklib/ui/main.py:207 +msgid "Reload Plugins" +msgstr "Recargar os engadidos" + +#: ../pybiklib/ui/main.py:208 +msgid "&Preferences …" +msgstr "&Preferencias…" + +#: ../pybiklib/ui/main.py:209 +msgid "&Toolbar" +msgstr "Barra de &ferramentas" + +#: ../pybiklib/ui/main.py:210 +msgid "&Status Bar" +msgstr "Barra de &estado" + +#: ../pybiklib/ui/main.py:211 +msgid "&Info …" +msgstr "&Información…" + +#: ../pybiklib/ui/main.py:212 +msgid "Rewind" +msgstr "Retroceder" + +#: ../pybiklib/ui/main.py:213 +msgid "Go to the previous mark (or the beginning) of the sequence of moves" +msgstr "Ir á marca anterior (ou ao principio) da secuencia de movementos" + +#: ../pybiklib/ui/main.py:214 +msgid "Previous" +msgstr "Anterior" + +#: ../pybiklib/ui/main.py:215 +msgid "Make one step backwards" +msgstr "Definir un paso atrás" + +#: ../pybiklib/ui/main.py:216 +msgid "Stop" +msgstr "Deter" + +#: ../pybiklib/ui/main.py:217 +msgid "Stop running the sequence of moves" +msgstr "Deter a execución da secuencia de movementos" + +#: ../pybiklib/ui/main.py:218 +msgid "Play" +msgstr "Xogar" + +#: ../pybiklib/ui/main.py:219 +msgid "Run forward through the sequence of moves" +msgstr "Executar cara diante a secuencia de movementos" + +#: ../pybiklib/ui/main.py:220 +msgid "Next" +msgstr "Seguinte" + +#: ../pybiklib/ui/main.py:221 +msgid "Make one step forwards" +msgstr "Definir un paso adiante" + +#: ../pybiklib/ui/main.py:222 +msgid "Forward" +msgstr "Avanzar" + +#: ../pybiklib/ui/main.py:223 +msgid "Go to the next mark (or the end) of the sequence of moves" +msgstr "Ir á seguinte marca (ou a fin) da secuencia de movementos" + +#: ../pybiklib/ui/main.py:224 +msgid "Add Mark" +msgstr "Engadir marca" + +#: ../pybiklib/ui/main.py:225 +msgid "Mark the current place in the sequence of moves" +msgstr "Marcar o lugar actual na secuencia de movementos" + +#: ../pybiklib/ui/main.py:226 +msgid "Remove Mark" +msgstr "Retirar marca" + +#: ../pybiklib/ui/main.py:227 +msgid "Remove the mark at the current place in the sequence of moves" +msgstr "Retirar a marcar do lugar actual na secuencia de movementos" + +#: ../pybiklib/ui/main.py:228 +msgid "&Edit Bar" +msgstr "&Editar barra" + +#: ../pybiklib/ui/main.py:229 +msgid "Normalize Cube Rotations" +msgstr "Homoxeneizar as rotacións do cubo" + +#: ../pybiklib/ui/model.py:78 +msgid "Select Model" +msgstr "Seleccionar modelo" + +#: ../pybiklib/ui/model.py:80 +msgid "Height:" +msgstr "Alto:" + +#: ../pybiklib/ui/model.py:81 +msgid "Depth:" +msgstr "Profundidade:" + +#: ../pybiklib/ui/preferences.py:252 +msgid "Preferences" +msgstr "Preferencias" + +#: ../pybiklib/ui/preferences.py:253 +msgid "Animation Speed:" +msgstr "Velocidade da animación:" + +#: ../pybiklib/ui/preferences.py:254 +msgid "Lighting" +msgstr "Iluminación" + +#: ../pybiklib/ui/preferences.py:255 +msgid "Mirror Distance:" +msgstr "Distancia do espello:" + +#: ../pybiklib/ui/preferences.py:256 +msgid "Antialiasing" +msgstr "Suavizado" + +#: ../pybiklib/ui/preferences.py:257 +msgid "Hardware:" +msgstr "Hardware:" + +#: ../pybiklib/ui/preferences.py:258 +msgid "Software:" +msgstr "Software:" + +#: ../pybiklib/ui/preferences.py:259 +msgid "" +"

The program needs to " +"be restarted for the changes to take effect.

" +msgstr "" +"

Necesita reiniciar o " +"programa para que os cambios teñan efecto.

" + +#: ../pybiklib/ui/preferences.py:260 +msgid "Graphic" +msgstr "Gráfico" + +#: ../pybiklib/ui/preferences.py:261 +msgid "Four directions" +msgstr "Catro direccións" + +#: ../pybiklib/ui/preferences.py:262 +msgid "" +"Simplified,\n" +"right button inverts move" +msgstr "" +"Simplificado,\n" +"o botón dereito inverte o movemento" + +#: ../pybiklib/ui/preferences.py:263 +msgid "Mouse" +msgstr "Rato" + +#: ../pybiklib/ui/preferences.py:264 ../pybiklib/ui/preferences.py:265 +msgid "Add" +msgstr "Engadir" + +#: ../pybiklib/ui/preferences.py:266 ../pybiklib/ui/preferences.py:267 +msgid "Remove" +msgstr "Retirar" + +#: ../pybiklib/ui/preferences.py:268 ../pybiklib/ui/preferences.py:269 +msgid "Reset" +msgstr "Restabelecer" + +#: ../pybiklib/ui/preferences.py:270 +msgid "Keys" +msgstr "Teclas" + +#: ../pybiklib/ui/preferences.py:271 +msgid "Color:" +msgstr "Cor:" + +#: ../pybiklib/ui/preferences.py:272 +msgid "Image File:" +msgstr "Ficheiro de imaxe:" + +#: ../pybiklib/ui/preferences.py:273 +msgid "Tiled" +msgstr "Teselado" + +#: ../pybiklib/ui/preferences.py:274 +msgid "Mosaic" +msgstr "Mosaico" + +#: ../pybiklib/ui/preferences.py:275 +msgid "Background:" +msgstr "Fondo:" + +#: ../pybiklib/ui/preferences.py:276 +msgid "Appearance" +msgstr "Aparencia" + +#. Add whatever keywords you want in your language, separated by semicolons. These keywords are used when searching for applications in dashes, etc. (Unity, GNOME Shell) +#: ../data/applications/pybik.desktop.in.h:4 +msgid "rubik;cube;puzzle;magic;" +msgstr "" + +#: ../data/plugins/01-challenges.algorithm.py:19 +#: ../data/plugins/01-challenges.algorithm.py:22 +#: ../data/plugins/01-challenges.algorithm.py:25 +#: ../data/plugins/01-challenges.algorithm.py:28 +#: ../data/plugins/01-challenges.algorithm.py:31 +#: ../data/plugins/01-challenges.algorithm.py:34 +#: ../data/plugins/01-challenges.algorithm.py:37 +#: ../data/plugins/01-challenges.algorithm.py:40 +#: ../data/plugins/01-challenges.algorithm.py:43 +#: ../data/plugins/01-challenges.algorithm.py:46 +#: ../data/plugins/01-challenges.algorithm.py:49 +msgid "Challenges" +msgstr "Retos" + +#: ../data/plugins/01-challenges.algorithm.py:20 +msgid "Solve random cube" +msgstr "Resolver o cuno ao chou" + +#: ../data/plugins/01-challenges.algorithm.py:23 +msgid "Solve in 1 move" +msgstr "Resolver nun movemento" + +#: ../data/plugins/01-challenges.algorithm.py:26 +msgid "Solve in 2 moves" +msgstr "Resolver en 2 movementos" + +#: ../data/plugins/01-challenges.algorithm.py:29 +msgid "Solve in 3 moves" +msgstr "Resolver en 3 movementos" + +#: ../data/plugins/01-challenges.algorithm.py:32 +msgid "Solve in 4 moves" +msgstr "Resolver en 4 movementos" + +#: ../data/plugins/01-challenges.algorithm.py:35 +msgid "Solve in 5 moves" +msgstr "Resolver en 5 movementos" + +#: ../data/plugins/01-challenges.algorithm.py:38 +msgid "Solve in 6 moves" +msgstr "Resolver en 6 movementos" + +#: ../data/plugins/01-challenges.algorithm.py:41 +msgid "Solve in 7 moves" +msgstr "Resolver en 7 movementos" + +#: ../data/plugins/01-challenges.algorithm.py:44 +msgid "Solve in 8 moves" +msgstr "Resolver en 8 movementos" + +#: ../data/plugins/01-challenges.algorithm.py:47 +msgid "Solve in 9 moves" +msgstr "Resolver en 9 movementos" + +#: ../data/plugins/01-challenges.algorithm.py:50 +msgid "Solve in 10 moves" +msgstr "Resolver en 10 movementos" + +#: ../data/plugins/10-spiegel.algorithm.py:35 +#: ../data/plugins/10-spiegel.algorithm.py:38 +#: ../data/plugins/10-spiegel.algorithm.py:67 +#: ../data/plugins/10-spiegel.algorithm.py:88 +#: ../data/plugins/10-spiegel.algorithm.py:103 +#: ../data/plugins/10-spiegel.algorithm.py:116 +#: ../data/plugins/10-spiegel.algorithm.py:133 +#: ../data/plugins/10-spiegel.algorithm.py:144 +#: ../data/plugins/11-spiegel-improved.algorithm.py:35 +#: ../data/plugins/11-spiegel-improved.algorithm.py:38 +#: ../data/plugins/11-spiegel-improved.algorithm.py:83 +#: ../data/plugins/11-spiegel-improved.algorithm.py:122 +#: ../data/plugins/11-spiegel-improved.algorithm.py:154 +#: ../data/plugins/11-spiegel-improved.algorithm.py:180 +#: ../data/plugins/11-spiegel-improved.algorithm.py:198 +#: ../data/plugins/11-spiegel-improved.algorithm.py:212 +#: ../data/plugins/12-lbl-leyan.algorithm.py:22 +#: ../data/plugins/12-lbl-leyan.algorithm.py:25 +#: ../data/plugins/12-lbl-leyan.algorithm.py:54 +#: ../data/plugins/12-lbl-leyan.algorithm.py:75 +#: ../data/plugins/12-lbl-leyan.algorithm.py:91 +#: ../data/plugins/12-lbl-leyan.algorithm.py:108 +#: ../data/plugins/12-lbl-leyan.algorithm.py:130 +#: ../data/plugins/12-lbl-leyan.algorithm.py:171 +#: ../data/plugins/20-2x2x2.algorithm.py:19 +#: ../data/plugins/20-2x2x2.algorithm.py:22 +#: ../data/plugins/20-2x2x2.algorithm.py:41 +#: ../data/plugins/20-2x2x2.algorithm.py:61 +msgid "Solvers" +msgstr "Solucionadores" + +#. Spiegel is the name of a solution method +#: ../data/plugins/10-spiegel.algorithm.py:37 +#: ../data/plugins/10-spiegel.algorithm.py:39 +#: ../data/plugins/10-spiegel.algorithm.py:68 +#: ../data/plugins/10-spiegel.algorithm.py:89 +#: ../data/plugins/10-spiegel.algorithm.py:104 +#: ../data/plugins/10-spiegel.algorithm.py:117 +#: ../data/plugins/10-spiegel.algorithm.py:134 +#: ../data/plugins/10-spiegel.algorithm.py:145 +msgid "Spiegel" +msgstr "Spiegel" + +#: ../data/plugins/10-spiegel.algorithm.py:40 +#: ../data/plugins/11-spiegel-improved.algorithm.py:40 +#: ../data/plugins/12-lbl-leyan.algorithm.py:27 +msgid "Top edges" +msgstr "Marxes superiores" + +#: ../data/plugins/10-spiegel.algorithm.py:69 +#: ../data/plugins/11-spiegel-improved.algorithm.py:85 +#: ../data/plugins/12-lbl-leyan.algorithm.py:56 +msgid "Top corners" +msgstr "Cantos superiores" + +#: ../data/plugins/10-spiegel.algorithm.py:90 +#: ../data/plugins/11-spiegel-improved.algorithm.py:124 +#: ../data/plugins/12-lbl-leyan.algorithm.py:77 +msgid "Middle slice" +msgstr "Banda do medio" + +#: ../data/plugins/10-spiegel.algorithm.py:105 +#: ../data/plugins/11-spiegel-improved.algorithm.py:156 +#: ../data/plugins/12-lbl-leyan.algorithm.py:173 +msgid "Bottom edge place" +msgstr "Situar o bordo inferior" + +#: ../data/plugins/10-spiegel.algorithm.py:118 +#: ../data/plugins/11-spiegel-improved.algorithm.py:182 +#: ../data/plugins/12-lbl-leyan.algorithm.py:93 +msgid "Bottom edge orient" +msgstr "Orientar o bordo inferior" + +#: ../data/plugins/10-spiegel.algorithm.py:135 +#: ../data/plugins/11-spiegel-improved.algorithm.py:200 +#: ../data/plugins/12-lbl-leyan.algorithm.py:110 +#: ../data/plugins/20-2x2x2.algorithm.py:43 +msgid "Bottom corner place" +msgstr "Situar o canto inferior" + +#: ../data/plugins/10-spiegel.algorithm.py:146 +#: ../data/plugins/11-spiegel-improved.algorithm.py:214 +#: ../data/plugins/12-lbl-leyan.algorithm.py:132 +#: ../data/plugins/20-2x2x2.algorithm.py:63 +msgid "Bottom corner orient" +msgstr "Orientar o canto inferior" + +#. Spiegel is the name of a solution method +#: ../data/plugins/11-spiegel-improved.algorithm.py:37 +#: ../data/plugins/11-spiegel-improved.algorithm.py:39 +#: ../data/plugins/11-spiegel-improved.algorithm.py:84 +#: ../data/plugins/11-spiegel-improved.algorithm.py:123 +#: ../data/plugins/11-spiegel-improved.algorithm.py:155 +#: ../data/plugins/11-spiegel-improved.algorithm.py:181 +#: ../data/plugins/11-spiegel-improved.algorithm.py:199 +#: ../data/plugins/11-spiegel-improved.algorithm.py:213 +msgid "Spiegel improved" +msgstr "Spiegel mellorado" + +#. Leyan Lo is the inventor of the solution method +#: ../data/plugins/12-lbl-leyan.algorithm.py:24 +#: ../data/plugins/12-lbl-leyan.algorithm.py:26 +#: ../data/plugins/12-lbl-leyan.algorithm.py:55 +#: ../data/plugins/12-lbl-leyan.algorithm.py:76 +#: ../data/plugins/12-lbl-leyan.algorithm.py:92 +#: ../data/plugins/12-lbl-leyan.algorithm.py:109 +#: ../data/plugins/12-lbl-leyan.algorithm.py:131 +#: ../data/plugins/12-lbl-leyan.algorithm.py:172 +msgid "Layer Method (Leyan Lo)" +msgstr "Método de capa (Leyan Lo)" + +#: ../data/plugins/20-2x2x2.algorithm.py:20 +#: ../data/plugins/20-2x2x2.algorithm.py:23 +#: ../data/plugins/20-2x2x2.algorithm.py:42 +#: ../data/plugins/20-2x2x2.algorithm.py:62 +msgid "2×2×2" +msgstr "2×2×2" + +#: ../data/plugins/20-2x2x2.algorithm.py:24 +msgid "Top slice" +msgstr "Banda superior" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:18 +#: ../data/plugins/80-pretty-patterns.algorithm.py:22 +#: ../data/plugins/80-pretty-patterns.algorithm.py:26 +#: ../data/plugins/80-pretty-patterns.algorithm.py:30 +#: ../data/plugins/80-pretty-patterns.algorithm.py:34 +#: ../data/plugins/80-pretty-patterns.algorithm.py:39 +#: ../data/plugins/80-pretty-patterns.algorithm.py:43 +#: ../data/plugins/80-pretty-patterns.algorithm.py:48 +#: ../data/plugins/80-pretty-patterns.algorithm.py:52 +#: ../data/plugins/80-pretty-patterns.algorithm.py:56 +#: ../data/plugins/80-pretty-patterns.algorithm.py:60 +#: ../data/plugins/80-pretty-patterns.algorithm.py:64 +#: ../data/plugins/80-pretty-patterns.algorithm.py:68 +#: ../data/plugins/80-pretty-patterns.algorithm.py:74 +#: ../data/plugins/80-pretty-patterns.algorithm.py:78 +#: ../data/plugins/80-pretty-patterns.algorithm.py:83 +#: ../data/plugins/80-pretty-patterns.algorithm.py:87 +#: ../data/plugins/80-pretty-patterns.algorithm.py:91 +#: ../data/plugins/80-pretty-patterns.algorithm.py:95 +#: ../data/plugins/80-pretty-patterns.algorithm.py:99 +#: ../data/plugins/80-pretty-patterns.algorithm.py:103 +#: ../data/plugins/80-pretty-patterns.algorithm.py:108 +#: ../data/plugins/80-pretty-patterns.algorithm.py:112 +#: ../data/plugins/80-pretty-patterns.algorithm.py:116 +#: ../data/plugins/80-pretty-patterns.algorithm.py:120 +#: ../data/plugins/80-pretty-patterns.algorithm.py:124 +#: ../data/plugins/80-pretty-patterns.algorithm.py:128 +#: ../data/plugins/80-pretty-patterns.algorithm.py:132 +#: ../data/plugins/80-pretty-patterns.algorithm.py:136 +#: ../data/plugins/80-pretty-patterns.algorithm.py:140 +msgid "Pretty patterns" +msgstr "Patróns agradábeis" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:19 +#: ../data/plugins/80-pretty-patterns.algorithm.py:23 +#: ../data/plugins/80-pretty-patterns.algorithm.py:27 +#: ../data/plugins/80-pretty-patterns.algorithm.py:31 +#: ../data/plugins/80-pretty-patterns.algorithm.py:35 +#: ../data/plugins/80-pretty-patterns.algorithm.py:40 +#: ../data/plugins/80-pretty-patterns.algorithm.py:44 +msgid "Stripes" +msgstr "Raias" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:49 +#: ../data/plugins/80-pretty-patterns.algorithm.py:53 +msgid "Criss-Cross" +msgstr "Entrelazado" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:57 +msgid "Fried Eggs" +msgstr "Ovos fritidos" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:61 +msgid "Big Fried Eggs" +msgstr "Ovos fritidos grandes" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:65 +msgid "4 Fried Eggs" +msgstr "4 ovos fritidos" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:69 +msgid "Chessboard" +msgstr "Taboleiro de xadrez" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:75 +msgid "Cross" +msgstr "Cruzamento" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:79 +msgid "Zig Zag" +msgstr "Zigzag" + +#. T is the shape formed by the cube labels +#: ../data/plugins/80-pretty-patterns.algorithm.py:85 +#: ../data/plugins/80-pretty-patterns.algorithm.py:88 +#: ../data/plugins/80-pretty-patterns.algorithm.py:92 +#: ../data/plugins/80-pretty-patterns.algorithm.py:96 +#: ../data/plugins/80-pretty-patterns.algorithm.py:100 +#: ../data/plugins/80-pretty-patterns.algorithm.py:104 +msgid "T-Time" +msgstr "T-tempo" + +#. C is the shape formed by the cube labels +#: ../data/plugins/80-pretty-patterns.algorithm.py:110 +msgid "C" +msgstr "C" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:113 +msgid "Cube in a Cube" +msgstr "Cubo nun cubo" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:117 +msgid "Striped Cube in a Cube" +msgstr "Cubo a raias nun cubo" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:121 +msgid "Six Square Cuboids" +msgstr "Cuboide de seis caras" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:125 +msgid "Superflip" +msgstr "Superflip" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:129 +msgid "Superflip easy" +msgstr "Superflip doado" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:133 +msgid "Green Mamba" +msgstr "Mamba verde" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:137 +msgid "Anaconda" +msgstr "Anaconda" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:141 +msgid "Duck Feet" +msgstr "Pé de pato" + +#: ../data/plugins/90-library.algorithm.py:20 +#: ../data/plugins/90-library.algorithm.py:23 +#: ../data/plugins/90-library.algorithm.py:26 +#: ../data/plugins/90-library.algorithm.py:29 +#: ../data/plugins/90-library.algorithm.py:32 +#: ../data/plugins/90-library.algorithm.py:35 +#: ../data/plugins/90-library.algorithm.py:38 +#: ../data/plugins/90-library.algorithm.py:41 +#: ../data/plugins/90-library.algorithm.py:44 +#: ../data/plugins/90-library.algorithm.py:47 +#: ../data/plugins/90-library.algorithm.py:50 +msgid "Library" +msgstr "Biblioteca" + +#: ../data/plugins/90-library.algorithm.py:21 +#: ../data/plugins/90-library.algorithm.py:24 +msgid "Middle Layer" +msgstr "Capa do medio" + +#: ../data/plugins/90-library.algorithm.py:22 +msgid "Front to Right" +msgstr "Fronte para dereita" + +#: ../data/plugins/90-library.algorithm.py:25 +msgid "Front to Left" +msgstr "Fronte para esquerda" + +#: ../data/plugins/90-library.algorithm.py:27 +#: ../data/plugins/90-library.algorithm.py:30 +#: ../data/plugins/90-library.algorithm.py:33 +#: ../data/plugins/90-library.algorithm.py:36 +msgid "Last Layer" +msgstr "Última capa" + +#: ../data/plugins/90-library.algorithm.py:28 +msgid "Swap Edges" +msgstr "Intercambiar os bordos" + +#: ../data/plugins/90-library.algorithm.py:31 +msgid "Flip Edges" +msgstr "Voltear os bordos" + +#: ../data/plugins/90-library.algorithm.py:34 +msgid "Swap Corners" +msgstr "Intercambiar os cantos" + +#: ../data/plugins/90-library.algorithm.py:37 +msgid "Rotate Corners" +msgstr "Rotar os cantos" + +#: ../data/plugins/90-library.algorithm.py:39 +#: ../data/plugins/90-library.algorithm.py:42 +#: ../data/plugins/90-library.algorithm.py:45 +msgid "Rotate Center" +msgstr "Rotar o centro" + +#: ../data/plugins/90-library.algorithm.py:40 +msgid "2×Up" +msgstr "2×arriba" + +#: ../data/plugins/90-library.algorithm.py:43 +msgid "Up and Front" +msgstr "Arriba e á fronte" + +#: ../data/plugins/90-library.algorithm.py:46 +msgid "Up and Down" +msgstr "Arriba e abaixo" + +#: ../data/plugins/90-library.algorithm.py:48 +#: ../data/plugins/90-library.algorithm.py:51 +msgid "Misc" +msgstr "Miscelánea" + +#: ../data/plugins/90-library.algorithm.py:49 +msgid "Back without Back" +msgstr "Atrás sen retorno" + +#: ../data/plugins/90-library.algorithm.py:52 +msgid "2×Back without Back" +msgstr "2×atrás sen retorno" diff -Nru pybik-0.5/po/he.po pybik-1.0.1/po/he.po --- pybik-0.5/po/he.po 1970-01-01 00:00:00.000000000 +0000 +++ pybik-1.0.1/po/he.po 2013-02-01 20:18:02.000000000 +0000 @@ -0,0 +1,908 @@ +# Hebrew translation for pybik +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the pybik package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: pybik\n" +"Report-Msgid-Bugs-To: https://bugs.launchpad.net/pybik/+filebug\n" +"POT-Creation-Date: 2013-01-31 14:25+0100\n" +"PO-Revision-Date: 2013-01-08 13:42+0000\n" +"Last-Translator: Yaron \n" +"Language-Team: Hebrew \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Launchpad-Export-Date: 2013-01-09 05:14+0000\n" +"X-Generator: Launchpad (build 16412)\n" + +#: ../pybiklib/application.py:304 +msgid "Press the Esc key to exit Edit Mode" +msgstr "יש ללחוץ על מקש ה־Esc כדי לצאת ממצב העריכה" + +#. substitution for {move_text} in statusbar text +#: ../pybiklib/application.py:313 +msgid "{current} / {total} move" +msgid_plural "{current} / {total} moves" +msgstr[0] "{current} / מהלך {total}" +msgstr[1] "{current} / {total} מהלכים" + +#. substitution for {solved_text} in statusbar text +#: ../pybiklib/application.py:317 ../pybiklib/ui/model.py:82 +msgid "solved" +msgstr "נפתר" + +#: ../pybiklib/application.py:317 +msgid "not solved" +msgstr "לא נפתר" + +#. statusbar text +#: ../pybiklib/application.py:320 +msgid "{model_text}, {move_text}, {solved_text}" +msgstr "{model_text}, {move_text}, {solved_text}" + +#: ../pybiklib/application.py:353 +msgid "Congratulations, you have solved the puzzle!" +msgstr "ברכות, פתרת את הפאזל!" + +#: ../pybiklib/config.py:30 ../pybiklib/ui/main.py:194 +#: ../data/applications/pybik.desktop.in.h:1 +msgid "Pybik" +msgstr "Pybik" + +#: ../pybiklib/config.py:59 ../data/applications/pybik.desktop.in.h:2 +msgid "3D Rubik's cube game" +msgstr "משחק קוביה הונגרית תלת־ממדי" + +#: ../pybiklib/config.py:61 +msgid "" +"Pybik is an interactive, graphical, single player puzzle about the cube " +"invented by Ernő Rubik. Besides the cube the program can handle towers and " +"bricks (non cubic puzzles). Pybik also has solvers, pretty patterns and a " +"collection of various moves. The cube can be manipulated with the mouse or " +"keyboard. You can change the colors or images on the faces of the cube." +msgstr "" +"Pybik הנו פאזל אינטראקטיבי, גרפי לשחקן יחיד על הקוביה שהמציא ארנו רוביק " +"(Ernő Rubik). מלבד הקוביה התכנית יכולה לטפל במגדלים ולבנים (פאזלים שאינם " +"בצורת קוביה). ל־Pybik יש גם אפשרויות פתרון, תבניות יפות ואוסף של מהלכים " +"מגוונים. ניתן לתפעל את הקוביה עם העכבר או עם המקלדת. ניתן לשנות את הצבעים או " +"התמונות על פאות הקוביה." + +#: ../pybiklib/config.py:69 +msgid "" +"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.\n" +"\n" +"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." +msgstr "" +"תכנית זו הנה תכנה חופשית; ניתן להפיץ אותה תחת תנאי הרישיון הציבורי הכללי של " +"גנו כפי שפורסם על ידי קרן התכנה החופשית, בין אם גרסה 3 של הרישיון או כל גרסה " +"עדכנית יותר לבחירתך.\n" +"\n" +"תכנית זו מופצת בתקווה שתביא תועלת אך אינה כוללת כל סוג של אחריות; אפילו לא " +"מרומזת לצורכי מסחר או התאמה לצרכים מסוימים. ניתן לעיין ברישיון הציבורי הכללי " +"של גנו לקבלת פרטים נוספים." + +#: ../pybiklib/config.py:79 +msgid "" +"Read the full text of the GNU General Public " +"License<|> or see ." +msgstr "" +"ניתן לקרוא את התוכן המלא של הרישיון הציבורי הכללי " +"של גנו<|> להיכנס ל־." + +#: ../pybiklib/config.py:82 +msgid "" +"You should have received a copy of the GNU General Public License along with " +"this program. If not, see ." +msgstr "" +"לתכנית זו אמור היה להיות מצורף עותק של הרישיון הציבורי הכללי של GNU; אם לא " +"צורף, ניתן לבקר בכתובת ." + +#: ../pybiklib/config.py:88 +msgid "" +"If you find any bugs in Pybik or have a suggestion for an improvement then " +"please submit a <{CONTACT_FILEBUG}|>bug report<|>. In the latter case you " +"can mark the bug report as \"Wishlist\"." +msgstr "" +"אם מצאת תקלות ב־Pybik או שיש לך הצעות לשיפורים נא לשלוח " +"<{CONTACT_FILEBUG}|>דיווח על תקלה<|>. במקרה השני שצוין ניתן לסמן את התקלה " +"בתור „משאלה“ (Wishlist)" + +#: ../pybiklib/config.py:94 +msgid "" +"Translations are managed by the " +"Launchpad " +"translation group<|>.\n" +"\n" +"If you want help to translate Pybik to your language you can do it through " +"the web interface<|>.\n" +"\n" +"Read more about \"Translating with " +"Launchpad\"<|> and " +"\"Starting to " +"translate\"<|>." +msgstr "" +"התרגומים מנוהלים באמצעות " +"קבוצת " +"התרגום של לאנצ׳פד<|>.\n" +"\n" +"אם בא לך לסייע בתרגום Pybik לשפתך ניתן לעשות זאת דרך " +"המנשק המקוון<|>.\n" +"\n" +"ניתן לקרוא עוד על \"תרגום עם " +"לאנצ׳פד\"<|> ועל " +"\"כיצד מתחילים " +"לתרגם\"<|>." + +#: ../pybiklib/dialogs.py:168 +msgid "Press a key …" +msgstr "נא ללחוץ על מקש כלשהו …" + +#: ../pybiklib/dialogs.py:296 +msgid "plain" +msgstr "פשוט" + +#: ../pybiklib/dialogs.py:301 +msgid "select …" +msgstr "בחירה …" + +#: ../pybiklib/dialogs.py:313 +msgid "Up" +msgstr "למעלה" + +#: ../pybiklib/dialogs.py:313 +msgid "Down" +msgstr "למטה" + +#: ../pybiklib/dialogs.py:313 +msgid "Left" +msgstr "שמאלה" + +#: ../pybiklib/dialogs.py:313 +msgid "Right" +msgstr "ימינה" + +#: ../pybiklib/dialogs.py:313 +msgid "Front" +msgstr "חזית" + +#: ../pybiklib/dialogs.py:313 +msgid "Back" +msgstr "אחורה" + +#: ../pybiklib/dialogs.py:331 +msgid "Move" +msgstr "הזזה" + +#: ../pybiklib/dialogs.py:332 +msgid "Key" +msgstr "מקש" + +#: ../pybiklib/dialogs.py:486 +msgid "Open Image" +msgstr "פתיחת תמונה" + +#: ../pybiklib/dialogs.py:536 ../pybiklib/ui/model.py:79 +msgid "Size:" +msgstr "גודל:‏" + +#: ../pybiklib/dialogs.py:536 +msgid "Basis:" +msgstr "בסיס:" + +#: ../pybiklib/dialogs.py:536 +msgid "Width:" +msgstr "רוחב:‏" + +#: ../pybiklib/dialogs.py:565 +msgid "Canceling operation, please wait" +msgstr "הפעולה מבוטלת, נא להמתין" + +#: ../pybiklib/dialogs.py:621 +msgid "Pybik project website" +msgstr "אתר המיזם Pybik" + +#: ../pybiklib/main.py:287 +msgid "" +"An error occurred while reading the settings:\n" +"{error_message}" +msgstr "" +"אירעה שגיאה בעת קריאת ההגדרות:\n" +"{error_message}" + +#: ../pybiklib/model.py:214 +msgid "Brick" +msgstr "לבנה" + +#: ../pybiklib/model.py:215 +msgid "{0}×{1}×{2}-Brick" +msgstr "{0}×{1}×{2}-לבנה" + +#: ../pybiklib/model.py:835 +msgid "Tower" +msgstr "מגדל" + +#: ../pybiklib/model.py:836 +msgid "{0}×{1}-Tower" +msgstr "{0}×{1}-מגדל" + +#: ../pybiklib/model.py:850 +msgid "Cube" +msgstr "קוביה" + +#: ../pybiklib/model.py:851 +msgid "{0}×{0}×{0}-Cube" +msgstr "{0}×{0}×{0}-קוביה" + +#: ../pybiklib/plugins.py:92 +msgid "This algorithm does not work for any model.\n" +msgstr "האלגוריתם הזה לא עובד עם כל דגם.\n" + +#: ../pybiklib/plugins.py:94 ../pybiklib/plugins.py:97 +msgid "This algorithm only works for:\n" +msgstr "האלגוריתם הזה עובד רק עם:\n" + +#: ../pybiklib/settings.py:256 +msgid "Settings can not be written to file: {error_message}" +msgstr "לא ניתן לכתוב את ההגדרות לקובץ: {error_message}" + +#: ../pybiklib/ui/about.py:131 +msgid "About Pybik" +msgstr "על אודות Pybik" + +#: ../pybiklib/ui/about.py:132 +msgid "About" +msgstr "על אודות" + +#: ../pybiklib/ui/about.py:133 +msgid "Feedback" +msgstr "משוב" + +#: ../pybiklib/ui/about.py:134 +msgid "Translation" +msgstr "תרגום" + +#: ../pybiklib/ui/about.py:135 +msgid "License" +msgstr "רישיון" + +#: ../pybiklib/ui/main.py:195 +msgid "&Game" +msgstr "מ&שחק" + +#: ../pybiklib/ui/main.py:196 +msgid "&Edit" +msgstr "ע&ריכה" + +#: ../pybiklib/ui/main.py:197 +msgid "&View" +msgstr "&תצוגה" + +#: ../pybiklib/ui/main.py:198 +msgid "&Help" +msgstr "ע&זרה" + +#: ../pybiklib/ui/main.py:199 +msgid "Pybik Toolbar" +msgstr "סרגל הכלים של Pybik" + +#: ../pybiklib/ui/main.py:200 +msgid "&New Random" +msgstr "אקראי &חדש" + +#: ../pybiklib/ui/main.py:201 +msgid "Ne&w Solved" +msgstr "&פתור חדש" + +#: ../pybiklib/ui/main.py:202 +msgid "&Quit" +msgstr "י&ציאה" + +#: ../pybiklib/ui/main.py:203 +msgid "&Select Model …" +msgstr "&בחירת דגם …" + +#: ../pybiklib/ui/main.py:204 +msgid "&Set as Initial State" +msgstr "ה&גדרה כמצב ההתחלתי" + +#: ../pybiklib/ui/main.py:205 +msgid "&Reset Rotation" +msgstr "איפוס ה&סיבוב" + +#: ../pybiklib/ui/main.py:206 +msgid "&Invert Moves" +msgstr "הי&פוך המהלכים" + +#: ../pybiklib/ui/main.py:207 +msgid "Reload Plugins" +msgstr "טעינת התוספים מחדש" + +#: ../pybiklib/ui/main.py:208 +msgid "&Preferences …" +msgstr "ה&עדפות …" + +#: ../pybiklib/ui/main.py:209 +msgid "&Toolbar" +msgstr "ס&רגל כלים" + +#: ../pybiklib/ui/main.py:210 +msgid "&Status Bar" +msgstr "&שורת מצב" + +#: ../pybiklib/ui/main.py:211 +msgid "&Info …" +msgstr "&פרטים …" + +#: ../pybiklib/ui/main.py:212 +msgid "Rewind" +msgstr "הרצה אחורנית" + +#: ../pybiklib/ui/main.py:213 +msgid "Go to the previous mark (or the beginning) of the sequence of moves" +msgstr "מעבר לנקודת הציון הקודמת (או ההתחלה) של רצף המהלכים" + +#: ../pybiklib/ui/main.py:214 +msgid "Previous" +msgstr "אחורה" + +#: ../pybiklib/ui/main.py:215 +msgid "Make one step backwards" +msgstr "לחזור שלב אחד אחורה" + +#: ../pybiklib/ui/main.py:216 +msgid "Stop" +msgstr "עצירה" + +#: ../pybiklib/ui/main.py:217 +msgid "Stop running the sequence of moves" +msgstr "עצירת הרצת רצף המהלכים" + +#: ../pybiklib/ui/main.py:218 +msgid "Play" +msgstr "נגינה" + +#: ../pybiklib/ui/main.py:219 +msgid "Run forward through the sequence of moves" +msgstr "הרצת רצף המהלכים בסדר כרונולוגי" + +#: ../pybiklib/ui/main.py:220 +msgid "Next" +msgstr "הבא" + +#: ../pybiklib/ui/main.py:221 +msgid "Make one step forwards" +msgstr "התקדמות לצעד הבא" + +#: ../pybiklib/ui/main.py:222 +msgid "Forward" +msgstr "קדימה" + +#: ../pybiklib/ui/main.py:223 +msgid "Go to the next mark (or the end) of the sequence of moves" +msgstr "מעבר לסימון הבא (או הסוף) של רצף המהלכים" + +#: ../pybiklib/ui/main.py:224 +msgid "Add Mark" +msgstr "הוספת סמן" + +#: ../pybiklib/ui/main.py:225 +msgid "Mark the current place in the sequence of moves" +msgstr "סימון המיקום הנוכחי ברצף המהלכים" + +#: ../pybiklib/ui/main.py:226 +msgid "Remove Mark" +msgstr "הסרת סמן" + +#: ../pybiklib/ui/main.py:227 +msgid "Remove the mark at the current place in the sequence of moves" +msgstr "הסרת סמן מהמיקום הנוכחי ברצף המהלכים" + +#: ../pybiklib/ui/main.py:228 +msgid "&Edit Bar" +msgstr "סרגל &עריכה" + +#: ../pybiklib/ui/main.py:229 +msgid "Normalize Cube Rotations" +msgstr "נרמול סיבובי הקוביה" + +#: ../pybiklib/ui/model.py:78 +msgid "Select Model" +msgstr "בחירת דגם" + +#: ../pybiklib/ui/model.py:80 +msgid "Height:" +msgstr "גובה:" + +#: ../pybiklib/ui/model.py:81 +msgid "Depth:" +msgstr "עומק:" + +#: ../pybiklib/ui/preferences.py:252 +msgid "Preferences" +msgstr "העדפות" + +#: ../pybiklib/ui/preferences.py:253 +msgid "Animation Speed:" +msgstr "מהירות ההנפשה:" + +#: ../pybiklib/ui/preferences.py:254 +msgid "Lighting" +msgstr "תאורה" + +#: ../pybiklib/ui/preferences.py:255 +msgid "Mirror Distance:" +msgstr "מרחק מהמראה:" + +#: ../pybiklib/ui/preferences.py:256 +msgid "Antialiasing" +msgstr "החלקת קצוות" + +#: ../pybiklib/ui/preferences.py:257 +msgid "Hardware:" +msgstr "חומרה:" + +#: ../pybiklib/ui/preferences.py:258 +msgid "Software:" +msgstr "תכנה:" + +#: ../pybiklib/ui/preferences.py:259 +msgid "" +"

The program needs to " +"be restarted for the changes to take effect.

" +msgstr "" +"

יש " +"להפעיל את התכנית מחדש כדי שהשינויים ייכנסו לתוקף.

" + +#: ../pybiklib/ui/preferences.py:260 +msgid "Graphic" +msgstr "גרפיקה" + +#: ../pybiklib/ui/preferences.py:261 +msgid "Four directions" +msgstr "ארבעה כיוונים" + +#: ../pybiklib/ui/preferences.py:262 +msgid "" +"Simplified,\n" +"right button inverts move" +msgstr "" +"פשוט,\n" +"הלחצן הימני הופך את המהלך" + +#: ../pybiklib/ui/preferences.py:263 +msgid "Mouse" +msgstr "עכבר" + +#: ../pybiklib/ui/preferences.py:264 ../pybiklib/ui/preferences.py:265 +msgid "Add" +msgstr "הוספה" + +#: ../pybiklib/ui/preferences.py:266 ../pybiklib/ui/preferences.py:267 +msgid "Remove" +msgstr "הסרה" + +#: ../pybiklib/ui/preferences.py:268 ../pybiklib/ui/preferences.py:269 +msgid "Reset" +msgstr "איפוס" + +#: ../pybiklib/ui/preferences.py:270 +msgid "Keys" +msgstr "מקשים" + +#: ../pybiklib/ui/preferences.py:271 +msgid "Color:" +msgstr "צבע:" + +#: ../pybiklib/ui/preferences.py:272 +msgid "Image File:" +msgstr "קובץ תמונה:" + +#: ../pybiklib/ui/preferences.py:273 +msgid "Tiled" +msgstr "פרוש" + +#: ../pybiklib/ui/preferences.py:274 +msgid "Mosaic" +msgstr "פסיפס" + +#: ../pybiklib/ui/preferences.py:275 +msgid "Background:" +msgstr "רקע:" + +#: ../pybiklib/ui/preferences.py:276 +msgid "Appearance" +msgstr "מראה" + +#. Add whatever keywords you want in your language, separated by semicolons. These keywords are used when searching for applications in dashes, etc. (Unity, GNOME Shell) +#: ../data/applications/pybik.desktop.in.h:4 +msgid "rubik;cube;puzzle;magic;" +msgstr "" + +#: ../data/plugins/01-challenges.algorithm.py:19 +#: ../data/plugins/01-challenges.algorithm.py:22 +#: ../data/plugins/01-challenges.algorithm.py:25 +#: ../data/plugins/01-challenges.algorithm.py:28 +#: ../data/plugins/01-challenges.algorithm.py:31 +#: ../data/plugins/01-challenges.algorithm.py:34 +#: ../data/plugins/01-challenges.algorithm.py:37 +#: ../data/plugins/01-challenges.algorithm.py:40 +#: ../data/plugins/01-challenges.algorithm.py:43 +#: ../data/plugins/01-challenges.algorithm.py:46 +#: ../data/plugins/01-challenges.algorithm.py:49 +msgid "Challenges" +msgstr "אתגרים" + +#: ../data/plugins/01-challenges.algorithm.py:20 +msgid "Solve random cube" +msgstr "פתירת קוביה אקראית" + +#: ../data/plugins/01-challenges.algorithm.py:23 +msgid "Solve in 1 move" +msgstr "פתירה במהלך אחד" + +#: ../data/plugins/01-challenges.algorithm.py:26 +msgid "Solve in 2 moves" +msgstr "פתירה בשני מהלכים" + +#: ../data/plugins/01-challenges.algorithm.py:29 +msgid "Solve in 3 moves" +msgstr "פתירה בשלושה מהלכים" + +#: ../data/plugins/01-challenges.algorithm.py:32 +msgid "Solve in 4 moves" +msgstr "פתירה בארבעה מהלכים" + +#: ../data/plugins/01-challenges.algorithm.py:35 +msgid "Solve in 5 moves" +msgstr "פתירה בחמישה מהלכים" + +#: ../data/plugins/01-challenges.algorithm.py:38 +msgid "Solve in 6 moves" +msgstr "פתירה בשישה מהלכים" + +#: ../data/plugins/01-challenges.algorithm.py:41 +msgid "Solve in 7 moves" +msgstr "פתירה בשבעה מהלכים" + +#: ../data/plugins/01-challenges.algorithm.py:44 +msgid "Solve in 8 moves" +msgstr "פתירה בשמונה מהלכים" + +#: ../data/plugins/01-challenges.algorithm.py:47 +msgid "Solve in 9 moves" +msgstr "פתירה בתשעה מהלכים" + +#: ../data/plugins/01-challenges.algorithm.py:50 +msgid "Solve in 10 moves" +msgstr "פתירה בעשרה מהלכים" + +#: ../data/plugins/10-spiegel.algorithm.py:35 +#: ../data/plugins/10-spiegel.algorithm.py:38 +#: ../data/plugins/10-spiegel.algorithm.py:67 +#: ../data/plugins/10-spiegel.algorithm.py:88 +#: ../data/plugins/10-spiegel.algorithm.py:103 +#: ../data/plugins/10-spiegel.algorithm.py:116 +#: ../data/plugins/10-spiegel.algorithm.py:133 +#: ../data/plugins/10-spiegel.algorithm.py:144 +#: ../data/plugins/11-spiegel-improved.algorithm.py:35 +#: ../data/plugins/11-spiegel-improved.algorithm.py:38 +#: ../data/plugins/11-spiegel-improved.algorithm.py:83 +#: ../data/plugins/11-spiegel-improved.algorithm.py:122 +#: ../data/plugins/11-spiegel-improved.algorithm.py:154 +#: ../data/plugins/11-spiegel-improved.algorithm.py:180 +#: ../data/plugins/11-spiegel-improved.algorithm.py:198 +#: ../data/plugins/11-spiegel-improved.algorithm.py:212 +#: ../data/plugins/12-lbl-leyan.algorithm.py:22 +#: ../data/plugins/12-lbl-leyan.algorithm.py:25 +#: ../data/plugins/12-lbl-leyan.algorithm.py:54 +#: ../data/plugins/12-lbl-leyan.algorithm.py:75 +#: ../data/plugins/12-lbl-leyan.algorithm.py:91 +#: ../data/plugins/12-lbl-leyan.algorithm.py:108 +#: ../data/plugins/12-lbl-leyan.algorithm.py:130 +#: ../data/plugins/12-lbl-leyan.algorithm.py:171 +#: ../data/plugins/20-2x2x2.algorithm.py:19 +#: ../data/plugins/20-2x2x2.algorithm.py:22 +#: ../data/plugins/20-2x2x2.algorithm.py:41 +#: ../data/plugins/20-2x2x2.algorithm.py:61 +msgid "Solvers" +msgstr "פותרים" + +#. Spiegel is the name of a solution method +#: ../data/plugins/10-spiegel.algorithm.py:37 +#: ../data/plugins/10-spiegel.algorithm.py:39 +#: ../data/plugins/10-spiegel.algorithm.py:68 +#: ../data/plugins/10-spiegel.algorithm.py:89 +#: ../data/plugins/10-spiegel.algorithm.py:104 +#: ../data/plugins/10-spiegel.algorithm.py:117 +#: ../data/plugins/10-spiegel.algorithm.py:134 +#: ../data/plugins/10-spiegel.algorithm.py:145 +msgid "Spiegel" +msgstr "שפיגל" + +#: ../data/plugins/10-spiegel.algorithm.py:40 +#: ../data/plugins/11-spiegel-improved.algorithm.py:40 +#: ../data/plugins/12-lbl-leyan.algorithm.py:27 +msgid "Top edges" +msgstr "קצוות עליונים" + +#: ../data/plugins/10-spiegel.algorithm.py:69 +#: ../data/plugins/11-spiegel-improved.algorithm.py:85 +#: ../data/plugins/12-lbl-leyan.algorithm.py:56 +msgid "Top corners" +msgstr "פינות עליונות" + +#: ../data/plugins/10-spiegel.algorithm.py:90 +#: ../data/plugins/11-spiegel-improved.algorithm.py:124 +#: ../data/plugins/12-lbl-leyan.algorithm.py:77 +msgid "Middle slice" +msgstr "חיתוך באמצע" + +#: ../data/plugins/10-spiegel.algorithm.py:105 +#: ../data/plugins/11-spiegel-improved.algorithm.py:156 +#: ../data/plugins/12-lbl-leyan.algorithm.py:173 +msgid "Bottom edge place" +msgstr "מיקום קצה תחתון" + +#: ../data/plugins/10-spiegel.algorithm.py:118 +#: ../data/plugins/11-spiegel-improved.algorithm.py:182 +#: ../data/plugins/12-lbl-leyan.algorithm.py:93 +msgid "Bottom edge orient" +msgstr "כיוון קצה תחתון" + +#: ../data/plugins/10-spiegel.algorithm.py:135 +#: ../data/plugins/11-spiegel-improved.algorithm.py:200 +#: ../data/plugins/12-lbl-leyan.algorithm.py:110 +#: ../data/plugins/20-2x2x2.algorithm.py:43 +msgid "Bottom corner place" +msgstr "מיקום פינה תחתונה" + +#: ../data/plugins/10-spiegel.algorithm.py:146 +#: ../data/plugins/11-spiegel-improved.algorithm.py:214 +#: ../data/plugins/12-lbl-leyan.algorithm.py:132 +#: ../data/plugins/20-2x2x2.algorithm.py:63 +msgid "Bottom corner orient" +msgstr "כיוון פינה תחתונה" + +#. Spiegel is the name of a solution method +#: ../data/plugins/11-spiegel-improved.algorithm.py:37 +#: ../data/plugins/11-spiegel-improved.algorithm.py:39 +#: ../data/plugins/11-spiegel-improved.algorithm.py:84 +#: ../data/plugins/11-spiegel-improved.algorithm.py:123 +#: ../data/plugins/11-spiegel-improved.algorithm.py:155 +#: ../data/plugins/11-spiegel-improved.algorithm.py:181 +#: ../data/plugins/11-spiegel-improved.algorithm.py:199 +#: ../data/plugins/11-spiegel-improved.algorithm.py:213 +msgid "Spiegel improved" +msgstr "שפיגל משופר" + +#. Leyan Lo is the inventor of the solution method +#: ../data/plugins/12-lbl-leyan.algorithm.py:24 +#: ../data/plugins/12-lbl-leyan.algorithm.py:26 +#: ../data/plugins/12-lbl-leyan.algorithm.py:55 +#: ../data/plugins/12-lbl-leyan.algorithm.py:76 +#: ../data/plugins/12-lbl-leyan.algorithm.py:92 +#: ../data/plugins/12-lbl-leyan.algorithm.py:109 +#: ../data/plugins/12-lbl-leyan.algorithm.py:131 +#: ../data/plugins/12-lbl-leyan.algorithm.py:172 +msgid "Layer Method (Leyan Lo)" +msgstr "שיטת השכבות (לֵיַאן לוֹ)" + +#: ../data/plugins/20-2x2x2.algorithm.py:20 +#: ../data/plugins/20-2x2x2.algorithm.py:23 +#: ../data/plugins/20-2x2x2.algorithm.py:42 +#: ../data/plugins/20-2x2x2.algorithm.py:62 +msgid "2×2×2" +msgstr "2×2×2" + +#: ../data/plugins/20-2x2x2.algorithm.py:24 +msgid "Top slice" +msgstr "חיתוך עליון" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:18 +#: ../data/plugins/80-pretty-patterns.algorithm.py:22 +#: ../data/plugins/80-pretty-patterns.algorithm.py:26 +#: ../data/plugins/80-pretty-patterns.algorithm.py:30 +#: ../data/plugins/80-pretty-patterns.algorithm.py:34 +#: ../data/plugins/80-pretty-patterns.algorithm.py:39 +#: ../data/plugins/80-pretty-patterns.algorithm.py:43 +#: ../data/plugins/80-pretty-patterns.algorithm.py:48 +#: ../data/plugins/80-pretty-patterns.algorithm.py:52 +#: ../data/plugins/80-pretty-patterns.algorithm.py:56 +#: ../data/plugins/80-pretty-patterns.algorithm.py:60 +#: ../data/plugins/80-pretty-patterns.algorithm.py:64 +#: ../data/plugins/80-pretty-patterns.algorithm.py:68 +#: ../data/plugins/80-pretty-patterns.algorithm.py:74 +#: ../data/plugins/80-pretty-patterns.algorithm.py:78 +#: ../data/plugins/80-pretty-patterns.algorithm.py:83 +#: ../data/plugins/80-pretty-patterns.algorithm.py:87 +#: ../data/plugins/80-pretty-patterns.algorithm.py:91 +#: ../data/plugins/80-pretty-patterns.algorithm.py:95 +#: ../data/plugins/80-pretty-patterns.algorithm.py:99 +#: ../data/plugins/80-pretty-patterns.algorithm.py:103 +#: ../data/plugins/80-pretty-patterns.algorithm.py:108 +#: ../data/plugins/80-pretty-patterns.algorithm.py:112 +#: ../data/plugins/80-pretty-patterns.algorithm.py:116 +#: ../data/plugins/80-pretty-patterns.algorithm.py:120 +#: ../data/plugins/80-pretty-patterns.algorithm.py:124 +#: ../data/plugins/80-pretty-patterns.algorithm.py:128 +#: ../data/plugins/80-pretty-patterns.algorithm.py:132 +#: ../data/plugins/80-pretty-patterns.algorithm.py:136 +#: ../data/plugins/80-pretty-patterns.algorithm.py:140 +msgid "Pretty patterns" +msgstr "תבניות יפות" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:19 +#: ../data/plugins/80-pretty-patterns.algorithm.py:23 +#: ../data/plugins/80-pretty-patterns.algorithm.py:27 +#: ../data/plugins/80-pretty-patterns.algorithm.py:31 +#: ../data/plugins/80-pretty-patterns.algorithm.py:35 +#: ../data/plugins/80-pretty-patterns.algorithm.py:40 +#: ../data/plugins/80-pretty-patterns.algorithm.py:44 +msgid "Stripes" +msgstr "רצועות" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:49 +#: ../data/plugins/80-pretty-patterns.algorithm.py:53 +msgid "Criss-Cross" +msgstr "משבצות" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:57 +msgid "Fried Eggs" +msgstr "ביצים מטוגנות" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:61 +msgid "Big Fried Eggs" +msgstr "ביצים גדולות מטוגנות" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:65 +msgid "4 Fried Eggs" +msgstr "4 ביצים מטוגנות" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:69 +msgid "Chessboard" +msgstr "לוח שח" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:75 +msgid "Cross" +msgstr "צלב" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:79 +msgid "Zig Zag" +msgstr "זיג זג" + +#. T is the shape formed by the cube labels +#: ../data/plugins/80-pretty-patterns.algorithm.py:85 +#: ../data/plugins/80-pretty-patterns.algorithm.py:88 +#: ../data/plugins/80-pretty-patterns.algorithm.py:92 +#: ../data/plugins/80-pretty-patterns.algorithm.py:96 +#: ../data/plugins/80-pretty-patterns.algorithm.py:100 +#: ../data/plugins/80-pretty-patterns.algorithm.py:104 +msgid "T-Time" +msgstr "זמן T" + +#. C is the shape formed by the cube labels +#: ../data/plugins/80-pretty-patterns.algorithm.py:110 +msgid "C" +msgstr "C" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:113 +msgid "Cube in a Cube" +msgstr "קובייה בתוך קובייה" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:117 +msgid "Striped Cube in a Cube" +msgstr "קוביה מפוספסת בתוך קוביה" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:121 +msgid "Six Square Cuboids" +msgstr "תיבות בעלות שישה ריבועים" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:125 +msgid "Superflip" +msgstr "סופר היפוך" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:129 +msgid "Superflip easy" +msgstr "סופר היפוך קל" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:133 +msgid "Green Mamba" +msgstr "ממבה ירוקה" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:137 +msgid "Anaconda" +msgstr "אנקונדה" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:141 +msgid "Duck Feet" +msgstr "רגלי ברווז" + +#: ../data/plugins/90-library.algorithm.py:20 +#: ../data/plugins/90-library.algorithm.py:23 +#: ../data/plugins/90-library.algorithm.py:26 +#: ../data/plugins/90-library.algorithm.py:29 +#: ../data/plugins/90-library.algorithm.py:32 +#: ../data/plugins/90-library.algorithm.py:35 +#: ../data/plugins/90-library.algorithm.py:38 +#: ../data/plugins/90-library.algorithm.py:41 +#: ../data/plugins/90-library.algorithm.py:44 +#: ../data/plugins/90-library.algorithm.py:47 +#: ../data/plugins/90-library.algorithm.py:50 +msgid "Library" +msgstr "ספרייה" + +#: ../data/plugins/90-library.algorithm.py:21 +#: ../data/plugins/90-library.algorithm.py:24 +msgid "Middle Layer" +msgstr "שכבה אמצעית" + +#: ../data/plugins/90-library.algorithm.py:22 +msgid "Front to Right" +msgstr "חזית לימין" + +#: ../data/plugins/90-library.algorithm.py:25 +msgid "Front to Left" +msgstr "חזית לשמאל" + +#: ../data/plugins/90-library.algorithm.py:27 +#: ../data/plugins/90-library.algorithm.py:30 +#: ../data/plugins/90-library.algorithm.py:33 +#: ../data/plugins/90-library.algorithm.py:36 +msgid "Last Layer" +msgstr "שכבה אחרונה" + +#: ../data/plugins/90-library.algorithm.py:28 +msgid "Swap Edges" +msgstr "החלפת קצוות" + +#: ../data/plugins/90-library.algorithm.py:31 +msgid "Flip Edges" +msgstr "היפוך קצוות" + +#: ../data/plugins/90-library.algorithm.py:34 +msgid "Swap Corners" +msgstr "היפוך פינות" + +#: ../data/plugins/90-library.algorithm.py:37 +msgid "Rotate Corners" +msgstr "סיבוב פינות" + +#: ../data/plugins/90-library.algorithm.py:39 +#: ../data/plugins/90-library.algorithm.py:42 +#: ../data/plugins/90-library.algorithm.py:45 +msgid "Rotate Center" +msgstr "סיבוב המרכז" + +#: ../data/plugins/90-library.algorithm.py:40 +msgid "2×Up" +msgstr "2×למעלה" + +#: ../data/plugins/90-library.algorithm.py:43 +msgid "Up and Front" +msgstr "למעלה ולחזית" + +#: ../data/plugins/90-library.algorithm.py:46 +msgid "Up and Down" +msgstr "למעלה ולמטה" + +#: ../data/plugins/90-library.algorithm.py:48 +#: ../data/plugins/90-library.algorithm.py:51 +msgid "Misc" +msgstr "שונות" + +#: ../data/plugins/90-library.algorithm.py:49 +msgid "Back without Back" +msgstr "גב ללא גב" + +#: ../data/plugins/90-library.algorithm.py:52 +msgid "2×Back without Back" +msgstr "2×גב ללא גב" diff -Nru pybik-0.5/po/ky.po pybik-1.0.1/po/ky.po --- pybik-0.5/po/ky.po 1970-01-01 00:00:00.000000000 +0000 +++ pybik-1.0.1/po/ky.po 2013-02-01 20:18:02.000000000 +0000 @@ -0,0 +1,872 @@ +# Kirghiz translation for pybik +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the pybik package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: pybik\n" +"Report-Msgid-Bugs-To: https://bugs.launchpad.net/pybik/+filebug\n" +"POT-Creation-Date: 2013-01-31 14:25+0100\n" +"PO-Revision-Date: 2012-12-14 10:00+0000\n" +"Last-Translator: blacktext \n" +"Language-Team: Kirghiz \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Launchpad-Export-Date: 2012-12-16 04:59+0000\n" +"X-Generator: Launchpad (build 16372)\n" + +#: ../pybiklib/application.py:304 +msgid "Press the Esc key to exit Edit Mode" +msgstr "" + +#. substitution for {move_text} in statusbar text +#: ../pybiklib/application.py:313 +msgid "{current} / {total} move" +msgid_plural "{current} / {total} moves" +msgstr[0] "" +msgstr[1] "" + +#. substitution for {solved_text} in statusbar text +#: ../pybiklib/application.py:317 ../pybiklib/ui/model.py:82 +msgid "solved" +msgstr "" + +#: ../pybiklib/application.py:317 +msgid "not solved" +msgstr "" + +#. statusbar text +#: ../pybiklib/application.py:320 +msgid "{model_text}, {move_text}, {solved_text}" +msgstr "" + +#: ../pybiklib/application.py:353 +msgid "Congratulations, you have solved the puzzle!" +msgstr "" + +#: ../pybiklib/config.py:30 ../pybiklib/ui/main.py:194 +#: ../data/applications/pybik.desktop.in.h:1 +msgid "Pybik" +msgstr "Pybik" + +#: ../pybiklib/config.py:59 ../data/applications/pybik.desktop.in.h:2 +msgid "3D Rubik's cube game" +msgstr "" + +#: ../pybiklib/config.py:61 +msgid "" +"Pybik is an interactive, graphical, single player puzzle about the cube " +"invented by Ernő Rubik. Besides the cube the program can handle towers and " +"bricks (non cubic puzzles). Pybik also has solvers, pretty patterns and a " +"collection of various moves. The cube can be manipulated with the mouse or " +"keyboard. You can change the colors or images on the faces of the cube." +msgstr "" + +#: ../pybiklib/config.py:69 +msgid "" +"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.\n" +"\n" +"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." +msgstr "" + +#: ../pybiklib/config.py:79 +msgid "" +"Read the full text of the GNU General Public " +"License<|> or see ." +msgstr "" + +#: ../pybiklib/config.py:82 +msgid "" +"You should have received a copy of the GNU General Public License along with " +"this program. If not, see ." +msgstr "" + +#: ../pybiklib/config.py:88 +msgid "" +"If you find any bugs in Pybik or have a suggestion for an improvement then " +"please submit a <{CONTACT_FILEBUG}|>bug report<|>. In the latter case you " +"can mark the bug report as \"Wishlist\"." +msgstr "" + +#: ../pybiklib/config.py:94 +msgid "" +"Translations are managed by the " +"Launchpad " +"translation group<|>.\n" +"\n" +"If you want help to translate Pybik to your language you can do it through " +"the web interface<|>.\n" +"\n" +"Read more about \"Translating with " +"Launchpad\"<|> and " +"\"Starting to " +"translate\"<|>." +msgstr "" + +#: ../pybiklib/dialogs.py:168 +msgid "Press a key …" +msgstr "Клавишаны басыңыз…" + +#: ../pybiklib/dialogs.py:296 +msgid "plain" +msgstr "" + +#: ../pybiklib/dialogs.py:301 +msgid "select …" +msgstr "тандоо…" + +#: ../pybiklib/dialogs.py:313 +msgid "Up" +msgstr "Өйдө" + +#: ../pybiklib/dialogs.py:313 +msgid "Down" +msgstr "Ылдый" + +#: ../pybiklib/dialogs.py:313 +msgid "Left" +msgstr "Солго" + +#: ../pybiklib/dialogs.py:313 +msgid "Right" +msgstr "Оңго" + +#: ../pybiklib/dialogs.py:313 +msgid "Front" +msgstr "Алды" + +#: ../pybiklib/dialogs.py:313 +msgid "Back" +msgstr "Арты" + +#: ../pybiklib/dialogs.py:331 +msgid "Move" +msgstr "Ташуу" + +#: ../pybiklib/dialogs.py:332 +msgid "Key" +msgstr "Клавиша" + +#: ../pybiklib/dialogs.py:486 +msgid "Open Image" +msgstr "Сүрөттү ачуу" + +#: ../pybiklib/dialogs.py:536 ../pybiklib/ui/model.py:79 +msgid "Size:" +msgstr "Өлчөм:" + +#: ../pybiklib/dialogs.py:536 +msgid "Basis:" +msgstr "" + +#: ../pybiklib/dialogs.py:536 +msgid "Width:" +msgstr "Туурасы:" + +#: ../pybiklib/dialogs.py:565 +msgid "Canceling operation, please wait" +msgstr "" + +#: ../pybiklib/dialogs.py:621 +msgid "Pybik project website" +msgstr "Pybik долбоорунун веб-сайты" + +#: ../pybiklib/main.py:287 +msgid "" +"An error occurred while reading the settings:\n" +"{error_message}" +msgstr "" + +#: ../pybiklib/model.py:214 +msgid "Brick" +msgstr "" + +#: ../pybiklib/model.py:215 +msgid "{0}×{1}×{2}-Brick" +msgstr "" + +#: ../pybiklib/model.py:835 +msgid "Tower" +msgstr "" + +#: ../pybiklib/model.py:836 +msgid "{0}×{1}-Tower" +msgstr "" + +#: ../pybiklib/model.py:850 +msgid "Cube" +msgstr "Куб" + +#: ../pybiklib/model.py:851 +msgid "{0}×{0}×{0}-Cube" +msgstr "" + +#: ../pybiklib/plugins.py:92 +msgid "This algorithm does not work for any model.\n" +msgstr "" + +#: ../pybiklib/plugins.py:94 ../pybiklib/plugins.py:97 +msgid "This algorithm only works for:\n" +msgstr "" + +#: ../pybiklib/settings.py:256 +msgid "Settings can not be written to file: {error_message}" +msgstr "" + +#: ../pybiklib/ui/about.py:131 +msgid "About Pybik" +msgstr "Pybik жөнүндө" + +#: ../pybiklib/ui/about.py:132 +msgid "About" +msgstr "Программа жөнүндө" + +#: ../pybiklib/ui/about.py:133 +msgid "Feedback" +msgstr "Кербайланыш" + +#: ../pybiklib/ui/about.py:134 +msgid "Translation" +msgstr "Котормо" + +#: ../pybiklib/ui/about.py:135 +msgid "License" +msgstr "Лицензия" + +#: ../pybiklib/ui/main.py:195 +msgid "&Game" +msgstr "&Оюн" + +#: ../pybiklib/ui/main.py:196 +msgid "&Edit" +msgstr "&Оңдоо" + +#: ../pybiklib/ui/main.py:197 +msgid "&View" +msgstr "&Көрүнүш" + +#: ../pybiklib/ui/main.py:198 +msgid "&Help" +msgstr "&Жардам" + +#: ../pybiklib/ui/main.py:199 +msgid "Pybik Toolbar" +msgstr "Pybik'тин аспап панели" + +#: ../pybiklib/ui/main.py:200 +msgid "&New Random" +msgstr "&Жаңы кокустук" + +#: ../pybiklib/ui/main.py:201 +msgid "Ne&w Solved" +msgstr "" + +#: ../pybiklib/ui/main.py:202 +msgid "&Quit" +msgstr "&Чыгуу" + +#: ../pybiklib/ui/main.py:203 +msgid "&Select Model …" +msgstr "Моделди &тандоо…" + +#: ../pybiklib/ui/main.py:204 +msgid "&Set as Initial State" +msgstr "" + +#: ../pybiklib/ui/main.py:205 +msgid "&Reset Rotation" +msgstr "&Тегеретүү түшүрүү" + +#: ../pybiklib/ui/main.py:206 +msgid "&Invert Moves" +msgstr "" + +#: ../pybiklib/ui/main.py:207 +msgid "Reload Plugins" +msgstr "Плагиндерди жаңыртуу" + +#: ../pybiklib/ui/main.py:208 +msgid "&Preferences …" +msgstr "&Параметрлер…" + +#: ../pybiklib/ui/main.py:209 +msgid "&Toolbar" +msgstr "&Аспап панели" + +#: ../pybiklib/ui/main.py:210 +msgid "&Status Bar" +msgstr "&Абал сабы" + +#: ../pybiklib/ui/main.py:211 +msgid "&Info …" +msgstr "&Инфо…" + +#: ../pybiklib/ui/main.py:212 +msgid "Rewind" +msgstr "" + +#: ../pybiklib/ui/main.py:213 +msgid "Go to the previous mark (or the beginning) of the sequence of moves" +msgstr "" + +#: ../pybiklib/ui/main.py:214 +msgid "Previous" +msgstr "Мурунку" + +#: ../pybiklib/ui/main.py:215 +msgid "Make one step backwards" +msgstr "" + +#: ../pybiklib/ui/main.py:216 +msgid "Stop" +msgstr "Токтотуу" + +#: ../pybiklib/ui/main.py:217 +msgid "Stop running the sequence of moves" +msgstr "" + +#: ../pybiklib/ui/main.py:218 +msgid "Play" +msgstr "Ойнотуу" + +#: ../pybiklib/ui/main.py:219 +msgid "Run forward through the sequence of moves" +msgstr "" + +#: ../pybiklib/ui/main.py:220 +msgid "Next" +msgstr "Кийинки" + +#: ../pybiklib/ui/main.py:221 +msgid "Make one step forwards" +msgstr "" + +#: ../pybiklib/ui/main.py:222 +msgid "Forward" +msgstr "Алга" + +#: ../pybiklib/ui/main.py:223 +msgid "Go to the next mark (or the end) of the sequence of moves" +msgstr "" + +#: ../pybiklib/ui/main.py:224 +msgid "Add Mark" +msgstr "Белгини кошуу" + +#: ../pybiklib/ui/main.py:225 +msgid "Mark the current place in the sequence of moves" +msgstr "" + +#: ../pybiklib/ui/main.py:226 +msgid "Remove Mark" +msgstr "Белгини өчүрүү" + +#: ../pybiklib/ui/main.py:227 +msgid "Remove the mark at the current place in the sequence of moves" +msgstr "" + +#: ../pybiklib/ui/main.py:228 +msgid "&Edit Bar" +msgstr "&Оңдоо панели" + +#: ../pybiklib/ui/main.py:229 +msgid "Normalize Cube Rotations" +msgstr "" + +#: ../pybiklib/ui/model.py:78 +msgid "Select Model" +msgstr "Моделди тандоо" + +#: ../pybiklib/ui/model.py:80 +msgid "Height:" +msgstr "" + +#: ../pybiklib/ui/model.py:81 +msgid "Depth:" +msgstr "Тереңдик:" + +#: ../pybiklib/ui/preferences.py:252 +msgid "Preferences" +msgstr "Параметрлер" + +#: ../pybiklib/ui/preferences.py:253 +msgid "Animation Speed:" +msgstr "Анимациянын ылдамдыгы:" + +#: ../pybiklib/ui/preferences.py:254 +msgid "Lighting" +msgstr "Жарык" + +#: ../pybiklib/ui/preferences.py:255 +msgid "Mirror Distance:" +msgstr "Күзгүнүн аралыгы:" + +#: ../pybiklib/ui/preferences.py:256 +msgid "Antialiasing" +msgstr "Тегиздөө" + +#: ../pybiklib/ui/preferences.py:257 +msgid "Hardware:" +msgstr "" + +#: ../pybiklib/ui/preferences.py:258 +msgid "Software:" +msgstr "Программалык камсыздоо:" + +#: ../pybiklib/ui/preferences.py:259 +msgid "" +"

The program needs to " +"be restarted for the changes to take effect.

" +msgstr "" + +#: ../pybiklib/ui/preferences.py:260 +msgid "Graphic" +msgstr "Графика" + +#: ../pybiklib/ui/preferences.py:261 +msgid "Four directions" +msgstr "" + +#: ../pybiklib/ui/preferences.py:262 +msgid "" +"Simplified,\n" +"right button inverts move" +msgstr "" + +#: ../pybiklib/ui/preferences.py:263 +msgid "Mouse" +msgstr "Чычкан" + +#: ../pybiklib/ui/preferences.py:264 ../pybiklib/ui/preferences.py:265 +msgid "Add" +msgstr "Кошуу" + +#: ../pybiklib/ui/preferences.py:266 ../pybiklib/ui/preferences.py:267 +msgid "Remove" +msgstr "Өчүрүү" + +#: ../pybiklib/ui/preferences.py:268 ../pybiklib/ui/preferences.py:269 +msgid "Reset" +msgstr "Түшүрүү" + +#: ../pybiklib/ui/preferences.py:270 +msgid "Keys" +msgstr "Клавишалар" + +#: ../pybiklib/ui/preferences.py:271 +msgid "Color:" +msgstr "Түс:" + +#: ../pybiklib/ui/preferences.py:272 +msgid "Image File:" +msgstr "Сүрөт файлы:" + +#: ../pybiklib/ui/preferences.py:273 +msgid "Tiled" +msgstr "" + +#: ../pybiklib/ui/preferences.py:274 +msgid "Mosaic" +msgstr "" + +#: ../pybiklib/ui/preferences.py:275 +msgid "Background:" +msgstr "Фон:" + +#: ../pybiklib/ui/preferences.py:276 +msgid "Appearance" +msgstr "" + +#. Add whatever keywords you want in your language, separated by semicolons. These keywords are used when searching for applications in dashes, etc. (Unity, GNOME Shell) +#: ../data/applications/pybik.desktop.in.h:4 +msgid "rubik;cube;puzzle;magic;" +msgstr "" + +#: ../data/plugins/01-challenges.algorithm.py:19 +#: ../data/plugins/01-challenges.algorithm.py:22 +#: ../data/plugins/01-challenges.algorithm.py:25 +#: ../data/plugins/01-challenges.algorithm.py:28 +#: ../data/plugins/01-challenges.algorithm.py:31 +#: ../data/plugins/01-challenges.algorithm.py:34 +#: ../data/plugins/01-challenges.algorithm.py:37 +#: ../data/plugins/01-challenges.algorithm.py:40 +#: ../data/plugins/01-challenges.algorithm.py:43 +#: ../data/plugins/01-challenges.algorithm.py:46 +#: ../data/plugins/01-challenges.algorithm.py:49 +msgid "Challenges" +msgstr "" + +#: ../data/plugins/01-challenges.algorithm.py:20 +msgid "Solve random cube" +msgstr "" + +#: ../data/plugins/01-challenges.algorithm.py:23 +msgid "Solve in 1 move" +msgstr "" + +#: ../data/plugins/01-challenges.algorithm.py:26 +msgid "Solve in 2 moves" +msgstr "" + +#: ../data/plugins/01-challenges.algorithm.py:29 +msgid "Solve in 3 moves" +msgstr "" + +#: ../data/plugins/01-challenges.algorithm.py:32 +msgid "Solve in 4 moves" +msgstr "" + +#: ../data/plugins/01-challenges.algorithm.py:35 +msgid "Solve in 5 moves" +msgstr "" + +#: ../data/plugins/01-challenges.algorithm.py:38 +msgid "Solve in 6 moves" +msgstr "" + +#: ../data/plugins/01-challenges.algorithm.py:41 +msgid "Solve in 7 moves" +msgstr "" + +#: ../data/plugins/01-challenges.algorithm.py:44 +msgid "Solve in 8 moves" +msgstr "" + +#: ../data/plugins/01-challenges.algorithm.py:47 +msgid "Solve in 9 moves" +msgstr "" + +#: ../data/plugins/01-challenges.algorithm.py:50 +msgid "Solve in 10 moves" +msgstr "" + +#: ../data/plugins/10-spiegel.algorithm.py:35 +#: ../data/plugins/10-spiegel.algorithm.py:38 +#: ../data/plugins/10-spiegel.algorithm.py:67 +#: ../data/plugins/10-spiegel.algorithm.py:88 +#: ../data/plugins/10-spiegel.algorithm.py:103 +#: ../data/plugins/10-spiegel.algorithm.py:116 +#: ../data/plugins/10-spiegel.algorithm.py:133 +#: ../data/plugins/10-spiegel.algorithm.py:144 +#: ../data/plugins/11-spiegel-improved.algorithm.py:35 +#: ../data/plugins/11-spiegel-improved.algorithm.py:38 +#: ../data/plugins/11-spiegel-improved.algorithm.py:83 +#: ../data/plugins/11-spiegel-improved.algorithm.py:122 +#: ../data/plugins/11-spiegel-improved.algorithm.py:154 +#: ../data/plugins/11-spiegel-improved.algorithm.py:180 +#: ../data/plugins/11-spiegel-improved.algorithm.py:198 +#: ../data/plugins/11-spiegel-improved.algorithm.py:212 +#: ../data/plugins/12-lbl-leyan.algorithm.py:22 +#: ../data/plugins/12-lbl-leyan.algorithm.py:25 +#: ../data/plugins/12-lbl-leyan.algorithm.py:54 +#: ../data/plugins/12-lbl-leyan.algorithm.py:75 +#: ../data/plugins/12-lbl-leyan.algorithm.py:91 +#: ../data/plugins/12-lbl-leyan.algorithm.py:108 +#: ../data/plugins/12-lbl-leyan.algorithm.py:130 +#: ../data/plugins/12-lbl-leyan.algorithm.py:171 +#: ../data/plugins/20-2x2x2.algorithm.py:19 +#: ../data/plugins/20-2x2x2.algorithm.py:22 +#: ../data/plugins/20-2x2x2.algorithm.py:41 +#: ../data/plugins/20-2x2x2.algorithm.py:61 +msgid "Solvers" +msgstr "" + +#. Spiegel is the name of a solution method +#: ../data/plugins/10-spiegel.algorithm.py:37 +#: ../data/plugins/10-spiegel.algorithm.py:39 +#: ../data/plugins/10-spiegel.algorithm.py:68 +#: ../data/plugins/10-spiegel.algorithm.py:89 +#: ../data/plugins/10-spiegel.algorithm.py:104 +#: ../data/plugins/10-spiegel.algorithm.py:117 +#: ../data/plugins/10-spiegel.algorithm.py:134 +#: ../data/plugins/10-spiegel.algorithm.py:145 +msgid "Spiegel" +msgstr "" + +#: ../data/plugins/10-spiegel.algorithm.py:40 +#: ../data/plugins/11-spiegel-improved.algorithm.py:40 +#: ../data/plugins/12-lbl-leyan.algorithm.py:27 +msgid "Top edges" +msgstr "" + +#: ../data/plugins/10-spiegel.algorithm.py:69 +#: ../data/plugins/11-spiegel-improved.algorithm.py:85 +#: ../data/plugins/12-lbl-leyan.algorithm.py:56 +msgid "Top corners" +msgstr "" + +#: ../data/plugins/10-spiegel.algorithm.py:90 +#: ../data/plugins/11-spiegel-improved.algorithm.py:124 +#: ../data/plugins/12-lbl-leyan.algorithm.py:77 +msgid "Middle slice" +msgstr "" + +#: ../data/plugins/10-spiegel.algorithm.py:105 +#: ../data/plugins/11-spiegel-improved.algorithm.py:156 +#: ../data/plugins/12-lbl-leyan.algorithm.py:173 +msgid "Bottom edge place" +msgstr "" + +#: ../data/plugins/10-spiegel.algorithm.py:118 +#: ../data/plugins/11-spiegel-improved.algorithm.py:182 +#: ../data/plugins/12-lbl-leyan.algorithm.py:93 +msgid "Bottom edge orient" +msgstr "" + +#: ../data/plugins/10-spiegel.algorithm.py:135 +#: ../data/plugins/11-spiegel-improved.algorithm.py:200 +#: ../data/plugins/12-lbl-leyan.algorithm.py:110 +#: ../data/plugins/20-2x2x2.algorithm.py:43 +msgid "Bottom corner place" +msgstr "" + +#: ../data/plugins/10-spiegel.algorithm.py:146 +#: ../data/plugins/11-spiegel-improved.algorithm.py:214 +#: ../data/plugins/12-lbl-leyan.algorithm.py:132 +#: ../data/plugins/20-2x2x2.algorithm.py:63 +msgid "Bottom corner orient" +msgstr "" + +#. Spiegel is the name of a solution method +#: ../data/plugins/11-spiegel-improved.algorithm.py:37 +#: ../data/plugins/11-spiegel-improved.algorithm.py:39 +#: ../data/plugins/11-spiegel-improved.algorithm.py:84 +#: ../data/plugins/11-spiegel-improved.algorithm.py:123 +#: ../data/plugins/11-spiegel-improved.algorithm.py:155 +#: ../data/plugins/11-spiegel-improved.algorithm.py:181 +#: ../data/plugins/11-spiegel-improved.algorithm.py:199 +#: ../data/plugins/11-spiegel-improved.algorithm.py:213 +msgid "Spiegel improved" +msgstr "" + +#. Leyan Lo is the inventor of the solution method +#: ../data/plugins/12-lbl-leyan.algorithm.py:24 +#: ../data/plugins/12-lbl-leyan.algorithm.py:26 +#: ../data/plugins/12-lbl-leyan.algorithm.py:55 +#: ../data/plugins/12-lbl-leyan.algorithm.py:76 +#: ../data/plugins/12-lbl-leyan.algorithm.py:92 +#: ../data/plugins/12-lbl-leyan.algorithm.py:109 +#: ../data/plugins/12-lbl-leyan.algorithm.py:131 +#: ../data/plugins/12-lbl-leyan.algorithm.py:172 +msgid "Layer Method (Leyan Lo)" +msgstr "" + +#: ../data/plugins/20-2x2x2.algorithm.py:20 +#: ../data/plugins/20-2x2x2.algorithm.py:23 +#: ../data/plugins/20-2x2x2.algorithm.py:42 +#: ../data/plugins/20-2x2x2.algorithm.py:62 +msgid "2×2×2" +msgstr "2×2×2" + +#: ../data/plugins/20-2x2x2.algorithm.py:24 +msgid "Top slice" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:18 +#: ../data/plugins/80-pretty-patterns.algorithm.py:22 +#: ../data/plugins/80-pretty-patterns.algorithm.py:26 +#: ../data/plugins/80-pretty-patterns.algorithm.py:30 +#: ../data/plugins/80-pretty-patterns.algorithm.py:34 +#: ../data/plugins/80-pretty-patterns.algorithm.py:39 +#: ../data/plugins/80-pretty-patterns.algorithm.py:43 +#: ../data/plugins/80-pretty-patterns.algorithm.py:48 +#: ../data/plugins/80-pretty-patterns.algorithm.py:52 +#: ../data/plugins/80-pretty-patterns.algorithm.py:56 +#: ../data/plugins/80-pretty-patterns.algorithm.py:60 +#: ../data/plugins/80-pretty-patterns.algorithm.py:64 +#: ../data/plugins/80-pretty-patterns.algorithm.py:68 +#: ../data/plugins/80-pretty-patterns.algorithm.py:74 +#: ../data/plugins/80-pretty-patterns.algorithm.py:78 +#: ../data/plugins/80-pretty-patterns.algorithm.py:83 +#: ../data/plugins/80-pretty-patterns.algorithm.py:87 +#: ../data/plugins/80-pretty-patterns.algorithm.py:91 +#: ../data/plugins/80-pretty-patterns.algorithm.py:95 +#: ../data/plugins/80-pretty-patterns.algorithm.py:99 +#: ../data/plugins/80-pretty-patterns.algorithm.py:103 +#: ../data/plugins/80-pretty-patterns.algorithm.py:108 +#: ../data/plugins/80-pretty-patterns.algorithm.py:112 +#: ../data/plugins/80-pretty-patterns.algorithm.py:116 +#: ../data/plugins/80-pretty-patterns.algorithm.py:120 +#: ../data/plugins/80-pretty-patterns.algorithm.py:124 +#: ../data/plugins/80-pretty-patterns.algorithm.py:128 +#: ../data/plugins/80-pretty-patterns.algorithm.py:132 +#: ../data/plugins/80-pretty-patterns.algorithm.py:136 +#: ../data/plugins/80-pretty-patterns.algorithm.py:140 +msgid "Pretty patterns" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:19 +#: ../data/plugins/80-pretty-patterns.algorithm.py:23 +#: ../data/plugins/80-pretty-patterns.algorithm.py:27 +#: ../data/plugins/80-pretty-patterns.algorithm.py:31 +#: ../data/plugins/80-pretty-patterns.algorithm.py:35 +#: ../data/plugins/80-pretty-patterns.algorithm.py:40 +#: ../data/plugins/80-pretty-patterns.algorithm.py:44 +msgid "Stripes" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:49 +#: ../data/plugins/80-pretty-patterns.algorithm.py:53 +msgid "Criss-Cross" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:57 +msgid "Fried Eggs" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:61 +msgid "Big Fried Eggs" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:65 +msgid "4 Fried Eggs" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:69 +msgid "Chessboard" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:75 +msgid "Cross" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:79 +msgid "Zig Zag" +msgstr "" + +#. T is the shape formed by the cube labels +#: ../data/plugins/80-pretty-patterns.algorithm.py:85 +#: ../data/plugins/80-pretty-patterns.algorithm.py:88 +#: ../data/plugins/80-pretty-patterns.algorithm.py:92 +#: ../data/plugins/80-pretty-patterns.algorithm.py:96 +#: ../data/plugins/80-pretty-patterns.algorithm.py:100 +#: ../data/plugins/80-pretty-patterns.algorithm.py:104 +msgid "T-Time" +msgstr "" + +#. C is the shape formed by the cube labels +#: ../data/plugins/80-pretty-patterns.algorithm.py:110 +msgid "C" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:113 +msgid "Cube in a Cube" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:117 +msgid "Striped Cube in a Cube" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:121 +msgid "Six Square Cuboids" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:125 +msgid "Superflip" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:129 +msgid "Superflip easy" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:133 +msgid "Green Mamba" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:137 +msgid "Anaconda" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:141 +msgid "Duck Feet" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:20 +#: ../data/plugins/90-library.algorithm.py:23 +#: ../data/plugins/90-library.algorithm.py:26 +#: ../data/plugins/90-library.algorithm.py:29 +#: ../data/plugins/90-library.algorithm.py:32 +#: ../data/plugins/90-library.algorithm.py:35 +#: ../data/plugins/90-library.algorithm.py:38 +#: ../data/plugins/90-library.algorithm.py:41 +#: ../data/plugins/90-library.algorithm.py:44 +#: ../data/plugins/90-library.algorithm.py:47 +#: ../data/plugins/90-library.algorithm.py:50 +msgid "Library" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:21 +#: ../data/plugins/90-library.algorithm.py:24 +msgid "Middle Layer" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:22 +msgid "Front to Right" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:25 +msgid "Front to Left" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:27 +#: ../data/plugins/90-library.algorithm.py:30 +#: ../data/plugins/90-library.algorithm.py:33 +#: ../data/plugins/90-library.algorithm.py:36 +msgid "Last Layer" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:28 +msgid "Swap Edges" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:31 +msgid "Flip Edges" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:34 +msgid "Swap Corners" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:37 +msgid "Rotate Corners" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:39 +#: ../data/plugins/90-library.algorithm.py:42 +#: ../data/plugins/90-library.algorithm.py:45 +msgid "Rotate Center" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:40 +msgid "2×Up" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:43 +msgid "Up and Front" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:46 +msgid "Up and Down" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:48 +#: ../data/plugins/90-library.algorithm.py:51 +msgid "Misc" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:49 +msgid "Back without Back" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:52 +msgid "2×Back without Back" +msgstr "" diff -Nru pybik-0.5/po/ms.po pybik-1.0.1/po/ms.po --- pybik-0.5/po/ms.po 1970-01-01 00:00:00.000000000 +0000 +++ pybik-1.0.1/po/ms.po 2013-02-01 20:18:02.000000000 +0000 @@ -0,0 +1,876 @@ +# Malay translation for pybik +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the pybik package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: pybik\n" +"Report-Msgid-Bugs-To: https://bugs.launchpad.net/pybik/+filebug\n" +"POT-Creation-Date: 2013-01-31 14:25+0100\n" +"PO-Revision-Date: 2012-12-23 03:45+0000\n" +"Last-Translator: abuyop \n" +"Language-Team: Malay \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Launchpad-Export-Date: 2012-12-24 04:43+0000\n" +"X-Generator: Launchpad (build 16378)\n" + +#: ../pybiklib/application.py:304 +msgid "Press the Esc key to exit Edit Mode" +msgstr "Tekan kekunci Esc untuk keluar dari Mod Sunting" + +#. substitution for {move_text} in statusbar text +#: ../pybiklib/application.py:313 +msgid "{current} / {total} move" +msgid_plural "{current} / {total} moves" +msgstr[0] "{current} / {total} gerakan" +msgstr[1] "{current} / {total} gerakan" + +#. substitution for {solved_text} in statusbar text +#: ../pybiklib/application.py:317 ../pybiklib/ui/model.py:82 +msgid "solved" +msgstr "diselesaikan" + +#: ../pybiklib/application.py:317 +msgid "not solved" +msgstr "tidak selesai" + +#. statusbar text +#: ../pybiklib/application.py:320 +msgid "{model_text}, {move_text}, {solved_text}" +msgstr "{model_text}, {move_text}, {solved_text}" + +#: ../pybiklib/application.py:353 +msgid "Congratulations, you have solved the puzzle!" +msgstr "Tahniah, anda telah berjaya menyelesaikannya!" + +#: ../pybiklib/config.py:30 ../pybiklib/ui/main.py:194 +#: ../data/applications/pybik.desktop.in.h:1 +msgid "Pybik" +msgstr "Pybik" + +#: ../pybiklib/config.py:59 ../data/applications/pybik.desktop.in.h:2 +msgid "3D Rubik's cube game" +msgstr "Permainan kiub Rubrik 3D" + +#: ../pybiklib/config.py:61 +msgid "" +"Pybik is an interactive, graphical, single player puzzle about the cube " +"invented by Ernő Rubik. Besides the cube the program can handle towers and " +"bricks (non cubic puzzles). Pybik also has solvers, pretty patterns and a " +"collection of various moves. The cube can be manipulated with the mouse or " +"keyboard. You can change the colors or images on the faces of the cube." +msgstr "" + +#: ../pybiklib/config.py:69 +msgid "" +"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.\n" +"\n" +"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." +msgstr "" + +#: ../pybiklib/config.py:79 +msgid "" +"Read the full text of the GNU General Public " +"License<|> or see ." +msgstr "" + +#: ../pybiklib/config.py:82 +msgid "" +"You should have received a copy of the GNU General Public License along with " +"this program. If not, see ." +msgstr "" +"Anda seharusnya menerima salinan GNU General Public License bersama program " +"ini. Jika tidak, sila layari ." + +#: ../pybiklib/config.py:88 +msgid "" +"If you find any bugs in Pybik or have a suggestion for an improvement then " +"please submit a <{CONTACT_FILEBUG}|>bug report<|>. In the latter case you " +"can mark the bug report as \"Wishlist\"." +msgstr "" + +#: ../pybiklib/config.py:94 +msgid "" +"Translations are managed by the " +"Launchpad " +"translation group<|>.\n" +"\n" +"If you want help to translate Pybik to your language you can do it through " +"the web interface<|>.\n" +"\n" +"Read more about \"Translating with " +"Launchpad\"<|> and " +"\"Starting to " +"translate\"<|>." +msgstr "" + +#: ../pybiklib/dialogs.py:168 +msgid "Press a key …" +msgstr "Tekan mana-mana kekunci ..." + +#: ../pybiklib/dialogs.py:296 +msgid "plain" +msgstr "biasa" + +#: ../pybiklib/dialogs.py:301 +msgid "select …" +msgstr "pilih ..." + +#: ../pybiklib/dialogs.py:313 +msgid "Up" +msgstr "Naik" + +#: ../pybiklib/dialogs.py:313 +msgid "Down" +msgstr "Turun" + +#: ../pybiklib/dialogs.py:313 +msgid "Left" +msgstr "Kiri" + +#: ../pybiklib/dialogs.py:313 +msgid "Right" +msgstr "Kanan" + +#: ../pybiklib/dialogs.py:313 +msgid "Front" +msgstr "Hadapan" + +#: ../pybiklib/dialogs.py:313 +msgid "Back" +msgstr "Undur" + +#: ../pybiklib/dialogs.py:331 +msgid "Move" +msgstr "Gerak" + +#: ../pybiklib/dialogs.py:332 +msgid "Key" +msgstr "Kekunci" + +#: ../pybiklib/dialogs.py:486 +msgid "Open Image" +msgstr "Buka Imej" + +#: ../pybiklib/dialogs.py:536 ../pybiklib/ui/model.py:79 +msgid "Size:" +msgstr "Saiz:" + +#: ../pybiklib/dialogs.py:536 +msgid "Basis:" +msgstr "Asas:" + +#: ../pybiklib/dialogs.py:536 +msgid "Width:" +msgstr "Lebar:" + +#: ../pybiklib/dialogs.py:565 +msgid "Canceling operation, please wait" +msgstr "Membatalkan operasi, sila tunggu" + +#: ../pybiklib/dialogs.py:621 +msgid "Pybik project website" +msgstr "Laman sesawang projek Pybik" + +#: ../pybiklib/main.py:287 +msgid "" +"An error occurred while reading the settings:\n" +"{error_message}" +msgstr "" +"Ralat berlaku semasa membaca tetapan:\n" +"{error_message}" + +#: ../pybiklib/model.py:214 +msgid "Brick" +msgstr "Bata" + +#: ../pybiklib/model.py:215 +msgid "{0}×{1}×{2}-Brick" +msgstr "Bata-{0}×{1}×{2}" + +#: ../pybiklib/model.py:835 +msgid "Tower" +msgstr "Menara" + +#: ../pybiklib/model.py:836 +msgid "{0}×{1}-Tower" +msgstr "Menara-{0}×{1}" + +#: ../pybiklib/model.py:850 +msgid "Cube" +msgstr "Kiub" + +#: ../pybiklib/model.py:851 +msgid "{0}×{0}×{0}-Cube" +msgstr "Kiub-{0}×{0}×{0}" + +#: ../pybiklib/plugins.py:92 +msgid "This algorithm does not work for any model.\n" +msgstr "Algoritma ini tidak berfungsi dengan mana-mana model.\n" + +#: ../pybiklib/plugins.py:94 ../pybiklib/plugins.py:97 +msgid "This algorithm only works for:\n" +msgstr "Algoritma ini hanya berfungsi untuk:\n" + +#: ../pybiklib/settings.py:256 +msgid "Settings can not be written to file: {error_message}" +msgstr "Tetapan tidak dapat ditulis ke fail: {error_message}" + +#: ../pybiklib/ui/about.py:131 +msgid "About Pybik" +msgstr "Perihal Pybik" + +#: ../pybiklib/ui/about.py:132 +msgid "About" +msgstr "Perihal" + +#: ../pybiklib/ui/about.py:133 +msgid "Feedback" +msgstr "Maklumbalas" + +#: ../pybiklib/ui/about.py:134 +msgid "Translation" +msgstr "Terjemahan" + +#: ../pybiklib/ui/about.py:135 +msgid "License" +msgstr "Lesen" + +#: ../pybiklib/ui/main.py:195 +msgid "&Game" +msgstr "Per&mainan" + +#: ../pybiklib/ui/main.py:196 +msgid "&Edit" +msgstr "&Sunting" + +#: ../pybiklib/ui/main.py:197 +msgid "&View" +msgstr "&Lihat" + +#: ../pybiklib/ui/main.py:198 +msgid "&Help" +msgstr "&Bantuan" + +#: ../pybiklib/ui/main.py:199 +msgid "Pybik Toolbar" +msgstr "Palang Alat Pybik" + +#: ../pybiklib/ui/main.py:200 +msgid "&New Random" +msgstr "Rawak &Baru" + +#: ../pybiklib/ui/main.py:201 +msgid "Ne&w Solved" +msgstr "Diselesai Ba&ru" + +#: ../pybiklib/ui/main.py:202 +msgid "&Quit" +msgstr "&Keluar" + +#: ../pybiklib/ui/main.py:203 +msgid "&Select Model …" +msgstr "&Pilih Model ..." + +#: ../pybiklib/ui/main.py:204 +msgid "&Set as Initial State" +msgstr "&Tetap sebagai Keadaan Awal" + +#: ../pybiklib/ui/main.py:205 +msgid "&Reset Rotation" +msgstr "&Tetap Semula Putaran" + +#: ../pybiklib/ui/main.py:206 +msgid "&Invert Moves" +msgstr "S&ongsang Gerakan" + +#: ../pybiklib/ui/main.py:207 +msgid "Reload Plugins" +msgstr "Muat Semula Pemalam" + +#: ../pybiklib/ui/main.py:208 +msgid "&Preferences …" +msgstr "K&eutamaan ..." + +#: ../pybiklib/ui/main.py:209 +msgid "&Toolbar" +msgstr "Palang Ala&t" + +#: ../pybiklib/ui/main.py:210 +msgid "&Status Bar" +msgstr "Palang &Status" + +#: ../pybiklib/ui/main.py:211 +msgid "&Info …" +msgstr "&Maklumat ..." + +#: ../pybiklib/ui/main.py:212 +msgid "Rewind" +msgstr "Ulang Semula" + +#: ../pybiklib/ui/main.py:213 +msgid "Go to the previous mark (or the beginning) of the sequence of moves" +msgstr "Pergi ke tanda terdahulu (atau permulaan) bagi jujukan gerakan" + +#: ../pybiklib/ui/main.py:214 +msgid "Previous" +msgstr "Terdahulu" + +#: ../pybiklib/ui/main.py:215 +msgid "Make one step backwards" +msgstr "Buat satu langkah mengundur" + +#: ../pybiklib/ui/main.py:216 +msgid "Stop" +msgstr "Henti" + +#: ../pybiklib/ui/main.py:217 +msgid "Stop running the sequence of moves" +msgstr "Henti menjalankan jujukan gerakan" + +#: ../pybiklib/ui/main.py:218 +msgid "Play" +msgstr "Main" + +#: ../pybiklib/ui/main.py:219 +msgid "Run forward through the sequence of moves" +msgstr "Jalan kehadapan menerusi jujukan gerakan" + +#: ../pybiklib/ui/main.py:220 +msgid "Next" +msgstr "" + +#: ../pybiklib/ui/main.py:221 +msgid "Make one step forwards" +msgstr "" + +#: ../pybiklib/ui/main.py:222 +msgid "Forward" +msgstr "" + +#: ../pybiklib/ui/main.py:223 +msgid "Go to the next mark (or the end) of the sequence of moves" +msgstr "" + +#: ../pybiklib/ui/main.py:224 +msgid "Add Mark" +msgstr "" + +#: ../pybiklib/ui/main.py:225 +msgid "Mark the current place in the sequence of moves" +msgstr "" + +#: ../pybiklib/ui/main.py:226 +msgid "Remove Mark" +msgstr "" + +#: ../pybiklib/ui/main.py:227 +msgid "Remove the mark at the current place in the sequence of moves" +msgstr "" + +#: ../pybiklib/ui/main.py:228 +msgid "&Edit Bar" +msgstr "" + +#: ../pybiklib/ui/main.py:229 +msgid "Normalize Cube Rotations" +msgstr "" + +#: ../pybiklib/ui/model.py:78 +msgid "Select Model" +msgstr "" + +#: ../pybiklib/ui/model.py:80 +msgid "Height:" +msgstr "" + +#: ../pybiklib/ui/model.py:81 +msgid "Depth:" +msgstr "" + +#: ../pybiklib/ui/preferences.py:252 +msgid "Preferences" +msgstr "" + +#: ../pybiklib/ui/preferences.py:253 +msgid "Animation Speed:" +msgstr "" + +#: ../pybiklib/ui/preferences.py:254 +msgid "Lighting" +msgstr "" + +#: ../pybiklib/ui/preferences.py:255 +msgid "Mirror Distance:" +msgstr "" + +#: ../pybiklib/ui/preferences.py:256 +msgid "Antialiasing" +msgstr "" + +#: ../pybiklib/ui/preferences.py:257 +msgid "Hardware:" +msgstr "" + +#: ../pybiklib/ui/preferences.py:258 +msgid "Software:" +msgstr "" + +#: ../pybiklib/ui/preferences.py:259 +msgid "" +"

The program needs to " +"be restarted for the changes to take effect.

" +msgstr "" + +#: ../pybiklib/ui/preferences.py:260 +msgid "Graphic" +msgstr "" + +#: ../pybiklib/ui/preferences.py:261 +msgid "Four directions" +msgstr "" + +#: ../pybiklib/ui/preferences.py:262 +msgid "" +"Simplified,\n" +"right button inverts move" +msgstr "" + +#: ../pybiklib/ui/preferences.py:263 +msgid "Mouse" +msgstr "" + +#: ../pybiklib/ui/preferences.py:264 ../pybiklib/ui/preferences.py:265 +msgid "Add" +msgstr "" + +#: ../pybiklib/ui/preferences.py:266 ../pybiklib/ui/preferences.py:267 +msgid "Remove" +msgstr "" + +#: ../pybiklib/ui/preferences.py:268 ../pybiklib/ui/preferences.py:269 +msgid "Reset" +msgstr "" + +#: ../pybiklib/ui/preferences.py:270 +msgid "Keys" +msgstr "" + +#: ../pybiklib/ui/preferences.py:271 +msgid "Color:" +msgstr "" + +#: ../pybiklib/ui/preferences.py:272 +msgid "Image File:" +msgstr "" + +#: ../pybiklib/ui/preferences.py:273 +msgid "Tiled" +msgstr "" + +#: ../pybiklib/ui/preferences.py:274 +msgid "Mosaic" +msgstr "" + +#: ../pybiklib/ui/preferences.py:275 +msgid "Background:" +msgstr "" + +#: ../pybiklib/ui/preferences.py:276 +msgid "Appearance" +msgstr "" + +#. Add whatever keywords you want in your language, separated by semicolons. These keywords are used when searching for applications in dashes, etc. (Unity, GNOME Shell) +#: ../data/applications/pybik.desktop.in.h:4 +msgid "rubik;cube;puzzle;magic;" +msgstr "" + +#: ../data/plugins/01-challenges.algorithm.py:19 +#: ../data/plugins/01-challenges.algorithm.py:22 +#: ../data/plugins/01-challenges.algorithm.py:25 +#: ../data/plugins/01-challenges.algorithm.py:28 +#: ../data/plugins/01-challenges.algorithm.py:31 +#: ../data/plugins/01-challenges.algorithm.py:34 +#: ../data/plugins/01-challenges.algorithm.py:37 +#: ../data/plugins/01-challenges.algorithm.py:40 +#: ../data/plugins/01-challenges.algorithm.py:43 +#: ../data/plugins/01-challenges.algorithm.py:46 +#: ../data/plugins/01-challenges.algorithm.py:49 +msgid "Challenges" +msgstr "" + +#: ../data/plugins/01-challenges.algorithm.py:20 +msgid "Solve random cube" +msgstr "" + +#: ../data/plugins/01-challenges.algorithm.py:23 +msgid "Solve in 1 move" +msgstr "" + +#: ../data/plugins/01-challenges.algorithm.py:26 +msgid "Solve in 2 moves" +msgstr "" + +#: ../data/plugins/01-challenges.algorithm.py:29 +msgid "Solve in 3 moves" +msgstr "" + +#: ../data/plugins/01-challenges.algorithm.py:32 +msgid "Solve in 4 moves" +msgstr "" + +#: ../data/plugins/01-challenges.algorithm.py:35 +msgid "Solve in 5 moves" +msgstr "" + +#: ../data/plugins/01-challenges.algorithm.py:38 +msgid "Solve in 6 moves" +msgstr "" + +#: ../data/plugins/01-challenges.algorithm.py:41 +msgid "Solve in 7 moves" +msgstr "" + +#: ../data/plugins/01-challenges.algorithm.py:44 +msgid "Solve in 8 moves" +msgstr "" + +#: ../data/plugins/01-challenges.algorithm.py:47 +msgid "Solve in 9 moves" +msgstr "" + +#: ../data/plugins/01-challenges.algorithm.py:50 +msgid "Solve in 10 moves" +msgstr "" + +#: ../data/plugins/10-spiegel.algorithm.py:35 +#: ../data/plugins/10-spiegel.algorithm.py:38 +#: ../data/plugins/10-spiegel.algorithm.py:67 +#: ../data/plugins/10-spiegel.algorithm.py:88 +#: ../data/plugins/10-spiegel.algorithm.py:103 +#: ../data/plugins/10-spiegel.algorithm.py:116 +#: ../data/plugins/10-spiegel.algorithm.py:133 +#: ../data/plugins/10-spiegel.algorithm.py:144 +#: ../data/plugins/11-spiegel-improved.algorithm.py:35 +#: ../data/plugins/11-spiegel-improved.algorithm.py:38 +#: ../data/plugins/11-spiegel-improved.algorithm.py:83 +#: ../data/plugins/11-spiegel-improved.algorithm.py:122 +#: ../data/plugins/11-spiegel-improved.algorithm.py:154 +#: ../data/plugins/11-spiegel-improved.algorithm.py:180 +#: ../data/plugins/11-spiegel-improved.algorithm.py:198 +#: ../data/plugins/11-spiegel-improved.algorithm.py:212 +#: ../data/plugins/12-lbl-leyan.algorithm.py:22 +#: ../data/plugins/12-lbl-leyan.algorithm.py:25 +#: ../data/plugins/12-lbl-leyan.algorithm.py:54 +#: ../data/plugins/12-lbl-leyan.algorithm.py:75 +#: ../data/plugins/12-lbl-leyan.algorithm.py:91 +#: ../data/plugins/12-lbl-leyan.algorithm.py:108 +#: ../data/plugins/12-lbl-leyan.algorithm.py:130 +#: ../data/plugins/12-lbl-leyan.algorithm.py:171 +#: ../data/plugins/20-2x2x2.algorithm.py:19 +#: ../data/plugins/20-2x2x2.algorithm.py:22 +#: ../data/plugins/20-2x2x2.algorithm.py:41 +#: ../data/plugins/20-2x2x2.algorithm.py:61 +msgid "Solvers" +msgstr "" + +#. Spiegel is the name of a solution method +#: ../data/plugins/10-spiegel.algorithm.py:37 +#: ../data/plugins/10-spiegel.algorithm.py:39 +#: ../data/plugins/10-spiegel.algorithm.py:68 +#: ../data/plugins/10-spiegel.algorithm.py:89 +#: ../data/plugins/10-spiegel.algorithm.py:104 +#: ../data/plugins/10-spiegel.algorithm.py:117 +#: ../data/plugins/10-spiegel.algorithm.py:134 +#: ../data/plugins/10-spiegel.algorithm.py:145 +msgid "Spiegel" +msgstr "" + +#: ../data/plugins/10-spiegel.algorithm.py:40 +#: ../data/plugins/11-spiegel-improved.algorithm.py:40 +#: ../data/plugins/12-lbl-leyan.algorithm.py:27 +msgid "Top edges" +msgstr "" + +#: ../data/plugins/10-spiegel.algorithm.py:69 +#: ../data/plugins/11-spiegel-improved.algorithm.py:85 +#: ../data/plugins/12-lbl-leyan.algorithm.py:56 +msgid "Top corners" +msgstr "" + +#: ../data/plugins/10-spiegel.algorithm.py:90 +#: ../data/plugins/11-spiegel-improved.algorithm.py:124 +#: ../data/plugins/12-lbl-leyan.algorithm.py:77 +msgid "Middle slice" +msgstr "" + +#: ../data/plugins/10-spiegel.algorithm.py:105 +#: ../data/plugins/11-spiegel-improved.algorithm.py:156 +#: ../data/plugins/12-lbl-leyan.algorithm.py:173 +msgid "Bottom edge place" +msgstr "" + +#: ../data/plugins/10-spiegel.algorithm.py:118 +#: ../data/plugins/11-spiegel-improved.algorithm.py:182 +#: ../data/plugins/12-lbl-leyan.algorithm.py:93 +msgid "Bottom edge orient" +msgstr "" + +#: ../data/plugins/10-spiegel.algorithm.py:135 +#: ../data/plugins/11-spiegel-improved.algorithm.py:200 +#: ../data/plugins/12-lbl-leyan.algorithm.py:110 +#: ../data/plugins/20-2x2x2.algorithm.py:43 +msgid "Bottom corner place" +msgstr "" + +#: ../data/plugins/10-spiegel.algorithm.py:146 +#: ../data/plugins/11-spiegel-improved.algorithm.py:214 +#: ../data/plugins/12-lbl-leyan.algorithm.py:132 +#: ../data/plugins/20-2x2x2.algorithm.py:63 +msgid "Bottom corner orient" +msgstr "" + +#. Spiegel is the name of a solution method +#: ../data/plugins/11-spiegel-improved.algorithm.py:37 +#: ../data/plugins/11-spiegel-improved.algorithm.py:39 +#: ../data/plugins/11-spiegel-improved.algorithm.py:84 +#: ../data/plugins/11-spiegel-improved.algorithm.py:123 +#: ../data/plugins/11-spiegel-improved.algorithm.py:155 +#: ../data/plugins/11-spiegel-improved.algorithm.py:181 +#: ../data/plugins/11-spiegel-improved.algorithm.py:199 +#: ../data/plugins/11-spiegel-improved.algorithm.py:213 +msgid "Spiegel improved" +msgstr "" + +#. Leyan Lo is the inventor of the solution method +#: ../data/plugins/12-lbl-leyan.algorithm.py:24 +#: ../data/plugins/12-lbl-leyan.algorithm.py:26 +#: ../data/plugins/12-lbl-leyan.algorithm.py:55 +#: ../data/plugins/12-lbl-leyan.algorithm.py:76 +#: ../data/plugins/12-lbl-leyan.algorithm.py:92 +#: ../data/plugins/12-lbl-leyan.algorithm.py:109 +#: ../data/plugins/12-lbl-leyan.algorithm.py:131 +#: ../data/plugins/12-lbl-leyan.algorithm.py:172 +msgid "Layer Method (Leyan Lo)" +msgstr "" + +#: ../data/plugins/20-2x2x2.algorithm.py:20 +#: ../data/plugins/20-2x2x2.algorithm.py:23 +#: ../data/plugins/20-2x2x2.algorithm.py:42 +#: ../data/plugins/20-2x2x2.algorithm.py:62 +msgid "2×2×2" +msgstr "" + +#: ../data/plugins/20-2x2x2.algorithm.py:24 +msgid "Top slice" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:18 +#: ../data/plugins/80-pretty-patterns.algorithm.py:22 +#: ../data/plugins/80-pretty-patterns.algorithm.py:26 +#: ../data/plugins/80-pretty-patterns.algorithm.py:30 +#: ../data/plugins/80-pretty-patterns.algorithm.py:34 +#: ../data/plugins/80-pretty-patterns.algorithm.py:39 +#: ../data/plugins/80-pretty-patterns.algorithm.py:43 +#: ../data/plugins/80-pretty-patterns.algorithm.py:48 +#: ../data/plugins/80-pretty-patterns.algorithm.py:52 +#: ../data/plugins/80-pretty-patterns.algorithm.py:56 +#: ../data/plugins/80-pretty-patterns.algorithm.py:60 +#: ../data/plugins/80-pretty-patterns.algorithm.py:64 +#: ../data/plugins/80-pretty-patterns.algorithm.py:68 +#: ../data/plugins/80-pretty-patterns.algorithm.py:74 +#: ../data/plugins/80-pretty-patterns.algorithm.py:78 +#: ../data/plugins/80-pretty-patterns.algorithm.py:83 +#: ../data/plugins/80-pretty-patterns.algorithm.py:87 +#: ../data/plugins/80-pretty-patterns.algorithm.py:91 +#: ../data/plugins/80-pretty-patterns.algorithm.py:95 +#: ../data/plugins/80-pretty-patterns.algorithm.py:99 +#: ../data/plugins/80-pretty-patterns.algorithm.py:103 +#: ../data/plugins/80-pretty-patterns.algorithm.py:108 +#: ../data/plugins/80-pretty-patterns.algorithm.py:112 +#: ../data/plugins/80-pretty-patterns.algorithm.py:116 +#: ../data/plugins/80-pretty-patterns.algorithm.py:120 +#: ../data/plugins/80-pretty-patterns.algorithm.py:124 +#: ../data/plugins/80-pretty-patterns.algorithm.py:128 +#: ../data/plugins/80-pretty-patterns.algorithm.py:132 +#: ../data/plugins/80-pretty-patterns.algorithm.py:136 +#: ../data/plugins/80-pretty-patterns.algorithm.py:140 +msgid "Pretty patterns" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:19 +#: ../data/plugins/80-pretty-patterns.algorithm.py:23 +#: ../data/plugins/80-pretty-patterns.algorithm.py:27 +#: ../data/plugins/80-pretty-patterns.algorithm.py:31 +#: ../data/plugins/80-pretty-patterns.algorithm.py:35 +#: ../data/plugins/80-pretty-patterns.algorithm.py:40 +#: ../data/plugins/80-pretty-patterns.algorithm.py:44 +msgid "Stripes" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:49 +#: ../data/plugins/80-pretty-patterns.algorithm.py:53 +msgid "Criss-Cross" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:57 +msgid "Fried Eggs" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:61 +msgid "Big Fried Eggs" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:65 +msgid "4 Fried Eggs" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:69 +msgid "Chessboard" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:75 +msgid "Cross" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:79 +msgid "Zig Zag" +msgstr "" + +#. T is the shape formed by the cube labels +#: ../data/plugins/80-pretty-patterns.algorithm.py:85 +#: ../data/plugins/80-pretty-patterns.algorithm.py:88 +#: ../data/plugins/80-pretty-patterns.algorithm.py:92 +#: ../data/plugins/80-pretty-patterns.algorithm.py:96 +#: ../data/plugins/80-pretty-patterns.algorithm.py:100 +#: ../data/plugins/80-pretty-patterns.algorithm.py:104 +msgid "T-Time" +msgstr "" + +#. C is the shape formed by the cube labels +#: ../data/plugins/80-pretty-patterns.algorithm.py:110 +msgid "C" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:113 +msgid "Cube in a Cube" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:117 +msgid "Striped Cube in a Cube" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:121 +msgid "Six Square Cuboids" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:125 +msgid "Superflip" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:129 +msgid "Superflip easy" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:133 +msgid "Green Mamba" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:137 +msgid "Anaconda" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:141 +msgid "Duck Feet" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:20 +#: ../data/plugins/90-library.algorithm.py:23 +#: ../data/plugins/90-library.algorithm.py:26 +#: ../data/plugins/90-library.algorithm.py:29 +#: ../data/plugins/90-library.algorithm.py:32 +#: ../data/plugins/90-library.algorithm.py:35 +#: ../data/plugins/90-library.algorithm.py:38 +#: ../data/plugins/90-library.algorithm.py:41 +#: ../data/plugins/90-library.algorithm.py:44 +#: ../data/plugins/90-library.algorithm.py:47 +#: ../data/plugins/90-library.algorithm.py:50 +msgid "Library" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:21 +#: ../data/plugins/90-library.algorithm.py:24 +msgid "Middle Layer" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:22 +msgid "Front to Right" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:25 +msgid "Front to Left" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:27 +#: ../data/plugins/90-library.algorithm.py:30 +#: ../data/plugins/90-library.algorithm.py:33 +#: ../data/plugins/90-library.algorithm.py:36 +msgid "Last Layer" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:28 +msgid "Swap Edges" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:31 +msgid "Flip Edges" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:34 +msgid "Swap Corners" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:37 +msgid "Rotate Corners" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:39 +#: ../data/plugins/90-library.algorithm.py:42 +#: ../data/plugins/90-library.algorithm.py:45 +msgid "Rotate Center" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:40 +msgid "2×Up" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:43 +msgid "Up and Front" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:46 +msgid "Up and Down" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:48 +#: ../data/plugins/90-library.algorithm.py:51 +msgid "Misc" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:49 +msgid "Back without Back" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:52 +msgid "2×Back without Back" +msgstr "" diff -Nru pybik-0.5/po/pt_BR.po pybik-1.0.1/po/pt_BR.po --- pybik-0.5/po/pt_BR.po 1970-01-01 00:00:00.000000000 +0000 +++ pybik-1.0.1/po/pt_BR.po 2013-02-01 20:18:02.000000000 +0000 @@ -0,0 +1,876 @@ +# Brazilian Portuguese translation for pybik +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the pybik package. +# FIRST AUTHOR , 2012. +# +msgid "" +msgstr "" +"Project-Id-Version: pybik\n" +"Report-Msgid-Bugs-To: https://bugs.launchpad.net/pybik/+filebug\n" +"POT-Creation-Date: 2013-01-31 14:25+0100\n" +"PO-Revision-Date: 2012-12-14 14:05+0000\n" +"Last-Translator: Rafael Neri \n" +"Language-Team: Brazilian Portuguese \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Launchpad-Export-Date: 2012-12-16 04:59+0000\n" +"X-Generator: Launchpad (build 16372)\n" + +#: ../pybiklib/application.py:304 +msgid "Press the Esc key to exit Edit Mode" +msgstr "Pressione a tecla ESC para sair do Modo edição" + +#. substitution for {move_text} in statusbar text +#: ../pybiklib/application.py:313 +msgid "{current} / {total} move" +msgid_plural "{current} / {total} moves" +msgstr[0] "" +msgstr[1] "" + +#. substitution for {solved_text} in statusbar text +#: ../pybiklib/application.py:317 ../pybiklib/ui/model.py:82 +msgid "solved" +msgstr "resolvido" + +#: ../pybiklib/application.py:317 +msgid "not solved" +msgstr "não resolvido" + +#. statusbar text +#: ../pybiklib/application.py:320 +msgid "{model_text}, {move_text}, {solved_text}" +msgstr "" + +#: ../pybiklib/application.py:353 +msgid "Congratulations, you have solved the puzzle!" +msgstr "Parabéns! Você resolveu o quebra-cabeças!" + +#: ../pybiklib/config.py:30 ../pybiklib/ui/main.py:194 +#: ../data/applications/pybik.desktop.in.h:1 +msgid "Pybik" +msgstr "Pybik" + +#: ../pybiklib/config.py:59 ../data/applications/pybik.desktop.in.h:2 +msgid "3D Rubik's cube game" +msgstr "Jogo 3D do cubo de Rubik" + +#: ../pybiklib/config.py:61 +msgid "" +"Pybik is an interactive, graphical, single player puzzle about the cube " +"invented by Ernő Rubik. Besides the cube the program can handle towers and " +"bricks (non cubic puzzles). Pybik also has solvers, pretty patterns and a " +"collection of various moves. The cube can be manipulated with the mouse or " +"keyboard. You can change the colors or images on the faces of the cube." +msgstr "" + +#: ../pybiklib/config.py:69 +msgid "" +"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.\n" +"\n" +"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." +msgstr "" + +#: ../pybiklib/config.py:79 +msgid "" +"Read the full text of the GNU General Public " +"License<|> or see ." +msgstr "" + +#: ../pybiklib/config.py:82 +msgid "" +"You should have received a copy of the GNU General Public License along with " +"this program. If not, see ." +msgstr "" +"Você deve ter recebido uma cópia da GNU General Public License junto com " +"este programa. Se não, veja ." + +#: ../pybiklib/config.py:88 +msgid "" +"If you find any bugs in Pybik or have a suggestion for an improvement then " +"please submit a <{CONTACT_FILEBUG}|>bug report<|>. In the latter case you " +"can mark the bug report as \"Wishlist\"." +msgstr "" + +#: ../pybiklib/config.py:94 +msgid "" +"Translations are managed by the " +"Launchpad " +"translation group<|>.\n" +"\n" +"If you want help to translate Pybik to your language you can do it through " +"the web interface<|>.\n" +"\n" +"Read more about \"Translating with " +"Launchpad\"<|> and " +"\"Starting to " +"translate\"<|>." +msgstr "" + +#: ../pybiklib/dialogs.py:168 +msgid "Press a key …" +msgstr "Pressione uma tecla ..." + +#: ../pybiklib/dialogs.py:296 +msgid "plain" +msgstr "plano" + +#: ../pybiklib/dialogs.py:301 +msgid "select …" +msgstr "" + +#: ../pybiklib/dialogs.py:313 +msgid "Up" +msgstr "Aumentar" + +#: ../pybiklib/dialogs.py:313 +msgid "Down" +msgstr "Para baixo" + +#: ../pybiklib/dialogs.py:313 +msgid "Left" +msgstr "Esquerda" + +#: ../pybiklib/dialogs.py:313 +msgid "Right" +msgstr "Direita" + +#: ../pybiklib/dialogs.py:313 +msgid "Front" +msgstr "Frente" + +#: ../pybiklib/dialogs.py:313 +msgid "Back" +msgstr "Para trás" + +#: ../pybiklib/dialogs.py:331 +msgid "Move" +msgstr "Mover" + +#: ../pybiklib/dialogs.py:332 +msgid "Key" +msgstr "Tecla" + +#: ../pybiklib/dialogs.py:486 +msgid "Open Image" +msgstr "Abrir imagem" + +#: ../pybiklib/dialogs.py:536 ../pybiklib/ui/model.py:79 +msgid "Size:" +msgstr "Tamanho:" + +#: ../pybiklib/dialogs.py:536 +msgid "Basis:" +msgstr "Base:" + +#: ../pybiklib/dialogs.py:536 +msgid "Width:" +msgstr "Largura:" + +#: ../pybiklib/dialogs.py:565 +msgid "Canceling operation, please wait" +msgstr "Cancelando a operação, por favor aguarde" + +#: ../pybiklib/dialogs.py:621 +msgid "Pybik project website" +msgstr "" + +#: ../pybiklib/main.py:287 +msgid "" +"An error occurred while reading the settings:\n" +"{error_message}" +msgstr "" + +#: ../pybiklib/model.py:214 +msgid "Brick" +msgstr "Tijolo" + +#: ../pybiklib/model.py:215 +msgid "{0}×{1}×{2}-Brick" +msgstr "" + +#: ../pybiklib/model.py:835 +msgid "Tower" +msgstr "Torre" + +#: ../pybiklib/model.py:836 +msgid "{0}×{1}-Tower" +msgstr "" + +#: ../pybiklib/model.py:850 +msgid "Cube" +msgstr "Cubo" + +#: ../pybiklib/model.py:851 +msgid "{0}×{0}×{0}-Cube" +msgstr "" + +#: ../pybiklib/plugins.py:92 +msgid "This algorithm does not work for any model.\n" +msgstr "" + +#: ../pybiklib/plugins.py:94 ../pybiklib/plugins.py:97 +msgid "This algorithm only works for:\n" +msgstr "" + +#: ../pybiklib/settings.py:256 +msgid "Settings can not be written to file: {error_message}" +msgstr "Não foi possível gravar as configurações no arquivo: {error_message}" + +#: ../pybiklib/ui/about.py:131 +msgid "About Pybik" +msgstr "Sobre o Pybik" + +#: ../pybiklib/ui/about.py:132 +msgid "About" +msgstr "Sobre" + +#: ../pybiklib/ui/about.py:133 +msgid "Feedback" +msgstr "Sugestões" + +#: ../pybiklib/ui/about.py:134 +msgid "Translation" +msgstr "Tradução" + +#: ../pybiklib/ui/about.py:135 +msgid "License" +msgstr "Licença" + +#: ../pybiklib/ui/main.py:195 +msgid "&Game" +msgstr "&Jogo" + +#: ../pybiklib/ui/main.py:196 +msgid "&Edit" +msgstr "&Editar" + +#: ../pybiklib/ui/main.py:197 +msgid "&View" +msgstr "&Visualizar" + +#: ../pybiklib/ui/main.py:198 +msgid "&Help" +msgstr "A&juda" + +#: ../pybiklib/ui/main.py:199 +msgid "Pybik Toolbar" +msgstr "Barra de ferramentas do Pybik" + +#: ../pybiklib/ui/main.py:200 +msgid "&New Random" +msgstr "" + +#: ../pybiklib/ui/main.py:201 +msgid "Ne&w Solved" +msgstr "" + +#: ../pybiklib/ui/main.py:202 +msgid "&Quit" +msgstr "&Sair" + +#: ../pybiklib/ui/main.py:203 +msgid "&Select Model …" +msgstr "&Selecionar modelo ..." + +#: ../pybiklib/ui/main.py:204 +msgid "&Set as Initial State" +msgstr "Definir como estado inicial" + +#: ../pybiklib/ui/main.py:205 +msgid "&Reset Rotation" +msgstr "" + +#: ../pybiklib/ui/main.py:206 +msgid "&Invert Moves" +msgstr "&Inverter movimentos" + +#: ../pybiklib/ui/main.py:207 +msgid "Reload Plugins" +msgstr "Atualizar plugins" + +#: ../pybiklib/ui/main.py:208 +msgid "&Preferences …" +msgstr "&Preferências" + +#: ../pybiklib/ui/main.py:209 +msgid "&Toolbar" +msgstr "Barra de ferramen&tas" + +#: ../pybiklib/ui/main.py:210 +msgid "&Status Bar" +msgstr "Barra de &status" + +#: ../pybiklib/ui/main.py:211 +msgid "&Info …" +msgstr "&Informações ..." + +#: ../pybiklib/ui/main.py:212 +msgid "Rewind" +msgstr "" + +#: ../pybiklib/ui/main.py:213 +msgid "Go to the previous mark (or the beginning) of the sequence of moves" +msgstr "" + +#: ../pybiklib/ui/main.py:214 +msgid "Previous" +msgstr "Anterior" + +#: ../pybiklib/ui/main.py:215 +msgid "Make one step backwards" +msgstr "" + +#: ../pybiklib/ui/main.py:216 +msgid "Stop" +msgstr "Parar" + +#: ../pybiklib/ui/main.py:217 +msgid "Stop running the sequence of moves" +msgstr "" + +#: ../pybiklib/ui/main.py:218 +msgid "Play" +msgstr "Reproduzir" + +#: ../pybiklib/ui/main.py:219 +msgid "Run forward through the sequence of moves" +msgstr "" + +#: ../pybiklib/ui/main.py:220 +msgid "Next" +msgstr "Próximo" + +#: ../pybiklib/ui/main.py:221 +msgid "Make one step forwards" +msgstr "" + +#: ../pybiklib/ui/main.py:222 +msgid "Forward" +msgstr "Avançar" + +#: ../pybiklib/ui/main.py:223 +msgid "Go to the next mark (or the end) of the sequence of moves" +msgstr "" + +#: ../pybiklib/ui/main.py:224 +msgid "Add Mark" +msgstr "Adicionar marcador" + +#: ../pybiklib/ui/main.py:225 +msgid "Mark the current place in the sequence of moves" +msgstr "Marcar o lugar atual na sequencia de movimentos" + +#: ../pybiklib/ui/main.py:226 +msgid "Remove Mark" +msgstr "Remover marcador" + +#: ../pybiklib/ui/main.py:227 +msgid "Remove the mark at the current place in the sequence of moves" +msgstr "" + +#: ../pybiklib/ui/main.py:228 +msgid "&Edit Bar" +msgstr "&Editar barra" + +#: ../pybiklib/ui/main.py:229 +msgid "Normalize Cube Rotations" +msgstr "" + +#: ../pybiklib/ui/model.py:78 +msgid "Select Model" +msgstr "Selecionar modelo" + +#: ../pybiklib/ui/model.py:80 +msgid "Height:" +msgstr "" + +#: ../pybiklib/ui/model.py:81 +msgid "Depth:" +msgstr "Profundidade:" + +#: ../pybiklib/ui/preferences.py:252 +msgid "Preferences" +msgstr "Perferências" + +#: ../pybiklib/ui/preferences.py:253 +msgid "Animation Speed:" +msgstr "Velocidade da animação:" + +#: ../pybiklib/ui/preferences.py:254 +msgid "Lighting" +msgstr "Iluminação" + +#: ../pybiklib/ui/preferences.py:255 +msgid "Mirror Distance:" +msgstr "" + +#: ../pybiklib/ui/preferences.py:256 +msgid "Antialiasing" +msgstr "Anti-serrilhamento" + +#: ../pybiklib/ui/preferences.py:257 +msgid "Hardware:" +msgstr "Hardware:" + +#: ../pybiklib/ui/preferences.py:258 +msgid "Software:" +msgstr "Programa:" + +#: ../pybiklib/ui/preferences.py:259 +msgid "" +"

The program needs to " +"be restarted for the changes to take effect.

" +msgstr "" +"

O programa precisa ser " +"reiniciado para que as alterações tenham efeito.

" + +#: ../pybiklib/ui/preferences.py:260 +msgid "Graphic" +msgstr "Gráfico" + +#: ../pybiklib/ui/preferences.py:261 +msgid "Four directions" +msgstr "Quatro direções" + +#: ../pybiklib/ui/preferences.py:262 +msgid "" +"Simplified,\n" +"right button inverts move" +msgstr "" + +#: ../pybiklib/ui/preferences.py:263 +msgid "Mouse" +msgstr "Mouse" + +#: ../pybiklib/ui/preferences.py:264 ../pybiklib/ui/preferences.py:265 +msgid "Add" +msgstr "Adicionar" + +#: ../pybiklib/ui/preferences.py:266 ../pybiklib/ui/preferences.py:267 +msgid "Remove" +msgstr "Remover" + +#: ../pybiklib/ui/preferences.py:268 ../pybiklib/ui/preferences.py:269 +msgid "Reset" +msgstr "Reiniciar" + +#: ../pybiklib/ui/preferences.py:270 +msgid "Keys" +msgstr "Chaves" + +#: ../pybiklib/ui/preferences.py:271 +msgid "Color:" +msgstr "Cor:" + +#: ../pybiklib/ui/preferences.py:272 +msgid "Image File:" +msgstr "Arquivo de imagem:" + +#: ../pybiklib/ui/preferences.py:273 +msgid "Tiled" +msgstr "" + +#: ../pybiklib/ui/preferences.py:274 +msgid "Mosaic" +msgstr "Mosaico" + +#: ../pybiklib/ui/preferences.py:275 +msgid "Background:" +msgstr "Plano de fundo:" + +#: ../pybiklib/ui/preferences.py:276 +msgid "Appearance" +msgstr "Aparência" + +#. Add whatever keywords you want in your language, separated by semicolons. These keywords are used when searching for applications in dashes, etc. (Unity, GNOME Shell) +#: ../data/applications/pybik.desktop.in.h:4 +msgid "rubik;cube;puzzle;magic;" +msgstr "" + +#: ../data/plugins/01-challenges.algorithm.py:19 +#: ../data/plugins/01-challenges.algorithm.py:22 +#: ../data/plugins/01-challenges.algorithm.py:25 +#: ../data/plugins/01-challenges.algorithm.py:28 +#: ../data/plugins/01-challenges.algorithm.py:31 +#: ../data/plugins/01-challenges.algorithm.py:34 +#: ../data/plugins/01-challenges.algorithm.py:37 +#: ../data/plugins/01-challenges.algorithm.py:40 +#: ../data/plugins/01-challenges.algorithm.py:43 +#: ../data/plugins/01-challenges.algorithm.py:46 +#: ../data/plugins/01-challenges.algorithm.py:49 +msgid "Challenges" +msgstr "Desafios" + +#: ../data/plugins/01-challenges.algorithm.py:20 +msgid "Solve random cube" +msgstr "" + +#: ../data/plugins/01-challenges.algorithm.py:23 +msgid "Solve in 1 move" +msgstr "Resolver em 1 movimento" + +#: ../data/plugins/01-challenges.algorithm.py:26 +msgid "Solve in 2 moves" +msgstr "Resolver em 2 movimentos" + +#: ../data/plugins/01-challenges.algorithm.py:29 +msgid "Solve in 3 moves" +msgstr "Resolver em 3 movimentos" + +#: ../data/plugins/01-challenges.algorithm.py:32 +msgid "Solve in 4 moves" +msgstr "Resolver em 4 movimentos" + +#: ../data/plugins/01-challenges.algorithm.py:35 +msgid "Solve in 5 moves" +msgstr "Resolver em 5 movimentos" + +#: ../data/plugins/01-challenges.algorithm.py:38 +msgid "Solve in 6 moves" +msgstr "Resolver em 6 movimentos" + +#: ../data/plugins/01-challenges.algorithm.py:41 +msgid "Solve in 7 moves" +msgstr "Resolver em 7 movimentos" + +#: ../data/plugins/01-challenges.algorithm.py:44 +msgid "Solve in 8 moves" +msgstr "Resolver em 8 movimentos" + +#: ../data/plugins/01-challenges.algorithm.py:47 +msgid "Solve in 9 moves" +msgstr "Resolver em 9 movimentos" + +#: ../data/plugins/01-challenges.algorithm.py:50 +msgid "Solve in 10 moves" +msgstr "Resolver em 10 movimentos" + +#: ../data/plugins/10-spiegel.algorithm.py:35 +#: ../data/plugins/10-spiegel.algorithm.py:38 +#: ../data/plugins/10-spiegel.algorithm.py:67 +#: ../data/plugins/10-spiegel.algorithm.py:88 +#: ../data/plugins/10-spiegel.algorithm.py:103 +#: ../data/plugins/10-spiegel.algorithm.py:116 +#: ../data/plugins/10-spiegel.algorithm.py:133 +#: ../data/plugins/10-spiegel.algorithm.py:144 +#: ../data/plugins/11-spiegel-improved.algorithm.py:35 +#: ../data/plugins/11-spiegel-improved.algorithm.py:38 +#: ../data/plugins/11-spiegel-improved.algorithm.py:83 +#: ../data/plugins/11-spiegel-improved.algorithm.py:122 +#: ../data/plugins/11-spiegel-improved.algorithm.py:154 +#: ../data/plugins/11-spiegel-improved.algorithm.py:180 +#: ../data/plugins/11-spiegel-improved.algorithm.py:198 +#: ../data/plugins/11-spiegel-improved.algorithm.py:212 +#: ../data/plugins/12-lbl-leyan.algorithm.py:22 +#: ../data/plugins/12-lbl-leyan.algorithm.py:25 +#: ../data/plugins/12-lbl-leyan.algorithm.py:54 +#: ../data/plugins/12-lbl-leyan.algorithm.py:75 +#: ../data/plugins/12-lbl-leyan.algorithm.py:91 +#: ../data/plugins/12-lbl-leyan.algorithm.py:108 +#: ../data/plugins/12-lbl-leyan.algorithm.py:130 +#: ../data/plugins/12-lbl-leyan.algorithm.py:171 +#: ../data/plugins/20-2x2x2.algorithm.py:19 +#: ../data/plugins/20-2x2x2.algorithm.py:22 +#: ../data/plugins/20-2x2x2.algorithm.py:41 +#: ../data/plugins/20-2x2x2.algorithm.py:61 +msgid "Solvers" +msgstr "" + +#. Spiegel is the name of a solution method +#: ../data/plugins/10-spiegel.algorithm.py:37 +#: ../data/plugins/10-spiegel.algorithm.py:39 +#: ../data/plugins/10-spiegel.algorithm.py:68 +#: ../data/plugins/10-spiegel.algorithm.py:89 +#: ../data/plugins/10-spiegel.algorithm.py:104 +#: ../data/plugins/10-spiegel.algorithm.py:117 +#: ../data/plugins/10-spiegel.algorithm.py:134 +#: ../data/plugins/10-spiegel.algorithm.py:145 +msgid "Spiegel" +msgstr "Spiegel" + +#: ../data/plugins/10-spiegel.algorithm.py:40 +#: ../data/plugins/11-spiegel-improved.algorithm.py:40 +#: ../data/plugins/12-lbl-leyan.algorithm.py:27 +msgid "Top edges" +msgstr "Margens superiores" + +#: ../data/plugins/10-spiegel.algorithm.py:69 +#: ../data/plugins/11-spiegel-improved.algorithm.py:85 +#: ../data/plugins/12-lbl-leyan.algorithm.py:56 +msgid "Top corners" +msgstr "Cantos superiores" + +#: ../data/plugins/10-spiegel.algorithm.py:90 +#: ../data/plugins/11-spiegel-improved.algorithm.py:124 +#: ../data/plugins/12-lbl-leyan.algorithm.py:77 +msgid "Middle slice" +msgstr "Fatia média" + +#: ../data/plugins/10-spiegel.algorithm.py:105 +#: ../data/plugins/11-spiegel-improved.algorithm.py:156 +#: ../data/plugins/12-lbl-leyan.algorithm.py:173 +msgid "Bottom edge place" +msgstr "" + +#: ../data/plugins/10-spiegel.algorithm.py:118 +#: ../data/plugins/11-spiegel-improved.algorithm.py:182 +#: ../data/plugins/12-lbl-leyan.algorithm.py:93 +msgid "Bottom edge orient" +msgstr "" + +#: ../data/plugins/10-spiegel.algorithm.py:135 +#: ../data/plugins/11-spiegel-improved.algorithm.py:200 +#: ../data/plugins/12-lbl-leyan.algorithm.py:110 +#: ../data/plugins/20-2x2x2.algorithm.py:43 +msgid "Bottom corner place" +msgstr "" + +#: ../data/plugins/10-spiegel.algorithm.py:146 +#: ../data/plugins/11-spiegel-improved.algorithm.py:214 +#: ../data/plugins/12-lbl-leyan.algorithm.py:132 +#: ../data/plugins/20-2x2x2.algorithm.py:63 +msgid "Bottom corner orient" +msgstr "" + +#. Spiegel is the name of a solution method +#: ../data/plugins/11-spiegel-improved.algorithm.py:37 +#: ../data/plugins/11-spiegel-improved.algorithm.py:39 +#: ../data/plugins/11-spiegel-improved.algorithm.py:84 +#: ../data/plugins/11-spiegel-improved.algorithm.py:123 +#: ../data/plugins/11-spiegel-improved.algorithm.py:155 +#: ../data/plugins/11-spiegel-improved.algorithm.py:181 +#: ../data/plugins/11-spiegel-improved.algorithm.py:199 +#: ../data/plugins/11-spiegel-improved.algorithm.py:213 +msgid "Spiegel improved" +msgstr "" + +#. Leyan Lo is the inventor of the solution method +#: ../data/plugins/12-lbl-leyan.algorithm.py:24 +#: ../data/plugins/12-lbl-leyan.algorithm.py:26 +#: ../data/plugins/12-lbl-leyan.algorithm.py:55 +#: ../data/plugins/12-lbl-leyan.algorithm.py:76 +#: ../data/plugins/12-lbl-leyan.algorithm.py:92 +#: ../data/plugins/12-lbl-leyan.algorithm.py:109 +#: ../data/plugins/12-lbl-leyan.algorithm.py:131 +#: ../data/plugins/12-lbl-leyan.algorithm.py:172 +msgid "Layer Method (Leyan Lo)" +msgstr "" + +#: ../data/plugins/20-2x2x2.algorithm.py:20 +#: ../data/plugins/20-2x2x2.algorithm.py:23 +#: ../data/plugins/20-2x2x2.algorithm.py:42 +#: ../data/plugins/20-2x2x2.algorithm.py:62 +msgid "2×2×2" +msgstr "2×2×2" + +#: ../data/plugins/20-2x2x2.algorithm.py:24 +msgid "Top slice" +msgstr "Fatia superior" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:18 +#: ../data/plugins/80-pretty-patterns.algorithm.py:22 +#: ../data/plugins/80-pretty-patterns.algorithm.py:26 +#: ../data/plugins/80-pretty-patterns.algorithm.py:30 +#: ../data/plugins/80-pretty-patterns.algorithm.py:34 +#: ../data/plugins/80-pretty-patterns.algorithm.py:39 +#: ../data/plugins/80-pretty-patterns.algorithm.py:43 +#: ../data/plugins/80-pretty-patterns.algorithm.py:48 +#: ../data/plugins/80-pretty-patterns.algorithm.py:52 +#: ../data/plugins/80-pretty-patterns.algorithm.py:56 +#: ../data/plugins/80-pretty-patterns.algorithm.py:60 +#: ../data/plugins/80-pretty-patterns.algorithm.py:64 +#: ../data/plugins/80-pretty-patterns.algorithm.py:68 +#: ../data/plugins/80-pretty-patterns.algorithm.py:74 +#: ../data/plugins/80-pretty-patterns.algorithm.py:78 +#: ../data/plugins/80-pretty-patterns.algorithm.py:83 +#: ../data/plugins/80-pretty-patterns.algorithm.py:87 +#: ../data/plugins/80-pretty-patterns.algorithm.py:91 +#: ../data/plugins/80-pretty-patterns.algorithm.py:95 +#: ../data/plugins/80-pretty-patterns.algorithm.py:99 +#: ../data/plugins/80-pretty-patterns.algorithm.py:103 +#: ../data/plugins/80-pretty-patterns.algorithm.py:108 +#: ../data/plugins/80-pretty-patterns.algorithm.py:112 +#: ../data/plugins/80-pretty-patterns.algorithm.py:116 +#: ../data/plugins/80-pretty-patterns.algorithm.py:120 +#: ../data/plugins/80-pretty-patterns.algorithm.py:124 +#: ../data/plugins/80-pretty-patterns.algorithm.py:128 +#: ../data/plugins/80-pretty-patterns.algorithm.py:132 +#: ../data/plugins/80-pretty-patterns.algorithm.py:136 +#: ../data/plugins/80-pretty-patterns.algorithm.py:140 +msgid "Pretty patterns" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:19 +#: ../data/plugins/80-pretty-patterns.algorithm.py:23 +#: ../data/plugins/80-pretty-patterns.algorithm.py:27 +#: ../data/plugins/80-pretty-patterns.algorithm.py:31 +#: ../data/plugins/80-pretty-patterns.algorithm.py:35 +#: ../data/plugins/80-pretty-patterns.algorithm.py:40 +#: ../data/plugins/80-pretty-patterns.algorithm.py:44 +msgid "Stripes" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:49 +#: ../data/plugins/80-pretty-patterns.algorithm.py:53 +msgid "Criss-Cross" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:57 +msgid "Fried Eggs" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:61 +msgid "Big Fried Eggs" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:65 +msgid "4 Fried Eggs" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:69 +msgid "Chessboard" +msgstr "Tabuleiro de xadrez" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:75 +msgid "Cross" +msgstr "Cruz" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:79 +msgid "Zig Zag" +msgstr "Zigue-zague" + +#. T is the shape formed by the cube labels +#: ../data/plugins/80-pretty-patterns.algorithm.py:85 +#: ../data/plugins/80-pretty-patterns.algorithm.py:88 +#: ../data/plugins/80-pretty-patterns.algorithm.py:92 +#: ../data/plugins/80-pretty-patterns.algorithm.py:96 +#: ../data/plugins/80-pretty-patterns.algorithm.py:100 +#: ../data/plugins/80-pretty-patterns.algorithm.py:104 +msgid "T-Time" +msgstr "" + +#. C is the shape formed by the cube labels +#: ../data/plugins/80-pretty-patterns.algorithm.py:110 +msgid "C" +msgstr "C" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:113 +msgid "Cube in a Cube" +msgstr "Cubo em um cubo" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:117 +msgid "Striped Cube in a Cube" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:121 +msgid "Six Square Cuboids" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:125 +msgid "Superflip" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:129 +msgid "Superflip easy" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:133 +msgid "Green Mamba" +msgstr "" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:137 +msgid "Anaconda" +msgstr "Anaconda" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:141 +msgid "Duck Feet" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:20 +#: ../data/plugins/90-library.algorithm.py:23 +#: ../data/plugins/90-library.algorithm.py:26 +#: ../data/plugins/90-library.algorithm.py:29 +#: ../data/plugins/90-library.algorithm.py:32 +#: ../data/plugins/90-library.algorithm.py:35 +#: ../data/plugins/90-library.algorithm.py:38 +#: ../data/plugins/90-library.algorithm.py:41 +#: ../data/plugins/90-library.algorithm.py:44 +#: ../data/plugins/90-library.algorithm.py:47 +#: ../data/plugins/90-library.algorithm.py:50 +msgid "Library" +msgstr "Biblioteca" + +#: ../data/plugins/90-library.algorithm.py:21 +#: ../data/plugins/90-library.algorithm.py:24 +msgid "Middle Layer" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:22 +msgid "Front to Right" +msgstr "Frente para Direita" + +#: ../data/plugins/90-library.algorithm.py:25 +msgid "Front to Left" +msgstr "Frente para Esquerda" + +#: ../data/plugins/90-library.algorithm.py:27 +#: ../data/plugins/90-library.algorithm.py:30 +#: ../data/plugins/90-library.algorithm.py:33 +#: ../data/plugins/90-library.algorithm.py:36 +msgid "Last Layer" +msgstr "Última camada" + +#: ../data/plugins/90-library.algorithm.py:28 +msgid "Swap Edges" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:31 +msgid "Flip Edges" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:34 +msgid "Swap Corners" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:37 +msgid "Rotate Corners" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:39 +#: ../data/plugins/90-library.algorithm.py:42 +#: ../data/plugins/90-library.algorithm.py:45 +msgid "Rotate Center" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:40 +msgid "2×Up" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:43 +msgid "Up and Front" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:46 +msgid "Up and Down" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:48 +#: ../data/plugins/90-library.algorithm.py:51 +msgid "Misc" +msgstr "Diversos" + +#: ../data/plugins/90-library.algorithm.py:49 +msgid "Back without Back" +msgstr "" + +#: ../data/plugins/90-library.algorithm.py:52 +msgid "2×Back without Back" +msgstr "" diff -Nru pybik-0.5/po/sr.po pybik-1.0.1/po/sr.po --- pybik-0.5/po/sr.po 2012-01-06 17:21:32.000000000 +0000 +++ pybik-1.0.1/po/sr.po 1970-01-01 00:00:00.000000000 +0000 @@ -1,593 +0,0 @@ -# Serbian translation for pybik -# Copyright (c) 2011 Rosetta Contributors and Canonical Ltd 2011 -# This file is distributed under the same license as the pybik package. -# FIRST AUTHOR , 2011. -# -msgid "" -msgstr "" -"Project-Id-Version: pybik\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2012-01-06 18:15+0100\n" -"PO-Revision-Date: 2011-08-03 15:38+0000\n" -"Last-Translator: Мирослав Николић \n" -"Language-Team: Serbian \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && " -"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" -"X-Launchpad-Export-Date: 2012-01-05 05:46+0000\n" -"X-Generator: Launchpad (build 14625)\n" -"Language: sr\n" - -#: ../pybiklib/application.py:140 -msgid "Name" -msgstr "" - -#: ../pybiklib/application.py:420 -msgid "not solved" -msgstr "" - -#: ../pybiklib/application.py:420 -msgid "solved" -msgstr "" - -#: ../pybiklib/application.py:424 -msgid "{current} / {total} move" -msgid_plural "{current} / {total} moves" -msgstr[0] "" -msgstr[1] "" - -#: ../pybiklib/config.py:41 ../pybiklib/config.py:42 -#: ../data/applications/pybik.desktop.in.h:1 -msgid "Pybik" -msgstr "" - -#: ../pybiklib/config.py:43 -msgid "Pybik is a 3 dimensional magic cube game." -msgstr "" - -#: ../pybiklib/config.py:44 -msgid "Pybik web site" -msgstr "" - -#: ../pybiklib/config.py:47 -msgid "" -"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." -msgstr "" - -#: ../pybiklib/config.py:52 -msgid "" -"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." -msgstr "" - -#: ../pybiklib/config.py:57 -msgid "" -"You should have received a copy of the GNU General Public License along with " -"this program. If not, see ." -msgstr "" - -#: ../pybiklib/dialogcolors.py:91 -msgid "Up" -msgstr "" - -#: ../pybiklib/dialogcolors.py:91 -msgid "Down" -msgstr "" - -#: ../pybiklib/dialogcolors.py:91 -msgid "Left" -msgstr "" - -#: ../pybiklib/dialogcolors.py:91 -msgid "Right" -msgstr "" - -#: ../pybiklib/dialogcolors.py:91 -msgid "Front" -msgstr "" - -#: ../pybiklib/dialogcolors.py:91 -msgid "Back" -msgstr "" - -#: ../pybiklib/dialogcolors.py:103 -msgid "Face" -msgstr "" - -#: ../pybiklib/dialogcolors.py:118 -msgid "plain" -msgstr "" - -#: ../pybiklib/dialogs.py:100 -msgid "" -"The Dimension of the cube has changed.\n" -"Start cube with new settings?" -msgstr "" - -#: ../pybiklib/glarea.py:624 -msgid "Cannot create image from file {filename}: {error}" -msgstr "" - -#. Translators: Strings from file main.py are visible only on the commandline and/or in the man-page -#: ../pybiklib/main.py:32 -msgid "usage: " -msgstr "" - -#: ../pybiklib/main.py:33 -msgid "optional arguments" -msgstr "" - -#: ../pybiklib/main.py:149 -msgid "Show help message and exit" -msgstr "" - -#: ../pybiklib/main.py:151 -msgid "Show version number and exit" -msgstr "" - -#: ../pybiklib/main.py:153 -msgid "Start with the cube already solved" -msgstr "" - -#: ../pybiklib/main.py:155 -msgid "Start with a N x N x N sized cube" -msgstr "" - -#: ../pybiklib/main.py:157 -msgid "Show N intermediate positions in animations" -msgstr "" - -#: ../pybiklib/main.py:159 -msgid "Use python module for rendering (very slow)" -msgstr "" - -#: ../pybiklib/main.py:161 -msgid "" -"Enable debug output, D is an integer or a comma-separated list of [{0}]" -msgstr "" - -#: ../pybiklib/main.py:178 -msgid "debug level out of range: {0}" -msgstr "" - -#: ../pybiklib/main.py:186 -msgid "unknown debug option: {0}" -msgstr "" - -#: ../pybiklib/plugins.py:276 -msgid "This script only works for:" -msgstr "" - -#: ../pybiklib/textures.py:177 -msgid "Pixbuf has wrong number of channels" -msgstr "" - -#: ../pybiklib/textures.py:180 -msgid "Pixbuf has unknown color space: {0}" -msgstr "" - -#: ../data/ui/pybik.ui.h:1 -msgid "Add mark" -msgstr "" - -#: ../data/ui/pybik.ui.h:2 -msgid "Animation:" -msgstr "" - -#: ../data/ui/pybik.ui.h:3 -msgid "Background:" -msgstr "" - -#: ../data/ui/pybik.ui.h:4 -msgid "Color selector" -msgstr "" - -#: ../data/ui/pybik.ui.h:5 -msgid "Color:" -msgstr "" - -#: ../data/ui/pybik.ui.h:6 -msgid "Displays the sequence of moves" -msgstr "" - -#: ../data/ui/pybik.ui.h:7 -msgid "Four directions" -msgstr "" - -#: ../data/ui/pybik.ui.h:8 -msgid "General" -msgstr "" - -#: ../data/ui/pybik.ui.h:9 -msgid "Go to the next mark (or the end) of the sequence of moves" -msgstr "" - -#: ../data/ui/pybik.ui.h:10 -msgid "Go to the previous mark (or the beginning) of the sequence of moves" -msgstr "" - -#: ../data/ui/pybik.ui.h:11 -msgid "Image File:" -msgstr "" - -#: ../data/ui/pybik.ui.h:12 -msgid "Lighting" -msgstr "" - -#: ../data/ui/pybik.ui.h:13 -msgid "Make one step backwards" -msgstr "" - -#: ../data/ui/pybik.ui.h:14 -msgid "Make one step forwards" -msgstr "" - -#: ../data/ui/pybik.ui.h:15 -msgid "Makes the cube appear illuminated" -msgstr "" - -#: ../data/ui/pybik.ui.h:16 -msgid "Mark the current place in the sequence of moves" -msgstr "" - -#: ../data/ui/pybik.ui.h:17 -msgid "Mouse" -msgstr "" - -#: ../data/ui/pybik.ui.h:18 -msgid "New _solved" -msgstr "" - -#: ../data/ui/pybik.ui.h:19 -msgid "New random cube" -msgstr "" - -#: ../data/ui/pybik.ui.h:20 -msgid "New solved cube" -msgstr "" - -#: ../data/ui/pybik.ui.h:21 -msgid "Pattern:" -msgstr "" - -#: ../data/ui/pybik.ui.h:22 -msgid "" -"Place a copy of the image\n" -"on each block" -msgstr "" - -#: ../data/ui/pybik.ui.h:24 -msgid "" -"Place a copy of the image across\n" -"the entire face of the cube" -msgstr "" - -#: ../data/ui/pybik.ui.h:26 -msgid "Play Toolbar" -msgstr "" - -#: ../data/ui/pybik.ui.h:27 -msgid "Preferences" -msgstr "" - -#: ../data/ui/pybik.ui.h:28 -msgid "Remove mark" -msgstr "" - -#: ../data/ui/pybik.ui.h:29 -msgid "Remove the mark at the current place in the sequence of moves" -msgstr "" - -#: ../data/ui/pybik.ui.h:30 -msgid "Rese_t rotation" -msgstr "" - -#: ../data/ui/pybik.ui.h:31 -msgid "Run forward through the sequence of moves" -msgstr "" - -#: ../data/ui/pybik.ui.h:32 -msgid "Select a color" -msgstr "" - -#: ../data/ui/pybik.ui.h:33 -msgid "Select image file" -msgstr "" - -#: ../data/ui/pybik.ui.h:34 -msgid "Sets the number of blocks in each side" -msgstr "" - -#: ../data/ui/pybik.ui.h:35 -msgid "" -"Simplified,\n" -"right button\n" -"inverts move" -msgstr "" - -#: ../data/ui/pybik.ui.h:38 -msgid "Size:" -msgstr "" - -#: ../data/ui/pybik.ui.h:39 -msgid "Status Bar" -msgstr "" - -#: ../data/ui/pybik.ui.h:40 -msgid "Stop running the sequence of moves" -msgstr "" - -#: ../data/ui/pybik.ui.h:41 -msgid "Use an image file on the cube face" -msgstr "" - -#: ../data/ui/pybik.ui.h:42 -msgid "_Dynamic script selection" -msgstr "" - -#: ../data/ui/pybik.ui.h:43 -msgid "_Edit" -msgstr "_Уређивање" - -#: ../data/ui/pybik.ui.h:44 -msgid "_Game" -msgstr "_Игра" - -#: ../data/ui/pybik.ui.h:45 -msgid "_Help" -msgstr "_Помоћ" - -#: ../data/ui/pybik.ui.h:46 -msgid "_Invert moves" -msgstr "" - -#: ../data/ui/pybik.ui.h:47 -msgid "_Mosaic" -msgstr "" - -#: ../data/ui/pybik.ui.h:48 -msgid "_New random" -msgstr "" - -#: ../data/ui/pybik.ui.h:49 -msgid "_Play Toolbar" -msgstr "" - -#: ../data/ui/pybik.ui.h:50 -msgid "_Reload scripts" -msgstr "" - -#: ../data/ui/pybik.ui.h:51 -msgid "_Set as initial state" -msgstr "" - -#: ../data/ui/pybik.ui.h:52 -msgid "_Status Bar" -msgstr "" - -#: ../data/ui/pybik.ui.h:53 -msgid "_Tiled" -msgstr "" - -#: ../data/ui/pybik.ui.h:54 -msgid "_View" -msgstr "П_реглед" - -#: ../data/scripts/10-spiegel.script.py:20 -#: ../data/scripts/10-spiegel.script.py:23 -#: ../data/scripts/10-spiegel.script.py:50 -#: ../data/scripts/10-spiegel.script.py:69 -#: ../data/scripts/10-spiegel.script.py:84 -#: ../data/scripts/10-spiegel.script.py:94 -#: ../data/scripts/10-spiegel.script.py:108 -#: ../data/scripts/10-spiegel.script.py:116 -#: ../data/scripts/11-spiegel-improved.script.py:20 -#: ../data/scripts/11-spiegel-improved.script.py:23 -#: ../data/scripts/11-spiegel-improved.script.py:67 -#: ../data/scripts/11-spiegel-improved.script.py:105 -#: ../data/scripts/11-spiegel-improved.script.py:137 -#: ../data/scripts/11-spiegel-improved.script.py:160 -#: ../data/scripts/11-spiegel-improved.script.py:175 -#: ../data/scripts/11-spiegel-improved.script.py:186 -#: ../data/scripts/15-mellor_solve.py:370 ../data/scripts/20-2x2x2.script.py:5 -#: ../data/scripts/20-2x2x2.script.py:8 ../data/scripts/20-2x2x2.script.py:27 -#: ../data/scripts/20-2x2x2.script.py:47 -msgid "Solvers" -msgstr "" - -#: ../data/scripts/10-spiegel.script.py:20 -#: ../data/scripts/10-spiegel.script.py:23 -#: ../data/scripts/10-spiegel.script.py:50 -#: ../data/scripts/10-spiegel.script.py:69 -#: ../data/scripts/10-spiegel.script.py:84 -#: ../data/scripts/10-spiegel.script.py:94 -#: ../data/scripts/10-spiegel.script.py:108 -#: ../data/scripts/10-spiegel.script.py:116 -msgid "Spiegel" -msgstr "" - -#: ../data/scripts/10-spiegel.script.py:23 -#: ../data/scripts/11-spiegel-improved.script.py:23 -#: ../data/scripts/15-mellor_solve.py:373 -msgid "Top edges" -msgstr "" - -#: ../data/scripts/10-spiegel.script.py:50 -#: ../data/scripts/11-spiegel-improved.script.py:67 -msgid "Top corners" -msgstr "" - -#: ../data/scripts/10-spiegel.script.py:69 -#: ../data/scripts/11-spiegel-improved.script.py:105 -#: ../data/scripts/15-mellor_solve.py:375 -msgid "Middle slice" -msgstr "" - -#: ../data/scripts/10-spiegel.script.py:84 -#: ../data/scripts/11-spiegel-improved.script.py:137 -#: ../data/scripts/15-mellor_solve.py:378 -msgid "Bottom edge place" -msgstr "" - -#: ../data/scripts/10-spiegel.script.py:94 -#: ../data/scripts/11-spiegel-improved.script.py:160 -#: ../data/scripts/15-mellor_solve.py:379 -msgid "Bottom edge orient" -msgstr "" - -#: ../data/scripts/10-spiegel.script.py:108 -#: ../data/scripts/11-spiegel-improved.script.py:175 -#: ../data/scripts/15-mellor_solve.py:376 -#: ../data/scripts/20-2x2x2.script.py:27 -msgid "Bottom corner place" -msgstr "" - -#: ../data/scripts/10-spiegel.script.py:116 -#: ../data/scripts/11-spiegel-improved.script.py:186 -#: ../data/scripts/15-mellor_solve.py:377 -#: ../data/scripts/20-2x2x2.script.py:47 -msgid "Bottom corner orient" -msgstr "" - -#: ../data/scripts/11-spiegel-improved.script.py:20 -#: ../data/scripts/11-spiegel-improved.script.py:23 -#: ../data/scripts/11-spiegel-improved.script.py:67 -#: ../data/scripts/11-spiegel-improved.script.py:105 -#: ../data/scripts/11-spiegel-improved.script.py:137 -#: ../data/scripts/11-spiegel-improved.script.py:160 -#: ../data/scripts/11-spiegel-improved.script.py:175 -#: ../data/scripts/11-spiegel-improved.script.py:186 -msgid "Spiegel improved" -msgstr "" - -#: ../data/scripts/15-mellor_solve.py:351 -msgid "This script only works on 3x3x3 cubes." -msgstr "" - -#. Translators: "Mellor" is the name of the original Author of the algorithm for this solution -#: ../data/scripts/15-mellor_solve.py:372 -msgid "Mellor (3x3)" -msgstr "" - -#: ../data/scripts/15-mellor_solve.py:374 ../data/scripts/20-2x2x2.script.py:8 -msgid "Top slice" -msgstr "" - -#: ../data/scripts/20-2x2x2.script.py:5 ../data/scripts/20-2x2x2.script.py:8 -#: ../data/scripts/20-2x2x2.script.py:27 ../data/scripts/20-2x2x2.script.py:47 -msgid "2×2×2" -msgstr "" - -#: ../data/scripts/80-pretty_patterns.py:42 -msgid "" -"This pretty pattern only works on cubes\n" -"with at least {count} slice." -msgid_plural "" -"This pretty pattern only works on cubes\n" -"with at least {count} slices." -msgstr[0] "" -msgstr[1] "" - -#: ../data/scripts/80-pretty_patterns.py:51 -msgid "Pretty patterns" -msgstr "" - -#: ../data/scripts/80-pretty_patterns.py:56 -msgid "Stripes" -msgstr "" - -#: ../data/scripts/80-pretty_patterns.py:57 -msgid "Criss-Cross" -msgstr "" - -#: ../data/scripts/80-pretty_patterns.py:58 -msgid "Fried Eggs" -msgstr "" - -#: ../data/scripts/80-pretty_patterns.py:59 -msgid "Fried Eggs v2" -msgstr "" - -#: ../data/scripts/80-pretty_patterns.py:60 -msgid "4 Fried Eggs" -msgstr "" - -#: ../data/scripts/80-pretty_patterns.py:61 -msgid "Chessboard odd" -msgstr "" - -#: ../data/scripts/80-pretty_patterns.py:62 -msgid "Chessboard even" -msgstr "" - -#: ../data/scripts/80-pretty_patterns.py:63 -msgid "Zig Zag" -msgstr "" - -#: ../data/scripts/80-pretty_patterns.py:64 -msgid "T-Time" -msgstr "" - -#: ../data/scripts/90-rand.py:39 -msgid "Randomize" -msgstr "" - -#: ../data/scripts/90-rand.py:42 -msgid "1 Move" -msgstr "" - -#: ../data/scripts/90-rand.py:43 -msgid "2 Moves" -msgstr "" - -#: ../data/scripts/90-rand.py:44 -msgid "3 Moves" -msgstr "" - -#: ../data/scripts/90-rand.py:45 -msgid "4 Moves" -msgstr "" - -#: ../data/scripts/90-rand.py:46 -msgid "5 Moves" -msgstr "" - -#: ../data/scripts/90-rand.py:47 -msgid "6 Moves" -msgstr "" - -#: ../data/scripts/90-rand.py:48 -msgid "7 Moves" -msgstr "" - -#: ../data/scripts/90-rand.py:49 -msgid "8 Moves" -msgstr "" - -#: ../data/scripts/90-rand.py:50 -msgid "50 Moves" -msgstr "" - -#: ../data/applications/pybik.desktop.in.h:2 -msgid "The magic cube" -msgstr "" - -#. Translators: Strings from file create_manpage.py are visible only in the man-page -#: ../tools/create_manpage.py:71 -msgid "NAME" -msgstr "" - -#: ../tools/create_manpage.py:74 -msgid "SYNOPSIS" -msgstr "" - -#: ../tools/create_manpage.py:76 -msgid "OPTIONS" -msgstr "" diff -Nru pybik-0.5/po/uk.po pybik-1.0.1/po/uk.po --- pybik-0.5/po/uk.po 1970-01-01 00:00:00.000000000 +0000 +++ pybik-1.0.1/po/uk.po 2013-02-01 20:18:02.000000000 +0000 @@ -0,0 +1,918 @@ +# Ukrainian translation for pybik +# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012 +# This file is distributed under the same license as the pybik package. +# +# FIRST AUTHOR , 2012. +# Yuri Chornoivan , 2012. +msgid "" +msgstr "" +"Project-Id-Version: pybik\n" +"Report-Msgid-Bugs-To: https://bugs.launchpad.net/pybik/+filebug\n" +"POT-Creation-Date: 2013-01-31 14:25+0100\n" +"PO-Revision-Date: 2012-12-15 08:39+0000\n" +"Last-Translator: Yuri Chornoivan \n" +"Language-Team: Ukrainian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && " +"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Launchpad-Export-Date: 2012-12-16 04:59+0000\n" +"X-Generator: Launchpad (build 16372)\n" +"Language: uk\n" + +#: ../pybiklib/application.py:304 +msgid "Press the Esc key to exit Edit Mode" +msgstr "Натисніть клавішу Esc, щоб вийти з режиму редагування" + +#. substitution for {move_text} in statusbar text +#: ../pybiklib/application.py:313 +msgid "{current} / {total} move" +msgid_plural "{current} / {total} moves" +msgstr[0] "{current} з {total} ходу" +msgstr[1] "{current} з {total} ходів" +msgstr[2] "{current} з {total} ходів" + +#. substitution for {solved_text} in statusbar text +#: ../pybiklib/application.py:317 ../pybiklib/ui/model.py:82 +msgid "solved" +msgstr "розв’язано" + +#: ../pybiklib/application.py:317 +msgid "not solved" +msgstr "не розв’язано" + +#. statusbar text +#: ../pybiklib/application.py:320 +msgid "{model_text}, {move_text}, {solved_text}" +msgstr "{model_text}, {move_text}, {solved_text}" + +#: ../pybiklib/application.py:353 +msgid "Congratulations, you have solved the puzzle!" +msgstr "Вітаємо, ви розв’язали головоломку!" + +#: ../pybiklib/config.py:30 ../pybiklib/ui/main.py:194 +#: ../data/applications/pybik.desktop.in.h:1 +msgid "Pybik" +msgstr "Pybik" + +#: ../pybiklib/config.py:59 ../data/applications/pybik.desktop.in.h:2 +msgid "3D Rubik's cube game" +msgstr "Тривимірний кубик Рубіка" + +#: ../pybiklib/config.py:61 +msgid "" +"Pybik is an interactive, graphical, single player puzzle about the cube " +"invented by Ernő Rubik. Besides the cube the program can handle towers and " +"bricks (non cubic puzzles). Pybik also has solvers, pretty patterns and a " +"collection of various moves. The cube can be manipulated with the mouse or " +"keyboard. You can change the colors or images on the faces of the cube." +msgstr "" +"Pybik — інтерактивна графічна головоломка для одного гравця, створена на " +"основі кубика винайденого Ерньо Рубіком. Окрім кубиків програма може " +"працювати з баштами та цеглинками (некубічними головоломками). У Pybik " +"передбачено інструменти розв’язування, створення візерунків та збірку " +"різноманітних ходів. Кубиком можна керувати за допомогою миші або " +"клавіатури. Передбачено можливість зміни кольорів або зображень на поверхнях " +"кубика." + +#: ../pybiklib/config.py:69 +msgid "" +"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.\n" +"\n" +"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." +msgstr "" +"Ця програма є вільним програмним забезпеченням. Ви можете поширювати і/або " +"змінювати її за умов дотримання GNU General Public License у тій формі, у " +"якій її оприлюднено Free Software Foundation; версії 3 цієї ліцензії або " +"(якщо бажаєте) будь-якої пізнішої її версії.\n" +"\n" +"Ця програм поширюється у сподіванні, що вона буде корисною, але її поширення " +"НЕ СУПРОВОДЖУЄТЬСЯ ЖОДНИМИ ГАРАНТІЯМИ навіть очевидними гарантіями " +"КОМЕРЦІЙНОЇ ЦІННОСТІ або ПРИДАТНОСТІ ДО ПЕВНОЇ МЕТИ. Докладніше про це можна " +"дізнатися з GNU General Public License." + +#: ../pybiklib/config.py:79 +msgid "" +"Read the full text of the GNU General Public " +"License<|> or see ." +msgstr "" +"Ознайомтеся з повним текстом Загальної громадської " +"ліцензії GNU<|> або відвідайте сторінку ." + +#: ../pybiklib/config.py:82 +msgid "" +"You should have received a copy of the GNU General Public License along with " +"this program. If not, see ." +msgstr "" +"Ви маєте отримати копію GNU General Public License разом з цією програмою. " +"Якщо цього не сталося, скористайтеся ." + +#: ../pybiklib/config.py:88 +msgid "" +"If you find any bugs in Pybik or have a suggestion for an improvement then " +"please submit a <{CONTACT_FILEBUG}|>bug report<|>. In the latter case you " +"can mark the bug report as \"Wishlist\"." +msgstr "" +"Якщо вами буде виявлено вади у Pybik або у вас виникнуть пропозиції щодо її " +"покращення, будь ласка, створіть відповідний <{CONTACT_FILEBUG}|>звіт щодо " +"вади<|>. У останньому випадку позначте звіт щодо вади міткою «Wishlist» " +"(«побажання»)." + +#: ../pybiklib/config.py:94 +msgid "" +"Translations are managed by the " +"Launchpad " +"translation group<|>.\n" +"\n" +"If you want help to translate Pybik to your language you can do it through " +"the web interface<|>.\n" +"\n" +"Read more about \"Translating with " +"Launchpad\"<|> and " +"\"Starting to " +"translate\"<|>." +msgstr "" +"Переклади виконуються групою перекладачів Launchpad<|>.\n" +"\n" +"Якщо ви хочете допомогти перекласти Pybik вашою мовою, скористайтеся " +"відповідним інтерфейсом<|>.\n" +"\n" +"Ознайомтеся з настановами щодо " +"перекладу за допомогою " +"Launchpad<|> та " +"початкових " +"кроків з перекладу<|>." + +#: ../pybiklib/dialogs.py:168 +msgid "Press a key …" +msgstr "Натисніть клавішу…" + +#: ../pybiklib/dialogs.py:296 +msgid "plain" +msgstr "площина" + +#: ../pybiklib/dialogs.py:301 +msgid "select …" +msgstr "вибрати…" + +#: ../pybiklib/dialogs.py:313 +msgid "Up" +msgstr "Вгору" + +#: ../pybiklib/dialogs.py:313 +msgid "Down" +msgstr "Вниз" + +#: ../pybiklib/dialogs.py:313 +msgid "Left" +msgstr "Ліворуч" + +#: ../pybiklib/dialogs.py:313 +msgid "Right" +msgstr "Праворуч" + +#: ../pybiklib/dialogs.py:313 +msgid "Front" +msgstr "Перед" + +#: ../pybiklib/dialogs.py:313 +msgid "Back" +msgstr "Зворот" + +#: ../pybiklib/dialogs.py:331 +msgid "Move" +msgstr "Хід" + +#: ../pybiklib/dialogs.py:332 +msgid "Key" +msgstr "Клавіша" + +#: ../pybiklib/dialogs.py:486 +msgid "Open Image" +msgstr "Відкрити зображення" + +#: ../pybiklib/dialogs.py:536 ../pybiklib/ui/model.py:79 +msgid "Size:" +msgstr "Розмір:" + +#: ../pybiklib/dialogs.py:536 +msgid "Basis:" +msgstr "Основа:" + +#: ../pybiklib/dialogs.py:536 +msgid "Width:" +msgstr "Ширина:" + +#: ../pybiklib/dialogs.py:565 +msgid "Canceling operation, please wait" +msgstr "Скасовуємо дію, зачекайте" + +#: ../pybiklib/dialogs.py:621 +msgid "Pybik project website" +msgstr "Сайт проекту Pybik" + +#: ../pybiklib/main.py:287 +msgid "" +"An error occurred while reading the settings:\n" +"{error_message}" +msgstr "" +"Під час спроби читання параметрів сталася помилка:\n" +"{error_message}" + +#: ../pybiklib/model.py:214 +msgid "Brick" +msgstr "Цеглинка" + +#: ../pybiklib/model.py:215 +msgid "{0}×{1}×{2}-Brick" +msgstr "Цеглинка-{0}×{1}×{2}" + +#: ../pybiklib/model.py:835 +msgid "Tower" +msgstr "Башта" + +#: ../pybiklib/model.py:836 +msgid "{0}×{1}-Tower" +msgstr "Башта-{0}×{1}" + +#: ../pybiklib/model.py:850 +msgid "Cube" +msgstr "Куб" + +#: ../pybiklib/model.py:851 +msgid "{0}×{0}×{0}-Cube" +msgstr "Куб-{0}×{0}×{0}" + +#: ../pybiklib/plugins.py:92 +msgid "This algorithm does not work for any model.\n" +msgstr "Цей алгоритм працює не для всіх моделей.\n" + +#: ../pybiklib/plugins.py:94 ../pybiklib/plugins.py:97 +msgid "This algorithm only works for:\n" +msgstr "Цей алгоритм працює лише для таких випадків:\n" + +#: ../pybiklib/settings.py:256 +msgid "Settings can not be written to file: {error_message}" +msgstr "Не вдалося записати параметри до файла: {error_message}" + +#: ../pybiklib/ui/about.py:131 +msgid "About Pybik" +msgstr "Про Pybik" + +#: ../pybiklib/ui/about.py:132 +msgid "About" +msgstr "Про програму" + +#: ../pybiklib/ui/about.py:133 +msgid "Feedback" +msgstr "Зворотній зв’язок" + +#: ../pybiklib/ui/about.py:134 +msgid "Translation" +msgstr "Переклад" + +#: ../pybiklib/ui/about.py:135 +msgid "License" +msgstr "Ліцензія" + +#: ../pybiklib/ui/main.py:195 +msgid "&Game" +msgstr "&Гра" + +#: ../pybiklib/ui/main.py:196 +msgid "&Edit" +msgstr "З&міни" + +#: ../pybiklib/ui/main.py:197 +msgid "&View" +msgstr "П&ерегляд" + +#: ../pybiklib/ui/main.py:198 +msgid "&Help" +msgstr "&Довідка" + +#: ../pybiklib/ui/main.py:199 +msgid "Pybik Toolbar" +msgstr "Панель інструментів Pybik" + +#: ../pybiklib/ui/main.py:200 +msgid "&New Random" +msgstr "&Новий випадковий" + +#: ../pybiklib/ui/main.py:201 +msgid "Ne&w Solved" +msgstr "Н&овий розв’язаний" + +#: ../pybiklib/ui/main.py:202 +msgid "&Quit" +msgstr "Ви&йти" + +#: ../pybiklib/ui/main.py:203 +msgid "&Select Model …" +msgstr "&Вибрати модель…" + +#: ../pybiklib/ui/main.py:204 +msgid "&Set as Initial State" +msgstr "З&робити початковим станом" + +#: ../pybiklib/ui/main.py:205 +msgid "&Reset Rotation" +msgstr "С&кинути обертання" + +#: ../pybiklib/ui/main.py:206 +msgid "&Invert Moves" +msgstr "&Інвертувати ходи" + +#: ../pybiklib/ui/main.py:207 +msgid "Reload Plugins" +msgstr "Перезавантажити додатки" + +#: ../pybiklib/ui/main.py:208 +msgid "&Preferences …" +msgstr "П&араметри…" + +#: ../pybiklib/ui/main.py:209 +msgid "&Toolbar" +msgstr "&Панель інструментів" + +#: ../pybiklib/ui/main.py:210 +msgid "&Status Bar" +msgstr "Смужка &стану" + +#: ../pybiklib/ui/main.py:211 +msgid "&Info …" +msgstr "Ін&формація…" + +#: ../pybiklib/ui/main.py:212 +msgid "Rewind" +msgstr "Повний назад" + +#: ../pybiklib/ui/main.py:213 +msgid "Go to the previous mark (or the beginning) of the sequence of moves" +msgstr "" +"Перейти до попередньої позначки (або до початку) послідовності обертань" + +#: ../pybiklib/ui/main.py:214 +msgid "Previous" +msgstr "Попередній" + +#: ../pybiklib/ui/main.py:215 +msgid "Make one step backwards" +msgstr "Повернутися на одне обертання назад" + +#: ../pybiklib/ui/main.py:216 +msgid "Stop" +msgstr "Зупинити" + +#: ../pybiklib/ui/main.py:217 +msgid "Stop running the sequence of moves" +msgstr "Припинити виконання послідовності обертань" + +#: ../pybiklib/ui/main.py:218 +msgid "Play" +msgstr "Пуск" + +#: ../pybiklib/ui/main.py:219 +msgid "Run forward through the sequence of moves" +msgstr "Запустити послідовність обертань" + +#: ../pybiklib/ui/main.py:220 +msgid "Next" +msgstr "Далі" + +#: ../pybiklib/ui/main.py:221 +msgid "Make one step forwards" +msgstr "Виконати наступне обертання" + +#: ../pybiklib/ui/main.py:222 +msgid "Forward" +msgstr "Вперед" + +#: ../pybiklib/ui/main.py:223 +msgid "Go to the next mark (or the end) of the sequence of moves" +msgstr "Перейти до наступної позначки (або кінця) послідовності ходів" + +#: ../pybiklib/ui/main.py:224 +msgid "Add Mark" +msgstr "Додати позначку" + +#: ../pybiklib/ui/main.py:225 +msgid "Mark the current place in the sequence of moves" +msgstr "Встановити позначку на поточній позиції у послідовності обертань" + +#: ../pybiklib/ui/main.py:226 +msgid "Remove Mark" +msgstr "Вилучити позначку" + +#: ../pybiklib/ui/main.py:227 +msgid "Remove the mark at the current place in the sequence of moves" +msgstr "Вилучити позначку з поточного місця у послідовності ходів" + +#: ../pybiklib/ui/main.py:228 +msgid "&Edit Bar" +msgstr "Панель &редагування" + +#: ../pybiklib/ui/main.py:229 +msgid "Normalize Cube Rotations" +msgstr "Нормалізувати обертання кубика" + +#: ../pybiklib/ui/model.py:78 +msgid "Select Model" +msgstr "Вибір моделі" + +#: ../pybiklib/ui/model.py:80 +msgid "Height:" +msgstr "Висота:" + +#: ../pybiklib/ui/model.py:81 +msgid "Depth:" +msgstr "Глибина:" + +#: ../pybiklib/ui/preferences.py:252 +msgid "Preferences" +msgstr "Параметри" + +#: ../pybiklib/ui/preferences.py:253 +msgid "Animation Speed:" +msgstr "Швидкість анімації:" + +#: ../pybiklib/ui/preferences.py:254 +msgid "Lighting" +msgstr "Підсвічування" + +#: ../pybiklib/ui/preferences.py:255 +msgid "Mirror Distance:" +msgstr "Відстань до дзеркала:" + +#: ../pybiklib/ui/preferences.py:256 +msgid "Antialiasing" +msgstr "Згладжування" + +#: ../pybiklib/ui/preferences.py:257 +msgid "Hardware:" +msgstr "Обладнання:" + +#: ../pybiklib/ui/preferences.py:258 +msgid "Software:" +msgstr "Програмне забезпечення:" + +#: ../pybiklib/ui/preferences.py:259 +msgid "" +"

The program needs to " +"be restarted for the changes to take effect.

" +msgstr "" +"

Щоб внесені зміни " +"набули чинності, програму слід перезапустити.

" + +#: ../pybiklib/ui/preferences.py:260 +msgid "Graphic" +msgstr "Графіка" + +#: ../pybiklib/ui/preferences.py:261 +msgid "Four directions" +msgstr "Чотири напрямки" + +#: ../pybiklib/ui/preferences.py:262 +msgid "" +"Simplified,\n" +"right button inverts move" +msgstr "" +"Спрощена,\n" +"права кнопка скасовує хід" + +#: ../pybiklib/ui/preferences.py:263 +msgid "Mouse" +msgstr "Миша" + +#: ../pybiklib/ui/preferences.py:264 ../pybiklib/ui/preferences.py:265 +msgid "Add" +msgstr "Додати" + +#: ../pybiklib/ui/preferences.py:266 ../pybiklib/ui/preferences.py:267 +msgid "Remove" +msgstr "Вилучити" + +#: ../pybiklib/ui/preferences.py:268 ../pybiklib/ui/preferences.py:269 +msgid "Reset" +msgstr "Скинути" + +#: ../pybiklib/ui/preferences.py:270 +msgid "Keys" +msgstr "Клавіші" + +#: ../pybiklib/ui/preferences.py:271 +msgid "Color:" +msgstr "Колір:" + +#: ../pybiklib/ui/preferences.py:272 +msgid "Image File:" +msgstr "Файл зображення:" + +#: ../pybiklib/ui/preferences.py:273 +msgid "Tiled" +msgstr "Плиткою" + +#: ../pybiklib/ui/preferences.py:274 +msgid "Mosaic" +msgstr "Мозаїка" + +#: ../pybiklib/ui/preferences.py:275 +msgid "Background:" +msgstr "Тло:" + +#: ../pybiklib/ui/preferences.py:276 +msgid "Appearance" +msgstr "Вигляд" + +#. Add whatever keywords you want in your language, separated by semicolons. These keywords are used when searching for applications in dashes, etc. (Unity, GNOME Shell) +#: ../data/applications/pybik.desktop.in.h:4 +msgid "rubik;cube;puzzle;magic;" +msgstr "" + +#: ../data/plugins/01-challenges.algorithm.py:19 +#: ../data/plugins/01-challenges.algorithm.py:22 +#: ../data/plugins/01-challenges.algorithm.py:25 +#: ../data/plugins/01-challenges.algorithm.py:28 +#: ../data/plugins/01-challenges.algorithm.py:31 +#: ../data/plugins/01-challenges.algorithm.py:34 +#: ../data/plugins/01-challenges.algorithm.py:37 +#: ../data/plugins/01-challenges.algorithm.py:40 +#: ../data/plugins/01-challenges.algorithm.py:43 +#: ../data/plugins/01-challenges.algorithm.py:46 +#: ../data/plugins/01-challenges.algorithm.py:49 +msgid "Challenges" +msgstr "Виклики" + +#: ../data/plugins/01-challenges.algorithm.py:20 +msgid "Solve random cube" +msgstr "Розв’язати випадковий куб" + +#: ../data/plugins/01-challenges.algorithm.py:23 +msgid "Solve in 1 move" +msgstr "Розв’язати за 1 хід" + +#: ../data/plugins/01-challenges.algorithm.py:26 +msgid "Solve in 2 moves" +msgstr "Розв’язати за 2 ходи" + +#: ../data/plugins/01-challenges.algorithm.py:29 +msgid "Solve in 3 moves" +msgstr "Розв’язати за 3 ходи" + +#: ../data/plugins/01-challenges.algorithm.py:32 +msgid "Solve in 4 moves" +msgstr "Розв’язати за 4 ходи" + +#: ../data/plugins/01-challenges.algorithm.py:35 +msgid "Solve in 5 moves" +msgstr "Розв’язати за 5 ходів" + +#: ../data/plugins/01-challenges.algorithm.py:38 +msgid "Solve in 6 moves" +msgstr "Розв’язати за 6 ходів" + +#: ../data/plugins/01-challenges.algorithm.py:41 +msgid "Solve in 7 moves" +msgstr "Розв’язати за 7 ходів" + +#: ../data/plugins/01-challenges.algorithm.py:44 +msgid "Solve in 8 moves" +msgstr "Розв’язати за 8 ходів" + +#: ../data/plugins/01-challenges.algorithm.py:47 +msgid "Solve in 9 moves" +msgstr "Розв’язати за 9 ходів" + +#: ../data/plugins/01-challenges.algorithm.py:50 +msgid "Solve in 10 moves" +msgstr "Розв’язати за 10 ходів" + +#: ../data/plugins/10-spiegel.algorithm.py:35 +#: ../data/plugins/10-spiegel.algorithm.py:38 +#: ../data/plugins/10-spiegel.algorithm.py:67 +#: ../data/plugins/10-spiegel.algorithm.py:88 +#: ../data/plugins/10-spiegel.algorithm.py:103 +#: ../data/plugins/10-spiegel.algorithm.py:116 +#: ../data/plugins/10-spiegel.algorithm.py:133 +#: ../data/plugins/10-spiegel.algorithm.py:144 +#: ../data/plugins/11-spiegel-improved.algorithm.py:35 +#: ../data/plugins/11-spiegel-improved.algorithm.py:38 +#: ../data/plugins/11-spiegel-improved.algorithm.py:83 +#: ../data/plugins/11-spiegel-improved.algorithm.py:122 +#: ../data/plugins/11-spiegel-improved.algorithm.py:154 +#: ../data/plugins/11-spiegel-improved.algorithm.py:180 +#: ../data/plugins/11-spiegel-improved.algorithm.py:198 +#: ../data/plugins/11-spiegel-improved.algorithm.py:212 +#: ../data/plugins/12-lbl-leyan.algorithm.py:22 +#: ../data/plugins/12-lbl-leyan.algorithm.py:25 +#: ../data/plugins/12-lbl-leyan.algorithm.py:54 +#: ../data/plugins/12-lbl-leyan.algorithm.py:75 +#: ../data/plugins/12-lbl-leyan.algorithm.py:91 +#: ../data/plugins/12-lbl-leyan.algorithm.py:108 +#: ../data/plugins/12-lbl-leyan.algorithm.py:130 +#: ../data/plugins/12-lbl-leyan.algorithm.py:171 +#: ../data/plugins/20-2x2x2.algorithm.py:19 +#: ../data/plugins/20-2x2x2.algorithm.py:22 +#: ../data/plugins/20-2x2x2.algorithm.py:41 +#: ../data/plugins/20-2x2x2.algorithm.py:61 +msgid "Solvers" +msgstr "Розв’язувачі" + +#. Spiegel is the name of a solution method +#: ../data/plugins/10-spiegel.algorithm.py:37 +#: ../data/plugins/10-spiegel.algorithm.py:39 +#: ../data/plugins/10-spiegel.algorithm.py:68 +#: ../data/plugins/10-spiegel.algorithm.py:89 +#: ../data/plugins/10-spiegel.algorithm.py:104 +#: ../data/plugins/10-spiegel.algorithm.py:117 +#: ../data/plugins/10-spiegel.algorithm.py:134 +#: ../data/plugins/10-spiegel.algorithm.py:145 +msgid "Spiegel" +msgstr "Метод Шпігеля" + +#: ../data/plugins/10-spiegel.algorithm.py:40 +#: ../data/plugins/11-spiegel-improved.algorithm.py:40 +#: ../data/plugins/12-lbl-leyan.algorithm.py:27 +msgid "Top edges" +msgstr "Верхні краї" + +#: ../data/plugins/10-spiegel.algorithm.py:69 +#: ../data/plugins/11-spiegel-improved.algorithm.py:85 +#: ../data/plugins/12-lbl-leyan.algorithm.py:56 +msgid "Top corners" +msgstr "Верхні кути" + +#: ../data/plugins/10-spiegel.algorithm.py:90 +#: ../data/plugins/11-spiegel-improved.algorithm.py:124 +#: ../data/plugins/12-lbl-leyan.algorithm.py:77 +msgid "Middle slice" +msgstr "Середній шар" + +#: ../data/plugins/10-spiegel.algorithm.py:105 +#: ../data/plugins/11-spiegel-improved.algorithm.py:156 +#: ../data/plugins/12-lbl-leyan.algorithm.py:173 +msgid "Bottom edge place" +msgstr "Місце нижнього краю" + +#: ../data/plugins/10-spiegel.algorithm.py:118 +#: ../data/plugins/11-spiegel-improved.algorithm.py:182 +#: ../data/plugins/12-lbl-leyan.algorithm.py:93 +msgid "Bottom edge orient" +msgstr "Орієнтація нижнього краю" + +#: ../data/plugins/10-spiegel.algorithm.py:135 +#: ../data/plugins/11-spiegel-improved.algorithm.py:200 +#: ../data/plugins/12-lbl-leyan.algorithm.py:110 +#: ../data/plugins/20-2x2x2.algorithm.py:43 +msgid "Bottom corner place" +msgstr "Місце нижнього кута" + +#: ../data/plugins/10-spiegel.algorithm.py:146 +#: ../data/plugins/11-spiegel-improved.algorithm.py:214 +#: ../data/plugins/12-lbl-leyan.algorithm.py:132 +#: ../data/plugins/20-2x2x2.algorithm.py:63 +msgid "Bottom corner orient" +msgstr "Орієнтація нижнього кута" + +#. Spiegel is the name of a solution method +#: ../data/plugins/11-spiegel-improved.algorithm.py:37 +#: ../data/plugins/11-spiegel-improved.algorithm.py:39 +#: ../data/plugins/11-spiegel-improved.algorithm.py:84 +#: ../data/plugins/11-spiegel-improved.algorithm.py:123 +#: ../data/plugins/11-spiegel-improved.algorithm.py:155 +#: ../data/plugins/11-spiegel-improved.algorithm.py:181 +#: ../data/plugins/11-spiegel-improved.algorithm.py:199 +#: ../data/plugins/11-spiegel-improved.algorithm.py:213 +msgid "Spiegel improved" +msgstr "Покращений метод Шпігеля" + +#. Leyan Lo is the inventor of the solution method +#: ../data/plugins/12-lbl-leyan.algorithm.py:24 +#: ../data/plugins/12-lbl-leyan.algorithm.py:26 +#: ../data/plugins/12-lbl-leyan.algorithm.py:55 +#: ../data/plugins/12-lbl-leyan.algorithm.py:76 +#: ../data/plugins/12-lbl-leyan.algorithm.py:92 +#: ../data/plugins/12-lbl-leyan.algorithm.py:109 +#: ../data/plugins/12-lbl-leyan.algorithm.py:131 +#: ../data/plugins/12-lbl-leyan.algorithm.py:172 +msgid "Layer Method (Leyan Lo)" +msgstr "Метод шарів (Леян Ло)" + +#: ../data/plugins/20-2x2x2.algorithm.py:20 +#: ../data/plugins/20-2x2x2.algorithm.py:23 +#: ../data/plugins/20-2x2x2.algorithm.py:42 +#: ../data/plugins/20-2x2x2.algorithm.py:62 +msgid "2×2×2" +msgstr "2×2×2" + +#: ../data/plugins/20-2x2x2.algorithm.py:24 +msgid "Top slice" +msgstr "Верхній шар" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:18 +#: ../data/plugins/80-pretty-patterns.algorithm.py:22 +#: ../data/plugins/80-pretty-patterns.algorithm.py:26 +#: ../data/plugins/80-pretty-patterns.algorithm.py:30 +#: ../data/plugins/80-pretty-patterns.algorithm.py:34 +#: ../data/plugins/80-pretty-patterns.algorithm.py:39 +#: ../data/plugins/80-pretty-patterns.algorithm.py:43 +#: ../data/plugins/80-pretty-patterns.algorithm.py:48 +#: ../data/plugins/80-pretty-patterns.algorithm.py:52 +#: ../data/plugins/80-pretty-patterns.algorithm.py:56 +#: ../data/plugins/80-pretty-patterns.algorithm.py:60 +#: ../data/plugins/80-pretty-patterns.algorithm.py:64 +#: ../data/plugins/80-pretty-patterns.algorithm.py:68 +#: ../data/plugins/80-pretty-patterns.algorithm.py:74 +#: ../data/plugins/80-pretty-patterns.algorithm.py:78 +#: ../data/plugins/80-pretty-patterns.algorithm.py:83 +#: ../data/plugins/80-pretty-patterns.algorithm.py:87 +#: ../data/plugins/80-pretty-patterns.algorithm.py:91 +#: ../data/plugins/80-pretty-patterns.algorithm.py:95 +#: ../data/plugins/80-pretty-patterns.algorithm.py:99 +#: ../data/plugins/80-pretty-patterns.algorithm.py:103 +#: ../data/plugins/80-pretty-patterns.algorithm.py:108 +#: ../data/plugins/80-pretty-patterns.algorithm.py:112 +#: ../data/plugins/80-pretty-patterns.algorithm.py:116 +#: ../data/plugins/80-pretty-patterns.algorithm.py:120 +#: ../data/plugins/80-pretty-patterns.algorithm.py:124 +#: ../data/plugins/80-pretty-patterns.algorithm.py:128 +#: ../data/plugins/80-pretty-patterns.algorithm.py:132 +#: ../data/plugins/80-pretty-patterns.algorithm.py:136 +#: ../data/plugins/80-pretty-patterns.algorithm.py:140 +msgid "Pretty patterns" +msgstr "Чудові візерунки" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:19 +#: ../data/plugins/80-pretty-patterns.algorithm.py:23 +#: ../data/plugins/80-pretty-patterns.algorithm.py:27 +#: ../data/plugins/80-pretty-patterns.algorithm.py:31 +#: ../data/plugins/80-pretty-patterns.algorithm.py:35 +#: ../data/plugins/80-pretty-patterns.algorithm.py:40 +#: ../data/plugins/80-pretty-patterns.algorithm.py:44 +msgid "Stripes" +msgstr "Смуги" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:49 +#: ../data/plugins/80-pretty-patterns.algorithm.py:53 +msgid "Criss-Cross" +msgstr "Хрест-навхрест" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:57 +msgid "Fried Eggs" +msgstr "Яєшня" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:61 +msgid "Big Fried Eggs" +msgstr "Велика оката яєшня" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:65 +msgid "4 Fried Eggs" +msgstr "4 очка у яєшні" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:69 +msgid "Chessboard" +msgstr "Шахова дошка" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:75 +msgid "Cross" +msgstr "Хрестик" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:79 +msgid "Zig Zag" +msgstr "Зиґзаґ" + +#. T is the shape formed by the cube labels +#: ../data/plugins/80-pretty-patterns.algorithm.py:85 +#: ../data/plugins/80-pretty-patterns.algorithm.py:88 +#: ../data/plugins/80-pretty-patterns.algorithm.py:92 +#: ../data/plugins/80-pretty-patterns.algorithm.py:96 +#: ../data/plugins/80-pretty-patterns.algorithm.py:100 +#: ../data/plugins/80-pretty-patterns.algorithm.py:104 +msgid "T-Time" +msgstr "Час-T" + +#. C is the shape formed by the cube labels +#: ../data/plugins/80-pretty-patterns.algorithm.py:110 +msgid "C" +msgstr "C" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:113 +msgid "Cube in a Cube" +msgstr "Куб у кубі" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:117 +msgid "Striped Cube in a Cube" +msgstr "Смуговий куб у кубі" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:121 +msgid "Six Square Cuboids" +msgstr "Шість квадратних кубоїдів" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:125 +msgid "Superflip" +msgstr "Супервіддзеркалення" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:129 +msgid "Superflip easy" +msgstr "Просте супервіддзеркалення" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:133 +msgid "Green Mamba" +msgstr "Зелена мамба" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:137 +msgid "Anaconda" +msgstr "Анаконда" + +#: ../data/plugins/80-pretty-patterns.algorithm.py:141 +msgid "Duck Feet" +msgstr "Качина лапа" + +#: ../data/plugins/90-library.algorithm.py:20 +#: ../data/plugins/90-library.algorithm.py:23 +#: ../data/plugins/90-library.algorithm.py:26 +#: ../data/plugins/90-library.algorithm.py:29 +#: ../data/plugins/90-library.algorithm.py:32 +#: ../data/plugins/90-library.algorithm.py:35 +#: ../data/plugins/90-library.algorithm.py:38 +#: ../data/plugins/90-library.algorithm.py:41 +#: ../data/plugins/90-library.algorithm.py:44 +#: ../data/plugins/90-library.algorithm.py:47 +#: ../data/plugins/90-library.algorithm.py:50 +msgid "Library" +msgstr "Бібліотека" + +#: ../data/plugins/90-library.algorithm.py:21 +#: ../data/plugins/90-library.algorithm.py:24 +msgid "Middle Layer" +msgstr "Середній шар" + +#: ../data/plugins/90-library.algorithm.py:22 +msgid "Front to Right" +msgstr "Перед праворуч" + +#: ../data/plugins/90-library.algorithm.py:25 +msgid "Front to Left" +msgstr "Перед ліворуч" + +#: ../data/plugins/90-library.algorithm.py:27 +#: ../data/plugins/90-library.algorithm.py:30 +#: ../data/plugins/90-library.algorithm.py:33 +#: ../data/plugins/90-library.algorithm.py:36 +msgid "Last Layer" +msgstr "Останній шар" + +#: ../data/plugins/90-library.algorithm.py:28 +msgid "Swap Edges" +msgstr "Поміняти місцями краї" + +#: ../data/plugins/90-library.algorithm.py:31 +msgid "Flip Edges" +msgstr "Перевернути краї" + +#: ../data/plugins/90-library.algorithm.py:34 +msgid "Swap Corners" +msgstr "Поміняти місцями кути" + +#: ../data/plugins/90-library.algorithm.py:37 +msgid "Rotate Corners" +msgstr "Обертати кути" + +#: ../data/plugins/90-library.algorithm.py:39 +#: ../data/plugins/90-library.algorithm.py:42 +#: ../data/plugins/90-library.algorithm.py:45 +msgid "Rotate Center" +msgstr "Обертати центр" + +#: ../data/plugins/90-library.algorithm.py:40 +msgid "2×Up" +msgstr "Подвійний вгору" + +#: ../data/plugins/90-library.algorithm.py:43 +msgid "Up and Front" +msgstr "Згори і спереду" + +#: ../data/plugins/90-library.algorithm.py:46 +msgid "Up and Down" +msgstr "Згори і знизу" + +#: ../data/plugins/90-library.algorithm.py:48 +#: ../data/plugins/90-library.algorithm.py:51 +msgid "Misc" +msgstr "Інше" + +#: ../data/plugins/90-library.algorithm.py:49 +msgid "Back without Back" +msgstr "Назад без повертання" + +#: ../data/plugins/90-library.algorithm.py:52 +msgid "2×Back without Back" +msgstr "Подвійний назад без повертання" diff -Nru pybik-0.5/pybik pybik-1.0.1/pybik --- pybik-0.5/pybik 2011-12-25 15:43:56.000000000 +0000 +++ pybik-1.0.1/pybik 1970-01-01 00:00:00.000000000 +0000 @@ -1,60 +0,0 @@ -#!/usr/bin/python -#-*- coding:utf-8 -*- - -# Pybik -- A 3 dimensional magic cube game. -# Copyright © 2009, 2011 B. Clausius -# -# 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 . - - -import sys, os -import gettext - -import pygtk -pygtk.require('2.0') - -lib_dir = os.path.dirname(os.path.realpath(__file__)) -src_dir, sub_dir = os.path.split(lib_dir) -root_dir = os.path.dirname(os.path.realpath(os.path.dirname(__file__))) - -if sub_dir == 'pybiklib': - sys.path[0] = src_dir - print 'Running from source directory' - -try: - from pybiklib import config -except ImportError: - print 'Pybik is not properly installed.' - sys.exit(1) - -if sub_dir == 'pybiklib': - # running from source - LOCALEDIR = os.path.join(src_dir, 'build', 'mo') -elif root_dir == sys.prefix: - # normal installation - LOCALEDIR = None -else: - # different root, e.g. /usr/local - LOCALEDIR = config.LOCALE_DIR -gettext.install(config.PACKAGE, LOCALEDIR, names=['ngettext']) - -import pybiklib.main - - -def main(): - pybiklib.main.run() - -if __name__ == '__main__': - main() - diff -Nru pybik-0.5/pybiklib/application.py pybik-1.0.1/pybiklib/application.py --- pybik-0.5/pybiklib/application.py 2012-01-05 19:39:20.000000000 +0000 +++ pybik-1.0.1/pybiklib/application.py 2012-12-12 05:47:55.000000000 +0000 @@ -16,474 +16,722 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . - # Ported from GNUbik # Original filename: widget-set.c # Original copyright and license: 2003, 2004 John Darrington, GPL3+ +from __future__ import print_function, division, unicode_literals -import os +from collections import OrderedDict -import gobject -import gtk -from gtk import gdk +# pylint: disable=W0614,W0401 +from PySide.QtCore import * +from PySide.QtGui import * from .debug import * +# pylint: enable=W0614,W0401 from . import config from . import dialogs -from . import dialogcolors from . import plugins -import state - -from . import glarea -from .confstore import confstore - +from .model import models +from . import gamestate +from . import drawingarea +from .settings import settings +from .ui.main import Ui_MainWindow -class Application (object): +try: + _, ngettext +except NameError: + debug('gettext not found') + _ = lambda string: string + ngettext = lambda singular, plural, cnt: singular if cnt == 1 else plural + + +class AnimType (object): # pylint: disable=R0903 + NONE, FWD, BWD, KEY, NEW = range(5) + + +class ElideLabel (QLabel): + def paintEvent(self, unused_event): + p = QPainter(self) + fm = QFontMetrics(self.font()) + rect = self.contentsRect() + if fm.width(self.text()) > rect.width(): + gradient = QLinearGradient(rect.topLeft(), rect.topRight()) + start = (rect.width() - 2*rect.height()) / rect.width() + gradient.setColorAt(start, self.palette().color(QPalette.WindowText)) + gradient.setColorAt(1.0, self.palette().color(QPalette.Window)) + pen = QPen() + pen.setBrush(QBrush(gradient)) + p.setPen(pen) + p.drawText(self.rect(), Qt.TextSingleLine, self.text()) + + +class MainWindow (QMainWindow): + + ### init ### + def __init__(self): - # create cube state - self.solved = False - self.current_movement = state.CurrentMovement() - - # - confstore.init_notify() - self.plugin_helper = plugins.PluginHelper(self) + QMainWindow.__init__(self) # UI - ui_file = os.path.join(config.UI_DIR, 'pybik.ui') - self.ui_xml = gtk.Builder() - self.ui_xml.props.translation_domain = config.PACKAGE - self.ui_xml.add_from_file(ui_file) - debug('Connect signals:', ui_file) - missing = self.ui_xml.connect_signals(self) - if missing: - debug(' ', len(missing), 'missing handlers:') - for m in missing: - debug(' def', m+'(self, unused_widget, *unused_args):') - debug(' pass') - else: - debug(' no missing handlers') - - self.window = self.ui_xml.get_object('window_main') - self.statusbar = self.ui_xml.get_object('statusbar_main') - self.entry_formula = self.ui_xml.get_object('entry_formula') - self.treeview = self.ui_xml.get_object('treeview_scripts') - self.selected_tree_path = None + self.ui = Ui_MainWindow() + self.ui.setupUi(self) + self.ui.splitter.setCollapsible(0, False) + self.ui.splitter.setStretchFactor(0, 1) + self.ui.splitter.setStretchFactor(1, 0) + + # set icons + self.setWindowIcon(QIcon(config.IMAGE_FILE)) + self.ui.button_edit_exec.setIcon(QIcon.fromTheme('system-run')) + self.ui.button_edit_clear.setIcon(QIcon.fromTheme('edit-clear')) + self.ui.action_new.setIcon(QIcon.fromTheme('document-new')) + self.ui.action_new_solved.setIcon(QIcon.fromTheme('document-new')) + #self.ui.action_selectmodel.setIcon(QIcon.fromTheme('document-properties')) + self.ui.action_quit.setIcon(QIcon.fromTheme('application-exit')) + self.ui.action_rewind.setIcon(QIcon.fromTheme('media-seek-backward')) + self.ui.action_previous.setIcon(QIcon.fromTheme('media-skip-backward')) + self.ui.action_stop.setIcon(QIcon.fromTheme('media-playback-stop')) + self.ui.action_play.setIcon(QIcon.fromTheme('media-playback-start')) + self.ui.action_next.setIcon(QIcon.fromTheme('media-skip-forward')) + self.ui.action_forward.setIcon(QIcon.fromTheme('media-seek-forward')) + self.ui.action_add_mark.setIcon(QIcon.fromTheme('list-add')) + self.ui.action_remove_mark.setIcon(QIcon.fromTheme('list-remove')) + self.ui.action_preferences.setIcon(QIcon.fromTheme('document-properties')) + self.ui.action_info.setIcon(QIcon.fromTheme('help-about')) + self.ui.action_selectmodel.setShortcut(QKeySequence(settings.action.selectmodel)) + self.ui.action_initial_state.setShortcut(QKeySequence(settings.action.initial_state)) + self.ui.action_reset_rotation.setShortcut(QKeySequence(settings.action.reset_rotation)) + self.ui.action_invert_moves.setShortcut(QKeySequence(settings.action.invert_moves)) + self.ui.action_reload_scripts.setShortcut(QKeySequence(settings.action.reload_scripts)) + self.ui.action_preferences.setShortcut(QKeySequence(settings.action.preferences)) + self.ui.action_normalize_complete_rotations.setShortcut( + QKeySequence(settings.action.normalize_complete_rotations)) + + # widgets that are not created with Qt Designer + self.playbarstate = self.create_toolbar() + self.cube_area = self.create_cube_area() + self.cube_area.drop_color.connect(self.on_cubearea_drop_color) + self.cube_area.drop_file.connect(self.on_cubearea_drop_file) + self.setTabOrder(self.ui.edit_moves, self.cube_area) + self.setTabOrder(self.cube_area, self.ui.box_sidepane) + self.cube_area.setFocus(Qt.OtherFocusReason) + # actions that belongs to no widget + self.action_jump_to_editbar = QAction(self) + self.action_jump_to_editbar.setShortcut(QKeySequence(settings.action.edit_moves)) + self.action_jump_to_editbar.triggered.connect(self.on_action_jump_to_editbar_triggered) + self.addAction(self.action_jump_to_editbar) + self.action_edit_model = QAction(self) + self.action_edit_model.setShortcut(QKeySequence(settings.action.edit_model)) + self.action_edit_model.triggered.connect(self.on_action_edit_model_triggered) + self.addAction(self.action_edit_model) + self.status_text = ElideLabel() + p = self.status_text.sizePolicy() + p.setHorizontalStretch(1) + p.setHorizontalPolicy(QSizePolicy.Ignored) + self.status_text.setSizePolicy(p) + self.ui.statusbar.addWidget(self.status_text) + # created when needed + self.progress_dialog = None - self.window.set_icon_from_file(config.IMAGE_FILE) - self.window.connect("delete-event", self.on_window_delete_event) + # plugins + self.treestore = QStandardItemModel() + self.selected_tree_path = None + self.active_script_group = 0 + self.plugin_helper = plugins.PluginHelper() + self.add_scripts_to_sidepane(False) + QTimer.singleShot(0, self.add_scripts_to_sidepane) + + self.unsolved = False + self.animtype = AnimType.NONE + + # Load window state from settings + self.ui.action_toolbar.setChecked(settings.window.toolbar) + self.ui.action_editbar.setChecked(settings.window.editbar) + self.ui.action_statusbar.setChecked(settings.window.statusbar) + self.ui.toolbar.setVisible(settings.window.toolbar) + self.ui.frame_editbar.setVisible(settings.window.editbar) + self.ui.statusbar.setVisible(settings.window.statusbar) + self.move_keys = self.get_move_key_dict() + + settings.keystore.changed.connect(self.on_settings_changed, Qt.QueuedConnection) + settings.keystore.error.connect(self.on_settings_error) + + # Reload last game + self.gamestate = gamestate.GameState() + QTimer.singleShot(0, self.load_game) + self.update_ui() - self.create_menu() - self.create_sidepane() + self.resize(*settings.window.size) + divider_position = settings.window.divider + self.show() + sizes = self.ui.splitter.sizes() + self.ui.splitter.setSizes([divider_position, sum(sizes)-divider_position]) + + def create_cube_area(self): + cube_area = drawingarea.CubeArea() + sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + cube_area.setSizePolicy(sizePolicy) + self.ui.verticalLayout.addWidget(cube_area) + cube_area.end_animation.connect(self.on_cubearea_end_animation) + cube_area.request_rotation.connect(self.on_cubearea_request_rotation) + cube_area.request_swap_blocks.connect(self.on_cubearea_request_swap_blocks) + cube_area.request_rotate_block.connect(self.on_cubearea_request_rotate_block) + glformat = cube_area.format() + dialogs.PreferencesDialog.accum_buffers = glformat.accum() + dialogs.PreferencesDialog.sample_buffers = max(glformat.samples(), 1) + return cube_area + + def create_toolbar(self): + play_actions = [self.ui.action_rewind, self.ui.action_previous, + self.ui.action_stop, self.ui.action_play, self.ui.action_next, + self.ui.action_forward, self.ui.action_add_mark, self.ui.action_remove_mark] + for action in play_actions: + self.ui.toolbar.addAction(action) + playbarstate = PlaybarState(play_actions) + return playbarstate - self.cube_area = glarea.CubeArea() - drawingarea_cube = self.ui_xml.get_object('drawingarea_cube') - self.cube_area.init(drawingarea_cube) - self.cube_area.connect('texture-changed', self.on_cubearea_texture_changed) - self.cube_area.connect('end-animation', self.on_cubearea_end_animation) - self.cube_area.connect('request-rotation', self.on_cubearea_request_rotation) - - if not os.path.exists(config.get_data_home()): - os.mkdir(config.get_data_home()) - accel_map_file = os.path.join(config.get_data_home(), 'accels') - gtk.accel_map_load(accel_map_file) - gtk.accel_map_get().connect('changed', self.on_accel_map_changed, accel_map_file) - - def on_accel_map_changed(self, unused_map, unused_path, unused_key, unused_mods, filename): - gtk.accel_map_save(filename) - - def on_cubearea_texture_changed(self, unused_widget): - if dialogcolors.ColorSelectDialog.this_dlg: - dialogcolors.ColorSelectDialog.this_dlg.redraw_swatches() - def on_cubearea_end_animation(self, unused_cubearea, last_move): - self.cube_area.apply_to_glmodel(self.current_movement.current_cube_state) - self.cube_area.update_selection() + ### helper functions ### + + @staticmethod + def keyval_from_name(keystr): + key = QKeySequence(keystr) + if key.count() == 0: + return 0 + key = key[0] + if 'KP' in keystr.split('+'): + key |= int(Qt.KeypadModifier) + return key + + def get_move_key_dict(self): + return {self.keyval_from_name(key): move for (move, key) in settings.draw.accels} + + def add_scripts_to_sidepane(self, load=True): + self.ui.treeview.setModel(None) + self.treestore.clear() + for widget in self.ui.box_sidepane.children(): + if isinstance(widget, QPushButton): + self.ui.layout_sidepane.removeWidget(widget) + widget.deleteLater() + if load: + algorithms = self.plugin_helper.load_plugins() + if self.plugin_helper.error_messages: + self.error_dialog('\n\n'.join(self.plugin_helper.error_messages)) + else: + algorithms = [] + ptree = OrderedDict() + for plugin_path, func in algorithms: + subtree = [None, ptree] + for name in plugin_path: + subtree = subtree[1].setdefault(name, [None, OrderedDict()]) + if plugin_path: + subtree[0] = func + def fill_treeview(parent, tree): + for name, [func, subtree] in tree.items(): + item = QStandardItem(_(name)) + item.setData(func) + parent.appendRow(item) + fill_treeview(item, subtree) + for i, (name, [func, subtree]) in enumerate(ptree.items()): + button = QPushButton(self.ui.box_sidepane) + button.setText(_(name)) + button.setFlat(True) + button.setFocusPolicy(Qt.TabFocus) + self.ui.layout_sidepane.addWidget(button) + obsc = lambda i: lambda: self.on_button_sidepane_clicked(i) + button.clicked.connect(obsc(i)) + fill_treeview(self.treestore, ptree) + self.set_active_script_group(self.active_script_group) + + def set_active_script_group(self, i): + self.ui.layout_sidepane.insertWidget(i+1, self.ui.treeview) + self.ui.treeview.setModel(self.treestore) + index = self.treestore.index(i, 0) + self.ui.treeview.setRootIndex(index) + self.active_script_group = i + + def load_game(self): + mtype, size, blocks = settings.game.type, settings.game.size, settings.game.blocks + Model = models[mtype] + mirror_distance = settings.draw.mirror_distance if settings.draw.mirror_faces else None + model = Model(size, mirror_distance) + self.gamestate.set_state(model, blocks, settings.game.moves, settings.game.position) + self.cube_area.set_model(model) + self.cube_area.apply_to_glmodel(self.gamestate.current_cube_state) + self.cube_area.update() + self.update_ui() - if not last_move: - # go again - self.update_statusbar() - move_data = self.current_movement.request_play() - if not self.start_animation(move_data, stop_after=False): - self.update_ui() + def new_game(self, mtype=None, size=None, solved=False): + if self.is_animating(): + return + if mtype is None: + model = self.gamestate.current_cube_state.model + if size is None: + size = model.sizes + Model = model.__class__ else: - self.update_ui() - def on_cubearea_request_rotation(self, unused_cubearea, maxis, mslice, mdir): - self.current_movement.request_rotation(maxis, mslice, mdir) - self.update_statusbar() - move_data = self.current_movement.request_play() - self.start_animation(move_data, stop_after=False) + Model = models[mtype] + assert size is not None + mirror_distance = settings.draw.mirror_distance if settings.draw.mirror_faces else None + model = Model(size, mirror_distance) + self.gamestate.new_game(model, solved) + self.unsolved = not solved + self.cube_area.set_model(model) + self.cube_area.apply_to_glmodel(self.gamestate.current_cube_state) + self.cube_area.update() + self.update_ui() + + def is_animating(self): + return self.cube_area.timer_animate.isActive() - def create_menu(self): - ui_file = os.path.join(config.UI_DIR, 'menu.ui') + def start_animation(self, move_data, stop_after, animtype): + if move_data: + blocks = self.gamestate.current_cube_state.identify_rotation_blocks( + move_data.axis, move_data.slice) + self.cube_area.animate_rotation(move_data, blocks, stop_after) + self.playbarstate.playing(self.gamestate.mark_before) + self.animtype = animtype + return True + return False - self.main_actions = self.ui_xml.get_object('actiongroup_main') - self.play_actions = self.ui_xml.get_object('actiongroup_play') + def update_statusbar(self): + '''This function must be called before any action that change the move queue length + to reflect total count of moves and after each single move''' - self.uimanager = gtk.UIManager() - self.uimanager.insert_action_group(self.main_actions) - self.uimanager.insert_action_group(self.play_actions) - self.uimanager.add_ui_from_file(ui_file) - - menubar = self.uimanager.get_widget('/menubar1') - vbox = self.ui_xml.get_object('vbox1') - vbox.pack_start(menubar, fill=False, expand=False) - vbox.reorder_child(menubar, 0) - - accel = self.uimanager.get_accel_group() - self.window.add_accel_group(accel) - - self.playbarstate = PlaybarState(self) - self.playbarstate.empty() - - @debug_func - def create_sidepane(self): - column = gtk.TreeViewColumn(_('Name'), gtk.CellRendererText(), text=0) - column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) - column.set_fixed_width(200) - self.treeview.append_column(column) + if self.cube_area.editing_model: + mesg = _('Press the Esc key to exit Edit Mode') + self.unsolved = False + else: + current = self.gamestate.all_moves.current_place + total = self.gamestate.all_moves.queue_length + solved = self.gamestate.current_cube_state.is_solved() + + model_text = unicode(self.gamestate.current_cube_state.model) + # substitution for {move_text} in statusbar text + move_text = ngettext("{current} / {total} move", + "{current} / {total} moves", + total).format(current=current, total=total) + # substitution for {solved_text} in statusbar text + solved_text = _('solved') if solved else _('not solved') + + # statusbar text + mesg = _('{model_text}, {move_text}, {solved_text}').format( + model_text=model_text, + move_text=move_text, + solved_text=solved_text) + if self.unsolved and solved: + self.unsolved = False + QTimer.singleShot(0, self.show_solved_message) + self.status_text.setText(mesg) - self.add_scripts_to_sidepane() + def update_ui(self): + # update toolbar + if self.gamestate.all_moves.at_start(): + if self.gamestate.all_moves.at_end(): + self.playbarstate.empty() + else: + self.playbarstate.first() + else: + if self.gamestate.all_moves.at_end(): + self.playbarstate.last(self.gamestate.all_moves.is_mark_after(-1)) + else: + self.playbarstate.mid(self.gamestate.all_moves.is_mark_current()) + + # update formula + code, pos, markup = self.gamestate.all_moves.format( + self.gamestate.current_cube_state.model) + self.set_edit_moves(code, pos, markup) - self.treeview.connect('row-activated', self.on_treeview_row_activated) - self.id_treeview_motion_notify_event = None - active = confstore.dynamic_script_selection - self.ui_xml.get_object('toggleaction_dynamic_script_selection').set_active(active) - #self.treeview.expand_all() - self.treeview.show_all() - - def add_scripts_to_sidepane(self): - treestore = gtk.TreeStore(gobject.TYPE_STRING, gobject.TYPE_PYOBJECT) - plugins = self.plugin_helper.load_plugins() - tree_iters = {():None} - for plugin_path, func in plugins: - for i in xrange(1, 5): - p_i = plugin_path[:i] - if p_i not in tree_iters: - name = _(p_i[-1]) - tree_iters[p_i] = treestore.append( - tree_iters[plugin_path[:i-1]], - [name, func if p_i == plugin_path else None]) - self.treeview.set_model(treestore) + self.update_statusbar() - def is_animating(self): - return self.cube_area.animation_in_progress + def show_solved_message(self): + dialog = QMessageBox(self) + dialog.setWindowTitle(_(config.APPNAME)) + mtype = _(self.gamestate.current_cube_state.model.type) + dialog.setText(_('Congratulations, you have solved the puzzle!')) + dialog.setIcon(QMessageBox.Information) + dialog.setStandardButtons(QMessageBox.Close) + self.cube_area.set_std_cursor() + dialog.exec_() - def on_treeview_motion_notify_event(self, treeview, event): - tpath_column = treeview.get_path_at_pos(int(event.x), int(event.y)) - if tpath_column is None or self.selected_tree_path == tpath_column[0]: - return True - tpath = tpath_column[0] - treeview.collapse_all() - treeview.expand_to_path(tpath) - treeview.expand_row(tpath, False) - treeview.set_cursor(tpath) - self.selected_tree_path = tpath - return True + def error_dialog(self, message): + '''Popup an error dialog box''' + dialog = QMessageBox(self) + dialog.setWindowTitle(_(config.APPNAME)) + dialog.setText(message) + dialog.setIcon(QMessageBox.Warning) + dialog.setStandardButtons(QMessageBox.Close) + self.cube_area.set_std_cursor() + dialog.exec_() + + def set_progress(self, step, message=None, value_max=None): + if self.progress_dialog is None: + self.progress_dialog = dialogs.ProgressDialog(self) + canceled = self.progress_dialog.tick(step, message, value_max) + qApp.processEvents() + return canceled + + def end_progress(self): + if self.progress_dialog is not None: + self.progress_dialog.done() + + ### application handlers ### + + def resizeEvent(self, event): + settings.window.size = event.size().width(), event.size().height() + sizes = self.ui.splitter.sizes() + if sum(sizes) > 0: # ignore the first resize event where sizes==[0,0] + settings.window.divider = sizes[0] + QMainWindow.resizeEvent(self, event) + + def closeEvent(self, event): + try: + dialogs.Dialog.delete() + model, blocks, moves, position = self.gamestate.get_state() + try: + mtype = models.index(model.__class__) + except ValueError: + print('unknown model') + else: + settings.keystore.changed.disconnect(self.cube_area.on_settings_changed) + settings.game.blocks = blocks + settings.game.moves = moves + settings.game.position = position + settings.game.type = mtype + settings.game.size = model.sizes + finally: + settings.close() + # Needed for PyQt4 to prevent warning: + # QObject::startTimer: QTimer can only be used with threads started with QThread + self.ui.treeview.setModel(None) + # this line prevents a segmentation fault with PySide if game->quit selected + self.cube_area.setMouseTracking(False) + finally: + QMainWindow.closeEvent(self, event) + + def on_settings_changed(self, key): + if key in ['draw.mirror_faces', 'draw.mirror_distance']: + sizes = self.gamestate.initial_cube_state.model.sizes + Model = self.gamestate.initial_cube_state.model.__class__ + mirror_distance = settings.draw.mirror_distance if settings.draw.mirror_faces else None + model = Model(sizes, mirror_distance) + self.gamestate.set_model(model) + self.cube_area.set_model(model) + self.cube_area.update() + elif key == 'draw.accels': + self.move_keys = self.get_move_key_dict() + + def on_settings_error(self, message): + self.status_text.setText(message) - def on_treeview_row_activated(self, treeview, path, unused_view_column): - if self.is_animating(): + MODIFIER_MASK = int(Qt.ShiftModifier | Qt.ControlModifier | Qt.KeypadModifier) + def keyPressEvent(self, event): + if event.key() == Qt.Key_Escape: + self.cube_area.set_editing_mode(False) + self.update_ui() + return + try: + move = self.move_keys[event.key() | int(event.modifiers()) & self.MODIFIER_MASK] + except KeyError: + event.ignore() + QMainWindow.keyPressEvent(self, event) return - unused_name, func = treeview.get_model()[path] - if self.plugin_helper.call(func): - self.cube_area.apply_to_glmodel(self.current_movement.current_cube_state) + else: + if self.is_animating() and self.animtype != AnimType.KEY: + return + if not self.is_animating(): + self.gamestate.all_moves.truncate() + self.gamestate.all_moves.parse(move, len(move), self.gamestate.current_cube_state.model) self.update_ui() - move_data = self.current_movement.request_play() - if not self.start_animation(move_data, stop_after=False): - self.cube_area.render() - - @debug_func - def run_main_loop(self): - self.window.show() - gtk.quit_add(0, self.on_quit) - gtk.main() - - def first_new_game(self, dimension, solved): - if solved: - self.solved = True + if not self.is_animating(): + move_data = self.gamestate.request_next() + self.start_animation(move_data, stop_after=False, animtype=AnimType.KEY) - if self.solved: - if dimension is None: - dimension = confstore.dimension - self.current_movement.set_solved(dimension) - self.cube_area.apply_to_glmodel(self.current_movement.current_cube_state) - else: - if dimension is None: - self.current_movement.set_saved_game( - confstore.dimension, - confstore.saved_state, - confstore.saved_moves, - confstore.saved_pos) - self.cube_area.apply_to_glmodel(self.current_movement.current_cube_state) + ### GL area handlers ### + + def on_cubearea_end_animation(self, last_move): + self.cube_area.apply_to_glmodel(self.gamestate.current_cube_state) + + if not last_move: + # go again + self.update_statusbar() + if self.animtype == AnimType.BWD: + move_data = self.gamestate.request_back() else: - self.current_movement.set_random(dimension) - self.cube_area.apply_to_glmodel(self.current_movement.current_cube_state) - - self.cube_area.render() - self.update_ui(first=True) + move_data = self.gamestate.request_next() + if not self.start_animation(move_data, stop_after=False, animtype=self.animtype): + self.update_ui() + else: + self.update_ui() + + def on_cubearea_request_rotation(self, maxis, mslice, mdir): + self.gamestate.request_rotation(maxis, mslice, mdir) + self.update_statusbar() + move_data = self.gamestate.request_next() + self.start_animation(move_data, stop_after=False, animtype=AnimType.NEW) - @debug_func - def new_game(self, new_size, solved): - assert not self.is_animating() - - if solved is not None: - self.solved = solved - - if new_size is not None: - self.cube_area.re_initialize() - if new_size <= 0: - new_size = self.current_movement.current_cube_state.dimension - - if self.solved: - self.current_movement.set_solved(new_size) + def on_cubearea_request_swap_blocks(self, blockpos, maxis, mslice, mdir): + self.gamestate.swap_block(blockpos, maxis, mslice, mdir) + self.cube_area.apply_to_glmodel(self.gamestate.current_cube_state) + + def on_cubearea_request_rotate_block(self, blockpos, rdir): + self.gamestate.rotate_block(blockpos, rdir) + self.cube_area.apply_to_glmodel(self.gamestate.current_cube_state) + + def on_cubearea_drop_color(self, blocknum, facesym, colorname): + if blocknum < 0: + settings.theme.bgcolor = colorname else: - self.current_movement.set_random(new_size) - self.cube_area.apply_to_glmodel(self.current_movement.current_cube_state) - self.cube_area.render() - self.current_movement.all_moves.reset() - self.update_ui() + colornum = self.gamestate.current_cube_state.get_colornum(blocknum, facesym) + settings.theme.face[colornum].color = colorname + + def on_cubearea_drop_file(self, blocknum, facesym, filename): + #TODO: background images + colornum = self.gamestate.current_cube_state.get_colornum(blocknum, facesym) + settings.theme.face[colornum].image = filename - return False + ### - # Request that the game be restarted - # If data is non zero, then all it's data will be reallocated - @debug_func - def request_new_game(self, unused_widget=None, new_size=None, solved=None): - #FIXME: fix abort_requested and use it here + @Slot(int, int) + def on_splitter_splitterMoved(self, pos, index): # pylint: disable=R0201 + if index == 1: + settings.window.divider = pos + + ### sidepane handlers ### + + def on_button_sidepane_clicked(self, i): + self.set_active_script_group(i) + + @Slot(QModelIndex) + def on_treeview_activated(self, index): if self.is_animating(): return - gobject.idle_add(self.new_game, new_size, solved) - - def start_animation(self, move_data, stop_after): - if move_data: - blocks = list(self.current_movement.current_cube_state.identify_rotation_blocks( - move_data.axis, move_data.slice)) - self.cube_area.animate_rotation(move_data, blocks, stop_after) - self.playbarstate.playing(self.current_movement.mark_before) - return True - return False - + func = index.data(Qt.UserRole + 1) + if func is None: + return + state, moves = self.plugin_helper.call(self, func) + if state is None: + self.unsolved = False + else: + self.gamestate.initial_cube_state = state + self.gamestate.current_cube_state = state.copy() + self.gamestate.all_moves.reset() + self.unsolved = True + position = self.gamestate.all_moves.mark_and_extend(moves) + if position >= 0: + self.gamestate.do_fast_forward(position) + self.cube_area.apply_to_glmodel(self.gamestate.current_cube_state) + self.update_ui() + move_data = self.gamestate.request_next() + self.start_animation(move_data, stop_after=False, animtype=AnimType.NEW) + elif state is not None: + self.cube_area.apply_to_glmodel(self.gamestate.current_cube_state) + self.update_ui() + self.cube_area.update() - # Action handlers - @debug_func - def on_quit(self): - (unused_dimension, confstore.saved_state, confstore.saved_moves, - confstore.saved_pos) = self.current_movement.get_saved_game() - return 0 - on_window_delete_event = gtk.main_quit - def on_action_new_activate(self, *unused_args): - self.request_new_game(solved=False) - def on_action_new_solved_activate(self, *unused_args): - self.request_new_game(solved=True) - def on_action_colors_activate(self, unused_widget): - dialogcolors.colorselect_dialog(self) - def on_action_preferences_activate(self, unused_widget): - dialogs.preferences_dialog(self) - def on_toggleaction_play_toolbar_toggled(self, widget): - self.play_toolbar.props.visible = widget.props.active - def on_toggleaction_statusbar_toggled(self, widget): - self.statusbar.props.visible = widget.props.active - def on_action_reset_rotation_activate(self, unused_widget): + ### action handlers ### + + @Slot() + def on_action_new_activated(self): + self.new_game(solved=False) + @Slot() + def on_action_new_solved_activated(self): + self.new_game(solved=True) + @Slot() + def on_action_selectmodel_activated(self): + dialog = dialogs.SelectModelDialog.run(self) + if dialog: + def response_ok(mtype, size, solved): + self.new_game(mtype, size, solved) + dialog.response_ok.connect(response_ok) + @Slot() + def on_action_quit_activated(self): + self.close() + @Slot() + def on_action_preferences_activated(self): + dialogs.PreferencesDialog.run(self) + @Slot(bool) + def on_action_toolbar_toggled(self, checked): + self.ui.toolbar.setVisible(checked) + settings.window.toolbar = checked + @Slot(bool) + def on_action_editbar_toggled(self, checked): + self.ui.frame_editbar.setVisible(checked) + settings.window.editbar = checked + @Slot(bool) + def on_action_statusbar_toggled(self, checked): + self.ui.statusbar.setVisible(checked) + settings.window.statusbar = checked + @Slot() + def on_action_reset_rotation_activated(self): self.cube_area.reset_rotation() - def on_toggleaction_dynamic_script_selection_toggled(self, widget): - confstore.dynamic_script_selection = widget.props.active - if widget.props.active: - self.id_treeview_motion_notify_event = ( - self.treeview.connect('motion-notify-event', self.on_treeview_motion_notify_event)) - else: - self.treeview.disconnect(self.id_treeview_motion_notify_event) - self.id_treeview_motion_notify_event = None - def on_action_info_activate(self, unused_widget): - dialogs.show_about(self.window) + @Slot() + def on_action_info_activated(self): + dialogs.show_about(self) - def on_action_rewind_activate(self, unused_widget): - if not self.is_animating(): - needs_update = self.current_movement.do_rewind_to_mark() - self.cube_area.apply_to_glmodel(self.current_movement.current_cube_state) + @Slot() + def on_action_rewind_activated(self): + if self.is_animating(): + self.cube_area.stop_requested = True + if self.animtype == AnimType.BWD: + self.gamestate.request_next() # undo the already applied move + self.gamestate.do_rewind_to_mark() + self.cube_area.animate_abort() + else: + needs_update = self.gamestate.do_rewind_to_mark() + self.cube_area.apply_to_glmodel(self.gamestate.current_cube_state) if needs_update: - self.cube_area.render() + self.cube_area.update() self.update_ui() - def on_action_previous_activate(self, unused_widget): - if not self.is_animating(): - move_data = self.current_movement.request_back() - self.start_animation(move_data, stop_after=True) - def on_action_stop_activate(self, unused_widget): - self.cube_area.stop_requested = 1 - def on_action_play_activate(self, unused_widget): - if not self.is_animating(): - move_data = self.current_movement.request_play() - self.start_animation(move_data, stop_after=False) - def on_action_next_activate(self, unused_widget): + @Slot() + def on_action_previous_activated(self): + if self.is_animating(): + if self.animtype == AnimType.BWD: + # request another BWD move + self.cube_area.stop_requested = False + else: + self.cube_area.stop_requested = True + self.gamestate.request_back() + self.cube_area.animate_abort() + self.cube_area.stop_requested = True + else: + move_data = self.gamestate.request_back() + self.start_animation(move_data, stop_after=True, animtype=AnimType.BWD) + @Slot() + def on_action_stop_activated(self): + if self.is_animating(): + if self.cube_area.stop_requested: + self.cube_area.animate_abort() + else: + self.cube_area.stop_requested = True + @Slot() + def on_action_play_activated(self): if not self.is_animating(): - move_data = self.current_movement.request_next() - self.start_animation(move_data, stop_after=True) - def on_action_forward_activate(self, unused_widget): + move_data = self.gamestate.request_next() + self.start_animation(move_data, stop_after=False, animtype=AnimType.FWD) + @Slot() + def on_action_next_activated(self): if self.is_animating(): - return - self.current_movement.do_fast_forward() - self.cube_area.apply_to_glmodel(self.current_movement.current_cube_state) - self.cube_area.render() - self.update_ui() - def on_action_add_mark_activate(self, unused_widget): - self.current_movement.request_mark_move_queue(True) + sr = self.cube_area.stop_requested + if self.animtype == AnimType.BWD: + self.cube_area.stop_requested = True + self.gamestate.request_next() + else: + self.cube_area.stop_requested = False + self.cube_area.animate_abort() + self.cube_area.stop_requested = sr + else: + move_data = self.gamestate.request_next() + self.start_animation(move_data, stop_after=True, animtype=AnimType.FWD) + @Slot() + def on_action_forward_activated(self): + if self.is_animating(): + self.cube_area.stop_requested = True + if self.animtype != AnimType.BWD: + self.gamestate.request_back() # undo the already applied move + self.gamestate.do_fast_forward() + self.cube_area.animate_abort() + else: + self.gamestate.do_fast_forward() + self.cube_area.apply_to_glmodel(self.gamestate.current_cube_state) + self.cube_area.update() + self.update_ui() + @Slot() + def on_action_add_mark_activated(self): + self.gamestate.all_moves.mark_current(True) self.update_ui() - def on_action_remove_mark_activate(self, unused_widget): - self.current_movement.request_mark_move_queue(False) + @Slot() + def on_action_remove_mark_activated(self): + self.gamestate.all_moves.mark_current(False) self.update_ui() - def on_action_set_as_initial_state_activate(self, unused_widget): + @Slot() + def on_action_initial_state_activated(self): if self.is_animating(): return - self.current_movement.set_as_initial_state() + self.gamestate.set_as_initial_state() self.update_ui() - def on_action_reload_scripts_activate(self, unused_widget): - self.plugin_helper = plugins.PluginHelper(self) + @Slot() + def on_action_reload_scripts_activated(self): self.add_scripts_to_sidepane() - def on_action_invert_moves_activate(self, unused_widget): + @Slot() + def on_action_invert_moves_activated(self): if self.is_animating(): return - self.current_movement.invert_moves() - self.cube_area.apply_to_glmodel(self.current_movement.current_cube_state) - self.cube_area.render() + self.gamestate.invert_moves() + self.cube_area.apply_to_glmodel(self.gamestate.current_cube_state) + self.cube_area.update() self.update_ui() - - - #Callbacks for PreferencesDialog - def on_button_size_reset_activate(self, unused_widget): - del confstore.dimension - def on_button_animspeed_reset_activate(self, unused_widget): - del confstore.frameQty - def on_button_lighting_reset_activate(self, unused_widget): - del confstore.lighting - - def on_button_color_reset_activate(self, unused_widget): - i = dialogcolors.ColorSelectDialog.this_dlg.active_face[0] - del confstore.colors[i].color - def on_button_pattern_reset_activate(self, unused_widget): - i = dialogcolors.ColorSelectDialog.this_dlg.active_face[0] - del confstore.colors[i].pattern - def on_button_image_reset_activate(self, unused_widget): - i = dialogcolors.ColorSelectDialog.this_dlg.active_face[0] - del confstore.colors[i].facetype - del confstore.colors[i].imagefile - del confstore.colors[i].imagemode - def on_button_background_color_set(self, button): - confstore.background_color = str(button.get_color()) - def on_button_background_reset_activate(self, unused_widget): - del confstore.background_color - - - # Callbacks for editing formulas - def on_entry_formula_activate(self, unused_widget=None): + @Slot() + def on_action_normalize_complete_rotations_activated(self): if self.is_animating(): - #TODO: Better: stop animating and proceed return - code = self.entry_formula.get_text() - pos = self.entry_formula.get_position() - self.current_movement.set_from_formula(code, pos) - self.cube_area.apply_to_glmodel(self.current_movement.current_cube_state) - self.cube_area.render() + self.gamestate.normalize_complete_rotations() + self.cube_area.apply_to_glmodel(self.gamestate.current_cube_state) + self.cube_area.update() self.update_ui() - def on_entry_formula_icon_press(self, unused_widget, icon_info, event): - if self.is_animating(): - #TODO: Better: stop animating and proceed - return - if event.button==1 and event.type==gdk.BUTTON_PRESS: - if icon_info.value_nick == 'primary': - return self.on_entry_formula_activate() - if icon_info.value_nick == 'secondary': - self.entry_formula.set_text('') - self.on_entry_formula_activate() - - def set_entry_formula(self, code, pos, unused_markup=None): - self.entry_formula.set_text(code) - self.entry_formula.set_position(pos) - #TODO: seems, that gtk.Entry doesn't work with pango markup, use one-line gtk.TextView? - - def update_statusbar(self, first=False): - '''This function must be called before any action that change the move queue length - to reflect total count of moves and after each single move''' - # update statusbar - # in cube.py NOT_SOLVED = 0, SOLVED = 1, HALF_SOLVED = 2 - #TODO: HALF_SOLVED is broken in some ways - # * see comment in on_action_rewind_activate - # * should only shown if asymetric pattern or image - - #FIXME: cube.cube_status_check() is broken, dont use it now - #status = cube.cube_status_check() - status = 0 - - if first: - plural = 0 - else: - plural = self.current_movement.all_moves.queue_length - status_text = [_('not solved'), _('solved'), _('solved')][status] - #status_text = [_('not solved'), _('solved'), _('rotated center')][status] - pass - - mesg = ngettext("{current} / {total} move", - "{current} / {total} moves", - plural).format( - current=self.current_movement.all_moves.current_place, - total=self.current_movement.all_moves.queue_length) - context = self.statusbar.get_context_id("move-count") - self.statusbar.pop(context) - self.statusbar.push(context, mesg) + ### edit formula handlers ### + + def on_action_jump_to_editbar_triggered(self): + self.ui.edit_moves.setFocus() - def update_ui(self, first=False): - # update toolbar - if self.current_movement.all_moves.at_start(): - if self.current_movement.all_moves.at_end(): - self.playbarstate.empty() - else: - self.playbarstate.first() - else: - if self.current_movement.all_moves.at_end(): - self.playbarstate.last(self.current_movement.all_moves.tail.mark_after) - else: - self.playbarstate.mid(self.current_movement.all_moves.prev().mark_after) - - # update formula - code, pos, markup = self.current_movement.all_moves.format( - self.current_movement.current_cube_state.dimension) - self.set_entry_formula(code, pos, markup) + @Slot() + def on_edit_moves_returnPressed(self): + if self.is_animating(): + self.cube_area.animate_abort(update=False) + code = self.ui.edit_moves.text() + pos = self.ui.edit_moves.cursorPosition() + self.gamestate.set_from_formula(code, pos) + self.cube_area.apply_to_glmodel(self.gamestate.current_cube_state) + self.cube_area.update() + self.update_ui() - self.update_statusbar(first=first) - - def error_dialog(self, message): - '''Popup an error dialog box''' - dialog = gtk.MessageDialog(self.window, - gtk.DIALOG_MODAL, gtk.MESSAGE_ERROR, gtk.BUTTONS_CLOSE, - message) - - dialog.set_transient_for(self.window) - # Destroy the dialog when the user responds to it (e.g. clicks a button) - #dialog.connect ("response", gtk.Widget.destroy) - #dialog.show_all () - dialog.run() - dialog.destroy() + @Slot() + def on_button_edit_clear_clicked(self): + self.ui.edit_moves.setText('') + self.on_edit_moves_returnPressed() + + @Slot() + def on_button_edit_exec_clicked(self): + self.on_edit_moves_returnPressed() + + def set_edit_moves(self, code, pos, unused_markup=None): + self.ui.edit_moves.setText(code) + self.ui.edit_moves.setCursorPosition(pos) + + def on_action_edit_model_triggered(self): + self.cube_area.animate_abort(False) + self.gamestate.do_rewind_to_start() + if DEBUG_ROTATE: + self.gamestate.current_cube_state.debug_blocksymbols(allsyms=True) + self.cube_area.apply_to_glmodel(self.gamestate.current_cube_state) + self.cube_area.set_editing_mode(True) + self.update_ui() class PlaybarState (object): - def __init__(self, application): - actions = [ 'action_rewind', 'action_previous', - 'action_stop', 'action_play', - 'action_next', 'action_forward', - 'action_add_mark', 'action_remove_mark'] - self.play_button_list = [application.play_actions.get_action(a) for a in actions] - #@debug_func + def __init__(self, play_actions): + self.play_button_list = play_actions + self.empty() + def set_toolbar_state(self, sflags, vflags, mark): if mark: vflags ^= 0b11 for a in reversed(self.play_button_list): - a.set_sensitive(sflags & 1) - a.set_visible(vflags & 1) + a.setEnabled(sflags & 1) + a.setVisible(vflags & 1) sflags >>= 1 vflags >>= 1 + + # pylint: disable=C0321 def empty(self): self.set_toolbar_state(0b00000000, 0b11011101, False) def first(self): self.set_toolbar_state(0b00011100, 0b11011101, False) def mid(self, mark): self.set_toolbar_state(0b11011111, 0b11011110, mark) def last(self, mark): self.set_toolbar_state(0b11000011, 0b11011110, mark) - def playing(self, mark): self.set_toolbar_state(0b00100000, 0b11101110, mark) + def playing(self, mark): self.set_toolbar_state(0b11101100, 0b11101110, mark) + # pylint: enable=C0321 diff -Nru pybik-0.5/pybiklib/config.py pybik-1.0.1/pybiklib/config.py --- pybik-0.5/pybiklib/config.py 2012-01-06 17:44:37.000000000 +0000 +++ pybik-1.0.1/pybiklib/config.py 2013-02-02 21:42:49.000000000 +0000 @@ -1,7 +1,7 @@ #-*- coding:utf-8 -*- # Pybik -- A 3 dimensional magic cube game. -# Copyright © 2009, 2011-2012 B. Clausius +# Copyright © 2009, 2011-2013 B. Clausius # # 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 @@ -16,49 +16,110 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -import os +from __future__ import print_function, division, unicode_literals -AUTHORS = ["B. Clausius"] -CONTACT = 'barcc@gmx.de' -COPYRIGHT = 'Copyright \xc2\xa9 2009-2011, B. Clausius' +import os, sys + +N_ = lambda s: s + +AUTHOR = 'B. Clausius' +CONTACT_EMAIL = 'barcc@gmx.de' +COPYRIGHT = 'Copyright © 2009-2013, B. Clausius' LICENSE_NAME = 'GNU GPL v3' PACKAGE = 'pybik' -PACKAGE_NAME = 'Pybik' -VERSION = '0.5' +APPNAME = N_('Pybik') +VERSION = '1.0.1' WEBSITE = 'https://launchpad.net/pybik/' +CONTACT_FILEBUG = 'https://bugs.launchpad.net/pybik/+filebug' + # The following two lines are replaced by setup.py data_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'data') appdata_dir = data_dir -IMAGE_FILE = os.path.join(data_dir, 'pixmaps', PACKAGE+'.png') -UI_DIR = os.path.join(appdata_dir, 'ui') -SCRIPT_DIR = os.path.join(appdata_dir, 'scripts') LOCALE_DIR = os.path.join(data_dir, 'locale') +QT_LOCALE_DIR = os.path.join(sys.prefix, 'share', 'qt4', 'translations') +PIXMAP_DIR = os.path.join(data_dir, 'pixmaps') +IMAGE_FILE = os.path.join(PIXMAP_DIR, PACKAGE+'.png') +LICENSE_FILE = os.path.join(appdata_dir, 'GPL-3') +MODELS_DIR = os.path.join(appdata_dir, 'models') +SCRIPT_DIR = os.path.join(appdata_dir, 'plugins') +UI_DIR = os.path.join(appdata_dir, 'ui') -# Using functions, so that this module can be used before gettext was set up. -pass -get_appname = lambda: _('Pybik') -get_appname_short = lambda: _('Pybik') -get_description = lambda: _('Pybik is a 3 dimensional magic cube game.') -get_website_label = lambda: _('Pybik web site') +def get_config_home(): + return os.environ.get('XDG_CONFIG_HOME', '') or os.path.expanduser("~/.config") +def get_data_home(): + return os.environ.get('XDG_DATA_HOME', '') or os.path.expanduser("~/.local/share") + +USER_CONFIG_DIR = os.path.join(get_config_home(), PACKAGE) +USER_SETTINGS_FILE = os.path.join(USER_CONFIG_DIR, 'settings.conf') +USER_VERSION_FILE = os.path.join(USER_CONFIG_DIR, 'version') +USER_SCRIPT_DIR = os.path.join(get_data_home(), PACKAGE, 'plugins') + +SHORT_DESCRIPTION = N_("3D Rubik's cube game") +LONG_DESCRIPTION = N_( + 'Pybik is an interactive, graphical, single player puzzle about the cube invented by' + ' Ernő Rubik. Besides the cube the program can handle towers and bricks (non cubic' + ' puzzles). Pybik also has solvers, pretty patterns and a collection of various' + ' moves. The cube can be manipulated with the mouse or keyboard. You can change the' + ' colors or images on the faces of the cube.' +) -get_license = lambda: [ - _('This program is free software: you can redistribute it and/or modify ' +LICENSE_INFO = N_( + '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.'), + '(at your option) any later version.\n\n' - _('This program is distributed in the hope that it will be useful, ' + '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 .') - ] - - -def get_data_home(): - return os.path.join(os.path.expanduser("~"), ".config", "pybik") + 'GNU General Public License for more details.') +LICENSE_FURTHER = N_( + 'Read the full text of the GNU General Public License' + '<|> or see .') +LICENSE_NOT_FOUND = N_( + 'You should have received a copy of the GNU General Public License' + ' along with this program. If not, see .') + +def get_filebug_text(): + # "Wishlist" is used on Launchpad for Importance, so this word should probably not be translated + return _( + 'If you find any bugs in Pybik or have a suggestion for an improvement then please ' + 'submit a <{CONTACT_FILEBUG}|>bug report<|>. ' + 'In the latter case you can mark the bug report as "Wishlist".' + ).format(CONTACT_FILEBUG=CONTACT_FILEBUG) + +TRANSLATION_TEXT = N_( + 'Translations are managed by the ' + '' + 'Launchpad translation group<|>.\n\n' + 'If you want help to translate Pybik to your language you can do it through ' + 'the web interface<|>.\n\n' + 'Read more about "Translating with Launchpad"<|> ' + 'and "Starting to translate"<|>.') + +def splitlines(description): + line = None + for word in description.split(): + if line is None: + line = word + elif len(line) + 1 + len(word) > 78: + yield line + line = word + else: + line = ' '.join((line, word)) + if line is not None: + yield line + +def wrap(text, sep='\n'): + if type(text) in [list, tuple]: + text, lines = text + else: + lines = None + text = sep.join(splitlines(text)) + if lines: + text += sep + sep + sep.join(lines) + return text + diff -Nru pybik-0.5/pybiklib/confstore.py pybik-1.0.1/pybiklib/confstore.py --- pybik-0.5/pybiklib/confstore.py 2012-01-06 16:32:52.000000000 +0000 +++ pybik-1.0.1/pybiklib/confstore.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,228 +0,0 @@ -#-*- coding:utf-8 -*- - -# Pybik -- A 3 dimensional magic cube game. -# Copyright © 2009, 2011-2012 B. Clausius -# -# 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 . - - -import gconf -import glib -import warnings - -UNDEFINED = 0 -COLORED = 1 -IMAGED = 2 - -TILED = 0 -MOSAIC = 1 - -SELECTIONMODE_QUAD = 0 -SELECTIONMODE_EXT = 1 - - -gconf_root = '/apps/pybik' - -defaults = { - 'dimension' : 3, - 'lighting' : False, - 'selection_mode': SELECTIONMODE_EXT, - 'frameQty' : 8, - 'dynamic_script_selection' : False, - 'saved_state' : 'Cube 3 identity:', - 'saved_moves' : '', - 'saved_pos' : 0, - 'colors/0/color': '#a81407', - 'colors/1/color': '#d94b1c', - 'colors/2/color': '#f0c829', - 'colors/3/color': '#e3e3e3', - 'colors/4/color': '#1d6311', - 'colors/5/color': '#00275e', - 'colors/0/facetype': COLORED, - 'colors/1/facetype': COLORED, - 'colors/2/facetype': COLORED, - 'colors/3/facetype': COLORED, - 'colors/4/facetype': COLORED, - 'colors/5/facetype': COLORED, - 'colors/0/pattern': -1, - 'colors/1/pattern': -1, - 'colors/2/pattern': -1, - 'colors/3/pattern': -1, - 'colors/4/pattern': -1, - 'colors/5/pattern': -1, - 'colors/0/imagefile': '', - 'colors/1/imagefile': '', - 'colors/2/imagefile': '', - 'colors/3/imagefile': '', - 'colors/4/imagefile': '', - 'colors/5/imagefile': '', - 'colors/0/imagemode': TILED, - 'colors/1/imagemode': TILED, - 'colors/2/imagemode': TILED, - 'colors/3/imagemode': TILED, - 'colors/4/imagemode': TILED, - 'colors/5/imagemode': TILED, - 'background_color': '#2B0011', - } - - -class ConfstoreDefault (object): - root = None - defaults = {} - - def __init__(self, parent, defaults_): - self.callbacks = [] - self.finalize(parent, defaults_) - - def init_notify(self): - pass - - def finalize(self, parent, defaults_): - if parent == None: - assert ConfstoreDefault.root == None, ConfstoreDefault.root - ConfstoreDefault.root = self - if not self.defaults: - self.defaults = {} - for key in defaults_: - if '/' not in key: - #debug('%s: self.defaults[%s] = %s' % (self.root_key, key, defaults_[key])) - self.defaults[key] = defaults_[key] - else: - key1, key2 = key.split('/', 1) - if key1 in self.defaults: - self.defaults[key1].finalize(self, {key2:defaults_[key]}) - else: - self.defaults[key1] = self.__class__(self, {key2:defaults_[key]}, key1) - - def __getitem__(self, key): - return self.__getattr__(str(key)) - - def __getattr__(self, keyname): - #debug('Default getattr', self.root_key, keyname) - return self.defaults[keyname] - - def set_color(self, i, color): - self.colors[i].color = str(color) - self.colors[i].facetype = COLORED - - def set_image_filename(self, i, image_filename): - self.colors[i].imagefile = image_filename - self.colors[i].facetype = IMAGED - - -class ConfstoreGConf (ConfstoreDefault): - client = None - - def __init__(self, parent, defaults_, key): - self.values = {} - - if parent is None: - self.root_key = key - assert ConfstoreGConf.client is None - ConfstoreGConf.client = gconf.client_get_default() - else: - self.root_key = '/'.join((parent.root_key, key)) - - ConfstoreDefault.__init__(self, parent, defaults_) - - def init_notify(self): - try: - self.client.add_dir(self.root_key, gconf.CLIENT_PRELOAD_RECURSIVE) - self.client.notify_add(self.root_key, self.on_gconf_notify) - except glib.GError as e: - warnings.warn(str(e)) - - def clear_cache(self): - self.values.clear() - - def on_gconf_notify(self, unused_client, unused_cnxn_id, entry, unused_args): - keys = entry.key[len(self.root_key)+1:].split('/') - #debug('on_gconf_notify', cnxn_id, entry.key, keys) - c = self - for key in keys[:-1]: - c = getattr(c, key) - try: - del c.values[keys[-1]] - except KeyError: - pass - for callback in self.callbacks: - callback(*keys) - - @staticmethod - def _gconf_typename(value): - typename = value.__class__.__name__ - if typename == "str": - typename = "string" - return typename - - def __getattr__(self, key): - # try cache - if key in self.values: - return self.values[key] - - # try gconf - try: - value = self.client.get('/'.join((self.root_key, key))) - except glib.GError as e: - warnings.warn(str(e)) - value = None - if value != None: - ret = getattr(value, "get_" + self._gconf_typename(self.defaults[key]))() - self.values[key] = ret - return ret - - # fallback default - return ConfstoreDefault.__getattr__(self, key) - - def __setattr__(self, key, value): - if key in self.defaults: - typename = self._gconf_typename(self.defaults[key]) - gconf_value = gconf.Value(typename) - getattr(gconf_value, 'set_'+typename)(value) - - #debug('Cache setattr', self.root_key, key, value) - self.values[key] = value - #debug('GConf setattr', self.root_key, key, gconf_value) - self.client.set('/'.join((self.root_key, key)), gconf_value) - else: - object.__setattr__(self, key, value) - - def __delattr__(self, key): - if key in self.defaults: - #self.__setattr__(key, self.defaults[key]) - if key in self.values: - #debug('Cache delattr', self.root_key, key) - del self.values[key] - #debug('GConf delattr', self.root_key, key) - self.client.unset('/'.join((self.root_key, key))) - else: - #debug('del', key) - object.__delattr__(self, key) - - @property - def mouse_left_handed(self): - try: - value = self.client.get('/desktop/gnome/peripherals/mouse/left_handed') - except glib.GError as e: - warnings.warn(str(e)) - value = None - if value != None: - ret = value.get_bool() - return ret - return False - - -# the Confstore root -confstore = ConfstoreGConf(None, defaults, gconf_root) - diff -Nru pybik-0.5/pybiklib/cube.py pybik-1.0.1/pybiklib/cube.py --- pybik-0.5/pybiklib/cube.py 2012-01-06 16:33:04.000000000 +0000 +++ pybik-1.0.1/pybiklib/cube.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,539 +0,0 @@ -#-*- coding:utf-8 -*- - -# Pybik -- A 3 dimensional magic cube game. -# Copyright © 2009-2012 B. Clausius -# -# 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 . - - -# Ported from GNUbik -# Original filename: cube.c -# Original copyright and license: 1998, 2003, 2004 Dale Mellor, John Darrington, GPL3+ - - -# This line makes pyrex happy -global __name__, __file__, __package__ - - -import cython - -#pxd from gl cimport * -#pxd from math cimport * -#px-2 -from OpenGL.GL import glGetFloatv, GL_PROJECTION_MATRIX -from math import atan2, pi as M_PI - -from debug import debug - -debug('Importing module:', __name__) -debug(' from package:', __package__) -debug(' compiled:', cython.compiled) - - -#pxd cdef enum: -#pxd MATRIX_DIM = 4 -#px- -MATRIX_DIM = 4 - -# Unique identifiers for the faces, which can be used to populate a -# bit-field. -#pxd cdef enum: -#pxd FACE_0 = (0x01 << 0) -#pxd FACE_1 = (0x01 << 1) -#pxd FACE_2 = (0x01 << 2) -#pxd FACE_3 = (0x01 << 3) -#pxd FACE_4 = (0x01 << 4) -#pxd FACE_5 = (0x01 << 5) -#px- -FACE_0, FACE_1, FACE_2, FACE_3, FACE_4, FACE_5 = [0x01 << __i for __i in range(6)] - - -# Is the cube solved? -#typedef enum _Cube_Status { NOT_SOLVED=0, SOLVED, HALF_SOLVED } Cube_Status; -NOT_SOLVED = 0 -SOLVED = 1 -HALF_SOLVED = 2 - -#pxd ctypedef float Point[4] -#pxd ctypedef float Vector[4] -#pxd ctypedef Vector* p_Vector -#pxd ctypedef Vector Matrix[4] -#px-4 -Point = lambda: [0] * MATRIX_DIM -Vector = Point -p_Vector = None -Matrix = lambda: [Vector() for unused_i in range(MATRIX_DIM)] - -#pxd cdef struct Face: -#pxd Vector quadrants[4] -#pxd Vector normal -#pxd Point centre -#pxd ctypedef Face *p_Face -#px-2 -class Face: - def __init__(self): - # An array of vectors showing the orientation of the blocks. There are four - # vectors per face. These are used to orientate the mouse pointer, to - # detect when the cube has been solved and to provide feedback to clients - # querying the state. - #px- - self.quadrants = [Vector() for __i in xrange(4)] - # The normal vector is orthogonal to the face of the block. When all - # normals are in the same direction, the cube colours are correct, but not - # necessarily their orientations. - #px- - self.normal = Vector() - # The position of the centre of the face, relative to the centre of the - # block. - #px- - self.centre = Point() - - -#pxd cdef struct Block: -#pxd int visible_faces -#pxd Face face[6] -#pxd Matrix transformation -#pxd int in_motion -#pxd ctypedef Block *p_Block -#px- -p_Block = None -#px-2 -class Block: - def __init__(self): - # Bit-field indicating which faces are on the surface of the cube, and - # should therefore be rendered to the framebuffer. - #px- - self.visible_faces = 0 # int - # A set of attributes for each face (including internal ones!) - #px- - self.face = [Face() for __i in xrange(6)] - # The position from the centre of the cube, and the rotation from the - # 'natural' position (note that the location vector is accessed as - # transformation+12). - #px-2 - self.transformation = Matrix() # Matrix - self.in_motion = False - - -#pxd cdef enum: -#pxd MAX_BLOCKS = 1000 -#px- -MAX_BLOCKS = 10**3 - -#pxd cdef struct _Cube: -#pxd unsigned int dimension -#pxd unsigned int dimension2 -#pxd unsigned int number_blocks -#pxd Block blocks[MAX_BLOCKS] -#px-3 -class _Cube: - dimension = dimension2 = number_blocks = None - blocks = [] -_cube = cython.declare(_Cube) -#px- -_cube = _Cube - -#TODO: remove -#pxd cdef _Cube* get_cube() -def get_cube(): - #px- - return _cube - return cython.address(_cube) - -def get_cube_dimension(): - return _cube.dimension - -def set_cube_dimension(cube_size): - cython.declare( - block = p_Block, - i = cython.int) - - if cube_size == 0: - return - - # The number of blocks per side of the cube. - _cube.dimension = cube_size - _cube.dimension2 = _cube.dimension * _cube.dimension - # _cube.dimension ** 3 - _cube.number_blocks = _cube.dimension2 * _cube.dimension - assert _cube.number_blocks <= MAX_BLOCKS - - # A set of attributes for every block (including internal ones!) - #px- - _cube.blocks = [Block() for i in xrange(_cube.number_blocks)] - - # Loop over the array of blocks, and initialize each one. - for i in range(_cube.number_blocks): - # Flagging only certain faces as visible allows us to avoid rendering - # invisible surfaces, thus slowing down animation. - _cube.blocks[i].visible_faces = int( - FACE_0 * int(0 == i / _cube.dimension2) - + FACE_1 * int(_cube.dimension - 1 == i / _cube.dimension2) - + FACE_2 * int(0 == i / _cube.dimension % _cube.dimension) - + FACE_3 * int(_cube.dimension - 1 == i / _cube.dimension % _cube.dimension) - + FACE_4 * int(0 == i % _cube.dimension) - + FACE_5 * int(_cube.dimension - 1 == i % _cube.dimension) - ) - - # Initialize all transformations to the identity matrix, then set the - # translation part to correspond to the initial position of the block. - for ky in range(3): - for kx in range(4): - _cube.blocks[i].transformation[ky][kx] = 0.0 - for kx in range(4): - _cube.blocks[i].transformation[kx][kx] = 1.0 - - _cube.blocks[i].transformation[3][0] = block_index_to_coords (i % _cube.dimension) - _cube.blocks[i].transformation[3][1] = block_index_to_coords ((i / _cube.dimension) % - _cube.dimension) - _cube.blocks[i].transformation[3][2] = block_index_to_coords ((i / _cube.dimension2) % - _cube.dimension) - - # Set all the face centres. - #px-2 - for j in range(6): - _cube.blocks[i].face[j].centre = [0, 0, 0, 0] - - _cube.blocks[i].face[0].centre[0] = 0.0 - _cube.blocks[i].face[0].centre[1] = 0.0 - _cube.blocks[i].face[0].centre[2] = -1.0 - _cube.blocks[i].face[0].centre[3] = 0.0 - - _cube.blocks[i].face[1].centre[0] = 0.0 - _cube.blocks[i].face[1].centre[1] = 0.0 - _cube.blocks[i].face[1].centre[2] = 1.0 - _cube.blocks[i].face[1].centre[3] = 0.0 - - _cube.blocks[i].face[2].centre[0] = 0.0 - _cube.blocks[i].face[2].centre[1] = -1.0 - _cube.blocks[i].face[2].centre[2] = 0.0 - _cube.blocks[i].face[2].centre[3] = 0.0 - - _cube.blocks[i].face[3].centre[0] = 0.0 - _cube.blocks[i].face[3].centre[1] = 1.0 - _cube.blocks[i].face[3].centre[2] = 0.0 - _cube.blocks[i].face[3].centre[3] = 0.0 - - _cube.blocks[i].face[4].centre[0] = -1.0 - _cube.blocks[i].face[4].centre[1] = 0.0 - _cube.blocks[i].face[4].centre[2] = 0.0 - _cube.blocks[i].face[4].centre[3] = 0.0 - - _cube.blocks[i].face[5].centre[0] = 1.0 - _cube.blocks[i].face[5].centre[1] = 0.0 - _cube.blocks[i].face[5].centre[2] = 0.0 - _cube.blocks[i].face[5].centre[3] = 0.0 - - _cube.blocks[i].in_motion = 0 - -# Cube co-ordinates have their origin at the centre of the cube, and their -# units are equivalent to one half of the length of one edge of a block. -def block_index_to_coords(i): - return float(2 * i - _cube.dimension + 1) - -#def block_coords_to_index(i): -# return int((i + _cube.dimension - 1) / 2.0) - -# Utility function to fetch a particular face of the cube. -#pxd cdef p_Face get_faces(int block) -def get_faces(block): - return _cube.blocks[block].face - - -# Cube co-ordinates have their origin at the centre of the cube, and their -# units are equivalent to one half of the length of one edge of a block. -# This func initialises the positions of the blocks which comprise the cube. -# The enumeration scheme I have chosen goes around four surfaces of the cube, -# then fills in the ends. Thus, for a 4x4x4 cube it looks like: -# -# ---------------------------------------------------------------------------- -# View this diagram with 132 coloumns! -# -# | 60 | 61 | 62 | 63 | -# | 44 | 45 | 46 | 47 | | 56 | 57 | 58 | 59 | -# | 28 | 29 | 30 | 31 | | 40 | 41 | 42 | 43 | | 52 | 53 | 54 | 55 | -# | 12 | 13 | 14 | 15 | | 24 | 25 | 26 | 27 | | 36 | 37 | 38 | 39 | | 48 | 49 | 50 | 51 | -# | 8 | 9 | 10 | 11 | | 20 | 21 | 22 | 23 | | 32 | 33 | 34 | 35 | -# | 4 | 5 | 6 | 7 | | 16 | 17 | 18 | 19 | -# | 0 | 1 | 2 | 3 | - - -def set_animation_blocks(blocks): - cython.declare( - i = cython.int) - for i in blocks: - _cube.blocks[i].in_motion = 1 - - -#pxd cdef bint vectors_equal(float *v1, float *v2) -def vectors_equal(v1, v2): - i = cython.declare(cython.int) - for i in range(MATRIX_DIM): - if v1[i] != v2[i]: - return False - return True - - -#******************** -#* The cube is solved iff for all faces the quadrant vectors point in the same -#* direction. If however all the normals point in the same direction, but the -#* quadrants do not, then the colours are all on the right faces, but not -#* correctly orientated. -#****** - -def cube_status_check(): - cython.declare( - face = cython.int, - v0 = cython.p_float, - v1 = cython.p_float, - q0 = cython.p_float, - q1 = cython.p_float, - i = cython.int) - q0 = cython.NULL - q1 = cython.NULL - - # Find out if the cube is at least half solved (the colours are right, but - # some orientations are wrong (this can be seen on a face away from an edge - # of the cube with a pixmap on it). If the cube is not at least - # half-solved, then it is definitely unsolved and this value is - # returned. - - for face in range(6): - mask = 0x01 << face - x = 0 - - for i in range(_cube.number_blocks-1, -1, -1): - if _cube.blocks[i].visible_faces & mask: - v0 = get_faces(i)[face].normal - if x == 0: - q0 = v0 - x = x+1 - else: - if not vectors_equal(q0, v0): - return NOT_SOLVED - - - # The cube is at least half-solved. Check if it is fully solved by checking - # the alignments of all the quadrant vectors. If any are out, then return - # the half-solved status to the caller. Note that it is only necessary to - # check two perpendicular quadrant vectors. - - for face in range(6): - mask = 0x01 << face - x = 0 - - for i in range(_cube.number_blocks-1, -1, -1): - # Ignore faces which are inside the cube. - if _cube.blocks[i].visible_faces & mask: - v0 = get_faces(i)[face].quadrants[0] - v1 = get_faces(i)[face].quadrants[1] - - if x == 0: - q0 = v0 - q1 = v1 - x = x+1 - elif not vectors_equal(q0, v0) or not vectors_equal(q1, v1): - return HALF_SOLVED - - # Cube is fully solved. - return SOLVED - - -#******************** -#* Cube accessor method. -#****** - -#pxd cdef bint is_face_visible(int block, int face) -def is_face_visible(block, face): - return _cube.blocks[block].visible_faces & (0x01 << face) - - -#******************** -#* Get the transformation of block number `block_id' from the origin, and store -#* it in transform. -#****** - -#pxd cdef Vector* _get_block_transform(int block_id) -def _get_block_transform(block_id): - return _cube.blocks[block_id].transformation - - -#******************** - -#pxd cdef void init_vector(float *v, w) -def init_vector(v, w): - cython.declare(k = cython.int) - for k in range(len(w)): - v[k] = w[k] -#pxd cdef void init_listuc_range(int i, int j, unsigned char *v, w) -def init_listuc_range(i, j, v, w): - cython.declare(k = cython.int) - for k in range(i, j): - v[k] = w[k-i] -#pxd cdef void init_listf_range(int i, int j, float *v, w) -def init_listf_range(i, j, v, w): - cython.declare(k = cython.int) - for k in range(i, j): - v[k] = w[k-i] -#pxd cdef void init_turn_axes_4(Vector *v, w1, w2, w3, w4) -def init_turn_axes_4(v, w1, w2, w3, w4): - init_vector(v[0], w1) - init_vector(v[1], w2) - init_vector(v[2], w3) - init_vector(v[3], w4) - -#pxd ctypedef Vector turn_axes_t[6][4] -#pxd ctypedef Vector turn_axes_center_t[6] -#px- -turn_axes_t = turn_axes_center_t = None -cython.declare(turn_axes = turn_axes_t, turn_axes_center = turn_axes_center_t) -#px-2 -turn_axes = [Matrix() for __i in range(6)] -turn_axes_center = [Vector() for __i in range(6)] - -turn_axesX = [ 1, 0, 0, 0] -turn_axes_X = [-1, 0, 0, 0] -turn_axesY = [ 0, 1, 0, 0] -turn_axes_Y = [ 0,-1, 0, 0] -turn_axesZ = [ 0, 0, 1, 0] -turn_axes_Z = [ 0, 0,-1, 0] - -init_turn_axes_4(turn_axes[0], turn_axes_Y, turn_axesX, turn_axesY, turn_axes_X) -init_turn_axes_4(turn_axes[1], turn_axesY, turn_axesX, turn_axes_Y, turn_axes_X) -init_turn_axes_4(turn_axes[2], turn_axesZ, turn_axesX, turn_axes_Z, turn_axes_X) -init_turn_axes_4(turn_axes[3], turn_axes_Z, turn_axesX, turn_axesZ, turn_axes_X) -init_turn_axes_4(turn_axes[4], turn_axes_Y, turn_axes_Z, turn_axesY, turn_axesZ) -init_turn_axes_4(turn_axes[5], turn_axesY, turn_axes_Z, turn_axes_Y, turn_axesZ) - -init_vector(turn_axes_center[0], turn_axesZ) -init_vector(turn_axes_center[1], turn_axes_Z) -init_vector(turn_axes_center[2], turn_axesY) -init_vector(turn_axes_center[3], turn_axes_Y) -init_vector(turn_axes_center[4], turn_axesX) -init_vector(turn_axes_center[5], turn_axes_X) - -# Convert a vector to a axis number. Obviously this assumes the vector -#is orthogonal to the frame of reference ( another nasty kludge ). -#pxd cdef int get_turn_axis(float* vector) -def get_turn_axis(vector): - if vector[0] != 0: return 0 - elif vector[1] != 0: return 1 - else: return 2 - -#pxd cdef int get_turn_slice(int block, int axis) -def get_turn_slice(block, axis): - slice_ = int(_cube.blocks[block].transformation[3][axis]) - slice_ = (slice_ + _cube.dimension - 1) // 2 - return slice_ - -# return the turn direction, based upon the turn axis vector -#pxd cdef int get_turn_dir(float* vector) -def get_turn_dir(vector): - # This is a horrendous kludge. It works only because we know that - # vector is arithemtically very simple - return vector[0] + vector[1] + vector[2] > 0 - -def get_selected_move(block, face, quadrant): - cython.declare( - vector = Vector, - pv = cython.p_float, - t = p_Vector) - #px- - vector = Vector() - - # Determine the axis about which to rotate the slice, from the objects - # selected by the cursor position - # Each edge (quadrant) on a block represents a different axis - # Select the untransformed vector for the selected edge - pv = turn_axes[face][quadrant] - # Fetch the selected block's transformation from its original orientation - t = _get_block_transform(block) - # transform it, so that we go the right way - transform(vector, t, pv) - - axis = get_turn_axis(vector) - slice_ = get_turn_slice(block, axis) - dir_ = get_turn_dir(vector) - return axis, slice_, dir_ - -def get_selected_move_center(block, face): - cython.declare( - vector = Vector, - pv = cython.p_float, - t = p_Vector) - #px- - vector = Vector() - - pv = turn_axes_center[face] - # Fetch the selected block's transformation from its original orientation - t = _get_block_transform(block) - # transform it, so that we go the right way - transform(vector, t, pv) - - axis = get_turn_axis(vector) - slice_ = get_turn_slice(block, axis) - dir_ = get_turn_dir(vector) - return axis, slice_, dir_ - -#pxd cdef inline p_Vector glGetProjectionMatrix(p_Vector m): -#pxd glGetFloatv(GL_PROJECTION_MATRIX, m) -#pxd return m -#px- -def glGetProjectionMatrix(unused_m): return glGetFloatv(GL_PROJECTION_MATRIX) - -def get_cursor_angle(block, face, quadrant): - # Here we take the orientation of the selected quadrant and multiply it - # by the projection matrix. The result gives us the angle (on the screen) - # at which the mouse cursor needs to be drawn. - cython.declare( - proj = Matrix, - proj_ = p_Vector, - v1 = cython.p_float, - v2 = Vector) - #px-2 - proj = None - v2 = Vector() - - proj_ = glGetProjectionMatrix(proj) - v1 = get_faces(block)[face].quadrants[quadrant] - transform(v2, proj_, v1) - return atan2(v2[0], v2[1]) * 180.0 / M_PI - - -# Pre-multiply a point or vector x, by matrix M -#pxd cdef void transform(Vector q, Matrix M, Vector x) -def transform(q, M, x): - cython.declare( - i = cython.int, - j = cython.int, - f = cython.float) - #px- - q[:] = [0] * MATRIX_DIM - - for i in range(MATRIX_DIM): - q[i] = 0 - for j in range(MATRIX_DIM): - q[i] += M[j][i] * x[j] - - -def cube_set_blocks(blocks): - cython.declare( - b = cython.int, - i = cython.int, - j = cython.int) - for b in range(_cube.number_blocks): - for i in range(4): - for j in range(4): - _cube.blocks[b].transformation[i][j] = float(blocks[b][i][j]) - diff -Nru pybik-0.5/pybiklib/cube_form.py pybik-1.0.1/pybiklib/cube_form.py --- pybik-0.5/pybiklib/cube_form.py 2011-12-22 11:41:24.000000000 +0000 +++ pybik-1.0.1/pybiklib/cube_form.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,383 +0,0 @@ -#-*- coding:utf-8 -*- - -# Pybik -- A 3 dimensional magic cube game. -# Copyright © 2009-2011 B. Clausius -# -# 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 . - - -import random -from copy import deepcopy - -from .debug import * - -class ParseBlockException (Exception): pass - - -# This class is currently used to store the initial state of the cube -# and to provide the cube to plugin scripts. -class CubeState (object): - flubrd = 'FLUBRD' - rand = random.Random() - if DEBUG_LEVEL > 0: - print 'rand.seed(123)' - rand.seed(123) - - def __init__(self): - self.type = 'Cube' - # Information is stored in module cube - self._dimension = None - self._faces = None - self._blocks = None - - def copy(self): - other = CubeState() - other._dimension = self._dimension - other._faces = deepcopy(self._faces) - other._blocks = deepcopy(self._blocks) - return other - - @property - def dimension(self): - return self._dimension - @property - def faces(self): - if self._faces is None: - self._faces = self._make_faces_cube() - return self._faces - @property - def blocks(self): - assert self._blocks - return self._blocks - - def set_solved(self, dimension=None): - assert self.type == 'Cube' - if dimension: - assert 0 < dimension <= 10 - self._dimension = dimension - self._set_cube_dimension() - self._faces = None - - def _set_cube_dimension(self): - if not self._dimension: - return - - def block_index_to_coord(i, d): - return float(2 * i - d + 1) - def block_index_to_coords(i, d): - return [ block_index_to_coord(i % d, d), - block_index_to_coord((i / d) % d, d), - block_index_to_coord((i / (d * d)) % d, d), - 1.0 - ] - - number_blocks = self._dimension ** 3 - # Initialize all transformations to the identity matrix, then set the - # translation part to correspond to the initial position of the block. - self._blocks = [] - for i in range(number_blocks): - self._blocks.append([[1.0, 0.0, 0.0, 0.0], - [0.0, 1.0, 0.0, 0.0], - [0.0, 0.0, 1.0, 0.0], - block_index_to_coords(i, self._dimension), - ]) - def _make_faces_cube(self): - if self.dimension is None: - return None - - MATRIX_DIM = 4 - number_blocks = self.dimension ** 3 - def transform(M, x): - q = [0] * MATRIX_DIM - - for i in range(MATRIX_DIM): - q[i] = 0 - for j in range(MATRIX_DIM): - q[i] += M[j][i] * x[j] - return q - def block_coords_to_index(i): - return int((i + self.dimension - 1) / 2.0) - - #char colours [6] [self.dimension] [self.dimension] - colours = [] - for j in range(6): - colour = [] - for i in range(self.dimension): - colour.append(list(' '*self.dimension)) - colours.append(colour) - - # Loop over all blocks and faces, but only process if the face is on the - # outside of the cube. - - _visible_faces = [ (lambda i, d: 0 == i / (d * d)), - (lambda i, d: d - 1 == i / (d * d)), - (lambda i, d: 0 == i / d % d), - (lambda i, d: d - 1 == i / d % d), - (lambda i, d: 0 == i % d), - (lambda i, d: d - 1 == i % d), - ] - - _cube_blocks_face = [[ 0.0, 0.0,-1.0, 0.0], - [ 0.0, 0.0, 1.0, 0.0], - [ 0.0,-1.0, 0.0, 0.0], - [ 0.0, 1.0, 0.0, 0.0], - [-1.0, 0.0, 0.0, 0.0], - [ 1.0, 0.0, 0.0, 0.0]] - for i in range(number_blocks-1, -1, -1): - for face in range(6): - if _visible_faces[face](i, self.dimension): - # Apply the rotation part of the block transformation to the - # offset of the face centre from the centre of the block. This - # will tell us the direction the face is now facing. - - face_direction_ = _cube_blocks_face[face] - face_direction = transform(self._blocks[i], face_direction_) - - # The face direction will have exactly one non-zero component - # this is in the direction of the normal, so we can infer which - # side of the cube we are on. Further, if we look at the other - # two components of the location part of the block - # transformation, we can infer the position of the block in the - # face. We set the appropriate element in the colours array to - # the colour of this face, which corresponds exactly with the - # original face the block was at. - - if abs(face_direction[0]) > 0.1: - if face_direction[0] < 0.0: f = 4 - else: f = 5 - colours[f] \ - [block_coords_to_index(self._blocks[i][3][1])] \ - [block_coords_to_index(self._blocks[i][3][2])] = face - elif abs(face_direction[1]) > 0.1: - if face_direction[1] < 0.0: f = 2 - else: f = 3 - colours[f] \ - [block_coords_to_index(self._blocks[i][3][0])] \ - [block_coords_to_index(self._blocks[i][3][2])] = face - else: - if face_direction[2] < 0.0: f = 0 - else: f = 1 - colours[f] \ - [block_coords_to_index(self._blocks[i][3][0])] \ - [block_coords_to_index(self._blocks[i][3][1])] = face - - # Now the colours array should be completely populated - - face_vector = [] - for face in range(6): - block_vector = [] - for j in range(self.dimension): - for i in range(self.dimension): - block_vector.append(colours[face][i][j]) - face_vector.append(block_vector) - - return face_vector - - def identify_rotation_blocks(self, axis, slice_): - assert self._blocks - - slice_pos = slice_ * 2 - self.dimension + 1 - for i, block in enumerate(self._blocks): - if slice_ == -1 or abs(block[3][axis] - slice_pos) < 0.1: - yield i - - def _rotate_slice(self, axis, slice_, dir_): - assert self._blocks - - MATRIX_DIM = 4 - def _cos_quadrant(quarters): - quarters = abs(quarters) % 4 - if quarters == 0: - return 1 - elif quarters == 2: - return -1 - else: - return 0 - def _sin_quadrant(quarters): - return _cos_quadrant(quarters - 1) - def _pre_mult(M, block): - N = self._blocks[block] - self._blocks[block] = T = [] - for k in range(MATRIX_DIM): - T.append([]) - for i in range(MATRIX_DIM): - T[k].append(0) - T[k][i] = sum(M[j][i] * N[k][j] for j in range(MATRIX_DIM)) - - # Create a matrix describing the rotation of we are about to perform. - # -90 degrees equals +270 degrees - rotation = [[1,0,0,0], [0,1,0,0], [0,0,1,0], [0,0,0,1]] - turns = 1 if dir_ else 3 - rotation[(axis + 1) % 3][(axis + 1) % 3] = _cos_quadrant(turns) - rotation[(axis + 2) % 3][(axis + 2) % 3] = _cos_quadrant(turns) - rotation[(axis + 2) % 3][(axis + 1) % 3] = _sin_quadrant(turns) - rotation[(axis + 1) % 3][(axis + 2) % 3] = -_sin_quadrant(turns) - - # Apply the rotation matrix to all the blocks in this slice. - if DEBUG_ROTATE: - debug('rotate axis={} slice={} dir={!s:5} blocks:'.format(axis, slice_, dir_), end=' ') - for i in self.identify_rotation_blocks(axis, slice_): - if DEBUG_ROTATE: debug('{!s:2}'.format(i), end=' ') - _pre_mult(rotation, i) - if DEBUG_ROTATE: debug() - self._faces = None - - def get_color(self, face, x, y): - return self.faces[face][x + y*self._dimension] - - def dump(self): - for i, f in enumerate(self.faces): - print 'Face %d:'%i, str(f) - print - #for i, b in enumerate(self._blocks): - # debug('Block %d:'%i, str(b)) - - rotation_matrices = [ - [[ 1,0,0,0], [0, 1,0,0], [0,0, 1,0]], # 0 empty - [[ 1,0,0,0], [0,-1,0,0], [0,0,-1,0]], # 1 ff lluu uull - [[-1,0,0,0], [0, 1,0,0], [0,0,-1,0]], # 2 ll ffuu uuff - [[-1,0,0,0], [0,-1,0,0], [0,0, 1,0]], # 3 uu ffll llff - - [[ 1,0,0,0], [0,0, 1,0], [0,-1,0,0]], # 4 f - [[ 1,0,0,0], [0,0,-1,0], [0, 1,0,0]], # 5 f' - [[-1,0,0,0], [0,0, 1,0], [0, 1,0,0]], # 6 fuu uuf' f'll llf - [[-1,0,0,0], [0,0,-1,0], [0,-1,0,0]], # 7 fll llf' f'uu uuf - - [[0, 1,0,0], [ 1,0,0,0], [0,0,-1,0]], # 8 ffu ull llu' u'ff - [[0, 1,0,0], [-1,0,0,0], [0,0, 1,0]], # 9 u - [[0,-1,0,0], [ 1,0,0,0], [0,0, 1,0]], #10 u' - [[0,-1,0,0], [-1,0,0,0], [0,0,-1,0]], #11 ffu' u'll llu uff - - [[0, 1,0,0], [0,0, 1,0], [ 1,0,0,0]], #12 fu ul lf - [[0, 1,0,0], [0,0,-1,0], [-1,0,0,0]], #13 f'u ul' l'f' - [[0,-1,0,0], [0,0, 1,0], [-1,0,0,0]], #14 fu' u'l' l'f - [[0,-1,0,0], [0,0,-1,0], [ 1,0,0,0]], #15 f'u' u'l lf' - - [[0,0, 1,0], [ 1,0,0,0], [0, 1,0,0]], #16 f'l' l'u' u'f' - [[0,0, 1,0], [-1,0,0,0], [0,-1,0,0]], #17 uf fl' l'u - [[0,0,-1,0], [ 1,0,0,0], [0,-1,0,0]], #18 fl lu' u'f - [[0,0,-1,0], [-1,0,0,0], [0, 1,0,0]], #19 lu uf' f'l - - [[0,0, 1,0], [0, 1,0,0], [-1,0,0,0]], #20 l' - [[0,0, 1,0], [0,-1,0,0], [ 1,0,0,0]], #21 ffl' l'uu uul lff - [[0,0,-1,0], [0, 1,0,0], [ 1,0,0,0]], #22 l - [[0,0,-1,0], [0,-1,0,0], [-1,0,0,0]], #23 ffl luu uul' l'ff - ] - - rotation_symbolic = [ - "", # 0 empty - "ff", # 1 lluu uull - "ll", # 2 ffuu uuff - "uu", # 3 ffll llff - - "f", # 4 - "f'", # 5 - "fuu", # 6 uuf' f'll llf - "fll", # 7 llf' f'uu uuf - - "ffu", # 8 ull llu' u'ff - "u", # 9 - "u'", #10 - "ffu'", #11 u'll llu uff - - "fu", #12 ul lf - "f'u", #13 ul' l'f' - "fu'", #14 u'l' l'f - "f'u'", #15 u'l lf' - - "f'l'", #16 l'u' u'f' - "uf", #17 fl' l'u - "fl", #18 lu' u'f - "lu", #19 uf' f'l - - "l'", #20 - "ffl'", #21 l'uu uul lff - "l", #22 - "ffl", #23 luu uul' l'ff - ] - - @staticmethod - def coord_to_slice(coord, size): - assert -size < coord < size - return int(coord+size-1)//2 - - def format_block_compact(self): - assert self._blocks - res = '%s %d blocks_compact:' % (self.type, self.dimension) - # every block is stored as 4-tuple (x,y,z,rot), - # where rot is an index to a list of all (24) rotation matrices. - for block in self._blocks: - rot = self.rotation_matrices.index(block[:-1]) - x, y, z = [self.coord_to_slice(i, self.dimension) for i in block[3][:3]] - res += ' %d,%d,%d,%s' % (x, y, z, self.rotation_symbolic[rot]) - return res - - @staticmethod - def slice_to_coord(slice_, size): - assert 0 <= slice_ < size, (slice_, size) - return float(slice_ * 2 - size + 1) - - def parse_block(self, code): - tdf, blocks = code.split(':', 1) - t, d, f = tdf.split(' ', 2) - if t != 'Cube': - raise ParseBlockException('Unknown model type: {}'.format(t)) - self._dimension = int(d) - if f == 'identity': - #self._blocks = 1 - self.set_solved() - assert self._blocks - return - if f != 'blocks_compact': - raise ParseBlockException('Unknown data format: {}'.format(f)) - blocks = blocks.strip().split(' ') - if len(blocks) != self._dimension**3: - raise ParseBlockException('Wrong block count: {}, expected: {}'.format( - len(blocks), self._dimension**3)) - for i, block in enumerate(blocks): - block = block.strip().split(',') - if len(block) != 4: - raise ParseBlockException('Wrong block size: {}, expected: {}'.format( - len(block), 4)) - rot = self.rotation_symbolic.index(block[3]) - for j in range(3): - block[j] = self.slice_to_coord(int(block[j]), self._dimension) - block[3] = 1 - blocks[i] = self.rotation_matrices[rot] + [block] - self._blocks = blocks - self._faces = None - - def randomize_and_apply(self): - assert self._dimension - self._set_cube_dimension() - - debug('random moves:', 20*self._dimension) - for unused_i in xrange(20 * self._dimension): - axis = self.rand.randrange(3) - dir_ = self.rand.randrange(2) - if self._dimension > 1 and self._dimension & 1: - slice_ = self.rand.randrange(self._dimension - 1) - if slice_ >= self._dimension // 2: - slice_ += 1 - else: - slice_ = self.rand.randrange(self._dimension) - self._rotate_slice(axis, slice_, dir_) - - def rotate_slice(self, move_data): - self._rotate_slice(move_data.axis, move_data.slice, move_data.dir) - - def rotate_slice_back(self, move_data): - self._rotate_slice(move_data.axis, move_data.slice, not move_data.dir) - - diff -Nru pybik-0.5/pybiklib/cubestate.py pybik-1.0.1/pybiklib/cubestate.py --- pybik-0.5/pybiklib/cubestate.py 1970-01-01 00:00:00.000000000 +0000 +++ pybik-1.0.1/pybiklib/cubestate.py 2012-12-07 07:48:41.000000000 +0000 @@ -0,0 +1,277 @@ +#-*- coding:utf-8 -*- + +# Pybik -- A 3 dimensional magic cube game. +# Copyright © 2009-2012 B. Clausius +# +# 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 . + +from __future__ import print_function, division, unicode_literals + +import random +from copy import deepcopy + +from .debug import * # pylint: disable=W0614,W0401 + + +# This class is currently used to store the initial state of the cube +# and to provide the cube to plugins. +class CubeState (object): + rand = random.Random() + if DEBUG_RAND: + print('rand.seed(123)') + rand.seed(123) + + def __init__(self, model): + self.model = model + self._blocksn = None + + def copy(self): + other = CubeState(self.model) + other._blocksn = deepcopy(self._blocksn) + return other + + @property + def type(self): + return self.model.type + @property + def size(self): + return self.model.size + @property + def blocks(self): + assert self._blocksn is not None + blocks = [self.model.rotation_symbolic_to_matrix(*blockn) + for blockn in self._blocksn] + return blocks + + def set_model(self, model): + assert self.model.type == model.type + assert self.model.sizes == model.sizes + self.model = model + + def set_solved(self): + # '' symbolic rotation for identity + self._blocksn = [(i, '') for i, unused_block in enumerate(self.model.blocks)] + + def is_solved(self): + '''Check whether the cube is solved. + + Only test the colors of the visible faces. + Cubes with rotated center faces are treated as solved. + ''' + face_colors = {} + for index, (unused_pos, rot) in enumerate(self._blocksn): + for face in self.model.blocks[index].visible_faces: + color = self.get_colorsymbol(index, face.lower()) + try: + color_ref = face_colors[face] + except KeyError: + face_colors[face] = color + else: + if color != color_ref: + return False + return True + + def is_solved_strict(self): + '''Check whether the cube is solved. + + Test the rotation and position of the blocks. + Cubes with rotated center faces are treated as not solved. + ''' + #FIXME: currently unused function, should be used for faces with images + allrot = self._blocksn[0][1] + for index, (pos, rot) in enumerate(self._blocksn): + if rot != allrot: + return False # Cubie rotated + block = self.model.rotated_position[index, rot] + if pos != block: + return False # Cubie at wrong place + return True + + def identify_rotation_blocks(self, maxis, mslice): + assert self._blocksn + if mslice == -1: + for i in range(len(self._blocksn)): + yield i, True + else: + for i, blockn in enumerate(self._blocksn): + bslice = self.model.blocks[blockn[0]].axis_to_slice(maxis) + yield i, bslice == mslice + + def _rotate_slice(self, axis, slice_, dir_): + assert self._blocksn + + if DEBUG_ROTATE: + print('rotate axis={} slice={} dir={!s:5}\n blocks:'.format(axis, slice_, dir_), end=' ') + for block_id, selected in self.identify_rotation_blocks(axis, slice_): + if selected: + if DEBUG_ROTATE: + print('{}:{}{}'.format(block_id, *self._blocksn[block_id]), end='') + block = self.model.rotate_symbolic(axis, dir_, *self._blocksn[block_id]) + if DEBUG_ROTATE: + print('-{}{}'.format(*block), end=' ') + self._blocksn[block_id] = block + if DEBUG_ROTATE: + print() + + def get_colorsymbol(self, blocknum, facesym): + for pos, rot in self._blocksn: + if pos == blocknum: + return self.model.face_symbolic_to_face_color(facesym, rot) + assert False, 'Should not be reached' + + def get_colornum(self, blocknum, facesym): + #FIXME: face and color symbols should be upper + colorsym = self.get_colorsymbol(blocknum, facesym.lower()) + return self.model.faces.index(colorsym.upper()) + + def format_block(self): + assert self._blocksn is not None + # every block is stored as pos-sym, where sym is a symbolic rotation + blocks = ['{}-{}'.format(pos, sym) for pos, sym in self._blocksn] + return 'idx-rot: ' + ' '.join(blocks) + + def parse_block(self, blocks): + if blocks == 'solved': + return self.set_solved() + bformat, blocks = blocks.split(':', 1) + if bformat != 'idx-rot': + raise ValueError('unknown block format:', bformat) + blocks = blocks.strip().split(' ') + if len(blocks) != len(self.model.blocks): + raise ValueError('wrong block count: %s, expected: %s' % (len(blocks), len(self.model.blocks))) + blocksn = [] + for block in blocks: + # every block is stored as idx-rot, where idx: index to blocklist, rot: symbolic rotation + block = block.strip().split('-', 1) + index, rot = block + index = int(index) + rot = self.model.norm_symbol(rot) + blocksn.append((index, rot)) + # test whether block indices is a permutation, + # in fact thats not enough, e.g. swap a corner cubie with an edge, + # also cubie rotation may be invalid, it can be possible that a + # label is rotated inside the cube. + for i1, i2 in enumerate(sorted(i for i, r in blocksn)): + if i1 != i2: + raise ValueError('block list is not a permutation') + self._blocksn = blocksn + + def randomize(self, count=-1): + if not sum(self.model.sizes): + return + if count >= 0: + midslice = -1 + count_ = count + else: + midslice = [s // 2 for s in self.model.sizes] + count_ = 20 * sum(self.model.sizes) + cubemoves = [] + debug('random moves:', count_) + lastaxis = None + lastslices = [] + for unused_i in xrange(count_): + while True: + maxis = self.rand.randrange(3) + mdir = bool(self.rand.randrange(2)) + msign = -1 if mdir else 1 + mslice = self.rand.randrange(self.model.sizes[maxis]) + if maxis != lastaxis: + lastaxis = maxis + lastslices = [0] * self.model.sizes[maxis] + lastslices[mslice] = msign + break # subsequent different axes are accepted + nslices = lastslices[mslice] + msign + if abs(nslices) < abs(lastslices[mslice]): + continue # moves that revert a previous one are rejected + if abs(nslices * self.model.symmetry[maxis]) > 180.: + continue # moves that rotate a slice more than 180° are rejected + lastslices[mslice] += msign + if (sum(1 for ls in lastslices if ls > 0 or ls * self.model.symmetry[maxis] == -180.) + > self.model.sizes[maxis] // 2): + lastslices[mslice] -= msign + continue + if (sum(1 for ls in lastslices if ls < 0 or ls * self.model.symmetry[maxis] == 180.) + > self.model.sizes[maxis] // 2): + lastslices[mslice] -= msign + continue + break + if mslice == midslice: + cubemoves.append((maxis, mdir)) + self._rotate_slice(maxis, mslice, mdir) + for maxis, mdir in reversed(cubemoves): + self._rotate_slice(maxis, -1, not mdir) + + def rotate_slice(self, move_data): + self._rotate_slice(*move_data) + + def swap_block(self, blockpos1, maxis, mslice, mdir): + if DEBUG_ROTATE: + print('rotate axis={} slice={} dir={!s:5}\n from:'.format(maxis, mslice, mdir), end=' ') + + for blockidx1, (pos, blockrot1) in enumerate(self._blocksn): + if pos == blockpos1: + break + else: + blockidx1 = blockrot1 = None + assert False + blockpos1r, blockrot1r = self.model.rotate_symbolic(maxis, mdir, blockpos1, blockrot1) + if DEBUG_ROTATE: + print('{}:{}{}->{}{}\n to:'.format(blockidx1, blockpos1, blockrot1, + blockpos1r, blockrot1r), end=' ') + for blockidx2, unused_selected in self.identify_rotation_blocks(maxis, mslice): + blockpos2, blockrot2 = self._blocksn[blockidx2] + if blockpos1r == blockpos2: + self._blocksn[blockidx1] = blockpos1r, blockrot1r + blockpos2r, blockrot2r = self.model.rotate_symbolic(maxis, not mdir, blockpos2, blockrot2) + if DEBUG_ROTATE: + print('{}:{}{}->{}{}'.format(blockidx2, blockpos2, blockrot2, + blockpos2r, blockrot2r), end=' ') + self._blocksn[blockidx2] = blockpos2r, blockrot2r + break + if DEBUG_ROTATE: + print() + + def rotate_block(self, blockpos, rdir): + for blockidx, (pos, blockrot) in enumerate(self._blocksn): + if pos == blockpos: + break + else: + blockidx = blockrot = None + assert False + block = self.model.blocks[blockpos] + try: + rot = block.inplace_rotations[-1 if rdir else 0] + except IndexError: + # not every block can be rotated inline: e.g. edges and center faces on the 4×4×4-Cube, + # edges and corners on towers and bricks + #TODO: swap edge at pos n with the one at pos (size-1 - n), + # rotate all center faces on the same ring + return + blockrot2 = self.model.norm_symbol(blockrot + rot) + self._blocksn[blockidx] = blockpos, blockrot2 + if DEBUG_ROTATE: + sym1, colorsym1 = self.model.block_index_to_block_symbolic(blockpos, blockrot) + sym2, colorsym2 = self.model.block_index_to_block_symbolic(blockpos, blockrot2) + print('{}:{}{}->{}{} ({}:{}->{}:{})'.format(blockidx, blockpos, blockrot, blockpos, blockrot2, + sym1, colorsym1, sym2, colorsym2)) + self.debug_blocksymbols(allsyms=False) + + def debug_blocksymbols(self, allsyms): + for blockpos, blockrot in self._blocksn: + blocksym, colorsym = self.model.block_index_to_block_symbolic(blockpos, blockrot) + if allsyms or blocksym != colorsym: + print(' {}:{}'.format(blocksym, colorsym), end='') + print('') + + diff -Nru pybik-0.5/pybiklib/debug.py pybik-1.0.1/pybiklib/debug.py --- pybik-0.5/pybiklib/debug.py 2011-12-25 15:14:30.000000000 +0000 +++ pybik-1.0.1/pybiklib/debug.py 2012-12-13 06:18:55.000000000 +0000 @@ -1,7 +1,7 @@ #-*- coding:utf-8 -*- # Pybik -- A 3 dimensional magic cube game. -# Copyright © 2009-2011 B. Clausius +# Copyright © 2009-2012 B. Clausius # # 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 @@ -16,23 +16,35 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -from __future__ import print_function +from __future__ import print_function, division, unicode_literals -__all__ = ['error', 'debug', 'debug_func', 'DEBUG_LEVEL', - 'DEBUG_FUNC', 'DEBUG_MSG', 'DEBUG_ROTATE', - 'DEBUG_DRAW', 'DEBUG_KEYS', 'DEBUG_TEST', 'DEBUG_PICK'] +import sys + + +DEBUG = False +DEBUG_FUNC = DEBUG_MSG = DEBUG_RAND = DEBUG_ROTATE = False +DEBUG_DRAW = DEBUG_KEYS = DEBUG_TEST = DEBUG_PICK = False +DEBUG_FPS = DEBUG_VFPS = DEBUG_NOLABEL = DEBUG_NOBEVEL = DEBUG_INNER = False +DEBUG_ALG = False + +__all__ = ['error', 'debug', 'debug_func', 'DEBUG', + ] + [__n for __n in dir(sys.modules[__name__]) if __n.startswith('DEBUG_')] def error(*args, **kwargs): print('ERROR:', *args, **kwargs) debug = lambda *args, **kwargs: None debug_func = lambda x: x -DEBUG_LEVEL = 0 -DEBUG_FUNC = DEBUG_MSG = DEBUG_ROTATE = DEBUG_DRAW = DEBUG_KEYS = DEBUG_TEST = DEBUG_PICK = False -def install(module, debug_modes): - for m, v in debug_modes.items(): - setattr(module, m, v) +def set_flags(debug_flags): + module = sys.modules[__name__] + module.DEBUG = True + + for flag in debug_flags: + setattr(module, 'DEBUG_' + flag.upper(), True) + + if module.DEBUG_VFPS: + module.DEBUG_FPS = True if module.DEBUG_FUNC: def _debug_pre_func(func, *args, **kwargs): @@ -42,18 +54,22 @@ if len(arg) > maxlen: return arg[:maxlen] return arg - print('%s--%s' % (' |'*debug_func.indent, func.func_name)) + try: + func_name = func.func_name + except AttributeError: + func_name = func.__name__ + print('%s--%s' % (' |'*debug_func.indent, func_name)) debug_func.indent += 1 for arg in args: try: print('%s: %s' % (' |'*debug_func.indent, short_arg(arg))) - except: - pass + except Exception: + pass for kw, arg in kwargs: try: print('%s: %s=%s' % (' |'*debug_func.indent, kw, short_arg(arg))) - except: - pass + except Exception: + pass def debug_func(func): def ret_func(*args, **kwargs): _debug_pre_func(func, *args, **kwargs) @@ -67,11 +83,17 @@ finally: debug_func.indent -= 1 print(' |'*debug_func.indent + "--'") - ret_func.__dict__ = func.__dict__ + try: + ret_func.__dict__ = func.__dict__ + except AttributeError: + pass ret_func.__doc__ = func.__doc__ ret_func.__module__ = func.__module__ ret_func.__name__ = func.__name__ - ret_func.func_defaults = func.func_defaults + try: + ret_func.func_defaults = func.func_defaults + except AttributeError: + pass return ret_func debug_func.indent = 0 debug_func.last_exc = None diff -Nru pybik-0.5/pybiklib/dialogcolors.py pybik-1.0.1/pybiklib/dialogcolors.py --- pybik-0.5/pybiklib/dialogcolors.py 2012-01-02 05:30:00.000000000 +0000 +++ pybik-1.0.1/pybiklib/dialogcolors.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,237 +0,0 @@ -#-*- coding:utf-8 -*- - -# Pybik -- A 3 dimensional magic cube game. -# Copyright © 2009, 2011-2012 B. Clausius -# -# 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 . - - -# Ported from GNUbik -# Original filename: colour-sel.c -# Original copyright and license: 2003 John Darrington, GPL3+ - - -import gobject -import gtk -from gtk import gdk - -from .debug import * -from . import textures -from .confstore import confstore, UNDEFINED, COLORED, IMAGED, TILED, MOSAIC - - -BOX_PADDING = 10 - - -@debug_func -def colorselect_dialog(application): - if ColorSelectDialog.this_dlg is None: - ColorSelectDialog(application) - ColorSelectDialog.this_dlg.run() - - -class ColorSelectDialog (object): - this_dlg = None - - def __init__(self, application): - assert self.this_dlg == None - ColorSelectDialog.this_dlg = self - - self.dialog = application.ui_xml.get_object('dialog_edit_colors') - self.dialog.connect ("response", lambda w, r: w.hide()) - self.dialog.connect ("delete-event", lambda *a: True) - - self.active_face = [0] - self.create_face_selector(application) - - self.button_color = application.ui_xml.get_object('colorbutton_face') - self.button_color.connect ("color-set", self.on_button_color_set) - - self.create_pattern_selector(application) - - self.button_image = application.ui_xml.get_object('filechooserbutton_image') - self.button_image.connect ("file-set", self.on_button_image_file_set) - self.button_image_tile = application.ui_xml.get_object('radiobutton_tile') - self.button_image_mosaic = application.ui_xml.get_object('radiobutton_mosaic') - self.button_image_tile.connect ("toggled", self.on_button_image_distr_toggled, TILED) - self.button_image_mosaic.connect ("toggled", self.on_button_image_distr_toggled, MOSAIC) - self.button_image_group = gtk.RadioButton.get_group (self.button_image_mosaic) - - self.button_background = application.ui_xml.get_object('button_background') - self.button_background.set_color(gdk.Color(confstore.background_color)) - - self.permit_callbacks = True - - #self.dialog.show_all() - confstore.callbacks.append(self.on_confstore_changed) - - def run(self): - assert self.this_dlg - self.dialog.show_all() - i = self.active_face[0] - self.treeview_faces.set_cursor(i) - - def create_face_selector(self, application): - self.liststore_faces = gtk.ListStore( - gobject.TYPE_INT, # 0 FaceNum - gobject.TYPE_STRING, # 1 FaceName - gdk.Pixbuf, # 2 Swatch - ) - face_names = [_('Up'), _('Down'), _('Left'), _('Right'), _('Front'), _('Back')] - for i in xrange(6): - self.liststore_faces.append((i, face_names[i], None,)) - - self.treeview_faces = application.ui_xml.get_object('treeview_faces') - self.treeview_faces.set_model(self.liststore_faces) - - #column = gtk.TreeViewColumn(_('Face'), gtk.CellRendererPixbuf(), pixbuf=2) - #column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) - #column.set_fixed_width(SWATCH_WIDTH_SMALLEST) - #self.treeview_faces.append_column(column) - pass - column = gtk.TreeViewColumn(_('Face'), gtk.CellRendererText(), text=1) - column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) - column.set_fixed_width(50) - self.treeview_faces.append_column(column) - self.treeview_faces.connect("cursor-changed", self.on_treeview_faces_cursor_changed) - - def create_pattern_selector(self, application): - liststore = gtk.ListStore( gobject.TYPE_INT, gobject.TYPE_INT, gdk.Pixbuf, gobject.TYPE_STRING) - #data = ''.join(chr(255)*8 for c in textures.stock_pattern[0].data) - #data = [((ord(c)>>(_i%8))&1)*255 for _i,c in enumerate(data)] - #data = ''.join(chr(c)*3+chr(255) for c in data) - #pixbuf = gdk.pixbuf_new_from_data(data, gdk.COLORSPACE_RGB, True, 8, - # textures.checkImageWidth, textures.checkImageHeight, - # textures.checkImageWidth*4) - pass - liststore.append((-1, 3, None, _('plain'))) - for i in xrange(6): - data = ''.join(chr(c)*8 for c in textures.stock_pattern[i].data) - data = [((ord(c)>>(_i%8))&1)*255 for _i, c in enumerate(data)] - data = ''.join(chr(c)*3+chr(255) for c in data) - pixbuf = gdk.pixbuf_new_from_data(data, gdk.COLORSPACE_RGB, True, 8, - textures.checkImageWidth, textures.checkImageHeight, - textures.checkImageWidth*4) - liststore.append((i, 1, pixbuf, None)) - - self.combobox_pattern = application.ui_xml.get_object('combobox_pattern') - - cr1 = gtk.CellRendererPixbuf() - self.combobox_pattern.pack_end(cr1) - cr2 = gtk.CellRendererText() - self.combobox_pattern.pack_end(cr2) - - self.combobox_pattern.set_model(liststore) - self.combobox_pattern.set_attributes(cr1, pixbuf=2) - self.combobox_pattern.set_attributes(cr2, text=3) - self.combobox_pattern.set_column_span_column(1) - self.combobox_pattern.connect ("changed", self.on_combobox_pattern_changed) - self.combobox_pattern.set_tooltip_text("Click here to use a pattern on the cube surface") - - - @debug_func - def on_treeview_faces_cursor_changed(self, widget): - path = widget.get_cursor()[0] - assert path - self.active_face = widget.get_model()[path] - face_num = path[0] - - self.permit_callbacks = False - self.button_color.set_color(gdk.Color(confstore.colors[face_num].color)) - self.combobox_pattern.set_active(confstore.colors[face_num].pattern+1) - image_file = confstore.colors[face_num].imagefile - if image_file: - self.button_image.set_filename(image_file) - else: - self.button_image.unselect_all() - distr_mode = confstore.colors[face_num].imagemode - self.button_image_tile.set_active(distr_mode==TILED) - self.button_image_mosaic.set_active(distr_mode==MOSAIC) - self.permit_callbacks = True - - - def on_confstore_changed(self, key, *subkeys): - self.permit_callbacks = False - if key == 'colors': - i = int(subkeys[0]) - if subkeys[1] == 'color': - self.button_color.set_color(gdk.Color(confstore.colors[i].color)) - elif subkeys[1] == 'pattern': - #self.button_color.set_value(confstore.colors[i].pattern) - pattern = confstore.colors[i].pattern - self.combobox_pattern.set_active(pattern+1) - elif subkeys[1] == 'imagefile': - image_file = confstore.colors[i].imagefile - if image_file: - self.button_image.set_filename(image_file) - else: - self.button_image.unselect_all() - elif subkeys[1] == 'imagemode': - imagemode = confstore.colors[i].imagemode - self.button_image_tile.set_active(imagemode==TILED) - self.button_image_mosaic.set_active(imagemode==MOSAIC) - elif key == 'background_color': - self.button_background.set_color(gdk.Color(confstore.background_color)) - self.permit_callbacks = True - - def on_button_color_set(self, button): - if self.permit_callbacks: - color = button.get_color() - confstore.set_color(self.active_face[0], color) - - @debug_func - def on_combobox_pattern_changed(self, widget): - if self.permit_callbacks: - active_iter = widget.get_active_iter() - if active_iter: - pattern = widget.get_model()[active_iter][0] - i = self.active_face[0] - confstore.colors[i].pattern = pattern - confstore.colors[i].facetype = COLORED - - def on_button_image_file_set(self, widget): - if self.permit_callbacks: - filename = widget.get_filename() - confstore.set_image_filename(self.active_face[0], filename) - - def on_button_image_distr_toggled(self, b, distr): - if self.permit_callbacks: - if not gtk.ToggleButton.get_active (b): - return - i = self.active_face[0] - confstore.colors[i].imagemode = distr - confstore.colors[i].facetype = IMAGED - - def get_pixbuf_for_swatch(self, i, size): - if confstore.colors[i].facetype == COLORED: - #FIXME - return None - elif confstore.colors[i].facetype == IMAGED: - width, height = size, size - pixbuf = textures.create_pixbuf_from_file(confstore.colors[i].imagefile) - assert pixbuf - scaled_pixbuf = pixbuf.scale_simple(width, height, gdk.INTERP_NEAREST) - assert scaled_pixbuf - return scaled_pixbuf - else: - #FIXME - #assert False, 'not_reached' - return None - - def redraw_swatches(self): - #for i in xrange(6): - #self.draw_swatch (self.swatches[i], None, i) - #FIXME update pixbufs in liststore - pass - diff -Nru pybik-0.5/pybiklib/dialogs.py pybik-1.0.1/pybiklib/dialogs.py --- pybik-0.5/pybiklib/dialogs.py 2012-01-04 03:34:06.000000000 +0000 +++ pybik-1.0.1/pybiklib/dialogs.py 2012-12-15 09:59:31.000000000 +0000 @@ -16,128 +16,624 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . - # Ported from GNUbik # Original filename: menus.c # Original copyright and license: 2003, 2004 John Darrington, GPL3+ +# pylint: disable=C0321 +from __future__ import print_function, division, unicode_literals -import gtk -from gtk import gdk +import os +import re -from . import config -from .confstore import confstore, SELECTIONMODE_QUAD, SELECTIONMODE_EXT +# pylint: disable=W0614,W0401 +from PySide.QtCore import * +from PySide.QtGui import * +from .debug import * +# pylint: enable=W0614,W0401 +from . import config +from .settings import settings +from .textures import textures +from .model import models + +try: + _ +except NameError: + _ = lambda t: t + -_preferences_dialog = None -def preferences_dialog(application): - global _preferences_dialog - if _preferences_dialog is None: - _preferences_dialog = PreferencesDialog(application) - _preferences_dialog.run() - -class PreferencesDialog (object): - def __init__(self, application): - self.dialog = application.ui_xml.get_object('dialog_preferences') - self.dialog.connect("response", self.on_dialog_preferences_response, application) - self.dialog.connect("delete-event", lambda *a: True) - - self.application = application - self.permit_callbacks = False - - self.button_size = application.ui_xml.get_object('button_size') - self.button_size.set_value(confstore.dimension) - self.button_size.connect("changed", self.on_size_changed) - - self.hscale_animspeed = application.ui_xml.get_object('hscale_animspeed') - self.hscale_animspeed.set_value(confstore.frameQty) - self.hscale_animspeed.connect("value-changed", self.on_hscale_animspeed_value_changed) - - self.button_lighting = application.ui_xml.get_object('button_lighting') - self.button_lighting.set_active(confstore.lighting) - self.button_lighting.connect("toggled", self.on_button_lighting_toggled) - - self.button_mousemode_quad = application.ui_xml.get_object('radiobutton_quad') - self.button_mousemode_ext = application.ui_xml.get_object('radiobutton_ext') - self.set_selection_mode(confstore.selection_mode) - self.button_mousemode_quad.connect("toggled", self.on_button_mousemode_toggled, SELECTIONMODE_QUAD) - self.button_mousemode_ext.connect("toggled", self.on_button_mousemode_toggled, SELECTIONMODE_EXT) - for name in ['image_mousemode_quad', 'image_mousemode_ext']: - image = application.ui_xml.get_object(name) - pixbuf = image.get_pixbuf().scale_simple(64, 64, gdk.INTERP_BILINEAR) - image.set_from_pixbuf(pixbuf) - - self.permit_callbacks = True - confstore.callbacks.append(self.on_confstore_changed) - - def run(self): - self.dialog.show_all() - - def set_selection_mode(self, mode): - if confstore.selection_mode == SELECTIONMODE_QUAD: - self.button_mousemode_quad.set_active(True) - elif confstore.selection_mode == SELECTIONMODE_EXT: - self.button_mousemode_ext.set_active(True) - - def on_confstore_changed(self, key, *unused_subkeys): - self.permit_callbacks = False - if key == 'dimension': - self.button_size.set_value(confstore.dimension) - elif key == 'frameQty': - self.hscale_animspeed.set_value(confstore.frameQty) - elif key == 'lighting': - self.button_lighting.set_active(confstore.lighting) - elif key == 'selection_mode': - self.set_selection_mode(confstore.selection_mode) - self.permit_callbacks = True - - def on_dialog_preferences_response(self, unused_dialog, response, application): - if (confstore.dimension != application.current_movement.current_cube_state.dimension - and response == 0): - dialog = gtk.MessageDialog(application.window, - gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, - gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO, - _("The Dimension of the cube has changed.\nStart cube with new settings?")) - def on_response(dialog, response, application): - if response == gtk.RESPONSE_YES: - application.request_new_game(None, confstore.dimension) - dialog.destroy() - dialog.connect("response", on_response, application) - dialog.show_all() - self.dialog.hide() - - def on_size_changed(self, editable): - if self.permit_callbacks: - str_ = editable.get_chars(0, -1) - confstore.dimension = int(str_ or 1) - - def on_hscale_animspeed_value_changed(self, widget): - if self.permit_callbacks: - confstore.frameQty = int(widget.get_value()) - - def on_button_lighting_toggled(self, toggle_button): - if self.permit_callbacks: - confstore.lighting = toggle_button.get_active() - - def on_button_mousemode_toggled(self, button, mode): - if button.get_active(): - confstore.selection_mode = mode +class Dialog (QDialog): + _instance = None + _classes = [] + + def __init__(self, parent, ui): + QDialog.__init__(self, parent) + self.ui = ui + self.ui.setupUi(self) + self.accepted.connect(self.on_response) + self._ignore_changed = False + self.bound = {} + settings.keystore.changed.connect(self.on_settings_changed, Qt.QueuedConnection) + + @classmethod + def run(cls, parent_window=None): + if cls._instance is None: + cls._instance = cls(parent_window) + ret = cls._instance + cls._classes.append(cls) + else: + ret = None + cls._instance.move(cls._instance.pos()) + cls._instance.show() + return ret + + @classmethod + def delete(cls): + for cls_ in cls._classes: + # pylint: disable=W0212 + cls_._instance.close() + cls_._instance.deleteLater() + # pylint: enable=W0212 + cls_._instance = None - + def bind(self, key, widget, getter, setter, signal): + if isinstance(getter, basestring): getter = getattr(widget, getter) + if isinstance(setter, basestring): setter = getattr(widget, setter) + if isinstance(signal, basestring): signal = getattr(widget, signal) + setter(getattr(settings, key)) + if signal is not None: + signal.connect(lambda: self.on_widget_changed(key)) + self.bound[key] = (getter, setter, signal) + + @staticmethod + def bind_reset(settings_key, button): + button.clicked.connect(lambda: delattr(settings, settings_key)) + + def on_response(self): + pass + + def on_widget_changed(self, key): + if self._ignore_changed: + return + try: + getter = self.bound[key][0] + except KeyError: + return + self._ignore_changed = True + setattr(settings, key, getter()) + self._ignore_changed = False + + def on_settings_changed(self, key): + if self._ignore_changed: + return + try: + setter = self.bound[key][1] + except KeyError: + return + self._ignore_changed = True + setter(getattr(settings, key)) + self._ignore_changed = False + + +class ColorIconEngine (QIconEngineV2): + def __init__(self): + QIconEngineV2.__init__(self) + self.color = 'black' + + def paint(self, painter, rect, unused_mode, unused_state): + painter.fillRect(rect, QColor(self.color)) + + +class ColorButton (QPushButton): + color_changed = Signal(str) + + def __init__(self, replace_button): + self._icon = ColorIconEngine() + parent = replace_button.parentWidget() + QPushButton.__init__(self, QIcon(self._icon), '', parent) + height = self.iconSize().height() + self.setIconSize(QSize(height * self.width() // self.height(), height)) + self.setSizePolicy(replace_button.sizePolicy()) + self.setObjectName(replace_button.objectName()) + + layout = replace_button.parentWidget().layout() + index = layout.indexOf(replace_button) + position = layout.getItemPosition(index) + layout.removeWidget(replace_button) + layout.addWidget(self, *position) + replace_button.deleteLater() + self.clicked.connect(self.on_clicked) + + def set_color(self, color): + self._icon.color = color + self.update() + + def get_color(self): + return self._icon.color + + def on_clicked(self): + dialog = QColorDialog(self) + dialog.setCurrentColor(QColor(self.get_color())) + if dialog.exec_() == QDialog.Accepted: + color = dialog.currentColor().name() + self.set_color(color) + self.color_changed.emit(color) + + +class ShortcutEditor (QLabel): + key_pressed = Signal() + + def __init__(self, parent): + QLabel.__init__(self, _(u'Press a key …'), parent) + self.setFocusPolicy(Qt.StrongFocus) + self.setAutoFillBackground(True) + self.key = None + + SAFE_MODIFIER_MASK = Qt.ShiftModifier | Qt.ControlModifier + IGNORE_KEYS = [Qt.Key_Shift, Qt.Key_Control, Qt.Key_Meta, Qt.Key_Alt, Qt.Key_AltGr, + Qt.Key_CapsLock, Qt.Key_NumLock, Qt.Key_ScrollLock] + + def keyPressEvent(self, event): + if event.key() in self.IGNORE_KEYS or event.count() != 1: + return QLabel.keyPressEvent(self, event) + mod = event.modifiers() & self.SAFE_MODIFIER_MASK + key = QKeySequence(event.key() | mod).toString().split('+') + if event.modifiers() & Qt.KeypadModifier: + key.insert(-1, 'KP') + self.key = '+'.join(key) + self.key_pressed.emit() + + +class ShortcutDelegate (QStyledItemDelegate): + def __init__(self, parent): + QStyledItemDelegate.__init__(self, parent) + + def createEditor(self, parent, unused_option, unused_index): + editor = ShortcutEditor(parent) + editor.key_pressed.connect(self.on_editor_key_pressed) + return editor + + def setEditorData(self, editor, index): + pass + + def setModelData(self, editor, model, index): + if editor.key is not None: + model.setData(index, editor.key, Qt.DisplayRole) + + def on_editor_key_pressed(self): + editor = self.sender() + self.commitData.emit(editor) + self.closeEditor.emit(editor, QAbstractItemDelegate.NoHint) + + +class PreferencesDialog (Dialog): + accum_buffers = False + sample_buffers = 0 + + def __init__(self, parent): + from .ui.preferences import Ui_DialogPreferences + Dialog.__init__(self, parent, Ui_DialogPreferences()) + + self.ui.button_animspeed_reset.setIcon(QIcon.fromTheme('edit-clear')) + self.ui.button_lighting_reset.setIcon(QIcon.fromTheme('edit-clear')) + self.ui.button_antialiasing_reset.setIcon(QIcon.fromTheme('edit-clear')) + self.ui.button_mirror_faces_reset.setIcon(QIcon.fromTheme('edit-clear')) + self.ui.button_movekey_add.setIcon(QIcon.fromTheme('list-add')) + self.ui.button_movekey_remove.setIcon(QIcon.fromTheme('list-remove')) + self.ui.button_movekey_reset.setIcon(QIcon.fromTheme('document-revert')) + self.ui.button_color_reset.setIcon(QIcon.fromTheme('edit-clear')) + self.ui.button_image_reset.setIcon(QIcon.fromTheme('edit-clear')) + self.ui.button_background_color_reset.setIcon(QIcon.fromTheme('edit-clear')) + self.ui.button_mousemode_quad.setIcon(QIcon(os.path.join(config.UI_DIR, "mousemode-quad.png"))) + self.ui.button_mousemode_ext.setIcon(QIcon(os.path.join(config.UI_DIR, "mousemode-ext.png"))) + + self.ui.buttonBox.button(QDialogButtonBox.Close).setDefault(True) + self.ui.label_needs_restarted.setVisible(False) + + # graphic tab + self.ui.slider_animspeed.setValue(settings.draw.speed) + self.ui.slider_animspeed.setRange(*settings.draw.speed_range) + self.bind('draw.speed', self.ui.slider_animspeed, 'value', 'setValue', 'valueChanged') + self.bind_reset('draw.speed', self.ui.button_animspeed_reset) + + self.bind('draw.lighting', self.ui.checkbox_lighting, 'isChecked', 'setChecked', 'toggled') + self.bind_reset('draw.lighting', self.ui.button_lighting_reset) + + for text in settings.draw.accum_range: + self.ui.combobox_antialiasing.addItem(_(text), text) + self.ui.combobox_antialiasing.setCurrentIndex(settings.draw.accum) + self.bind('draw.accum', self.ui.combobox_antialiasing, + 'currentIndex', 'setCurrentIndex', 'currentIndexChanged') + def reset_antialiasing(): + del settings.draw.accum + del settings.draw.samples + self.ui.button_antialiasing_reset.clicked.connect(reset_antialiasing) + for text in settings.draw.samples_range: + self.ui.combobox_samples.addItem(_(text), text) + self.ui.combobox_samples.setCurrentIndex(settings.draw.samples) + self.bind('draw.samples', self.ui.combobox_samples, + 'currentIndex', 'setCurrentIndex', 'currentIndexChanged') + + self.ui.spinbox_mirror_faces.setRange(*settings.draw.mirror_distance_range) + def set_mirror_faces(checked): + self.ui.checkbox_mirror_faces.setChecked(checked) + self.ui.spinbox_mirror_faces.setEnabled(checked) + self.bind('draw.mirror_faces', self.ui.checkbox_mirror_faces, 'isChecked', set_mirror_faces, 'toggled') + self.bind_reset('draw.mirror_faces', self.ui.button_mirror_faces_reset) + self.bind('draw.mirror_distance', self.ui.spinbox_mirror_faces, 'value', 'setValue', 'valueChanged') + self.bind_reset('draw.mirror_distance', self.ui.button_mirror_faces_reset) + + # mouse tab + def set_selection_mode(unused_mode): + if settings.draw.selection_nick == 'quadrant': + self.ui.button_mousemode_quad.setChecked(True) + elif settings.draw.selection_nick == 'simple': + self.ui.button_mousemode_ext.setChecked(True) + self.bind('draw.selection', None, None, set_selection_mode, None) + + # keys tab + self.liststore_movekeys = QStandardItemModel(self) + self.fill_liststore_movekeys() + self.ui.listview_movekeys.setModel(self.liststore_movekeys) + self.liststore_movekeys.itemChanged.connect(self.on_liststore_movekeys_itemChanged) + self.shortcut_delegate = ShortcutDelegate(self.ui.listview_movekeys) + self.ui.listview_movekeys.setItemDelegateForColumn(1, self.shortcut_delegate) + + # design tab + self.image_dirname = os.environ.get('HOME', '') #TODO: Use Picture folder, Qt5 has a class for that + self.active_face = 0 + self.liststore_faces = self.create_face_selector() + + self.button_color = ColorButton(self.ui.button_color) + self.ui.button_color = None + self.setTabOrder(self.ui.listview_faces, self.button_color) + self.button_color.color_changed.connect(self.on_button_color_color_changed) + self.button_background_color = ColorButton(self.ui.button_background_color) + self.ui.button_background_color = None + self.setTabOrder(self.ui.radiobutton_mosaic, self.button_background_color) + + self.ui.combobox_image.addItem(_('plain'), '') + for filename in textures.stock_files: + pixmap = QPixmap(textures.get_stock_pixbuf(filename)) + icon = QIcon(pixmap) + self.ui.combobox_image.addItem(icon, '', filename) + self.ui.combobox_image.addItem(_(u'select …'), '/') + + self.bind_reset_item('theme.face.{}.color', self.ui.button_color_reset) + self.bind_reset_item('theme.face.{}.image', self.ui.button_image_reset) + self.bind('theme.bgcolor', self.button_background_color, 'get_color', 'set_color', 'color_changed') + self.bind_reset('theme.bgcolor', self.ui.button_background_color_reset) + + index = self.liststore_faces.index(self.active_face, 1) + self.ui.listview_faces.setCurrentIndex(index) + + def create_face_selector(self): + liststore_faces = QStandardItemModel() + face_names = [_('Up'), _('Down'), _('Left'), _('Right'), _('Front'), _('Back')] + for i in xrange(6): + liststore_faces.appendRow((QStandardItem(i), QStandardItem(face_names[i]))) + filename = settings.theme.face[i].image + if filename.startswith('/'): + self.image_dirname = os.path.dirname(filename) + self.ui.listview_faces.setModel(liststore_faces) + self.ui.listview_faces.setModelColumn(1) + #XXX: workaround, listview_faces should automatically set to the correct width + fm = QFontMetrics(self.ui.listview_faces.font()) + width = max(fm.width(fn) for fn in face_names) + 8 + self.ui.listview_faces.setMaximumWidth(width) + self.ui.listview_faces.selectionModel().currentChanged.connect(self.on_listview_faces_currentChanged) + return liststore_faces + + def fill_liststore_movekeys(self): + for move, key in settings.draw.accels: + self.liststore_movekeys.appendRow([QStandardItem(move), QStandardItem(key)]) + self.liststore_movekeys.setHeaderData(0, Qt.Horizontal, _('Move')) + self.liststore_movekeys.setHeaderData(1, Qt.Horizontal, _('Key')) + + def bind_reset_item(self, settings_key, button): + def on_clicked(): + delattr(settings, settings_key.format(self.active_face)) + button.clicked.connect(on_clicked) + + @ staticmethod + def _accel_mods_to_str(accel_mods): + accel_str = '' + for a in accel_mods.value_nicks: + if accel_str: + accel_str += '+' + if a.endswith('-mask'): + a = a[:-5] + accel_str += a + return accel_str + + def set_imagefile(self, imagefile): + index_icon = len(textures.stock_files) + 1 + if not imagefile: + index = 0 + icon = QIcon() + elif imagefile.startswith('/'): + index = index_icon + icon = QIcon(imagefile) + else: + try: + index = textures.stock_files.index(imagefile) + 1 + except ValueError: + index = 0 + icon = QIcon() + self.ui.combobox_image.setItemIcon(index_icon, icon) + self.ui.combobox_image.setCurrentIndex(index) + + def on_settings_changed(self, key): + Dialog.on_settings_changed(self, key) + if self._ignore_changed: + return + self._ignore_changed = True + if key in ['draw.accum', 'draw.samples']: + if not self.accum_buffers and settings.draw.accum > 0: + visible = True + elif self.sample_buffers != 2**settings.draw.samples > 1: + visible = True + else: + visible = False + self.ui.label_needs_restarted.setVisible(visible) + elif key == 'draw.accels': + self.liststore_movekeys.clear() + self.fill_liststore_movekeys() + elif key == 'theme.face.{}.color'.format(self.active_face): + self.button_color.set_color(settings.theme.face[self.active_face].color) + elif key == 'theme.face.{}.image'.format(self.active_face): + self.set_imagefile(settings.theme.face[self.active_face].image) + elif key == 'theme.face.{}.mode': + imagemode = settings.theme.face[self.active_face].mode_nick + if imagemode == 'tiled': + self.ui.radiobutton_tiled.setChecked(True) + elif imagemode == 'mosaic': + self.ui.radiobutton_mosaic.setChecked(True) + self._ignore_changed = False + + ### + + @Slot(bool) + def on_checkbox_mirror_faces_toggled(self, checked): + self.ui.spinbox_mirror_faces.setEnabled(checked) + + ### mouse handlers ### + + def set_mousemode(self, checked, mode): + if self._ignore_changed: + return + if checked: + self._ignore_changed = True + settings.draw.selection_nick = mode + self._ignore_changed = False + + @Slot(bool) + def on_button_mousemode_quad_toggled(self, checked): + self.set_mousemode(checked, 'quadrant') + + @Slot(bool) + def on_button_mousemode_ext_toggled(self, checked): + self.set_mousemode(checked, 'simple') + + ### key handlers ### + + def get_move_key_list(self): + move_keys = [] + for i in range(self.liststore_movekeys.rowCount()): + move, key = [self.liststore_movekeys.item(i, j).data(Qt.DisplayRole) for j in (0, 1)] + move_keys.append((move, key)) + return move_keys + + @Slot() + def on_button_movekey_add_clicked(self): + row = self.ui.listview_movekeys.currentIndex().row() + self._ignore_changed = True + self.liststore_movekeys.insertRow(row, (QStandardItem(''), QStandardItem(''))) + index = self.liststore_movekeys.index(row, 0) + self.ui.listview_movekeys.setCurrentIndex(index) + self.ui.listview_movekeys.edit(index) + self._ignore_changed = False + + @Slot() + def on_button_movekey_remove_clicked(self): + row = self.ui.listview_movekeys.currentIndex().row() + self._ignore_changed = True + self.liststore_movekeys.takeRow(row) + settings.draw.accels = self.get_move_key_list() + self._ignore_changed = False + + @Slot() + def on_button_movekey_reset_clicked(self): # pylint: disable=R0201 + del settings.draw.accels + + def on_liststore_movekeys_itemChanged(self, unused_item): + self._ignore_changed = True + settings.draw.accels = self.get_move_key_list() + self._ignore_changed = False + + ### appearance handlers ### + + def on_listview_faces_currentChanged(self, current): + self.active_face = current.row() + self._ignore_changed = True + self.button_color.set_color(settings.theme.face[self.active_face].color) + self.set_imagefile(settings.theme.face[self.active_face].image) + imagemode = settings.theme.face[self.active_face].mode_nick + if imagemode == 'tiled': + self.ui.radiobutton_tiled.setChecked(True) + elif imagemode == 'mosaic': + self.ui.radiobutton_mosaic.setChecked(True) + self._ignore_changed = False + + def on_button_color_color_changed(self, color): + if self._ignore_changed: + return + self._ignore_changed = True + settings.theme.face[self.active_face].color = color + self._ignore_changed = False + + @Slot(int) + def on_combobox_image_activated(self, index): + if self._ignore_changed: + return + if index == 0: + filename = '' + else: + try: + filename = textures.stock_files[index-1] + except IndexError: + filename = QFileDialog.getOpenFileName(self, _("Open Image"), self.image_dirname) + if isinstance(filename, (tuple, list)): + filename = filename[0] + if filename == '': + # canceled, set the old image + filename = settings.theme.face[self.active_face].image + self.set_imagefile(filename) + else: + self.image_dirname = os.path.dirname(filename) + self._ignore_changed = True + settings.theme.face[self.active_face].image = filename + self._ignore_changed = False + + @Slot(bool) + def on_radiobutton_tiled_toggled(self, checked): + self.set_imagemode(checked, 'tiled') + @Slot(bool) + def on_radiobutton_mosaic_toggled(self, checked): + self.set_imagemode(checked, 'mosaic') + + def set_imagemode(self, checked, mode): + if self._ignore_changed: + return + if checked: + self._ignore_changed = True + settings.theme.face[self.active_face].mode_nick = mode + self._ignore_changed = False + + +class SelectModelDialog (Dialog): + response_ok = Signal(int, tuple, bool) + + def __init__(self, parent): + from .ui.model import Ui_DialogSelectModel + Dialog.__init__(self, parent, Ui_DialogSelectModel()) + + for text in settings.game.type_range: + self.ui.combobox_model.addItem(_(text), text) + mtype = settings.game.type + self.ui.combobox_model.setCurrentIndex(mtype) + self.on_combobox_model_activated(mtype) + size = settings.game.size + width, height, depth = size + self.ui.spin_size1.setValue(width) + self.ui.spin_size2.setValue(height) + self.ui.spin_size3.setValue(depth) + + @Slot(int) + def on_combobox_model_activated(self, index): + mtype = models[index].type + self.ui.label_width.setText({'Cube':_('Size:'), 'Tower':_('Basis:')}.get(mtype, _('Width:'))) + self.ui.label_width.setEnabled(mtype in ['Cube', 'Tower', 'Brick']) + self.ui.label_heigth.setEnabled(mtype in ['Tower', 'Brick']) + self.ui.label_depth.setEnabled(mtype == 'Brick') + self.ui.spin_size1.setEnabled(mtype in ['Cube', 'Tower', 'Brick']) + self.ui.spin_size2.setEnabled(mtype in ['Tower', 'Brick']) + self.ui.spin_size3.setEnabled(mtype == 'Brick') + + def on_response(self): + self.response_ok.emit( + self.ui.combobox_model.currentIndex(), + (self.ui.spin_size1.value(), self.ui.spin_size2.value(), self.ui.spin_size3.value()), + self.ui.checkbox_solved.isChecked()) + + +class ProgressDialog (QProgressDialog): + def __init__(self, parent): + QProgressDialog.__init__(self, parent) + self.canceled_ = False + self.value_max = 10 + self.value = 0 + self.setWindowModality(Qt.WindowModal) + self.setMaximum(self.value_max) + self.setMinimumDuration(0) + self.setAutoReset(False) + self.canceled.connect(self.on_canceled) + + def on_canceled(self): + self.canceled_ = True + self.setLabelText(_('Canceling operation, please wait')) + + def tick(self, step, message=None, value_max=None): + if not self.isVisible(): + self.show() + if message is not None: + self.setLabelText(message) + if value_max is not None: + self.value_max = value_max + self.value = 0 + self.setMaximum(value_max) + if step < 0 or self.value > self.value_max: + self.setValue(0) + self.setMaximum(0) + else: + self.setValue(self.value) + self.value += step + return self.canceled_ + + def done(self): + self.canceled_ = False + self.reset() + +def linkedtext_to_html(text): + html = QTextDocumentFragment.fromPlainText(text).toHtml() + html = re.sub(r'<((?:http:|https:|text:).*?)\|>', r'', html) + html = re.sub(r'<\|>', r'', html) + return re.sub(r'<((?:http:|https:).*?)>', r'<\1>', html) + def show_about(toplevel): - about = gtk.AboutDialog() - about.set_transient_for(toplevel) - about.set_name(config.get_appname()) - about.set_version(config.VERSION) - about.set_copyright(config.COPYRIGHT) - about.set_license('\n\n'.join(config.get_license())) - about.set_wrap_license(True) - about.set_comments(config.get_description()) - about.set_authors(config.AUTHORS) - about.set_website(config.WEBSITE) - about.set_website_label(config.get_website_label()) - about.set_logo_icon_name("pybik") - #about.set_translator_credits(_("translator-credits")) - about.connect("response", lambda d, r: d.destroy()) - about.show() + from .ui.about import Ui_AboutDialog + dialog = QDialog(toplevel) + about = Ui_AboutDialog() + about.setupUi(dialog) + about.label_appname.setText(_(config.APPNAME)) + about.label_version.setText(config.VERSION) + about.label_copyright.setText(config.COPYRIGHT) + html = linkedtext_to_html(config.get_filebug_text()) + about.label_feedback.setText(html) + html = linkedtext_to_html(_(config.TRANSLATION_TEXT)) + about.label_translation.setText(html) + about.text_license_short.hide() + about.text_license_full.hide() + html = linkedtext_to_html('\n\n'.join((_(config.LICENSE_INFO), _(config.LICENSE_FURTHER)))) + about.text_license_short.setHtml(html) + try: + with open(config.LICENSE_FILE) as license_file: + text = license_file.read() + except EnvironmentError: + text = _(config.LICENSE_NOT_FOUND) + about.text_license_full.setLineWrapMode(QTextEdit.WidgetWidth) + html = linkedtext_to_html(text) + about.text_license_full.setHtml(html) + about.label_description.setText(_(config.SHORT_DESCRIPTION)) + about.label_website.setText( + '

{}

' + .format(config.WEBSITE, _('Pybik project website'))) + about.label_icon.setPixmap(QPixmap(os.path.join(config.PIXMAP_DIR, 'pybik-64'))) + license_index = about.tab_widget.indexOf(about.tab_license) + def tab_widget_currentChanged(index): + if index == license_index: + about.text_license_short.setVisible(True) + about.text_license_full.setVisible(False) + QTimer.singleShot(0, dialog.adjustSize) + about.tab_widget.currentChanged.connect(tab_widget_currentChanged) + def text_license_anchorClicked(url): + if url.toString() == 'text:FULL_LICENSE_TEXT': + about.text_license_short.setVisible(False) + about.text_license_full.setVisible(True) + else: + QDesktopServices.openUrl(url) + about.text_license_short.anchorClicked.connect(text_license_anchorClicked) + dialog.exec_() + dialog.deleteLater() diff -Nru pybik-0.5/pybiklib/drawingarea.py pybik-1.0.1/pybiklib/drawingarea.py --- pybik-0.5/pybiklib/drawingarea.py 1970-01-01 00:00:00.000000000 +0000 +++ pybik-1.0.1/pybiklib/drawingarea.py 2012-12-10 16:00:46.000000000 +0000 @@ -0,0 +1,530 @@ +#-*- coding:utf-8 -*- + +# Pybik -- A 3 dimensional magic cube game. +# Copyright © 2009-2012 B. Clausius +# +# 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 . + +# Ported from GNUbik +# Original filename: glarea.c +# Original copyright and license: 2003, 2004 John Darrington, GPL3+ + +from __future__ import print_function, division, unicode_literals + +import os +from collections import namedtuple +import math + +# pylint: disable=W0614,W0401 +from .debug import * + +from PySide.QtOpenGL import * +from PySide.QtCore import * +from PySide.QtGui import * +# pylint: enable=W0614,W0401 + +# no need for OpenGL module for just two constants +GL_RGBA, GL_TEXTURE_2D = 6408, 3553 +if DEBUG: + from OpenGL import GL + assert GL.GL_RGBA == GL_RGBA and GL.GL_TEXTURE_2D == GL_TEXTURE_2D + +from . import config +import gldraw +import glarea +from .textures import textures +from .settings import settings +from . import model + + +class CubeArea (QGLWidget): + end_animation = Signal(bool) + request_rotation = Signal((int, int, bool)) + request_swap_blocks = Signal((int, int, int, bool)) + request_rotate_block = Signal((int, bool)) + drop_color = Signal((int, str, str)) + drop_file = Signal((int, str, str)) + + def __init__(self): + glformat = QGLFormat() + if settings.draw.samples > 0: + glformat.setSampleBuffers(True) + glformat.setSamples(2**settings.draw.samples) + if settings.draw.accum > 0: + glformat.setAccum(True) + else: + accum_buffers = 0 + QGLWidget.__init__(self, glformat) + + self.model = model.empty_model + + self.selection_debug_info = None + + self.last_mouse_x = -1 + self.last_mouse_y = -1 + self.button_down_background = False + self.timer_animate = QTimer() # the animate timer + self.timer_animate.timeout.connect(self._on_animate) + self.mouse_xy = -1, -1 + # Structure to hold copy of the last selection taken or None + self.pickdata = None + self.selection_mode = None + self.editing_model = False + self.stop_requested = False + settings.keystore.changed.connect(self.on_settings_changed, Qt.QueuedConnection) + + if DEBUG_FPS: + self.monotonic_time = QElapsedTimer() + self.monotonic_time.start() + self.render_count = 0 + self.fps = 0. + + self.speed = settings.draw.speed + glarea.init_module() + gldraw.init_module() + self.rotation_x, self.rotation_y = glarea.set_rotation_xy(*settings.draw.default_rotation) + accum_buffers = settings.draw.accum if self.format().accum() else 0 + sample_buffers = self.format().sampleBuffers() + glarea.set_antialiasing(accum_buffers, sample_buffers) + + self.setAcceptDrops(True) + self.setFocusPolicy(Qt.StrongFocus) + self.setMinimumSize(200, 200) + + self.cursors = None + self.load_cursors() + self.update_selection_pending = False + self.set_cursor() + self.setMouseTracking(True) + + def load_cursors(self): + cursors = [] + # Load 3 cursors from file (n - ne) + for i, (x, y) in enumerate([(8, 0), (15, 0), (15, 0)]): + filename = os.path.join(config.UI_DIR, 'mouse_{}.png'.format(i)) + image = QImage(filename) + cursors.append((image, x, y)) + # 1 cursor (nnw) + image, x, y = cursors[1] + cursors.insert(0, (image.mirrored(True, False), 15-x, y)) + # 12 cursors (ene - nw) + transform = QTransform() + transform.rotate(90) + for i in range(4, 16): + image, x, y = cursors[-4] + cursors.append((image.transformed(transform), 15-y, x)) + cursors.append(cursors[0]) + self.cursors = [QCursor(QPixmap.fromImage(image), x, y) for image, x, y in cursors[1:]] + # cursor for center faces + filename = os.path.join(config.UI_DIR, 'mouse_ccw.png') + cursor = QCursor(QPixmap(filename), 7, 7) + self.cursors.append(cursor) + # background cursor + cursor = QCursor() + cursor.setShape(Qt.CursorShape.CrossCursor) + self.cursors.append(cursor) + + def apply_design(self): + for i in xrange(6): + color = settings.theme.face[i].color + imagefile = settings.theme.face[i].image + imagemode = settings.theme.face[i].mode + self.set_face_design(i, color, imagefile, imagemode) + self.set_lighting(settings.draw.lighting) + self.set_background_color(settings.theme.bgcolor) + + stock_texnames = [-1, 0] + def set_face_texture(self, faceidx, imagefile): + if imagefile.startswith('/'): + pixbuf = textures.create_pixbuf_from_file(imagefile) + else: + pixbuf = textures.get_stock_pixbuf(imagefile) + if pixbuf is None: + texname = -1 + else: + texname = self.bindTexture(pixbuf, GL_TEXTURE_2D, GL_RGBA, + QGLContext.BindOption.LinearFilteringBindOption| + QGLContext.BindOption.MipmapBindOption) + if not imagefile.startswith('/') and texname not in self.stock_texnames: + self.stock_texnames.append(texname) + texname = gldraw.set_face_texture(faceidx, texname) + if texname not in self.stock_texnames: + self.deleteTexture(texname) + + def set_face_design(self, i, color, imagefile, imagemode): + rgba = QColor() + rgba.setNamedColor(color) + gldraw.set_face_rendering(i, red=rgba.redF(), green=rgba.greenF(), blue=rgba.blueF(), + imagemode=imagemode) + self.set_face_texture(i, imagefile) + + def set_model(self, model_): + self.model = model_ + glarea.set_frustrum(self.model.bounding_sphere_radius, settings.draw.zoom) + gldraw.set_model(self.model) + self.set_selection_mode(settings.draw.selection) + + @staticmethod + def apply_to_glmodel(cubestate): + gldraw.set_transformations(cubestate.blocks) + + def initializeGL(self): + if DEBUG_MSG: + glcontext = self.context() + glformat = glcontext.format() + glrformat = glcontext.requestedFormat() + def printglattr(name, *attrs): + print(' {}: '.format(name), end='') + def get_value(glformat, attr): + if isinstance(attr, basestring): + return getattr(glformat, attr)() + else: + return attr(glformat) + values = [get_value(glformat, a) for a in attrs] + rvalues = [get_value(glrformat, a) for a in attrs] + if values == rvalues: + print(*values) + else: + print(*values, end=' (') + print(*rvalues, end=')\n') + print('OpenGL format:') + printglattr('accum', 'accum', 'accumBufferSize') + printglattr('alpha', 'alpha', 'alphaBufferSize') + printglattr('rgb', 'redBufferSize', 'greenBufferSize', 'blueBufferSize') + printglattr('depth', 'depth', 'depthBufferSize') + printglattr('directRendering', 'directRendering') + printglattr('doubleBuffer', 'doubleBuffer') + printglattr('hasOverlay', 'hasOverlay') + printglattr('version', lambda glformat: '{}.{} 0x{:x}'.format( + glformat.majorVersion(), + glformat.minorVersion(), + int(glformat.openGLVersionFlags()))) + printglattr('plane', 'plane') + printglattr('profile', 'profile') + printglattr('rgba', 'rgba') + printglattr('samples', 'sampleBuffers', 'samples') + printglattr('stencil', 'stencil', 'stencilBufferSize') + printglattr('stereo', 'stereo') + printglattr('swapInterval', 'swapInterval') + glarea.init_glarea() + self.apply_design() + + def draw_face_debug(self): + maxis, mslice, mdir, block, symbol, face, center, angle = self.pickdata + self.qglColor(QColor(255, 255, 255)) + self.renderText(2, 18, "block %s, face %s (%s), center %s" % (block.index, symbol, face, center)) + self.renderText(2, 34, "axis %s, slice %s, dir %s" % (maxis, mslice, mdir)) + self.renderText(2, 50, "angle %s" % (angle)) + + def paintGL(self): + glarea.display() + if DEBUG: + if DEBUG_DRAW: + if self.pickdata is not None: + self.draw_face_debug() + if self.selection_debug_info is not None: + gldraw.draw_select_debug(*self.selection_debug_info) + if DEBUG_FPS: + self.render_count += 1 + if self.monotonic_time.elapsed() > 1000: + elapsed = self.monotonic_time.restart() + self.fps = 1000. / elapsed * self.render_count + self.render_count = 0 + self.qglColor(QColor(255, 255, 255)) + self.renderText(2, 18, "FPS %.1f" % self.fps) + + def resizeGL(self, width, height): + glarea.resize(width, height) + + MODIFIER_MASK = int(Qt.ShiftModifier | Qt.ControlModifier) + def keyPressEvent(self, event): + modifiers = int(event.modifiers()) & self.MODIFIER_MASK + if modifiers: + return QGLWidget.keyPressEvent(self, event) + elif event.key() == Qt.Key_Right: + self.rotation_x += 2 + elif event.key() == Qt.Key_Left: + self.rotation_x -= 2 + elif event.key() == Qt.Key_Up: + self.rotation_y -= 2 + elif event.key() == Qt.Key_Down: + self.rotation_y += 2 + else: + return QGLWidget.keyPressEvent(self, event) + + self.rotation_x, self.rotation_y = glarea.set_rotation_xy(self.rotation_x, self.rotation_y) + self.update() + self.update_selection() + + PickData = namedtuple('PickData', 'maxis mslice mdir block symbol face center angle') + def pick_polygons(self, x, y): + '''Identify the block at screen co-ordinates x,y.''' + + height = self.height() + index = glarea.pick_polygons(x, height-y, 1) + if not index: + self.selection_debug_info = None + self.pickdata = None + return + maxis, mslice, mdir, face, center, block, symbol, face_center, edge_center = self.model.pick_data[index] + + if center: + angle, self.selection_debug_info = None, None + else: + angle, self.selection_debug_info = glarea.get_cursor_angle(face_center, edge_center) + self.pickdata = self.PickData(maxis, mslice, mdir, block, symbol, face, center, angle) + + def update_selection(self): + '''This func determines which block the mouse is pointing at''' + if self.timer_animate.isActive(): + if self.pickdata is not None: + self.pickdata = None + self.set_cursor() + return + if self.update_selection_pending: + return + QTimer.singleShot(0, self.on_idle_update_selection) + self.update_selection_pending = True + + def on_idle_update_selection(self): + if self.timer_animate.isActive(): + if self.pickdata is not None: + self.pickdata = None + self.set_cursor() + else: + self.pick_polygons(*self.mouse_xy) + self.set_cursor() + if DEBUG_DRAW: + if not self.timer_animate.isActive(): + self.updateGL() + self.update_selection_pending = False + + def mouseMoveEvent(self, event): + self.mouse_xy = event.x(), event.y() + + if not self.button_down_background: + self.update_selection() + return + + # perform rotation + offset_x = event.x() - self.last_mouse_x + offset_y = event.y() - self.last_mouse_y + self.rotation_x, self.rotation_y = glarea.set_rotation_xy( + self.rotation_x + offset_x, + self.rotation_y + offset_y) + self.rotation_x -= offset_x + self.rotation_y -= offset_y + self.update() + + def mousePressEvent(self, event): + if self.pickdata is not None: + if self.timer_animate.isActive(): + return + # make a move + if self.editing_model: + if event.modifiers() & Qt.ControlModifier: + if event.button() == Qt.LeftButton: + self.request_rotate_block.emit(self.pickdata.block.index, False) + elif event.button() == Qt.RightButton: + self.request_rotate_block.emit(self.pickdata.block.index, True) + else: + if event.button() == Qt.LeftButton: + self.request_swap_blocks.emit(self.pickdata.block.index, + self.pickdata.maxis, self.pickdata.mslice, self.pickdata.mdir) + else: + mslice = -1 if event.modifiers() & Qt.ControlModifier else self.pickdata.mslice + if event.button() == Qt.LeftButton: + self.request_rotation.emit(self.pickdata.maxis, mslice, self.pickdata.mdir) + elif event.button() == Qt.RightButton and settings.draw.selection_nick == 'simple': + self.request_rotation.emit(self.pickdata.maxis, mslice, not self.pickdata.mdir) + elif event.button() == Qt.LeftButton: + # start rotation + self.button_down_background = True + self.last_mouse_x = event.x() + self.last_mouse_y = event.y() + self.update() + + def mouseReleaseEvent(self, event): + if event.button() != Qt.LeftButton: + return + + if self.button_down_background: + # end rotation + self.rotation_x += event.x() - self.last_mouse_x + self.rotation_y += event.y() - self.last_mouse_y + self.button_down_background = False + self.update_selection() + + def wheelEvent(self, event): + if event.orientation() == Qt.Vertical: + zoom = settings.draw.zoom * math.pow(1.1, -event.delta() / 120) + zoom_min, zoom_max = settings.draw.zoom_range + if zoom < zoom_min: + zoom = zoom_min + if zoom > zoom_max: + zoom = zoom_max + settings.draw.zoom = zoom + + def dragEnterEvent(self, event): + debug('drag enter:', event.mimeData().formats()) + if (event.mimeData().hasFormat("text/uri-list") or + event.mimeData().hasFormat("application/x-color")): + event.acceptProposedAction() + + def dropEvent(self, event): + # when a drag is in progress the pickdata is not updated, so do it now + self.pick_polygons(event.pos().x(), event.pos().y()) + + mime_data = event.mimeData() + if mime_data.hasFormat("application/x-color"): + color = mime_data.colorData() + if color is None: + debug("Received invalid color data") + return + + if self.pickdata is not None: + self.drop_color.emit(self.pickdata.block.index, self.pickdata.symbol, color.name()) + else: + self.drop_color.emit(-1, '', color.name()) + elif mime_data.hasFormat("text/uri-list"): + if self.pickdata is None: + debug('Background image is not supported.') + return + uris = mime_data.urls() + for uri in uris: + if not uri.isLocalFile(): + debug('filename "%s" not found or not a local file.' % uri.toString()) + continue + filename = uri.toLocalFile() + if not filename or not os.path.exists(filename): + debug('filename "%s" not found.' % filename) + continue + self.drop_file.emit(self.pickdata.block.index, self.pickdata.symbol, filename) + break # For now, just use the first one. + # Ignore all others + + def set_cursor(self): + if self.pickdata is None or self.button_down_background: + index = -1 + elif self.pickdata.angle is None: + index = -2 + else: + index = int((self.pickdata.angle+180) / 22.5 + 0.5) % 16 + self.setCursor(self.cursors[index]) + + def set_std_cursor(self): + QTimer.singleShot(0, lambda: self.unsetCursor()) + + @staticmethod + def set_lighting(enable): + glarea.set_lighting(enable) + + def set_selection_mode(self, mode): + self.selection_mode = mode + gldraw.set_pick_model(*self.model.gl_pick_data(mode)) + self.update_selection() + + def set_editing_mode(self, enable): + self.editing_model = enable + if enable: + gldraw.set_pick_model(*self.model.gl_pick_data(0)) + else: + gldraw.set_pick_model(*self.model.gl_pick_data(self.selection_mode)) + self.update_selection() + + @staticmethod + def set_background_color(color): + rgba = QColor() + rgba.setNamedColor(color) + glarea.set_background_color(rgba.redF(), rgba.greenF(), rgba.blueF()) + + def reset_rotation(self): + '''Reset cube rotation''' + self.rotation_x, self.rotation_y = glarea.set_rotation_xy(*settings.draw.default_rotation) + self.update() + + ### Animation + + def animate_rotation(self, move_data, blocks, stop_after): + self.stop_requested = stop_after + axis = (self.model.axesI if move_data.dir else self.model.axes)[move_data.axis] + angle = self.model.symmetry[move_data.axis] + gldraw.start_animate(angle, *axis) + for block_id, selected in blocks: + gldraw.set_animation_block(block_id, selected) + self.timer_animate.start(0 if DEBUG_VFPS else 20) + self.update_selection() + + def _on_animate(self): + increment = self.speed * 1e-02 * 20 + increment = min(increment, 45) + unfinished = gldraw.step_animate(increment) + if unfinished: + self.updateGL() + return + + # we have finished the animation sequence now + gldraw.end_animate() + self.timer_animate.stop() + self.end_animation.emit(self.stop_requested) + self.updateGL() + self.update_selection() + self.stop_requested = False + + def animate_abort(self, update=True): + self.timer_animate.stop() + gldraw.end_animate() + if update: + self.end_animation.emit(self.stop_requested) + self.update() + self.update_selection() + self.stop_requested = False + + def on_settings_changed(self, key): + if key == 'draw.speed': + self.speed = settings.draw.speed + elif key == 'draw.lighting': + self.set_lighting(settings.draw.lighting) + elif key == 'draw.accum': + if self.format().accum(): + glarea.set_antialiasing(settings.draw.accum) + elif key == 'draw.samples': + if self.format().samples(): + samples = 2**settings.draw.samples + if samples == 1: + glarea.set_antialiasing(None, False) + elif samples == self.format().samples(): + glarea.set_antialiasing(None, True) + elif key == 'draw.selection': + self.set_selection_mode(settings.draw.selection) + elif key.startswith('theme.face.'): + i = int(key.split('.')[2]) + if key == 'theme.face.{}.color'.format(i): + color = QColor() + color.setNamedColor(settings.theme.face[i].color) + gldraw.set_face_rendering(i, red=color.redF(), green=color.greenF(), blue=color.blueF()) + elif key == 'theme.face.{}.image'.format(i): + self.set_face_texture(i, settings.theme.face[i].image) + elif key == 'theme.face.{}.mode'.format(i): + imagemode = settings.theme.face[i].mode + gldraw.set_face_rendering(i, imagemode=imagemode) + elif key == 'theme.bgcolor': + self.set_background_color(settings.theme.bgcolor) + elif key == 'draw.zoom': + glarea.set_frustrum(self.model.bounding_sphere_radius, settings.draw.zoom) + else: + debug('Unknown settings key changed:', key) + self.update() + + diff -Nru pybik-0.5/pybiklib/drwBlock.py pybik-1.0.1/pybiklib/drwBlock.py --- pybik-0.5/pybiklib/drwBlock.py 2011-12-30 22:59:24.000000000 +0000 +++ pybik-1.0.1/pybiklib/drwBlock.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,688 +0,0 @@ -#-*- coding:utf-8 -*- - -# Pybik -- A 3 dimensional magic cube game. -# Copyright © 2009-2011 B. Clausius -# -# 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 . - - -# Ported from GNUbik -# Original filename: drwBlock.c -# Original copyright and license: 1998, 2003 John Darrington, GPL3+ - - -# This line makes pyrex happy -global __name__, __file__, __package__ - -import cython - -from debug import debug, DEBUG_DRAW, DEBUG_PICK - -debug('Importing module:', __name__) -debug(' from package:', __package__) -debug(' compiled:', cython.compiled) - -#pxd from gl cimport * -#pxd from cube_c cimport * - -#px-5 -from OpenGL.GL import * -from cube import MATRIX_DIM, p_Vector, Matrix, MAX_BLOCKS -from cube import get_cube, get_faces, is_face_visible -from cube import init_vector, init_listuc_range, init_listf_range -from cube import _get_block_transform - - -#pxd cdef inline p_Vector glGetModelView(p_Vector m): -#pxd glGetFloatv(GL_MODELVIEW_MATRIX, m) -#pxd return m -#px- -def glGetModelView(unused_m): return glGetFloatv(GL_MODELVIEW_MATRIX) -#pxd cdef inline void glMultMatrixM(p_Vector m): -#pxd glMultMatrixf(m) -#px- -glMultMatrixM = glMultMatrixf - - -# We use a little bit of glut in debug mode -if DEBUG_DRAW: - from OpenGL import GLUT as glut -def glutInit(argv): - if DEBUG_DRAW: - glut.glutInit(len(argv), *argv[:]) -def renderString(string): - glut.glutStrokeString(glut.GLUT_STROKE_MONO_ROMAN, string) - - -# this macro produces +1 if i is even. -1 if i is odd -# We use it to g the faces of the block from zero, to the -# appropriate place -#pxd cdef int SHIFT(int i) -def SHIFT(i): - return (i%2) * 2 - 1 - - -#******************** -#* Set the normal vector for block/face. -#****** - -#pxd cdef void set_normal_vector_vj(int block, int face, int vj, int j) -def set_normal_vector_vj(block, face, vj, j): - cython.declare( - view = Matrix, - view_ = p_Vector, - dest = cython.p_float) - #px- - view = None - view_ = glGetModelView(view) - dest = get_faces(block)[face].normal - transform_vj(dest, view_, vj, j) - - -#******************** -#* Set the vector for block/face/quadrant to v. -#******/ - -#pxd cdef void set_quadrant_vector_vj(int block, int face, int quadrant, int vj, int j) -def set_quadrant_vector_vj(block, face, quadrant, vj, j): - cython.declare( - view = Matrix, - view_ = p_Vector, - dest = cython.p_float) - #px- - view = None - view_ = glGetModelView(view) - dest = get_faces(block)[face].quadrants[quadrant] - transform_vj(dest, view_, vj, j) - -#pxd cdef void transform_vj(float *r, Matrix M, float vj, int j) -def transform_vj(r, M, vj, j): - i = cython.declare(cython.int) - for i in range(MATRIX_DIM): - r[i] = M[j][i] * vj - - -_AnimationState = cython.struct( - running = cython.int, - angle = cython.float, - move_axis = cython.int, - move_slice = cython.int, - move_dir = cython.int, -) -anim_state = cython.declare(_AnimationState) -anim_state.running = 0 -anim_state.angle = 0 -anim_state.move_axis = 0 -anim_state.move_slice = 0 -anim_state.move_dir = 0 - -def start_animate(axis, slice_, dir_): - anim_state.move_axis = axis - anim_state.move_slice = slice_ - anim_state.move_dir = dir_ - anim_state.angle = 0.0 - anim_state.running = 1 - -@cython.locals(increment = cython.float) -def step_animate(increment): - anim_state.angle -= increment - return abs(anim_state.angle) < 90.0 - -def end_animate(): - anim_state.running = 0 - -#pxd cdef void draw_cube() -def draw_cube(): - #px- - if DEBUG_DRAW: draw_cube_debug() - _draw_cube(True) - -#pxd cdef void pick_cube() -def pick_cube(): - _draw_cube(False) - -# render the cube -#pxd cdef void _draw_cube(bint render_mode) -def _draw_cube(render_mode): - cython.declare( - i = cython.int, - axis_ = cython.int, - angle = cython.float, - unity = cython.float, - M = p_Vector) - - for i in range(get_cube().number_blocks): - glPushMatrix () - # Find out if this block is one of those currently being - # turned. If so, j will be < turning_block_qty - if anim_state.running: - if get_cube().blocks[i].in_motion: - # Blocks which are in motion, need to be animated. - # so we rotate them according to however much the - # animation angle is - angle = anim_state.angle - - if anim_state.move_dir: - unity = 1 - else: - unity = -1 - - axis_ = anim_state.move_axis - if axis_ >= 3: - axis_ -= 3 - - if axis_ == 0: - glRotatef (angle, unity, 0, 0) - elif axis_ == 1: - glRotatef (angle, 0, unity, 0) - elif axis_ == 2: - glRotatef (angle, 0, 0, unity) - - - # place the block in its current position and - # orientation - M = _get_block_transform (i) - glPushMatrix() - glMultMatrixM(M) - - # and draw the block - draw_block(0, i, render_mode) - glPopMatrix () - - glPopMatrix () - - -##### experimental pick2 -#pxd cdef void pick2_cube() -def pick2_cube(): - cython.declare( - i = cython.int, - axis = cython.int, - mask = cython.int) - - # Rasterise only the exterior faces, to speed things up - glEnable (GL_CULL_FACE) - - for i in range(6): - glPushMatrix () - if i <= 1: - #glTranslated (0, 0, SHIFT (i)) - axis = 0 - elif i <= 3: - #glTranslated (0, SHIFT (i), 0) - glRotatef (-90, 1, 0, 0) - axis = 1 - else: - #glTranslated (SHIFT (i), 0, 0) - glRotatef (90, 0, 1, 0) - axis = 2 - - # make sure all the sides are faced with their visible - # surface pointing to the outside!! - if not (i % 2): - glRotatef (180, 1, 0, 0) - - # draw the face, iff it is visible - mask = 0x01 << i - pick2_face(i, axis) - - glPopMatrix() - break -#pxd cdef void pick2_face(int face, int axis) -def pick2_face(face, axis): - # This polygon is drawn as four quadrants, thus: - # _______ - # |\ /| - # | \ 1 / | - # | \ / | - # | 0 \ 2 | - # | / \ | - # | / 3 \ | - # |/____ \| - # - # The reason for this is to provide support for an enhanced selection - # mechanism which can detect which edge of the face is being pointed to. - cython.declare( - col = cython.short, - r = cython.uchar, - g = cython.uchar, - dim2 = cython.int) - r = axis - dim2 = get_cube().dimension2 - - glEnableClientState(GL_VERTEX_ARRAY) - glEnableClientState(GL_COLOR_ARRAY) - - glColorPointer(3, GL_UNSIGNED_BYTE, 0, model_data_pick2_colors) - glVertexPointer(3, GL_FLOAT, 0, model_data_pick2_vertices) - glDrawArrays(GL_POLYGON, 0, 2*dim2*4*3*3) - - glDisableClientState(GL_COLOR_ARRAY) - glDisableClientState(GL_VERTEX_ARRAY) -##### - - -# render the block pointed to by attrib. -# if highlight is true, then the outline is white, -# otherwise it is black -#pxd cdef void draw_block(int highlight, int block_id, bint) -def draw_block(highlight, block_id, render_mode): - cython.declare( - i = cython.int, - mask = cython.int) - - # Rasterise only the exterior faces, to speed things up - glEnable (GL_CULL_FACE) - - for i in range(6): - glPushMatrix () - if i <= 1: - glTranslated (0, 0, SHIFT (i)) - elif i <= 3: - glTranslated (0, SHIFT (i), 0) - glRotatef (-90, 1, 0, 0) - else: - glTranslated (SHIFT (i), 0, 0) - glRotatef (90, 0, 1, 0) - - # make sure all the sides are faced with their visible - # surface pointing to the outside!! - if not (i % 2): - glRotatef (180, 1, 0, 0) - - # draw the face, iff it is visible - mask = 0x01 << i - if is_face_visible(block_id, i): - if render_mode and not DEBUG_PICK: - draw_face(i, highlight, block_id) - draw_label(i, block_id) - else: - pick_face(i, block_id) - if render_mode and DEBUG_DRAW: - draw_face_debug(i, block_id) - elif anim_state.running: - if render_mode: - draw_face(i, highlight, block_id) - - glPopMatrix() - - -#pxd ctypedef float Vertex[3] -#pxd ctypedef float FaceTexPos[4*2] -#pxd ctypedef FaceTexPos *p_FaceTexPos -#pxd ctypedef FaceTexPos BlockTexPos[6] -#pxd ctypedef BlockTexPos BlocksTexPos[MAX_BLOCKS] -#pxd ctypedef BlockTexPos *p_BlockTexPos -#px-3 -FaceTexPos = lambda: [0] * 4 * 2 -BlockTexPos = lambda: [FaceTexPos() for __i in range(6)] -BlocksTexPos = lambda: [BlockTexPos() for __i in range(MAX_BLOCKS)] -#TODO: don't store the texpos of hidden faces -cython.declare( - model_data_vertex = cython.float[3*4], - model_data_pick = cython.float[3*12], - model_data_label = cython.float[3*4], - model_data_label180 = cython.float[3*4], - model_data_texpos_mosaic = BlocksTexPos, - model_data_texpos_tiled = BlocksTexPos, - model_data_pick2_vertices = cython.float[6*10*10*4*3*3], - model_data_pick2_colors = cython.uchar[6*10*10*4*3*3]) -#px-8 -model_data_vertex = [0]*3*4 -model_data_pick = [0]*3*12 -model_data_label = [0]*3*4 -model_data_label180 = [0]*3*4 -model_data_texpos_mosaic = BlocksTexPos() -model_data_texpos_tiled = BlocksTexPos() -model_data_pick2_vertices = [0]*(6*10*10*4*3*3) -model_data_pick2_colors = [0]*(6*10*10*4*3*3) - -def init_model(): - cython.declare( - dim = cython.int, - dim2 = cython.int, - b = cython.int, - f = cython.int, - v = cython.int, - i = cython.int, - block = cython.int, - face = cython.int, - x = cython.int, - y = cython.int, - xpos = cython.int, - ypos = cython.int, - size = cython.float) - init_vector(model_data_vertex, [-1, 1, 0, -1,-1, 0, 1,-1, 0, 1, 1, 0,]) - init_vector(model_data_pick, [ 0, 0, 0, -1, 1, 0, -1,-1, 0, - 0, 0, 0, 1, 1, 0, -1, 1, 0, - 0, 0, 0, 1,-1, 0, 1, 1, 0, - 0, 0, 0, -1,-1, 0, 1,-1, 0]) - - lratio = cython.declare(cython.float, 0.9) - init_vector(model_data_label, [-lratio, lratio, 0.01, - -lratio,-lratio, 0.01, - lratio,-lratio, 0.01, - lratio, lratio, 0.01]) - - init_vector(model_data_label180, [ lratio,-lratio, 0.01, - lratio, lratio, 0.01, - -lratio, lratio, 0.01, - -lratio,-lratio, 0.01]) - - dim = get_cube().dimension - dim2 = get_cube().dimension2 - for block in range(get_cube().number_blocks): - for face in range(6): - size = 1.0 / dim - if face & 6 == 0: # 0 or 1 - xpos = block % dim - ypos = block % dim2 / dim - ypos = dim - ypos - 1 - elif face & 6 == 2: # 2 or 3 - xpos = block % dim - ypos = block / dim2 - else:#if face & 6 == 4: # 4 or 5 - xpos = block / dim2 - ypos = block % dim2 / dim - ypos = dim - ypos - 1 - - # Invert positions as necessary - if face == 0: - xpos = dim - xpos - 1 - elif face == 2: - xpos = dim - xpos - 1 - elif face == 5: - xpos = dim - xpos - 1 - - init_vector(model_data_texpos_mosaic[block][face], [size*xpos, size*ypos, - size*xpos, size*(ypos+1), - size*(xpos+1), size*(ypos+1), - size*(xpos+1), size*ypos]) - - init_vector(model_data_texpos_tiled[block][face], [0, 0, 0, 1, 1, 1, 1, 0]) - # face 0 - i = 0 - for y in range(dim): - for x in range(dim): - init_listf_range(i, i+36, model_data_pick2_vertices, - [-dim+1+x,-dim+1+y,-dim, -dim+1-1+x,-dim+1+1+y,-dim, -dim+1-1+x,-dim+1-1+y,-dim, - -dim+1+x,-dim+1+y,-dim, -dim+1+1+x,-dim+1+1+y,-dim, -dim+1-1+x,-dim+1+1+y,-dim, - -dim+1+x,-dim+1+y,-dim, -dim+1+1+x,-dim+1-1+y,-dim, -dim+1+1+x,-dim+1+1+y,-dim, - -dim+1+x,-dim+1+y,-dim, -dim+1-1+x,-dim+1-1+y,-dim, -dim+1+1+x,-dim+1-1+y,-dim,]) - init_listuc_range(i, i+36, model_data_pick2_colors, - [1,y,1, 1,y,1, 1,y,1, - 0,x,1, 0,x,1, 0,x,1, - 1,y,2, 1,y,2, 1,y,2, - 0,x,2, 0,x,2, 0,x,2]) - i += 36 - # face 1 - for y in range(dim): - for x in range(dim): - init_listf_range(i, i+36, model_data_pick2_vertices, - [-dim+1+2*x,-dim+1+2*y,dim, -dim+1-1+2*x,-dim+1+1+2*y,dim, -dim+1-1+2*x,-dim+1-1+2*y,dim, - -dim+1+2*x,-dim+1+2*y,dim, -dim+1+1+2*x,-dim+1+1+2*y,dim, -dim+1-1+2*x,-dim+1+1+2*y,dim, - -dim+1+2*x,-dim+1+2*y,dim, -dim+1+1+2*x,-dim+1-1+2*y,dim, -dim+1+1+2*x,-dim+1+1+2*y,dim, - -dim+1+2*x,-dim+1+2*y,dim, -dim+1-1+2*x,-dim+1-1+2*y,dim, -dim+1+1+2*x,-dim+1-1+2*y,dim,]) - init_listuc_range(i, i+36, model_data_pick2_colors, - [1,y,1, 1,y,1, 1,y,1, - 0,x,1, 0,x,1, 0,x,1, - 1,y,2, 1,y,2, 1,y,2, - 0,x,2, 0,x,2, 0,x,2]) - i += 36 - assert i == 2*dim2*36 - -# render the surface of the cube, that is the plastic material the thing is constructed from -#pxd cdef void draw_face(int face, bint highlight, int block_id) -def draw_face(face, highlight, block_id): - if highlight: - glColor3fv(_color_white) - else: - glColor3fv(_color_black) - - set_normal_vector_vj (block_id, face, -1, 2) - - glEnableClientState(GL_VERTEX_ARRAY) - glVertexPointer(3, GL_FLOAT, 0, model_data_vertex) - glDrawArrays(GL_POLYGON, 0, 4) - glDisableClientState(GL_VERTEX_ARRAY) - -# render the colours (ie the little sticky labels) -#pxd cdef void draw_label(int face, int block_id) -def draw_label(face, block_id): - cython.declare( - image_segment_size = cython.float, - xpos = cython.int, - ypos = cython.int) - - glColor3fv (face_rendering[face].color) - - if face_rendering[face].texName == -1: - glDisable (GL_TEXTURE_2D) - else: - glEnable (GL_TEXTURE_2D) - if face_rendering[face].type_ == IMAGED: - glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL) - else: - glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE) - glBindTexture (GL_TEXTURE_2D, face_rendering[face].texName) - - glEnableClientState(GL_TEXTURE_COORD_ARRAY) - glEnableClientState(GL_VERTEX_ARRAY) - if face_rendering[face].type_ == IMAGED and face_rendering[face].distr == _MOSAIC: - glTexCoordPointer(2, GL_FLOAT, 0, model_data_texpos_mosaic[block_id][face]) - else: # TILED - glTexCoordPointer(2, GL_FLOAT, 0, model_data_texpos_tiled[block_id][face]) - if face % 2: - glVertexPointer(3, GL_FLOAT, 0, model_data_label) - else: - glVertexPointer(3, GL_FLOAT, 0, model_data_label180) - glDrawArrays(GL_POLYGON, 0, 4) - glDisableClientState(GL_TEXTURE_COORD_ARRAY) - glDisableClientState(GL_VERTEX_ARRAY) - - glDisable (GL_TEXTURE_2D) - -#pxd cdef void pick_face (int face, int block_id) -def pick_face(face, block_id): - # This polygon is drawn as four quadrants, thus: - # _______ - # |\ /| - # | \ 1 / | - # | \ / | - # | 0 \ 2 | - # | / \ | - # | / 3 \ | - # |/____ \| - # - # The reason for this is to provide support for an enhanced selection - # mechanism which can detect which edge of the face is being pointed to. - cython.declare( - col = cython.short, - r = cython.uchar, - g = cython.uchar) - col = (block_id << 3) | face - r = (col >> 8) + 68 - g = col & 0xFF - - glEnableClientState(GL_VERTEX_ARRAY) - - set_normal_vector_vj (block_id, face, -1, 2) - - glColor3ub(r, g, 1) - glVertexPointer(3, GL_FLOAT, 0, model_data_pick) - glDrawArrays(GL_POLYGON, 0, 3) - set_quadrant_vector_vj (block_id, face, 0, 1, 0) - - glColor3ub(r, g, 0x55) - glVertexPointer(3, GL_FLOAT, 0, model_data_pick) - glDrawArrays(GL_POLYGON, 3, 3) - set_quadrant_vector_vj (block_id, face, 1, -1, 1) - - glColor3ub(r, g, 0xaa) - glVertexPointer(3, GL_FLOAT, 0, model_data_pick) - glDrawArrays(GL_POLYGON, 6, 3) - set_quadrant_vector_vj (block_id, face, 2, -1, 0) - - glColor3ub(r, g, 0xff) - glVertexPointer(3, GL_FLOAT, 0, model_data_pick) - glDrawArrays(GL_POLYGON, 9, 3) - set_quadrant_vector_vj (block_id, face, 3, 1, 1) - - glDisableClientState(GL_VERTEX_ARRAY) - - -def draw_cube_debug(): - offset = 1.4 * get_cube().dimension - - # Show the directions of the axes - glColor3f(1, 1, 1) - - # X axis - glPushMatrix() - glTranslatef(-offset, -offset, -get_cube().dimension) - glBegin(GL_LINES) - glVertex3f(0, 0, 0) - glVertex3f(2*get_cube().dimension, 0, 0) - glEnd() - - glRasterPos3d(offset*1.1, 0, 0) - #px- - glut.glutBitmapCharacter(glut.GLUT_BITMAP_9_BY_15, ord('X')) - glPopMatrix() - - # Y axis - glPushMatrix() - glTranslatef(-offset, -offset, -get_cube().dimension) - glBegin(GL_LINES) - glVertex3f(0, 0, 0) - glVertex3f(0, 2*get_cube().dimension, 0) - glEnd() - - glRasterPos3d(0.1*offset, offset, 0) - #px- - glut.glutBitmapCharacter(glut.GLUT_BITMAP_9_BY_15, ord('Y')) - glPopMatrix() - - # Z axis - glPushMatrix() - glTranslatef(-offset, -offset, -get_cube().dimension) - glBegin(GL_LINES) - glVertex3f(0, 0, 0) - glVertex3f(0, 0, 2*get_cube().dimension) - glEnd() - - glRasterPos3d(0.1*offset, 0, offset) - #px- - glut.glutBitmapCharacter(glut.GLUT_BITMAP_9_BY_15, ord('Z')) - glPopMatrix () - -#pxd cdef void draw_face_debug(int face, int block_id) -def draw_face_debug(face, block_id): - # render the block number - glPushMatrix() - glColor3f(0, 0, 0) - - glTranslatef(-1, -0.8, 0.02) - glScalef(0.0075, 0.0075, 0.0075) - - renderString("%d" % block_id) - glPopMatrix() - - # render the face number, a little bit smaller - # so we can see what's what. - glPushMatrix() - glTranslatef(-0.5, 0.0, 0.02) - glScalef(0.0075, 0.0075, 0.0075) - renderString(['U0','D1','L2','R3','F4','B5'][face]) - glPopMatrix() - - -#pxd cdef enum: -#pxd _TILED = 0 -#pxd _MOSAIC = 1 -#px- -if True: _TILED = 0; _MOSAIC = 1 - -#pxd cdef enum: -#pxd UNDEFINED = 0 -#pxd COLORED = 1 -#pxd IMAGED = 2 -#px- -if True: UNDEFINED = 0; COLORED = 1; IMAGED = 2 - - -colors = [ - [1.0, 0.0, 0.0], - [0.0, 1.0, 0.0], - [0.0, 0.0, 1.0], - [0.0, 1.0, 1.0], - [1.0, 0.0, 1.0], - [1.0, 1.0, 0.0], - ] -color_black = [0.1, 0.1, 0.1] -color_white = [1.0, 1.0, 1.0] -#pxd ctypedef float color_t[3] -#px- -color_t = list -cython.declare( - _color_black = color_t, - _color_white = color_t, - ) -#px-2 -_color_black = [0] * 3 -_color_white = [0] * 3 - - -#pxd cdef struct _FaceRendering: -#pxd color_t color -#pxd int type_ -#pxd int texName -#pxd int distr -#px- -class _FaceRenderings: pass - -#pxd ctypedef _FaceRendering _FaceRenderings[6] -face_rendering = cython.declare(_FaceRenderings) -#px- -face_rendering = [_FaceRenderings() for __i in range(6)] - -#pxd cdef void init_face_rendering() -def init_face_rendering(): - cython.declare( - i = cython.int, - j = cython.int,) - for i in range(6): - #px- - face_rendering[i].color = [0]*3 - for j in range(3): - face_rendering[i].color[j] = colors[i][j] - for j in range(3): - _color_black[j] = color_black[j] - _color_white[j] = color_white[j] -init_face_rendering() - - -def face_rendering_set(swatch, red=-1, green=-1, blue=-1, facetype=UNDEFINED, texname=None, distr=-1): - if red >= 0: face_rendering[swatch].color[0] = red - if green >= 0: face_rendering[swatch].color[1] = green - if blue >= 0: face_rendering[swatch].color[2] = blue - - if facetype > 0: face_rendering[swatch].type_ = facetype - - if texname is not None: - face_rendering[swatch].texName = texname - - if distr >= 0: face_rendering[swatch].distr = distr - - diff -Nru pybik-0.5/pybiklib/gamestate.py pybik-1.0.1/pybiklib/gamestate.py --- pybik-0.5/pybiklib/gamestate.py 1970-01-01 00:00:00.000000000 +0000 +++ pybik-1.0.1/pybiklib/gamestate.py 2012-12-04 15:17:48.000000000 +0000 @@ -0,0 +1,180 @@ +#-*- coding:utf-8 -*- + +# Pybik -- A 3 dimensional magic cube game. +# Copyright © 2009-2012 B. Clausius +# +# 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 . + +# Ported from GNUbik +# Original filename: ui.c +# Original copyright and license: GPL3+ +# 1998, 2003 John Darrington +# 2004 John Darrington, Dale Mellor + +from __future__ import print_function, division, unicode_literals + +from .debug import * # pylint: disable=W0614,W0401 + +from .model import empty_model +from . import cubestate +from .moves import MoveQueue + + +class GameState (object): + def __init__(self): + self.mark_before = False + self.initial_cube_state = cubestate.CubeState(empty_model) + self.initial_cube_state.set_solved() + self.current_cube_state = self.initial_cube_state.copy() + self.all_moves = MoveQueue() + + def copy(self): + gamestate = GameState() + gamestate.mark_before = self.mark_before + gamestate.initial_cube_state = self.initial_cube_state.copy() + gamestate.current_cube_state = self.current_cube_state.copy() + gamestate.all_moves = self.all_moves.copy() + return gamestate + + def set_state(self, model, blocks, moves, position): + self.initial_cube_state = cubestate.CubeState(model) + try: + self.initial_cube_state.parse_block(blocks) + except ValueError as e: + debug('Invalid block list:', *e.args) + debug(' start with solved game') + self.initial_cube_state.set_solved() + self.current_cube_state = self.initial_cube_state.copy() + self.all_moves = MoveQueue() + if moves.startswith('native:'): + moves = moves.split(':', 1)[1].lstrip() + else: + moves = '' + pos = self.all_moves.parse(moves, position, model) + self.do_fast_forward(to_pos=pos) + + def get_state(self): + model = self.initial_cube_state.model + blocks = self.initial_cube_state.format_block() + moves, position, unused_markup = self.all_moves.format(model) + return model, blocks, 'native: ' + moves, position + + def set_model(self, model): + self.initial_cube_state.set_model(model) + self.current_cube_state.set_model(model) + + def new_game(self, model, solved): + self.initial_cube_state = cubestate.CubeState(model) + self.initial_cube_state.set_solved() + if not solved: + self.initial_cube_state.randomize() + self.current_cube_state = self.initial_cube_state.copy() + self.all_moves.reset() + + ### Funktions to control the cube for use in callbacks and plugins + + def request_back(self): + '''One step back in the sequence of moves''' + if self.all_moves.at_start(): + return None + self.mark_before = self.all_moves.is_mark_current() + self.all_moves.retard() + move = self.all_moves.current().inverted() + self.current_cube_state.rotate_slice(move) + return move + + def request_next(self): + '''One step forward in the sequence of moves''' + move = self.all_moves.current() + if move: + self.mark_before = self.all_moves.is_mark_current() + self.current_cube_state.rotate_slice(move) + self.all_moves.advance() + return move + + def request_rotation(self, maxis, mslice, mdir): + '''Make one new move. + + The usual rotation request, called when user uses mouse to rotate the cube by + hand. The move is put into the `current' place, and all the moves in + all_moves afterwards are zapped.''' + self.all_moves.push_current((maxis, mslice, mdir)) + + def do_rewind_to_mark(self): + if self.all_moves.at_start(): + return False + while True: + self.all_moves.retard() + move = self.all_moves.current().inverted() + self.current_cube_state.rotate_slice(move) + if self.all_moves.is_mark_current(): + break + return True + + def do_rewind_to_start(self): + # for edit mode cloning is a must, even if already at start + self.current_cube_state = self.initial_cube_state.copy() + self.all_moves.rewind_start() + + def do_fast_forward(self, to_pos=-1): + '''Go to end of the sequence of moves. + + All the moves take place on the cube, not via the animation + routines, so the effect is to show the result instantaneously.''' + move = self.all_moves.current() + while move: + if to_pos == self.all_moves.current_place: + break + self.current_cube_state.rotate_slice(move) + self.all_moves.advance() + if to_pos < 0 and self.all_moves.is_mark_current(): + break + move = self.all_moves.current() + + def set_from_formula(self, code, pos): + self.current_cube_state = self.initial_cube_state.copy() + self.all_moves.rewind_start() + self.all_moves.reset() + pos = self.all_moves.parse(code, pos, self.current_cube_state.model) + self.do_fast_forward(to_pos=pos) + + def set_as_initial_state(self): + self.initial_cube_state = self.current_cube_state.copy() + self.all_moves.truncate_before() + + def invert_moves(self): + self.current_cube_state = self.initial_cube_state.copy() + self.all_moves.invert() + pos = self.all_moves.current_place + self.all_moves.rewind_start() + self.do_fast_forward(to_pos=pos) + + def normalize_complete_rotations(self): + self.current_cube_state = self.initial_cube_state.copy() + self.all_moves.normalize_complete_rotations(self.initial_cube_state.model) + pos = self.all_moves.current_place + self.all_moves.rewind_start() + self.do_fast_forward(to_pos=pos) + + def swap_block(self, blockpos, maxis, mslice, mdir): + self.initial_cube_state.swap_block(blockpos, maxis, mslice, mdir) + # Because initial_cube_state changed, current_cube_state must be cloned now, + # do_rewind_to_start does that. + self.do_rewind_to_start() + + def rotate_block(self, blockpos, rdir): + self.initial_cube_state.rotate_block(blockpos, rdir) + self.do_rewind_to_start() + + diff -Nru pybik-0.5/pybiklib/gl.pxd pybik-1.0.1/pybiklib/gl.pxd --- pybik-0.5/pybiklib/gl.pxd 2011-06-28 06:10:20.000000000 +0000 +++ pybik-1.0.1/pybiklib/gl.pxd 2012-08-20 15:55:56.000000000 +0000 @@ -1,8 +1,8 @@ # pybiklib/gl.pxd +# generated with tools/create-gl-pxd.py -# This section was generated with: -# grep "#define GL_" | awk '{ print "\ \ \ \ enum: " $2 }' +# from /usr/include/GL/gl.h: cdef extern from 'GL/gl.h': enum: GL_VERSION_1_1 @@ -430,6 +430,8 @@ enum: GL_TEXTURE_ENV_COLOR enum: GL_TEXTURE_GEN_S enum: GL_TEXTURE_GEN_T + enum: GL_TEXTURE_GEN_R + enum: GL_TEXTURE_GEN_Q enum: GL_TEXTURE_GEN_MODE enum: GL_TEXTURE_BORDER_COLOR enum: GL_TEXTURE_WIDTH @@ -460,8 +462,6 @@ enum: GL_T enum: GL_R enum: GL_Q - enum: GL_TEXTURE_GEN_R - enum: GL_TEXTURE_GEN_Q enum: GL_VENDOR enum: GL_RENDERER enum: GL_VERSION @@ -816,10 +816,10 @@ enum: GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER_EXT enum: GL_ATI_blend_equation_separate enum: GL_ALPHA_BLEND_EQUATION_ATI + enum: GL_OES_EGL_image -# This section was generated from GL/gl.h with: -# sed -n '/typedef/s/^\([^;]*\);\(.*\)$/c\1/p' | grep -v APIENTRYP +# from /usr/include/GL/gl.h: ctypedef unsigned int GLenum ctypedef unsigned char GLboolean @@ -836,21 +836,14 @@ ctypedef float GLclampf ctypedef double GLdouble ctypedef double GLclampd -ctypedef void (*GLprogramcallbackMESA)(GLenum target, GLvoid *data) -# This section was generated from GL/glext.h with: -# sed -n '/typedef/s/^\([^;]*\);\(.*\)$/c\1/p' | grep -v APIENTRYP | grep -v "int.._t" | grep -v struct | grep -v ptrdiff_t +# from /usr/include/GL/glext.h: ctypedef char GLchar -ctypedef char GLcharARB -ctypedef unsigned int GLhandleARB -ctypedef unsigned short GLhalfARB -ctypedef unsigned short GLhalfNV -# This section was generated with: -# sed -n -e :a -e '/([^)]*$/N; /([^)]*$/N; /([^)]*$/N; s/^GLAPI\(.*\)GLAPIENTRY\([^(]*\)\(([^)]*)\);/\ \ \ \ cdef\1\2\3/p; ta' | sed "s/const //g" | sed 'sx\(/\*.*\*/\)$x#\1xg' | sed 's/( *void *)/()/' +# from /usr/include/GL/gl.h with: cdef extern from 'GL/gl.h': cdef void glClearIndex( GLfloat c ) @@ -1186,6 +1179,16 @@ GLenum pname, GLfloat *params ) cdef void glGetTexLevelParameteriv( GLenum target, GLint level, GLenum pname, GLint *params ) + cdef void glTexImage1D( GLenum target, GLint level, + GLint internalFormat, + GLsizei width, GLint border, + GLenum format, GLenum type, + GLvoid *pixels ) + cdef void glTexImage2D( GLenum target, GLint level, + GLint internalFormat, + GLsizei width, GLsizei height, + GLint border, GLenum format, GLenum type, + GLvoid *pixels ) cdef void glGetTexImage( GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels ) @@ -1203,10 +1206,20 @@ GLint xoffset, GLsizei width, GLenum format, GLenum type, GLvoid *pixels ) + cdef void glTexSubImage2D( GLenum target, GLint level, + GLint xoffset, GLint yoffset, + GLsizei width, GLsizei height, + GLenum format, GLenum type, + GLvoid *pixels ) cdef void glCopyTexImage1D( GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border ) + cdef void glCopyTexImage2D( GLenum target, GLint level, + GLenum internalformat, + GLint x, GLint y, + GLsizei width, GLsizei height, + GLint border ) cdef void glCopyTexSubImage1D( GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width ) @@ -1262,6 +1275,23 @@ cdef void glPopName() cdef void glDrawRangeElements( GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, GLvoid *indices ) + cdef void glTexImage3D( GLenum target, GLint level, + GLint internalFormat, + GLsizei width, GLsizei height, + GLsizei depth, GLint border, + GLenum format, GLenum type, + GLvoid *pixels ) + cdef void glTexSubImage3D( GLenum target, GLint level, + GLint xoffset, GLint yoffset, + GLint zoffset, GLsizei width, + GLsizei height, GLsizei depth, + GLenum format, + GLenum type, GLvoid *pixels) + cdef void glCopyTexSubImage3D( GLenum target, GLint level, + GLint xoffset, GLint yoffset, + GLint zoffset, GLint x, + GLint y, GLsizei width, + GLsizei height ) cdef void glColorTable( GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, GLvoid *table ) @@ -1382,45 +1412,556 @@ cdef void glMultTransposeMatrixd( GLdouble m[16] ) cdef void glMultTransposeMatrixf( GLfloat m[16] ) cdef void glSampleCoverage( GLclampf value, GLboolean invert ) - cdef void glActiveTextureARB(GLenum texture) - cdef void glClientActiveTextureARB(GLenum texture) - cdef void glMultiTexCoord1dARB(GLenum target, GLdouble s) - cdef void glMultiTexCoord1dvARB(GLenum target, GLdouble *v) - cdef void glMultiTexCoord1fARB(GLenum target, GLfloat s) - cdef void glMultiTexCoord1fvARB(GLenum target, GLfloat *v) - cdef void glMultiTexCoord1iARB(GLenum target, GLint s) - cdef void glMultiTexCoord1ivARB(GLenum target, GLint *v) - cdef void glMultiTexCoord1sARB(GLenum target, GLshort s) - cdef void glMultiTexCoord1svARB(GLenum target, GLshort *v) - cdef void glMultiTexCoord2dARB(GLenum target, GLdouble s, GLdouble t) - cdef void glMultiTexCoord2dvARB(GLenum target, GLdouble *v) - cdef void glMultiTexCoord2fARB(GLenum target, GLfloat s, GLfloat t) - cdef void glMultiTexCoord2fvARB(GLenum target, GLfloat *v) - cdef void glMultiTexCoord2iARB(GLenum target, GLint s, GLint t) - cdef void glMultiTexCoord2ivARB(GLenum target, GLint *v) - cdef void glMultiTexCoord2sARB(GLenum target, GLshort s, GLshort t) - cdef void glMultiTexCoord2svARB(GLenum target, GLshort *v) - cdef void glMultiTexCoord3dARB(GLenum target, GLdouble s, GLdouble t, GLdouble r) - cdef void glMultiTexCoord3dvARB(GLenum target, GLdouble *v) - cdef void glMultiTexCoord3fARB(GLenum target, GLfloat s, GLfloat t, GLfloat r) - cdef void glMultiTexCoord3fvARB(GLenum target, GLfloat *v) - cdef void glMultiTexCoord3iARB(GLenum target, GLint s, GLint t, GLint r) - cdef void glMultiTexCoord3ivARB(GLenum target, GLint *v) - cdef void glMultiTexCoord3sARB(GLenum target, GLshort s, GLshort t, GLshort r) - cdef void glMultiTexCoord3svARB(GLenum target, GLshort *v) - cdef void glMultiTexCoord4dARB(GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q) - cdef void glMultiTexCoord4dvARB(GLenum target, GLdouble *v) - cdef void glMultiTexCoord4fARB(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q) - cdef void glMultiTexCoord4fvARB(GLenum target, GLfloat *v) - cdef void glMultiTexCoord4iARB(GLenum target, GLint s, GLint t, GLint r, GLint q) - cdef void glMultiTexCoord4ivARB(GLenum target, GLint *v) - cdef void glMultiTexCoord4sARB(GLenum target, GLshort s, GLshort t, GLshort r, GLshort q) - cdef void glMultiTexCoord4svARB(GLenum target, GLshort *v) - cdef GLhandleARB glCreateDebugObjectMESA () - cdef void glClearDebugLogMESA (GLhandleARB obj, GLenum logType, GLenum shaderType) - cdef void glGetDebugLogMESA (GLhandleARB obj, GLenum logType, GLenum shaderType, GLsizei maxLength, - GLsizei *length, GLcharARB *debugLog) - cdef GLsizei glGetDebugLogLengthMESA (GLhandleARB obj, GLenum logType, GLenum shaderType) - cdef void glProgramCallbackMESA(GLenum target, GLprogramcallbackMESA callback, GLvoid *data) - cdef void glGetProgramRegisterfvMESA(GLenum target, GLsizei len, GLubyte *name, GLfloat *v) - cdef void glBlendEquationSeparateATI( GLenum modeRGB, GLenum modeA ) + + +# from /usr/include/GL/glext.h with: + +cdef extern from 'GL/glext.h': + cdef void glBlendColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) + cdef void glBlendEquation (GLenum mode) + cdef void glDrawRangeElements (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, GLvoid *indices) + cdef void glTexImage3D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, GLvoid *pixels) + cdef void glTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid *pixels) + cdef void glCopyTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height) + cdef void glColorTable (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, GLvoid *table) + cdef void glColorTableParameterfv (GLenum target, GLenum pname, GLfloat *params) + cdef void glColorTableParameteriv (GLenum target, GLenum pname, GLint *params) + cdef void glCopyColorTable (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width) + cdef void glGetColorTable (GLenum target, GLenum format, GLenum type, GLvoid *table) + cdef void glGetColorTableParameterfv (GLenum target, GLenum pname, GLfloat *params) + cdef void glGetColorTableParameteriv (GLenum target, GLenum pname, GLint *params) + cdef void glColorSubTable (GLenum target, GLsizei start, GLsizei count, GLenum format, GLenum type, GLvoid *data) + cdef void glCopyColorSubTable (GLenum target, GLsizei start, GLint x, GLint y, GLsizei width) + cdef void glConvolutionFilter1D (GLenum target, GLenum internalformat, GLsizei width, GLenum format, GLenum type, GLvoid *image) + cdef void glConvolutionFilter2D (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *image) + cdef void glConvolutionParameterf (GLenum target, GLenum pname, GLfloat params) + cdef void glConvolutionParameterfv (GLenum target, GLenum pname, GLfloat *params) + cdef void glConvolutionParameteri (GLenum target, GLenum pname, GLint params) + cdef void glConvolutionParameteriv (GLenum target, GLenum pname, GLint *params) + cdef void glCopyConvolutionFilter1D (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width) + cdef void glCopyConvolutionFilter2D (GLenum target, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height) + cdef void glGetConvolutionFilter (GLenum target, GLenum format, GLenum type, GLvoid *image) + cdef void glGetConvolutionParameterfv (GLenum target, GLenum pname, GLfloat *params) + cdef void glGetConvolutionParameteriv (GLenum target, GLenum pname, GLint *params) + cdef void glGetSeparableFilter (GLenum target, GLenum format, GLenum type, GLvoid *row, GLvoid *column, GLvoid *span) + cdef void glSeparableFilter2D (GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *row, GLvoid *column) + cdef void glGetHistogram (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values) + cdef void glGetHistogramParameterfv (GLenum target, GLenum pname, GLfloat *params) + cdef void glGetHistogramParameteriv (GLenum target, GLenum pname, GLint *params) + cdef void glGetMinmax (GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values) + cdef void glGetMinmaxParameterfv (GLenum target, GLenum pname, GLfloat *params) + cdef void glGetMinmaxParameteriv (GLenum target, GLenum pname, GLint *params) + cdef void glHistogram (GLenum target, GLsizei width, GLenum internalformat, GLboolean sink) + cdef void glMinmax (GLenum target, GLenum internalformat, GLboolean sink) + cdef void glResetHistogram (GLenum target) + cdef void glResetMinmax (GLenum target) + cdef void glActiveTexture (GLenum texture) + cdef void glSampleCoverage (GLclampf value, GLboolean invert) + cdef void glCompressedTexImage3D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, GLvoid *data) + cdef void glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, GLvoid *data) + cdef void glCompressedTexImage1D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, GLvoid *data) + cdef void glCompressedTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, GLvoid *data) + cdef void glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, GLvoid *data) + cdef void glCompressedTexSubImage1D (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, GLvoid *data) + cdef void glGetCompressedTexImage (GLenum target, GLint level, GLvoid *img) + cdef void glClientActiveTexture (GLenum texture) + cdef void glMultiTexCoord1d (GLenum target, GLdouble s) + cdef void glMultiTexCoord1dv (GLenum target, GLdouble *v) + cdef void glMultiTexCoord1f (GLenum target, GLfloat s) + cdef void glMultiTexCoord1fv (GLenum target, GLfloat *v) + cdef void glMultiTexCoord1i (GLenum target, GLint s) + cdef void glMultiTexCoord1iv (GLenum target, GLint *v) + cdef void glMultiTexCoord1s (GLenum target, GLshort s) + cdef void glMultiTexCoord1sv (GLenum target, GLshort *v) + cdef void glMultiTexCoord2d (GLenum target, GLdouble s, GLdouble t) + cdef void glMultiTexCoord2dv (GLenum target, GLdouble *v) + cdef void glMultiTexCoord2f (GLenum target, GLfloat s, GLfloat t) + cdef void glMultiTexCoord2fv (GLenum target, GLfloat *v) + cdef void glMultiTexCoord2i (GLenum target, GLint s, GLint t) + cdef void glMultiTexCoord2iv (GLenum target, GLint *v) + cdef void glMultiTexCoord2s (GLenum target, GLshort s, GLshort t) + cdef void glMultiTexCoord2sv (GLenum target, GLshort *v) + cdef void glMultiTexCoord3d (GLenum target, GLdouble s, GLdouble t, GLdouble r) + cdef void glMultiTexCoord3dv (GLenum target, GLdouble *v) + cdef void glMultiTexCoord3f (GLenum target, GLfloat s, GLfloat t, GLfloat r) + cdef void glMultiTexCoord3fv (GLenum target, GLfloat *v) + cdef void glMultiTexCoord3i (GLenum target, GLint s, GLint t, GLint r) + cdef void glMultiTexCoord3iv (GLenum target, GLint *v) + cdef void glMultiTexCoord3s (GLenum target, GLshort s, GLshort t, GLshort r) + cdef void glMultiTexCoord3sv (GLenum target, GLshort *v) + cdef void glMultiTexCoord4d (GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q) + cdef void glMultiTexCoord4dv (GLenum target, GLdouble *v) + cdef void glMultiTexCoord4f (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q) + cdef void glMultiTexCoord4fv (GLenum target, GLfloat *v) + cdef void glMultiTexCoord4i (GLenum target, GLint s, GLint t, GLint r, GLint q) + cdef void glMultiTexCoord4iv (GLenum target, GLint *v) + cdef void glMultiTexCoord4s (GLenum target, GLshort s, GLshort t, GLshort r, GLshort q) + cdef void glMultiTexCoord4sv (GLenum target, GLshort *v) + cdef void glLoadTransposeMatrixf (GLfloat *m) + cdef void glLoadTransposeMatrixd (GLdouble *m) + cdef void glMultTransposeMatrixf (GLfloat *m) + cdef void glMultTransposeMatrixd (GLdouble *m) + cdef void glBlendFuncSeparate (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) + cdef void glMultiDrawArrays (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount) + cdef void glMultiDrawElements (GLenum mode, GLsizei *count, GLenum type, GLvoid* *indices, GLsizei primcount) + cdef void glPointParameterf (GLenum pname, GLfloat param) + cdef void glPointParameterfv (GLenum pname, GLfloat *params) + cdef void glPointParameteri (GLenum pname, GLint param) + cdef void glPointParameteriv (GLenum pname, GLint *params) + cdef void glFogCoordf (GLfloat coord) + cdef void glFogCoordfv (GLfloat *coord) + cdef void glFogCoordd (GLdouble coord) + cdef void glFogCoorddv (GLdouble *coord) + cdef void glFogCoordPointer (GLenum type, GLsizei stride, GLvoid *pointer) + cdef void glSecondaryColor3b (GLbyte red, GLbyte green, GLbyte blue) + cdef void glSecondaryColor3bv (GLbyte *v) + cdef void glSecondaryColor3d (GLdouble red, GLdouble green, GLdouble blue) + cdef void glSecondaryColor3dv (GLdouble *v) + cdef void glSecondaryColor3f (GLfloat red, GLfloat green, GLfloat blue) + cdef void glSecondaryColor3fv (GLfloat *v) + cdef void glSecondaryColor3i (GLint red, GLint green, GLint blue) + cdef void glSecondaryColor3iv (GLint *v) + cdef void glSecondaryColor3s (GLshort red, GLshort green, GLshort blue) + cdef void glSecondaryColor3sv (GLshort *v) + cdef void glSecondaryColor3ub (GLubyte red, GLubyte green, GLubyte blue) + cdef void glSecondaryColor3ubv (GLubyte *v) + cdef void glSecondaryColor3ui (GLuint red, GLuint green, GLuint blue) + cdef void glSecondaryColor3uiv (GLuint *v) + cdef void glSecondaryColor3us (GLushort red, GLushort green, GLushort blue) + cdef void glSecondaryColor3usv (GLushort *v) + cdef void glSecondaryColorPointer (GLint size, GLenum type, GLsizei stride, GLvoid *pointer) + cdef void glWindowPos2d (GLdouble x, GLdouble y) + cdef void glWindowPos2dv (GLdouble *v) + cdef void glWindowPos2f (GLfloat x, GLfloat y) + cdef void glWindowPos2fv (GLfloat *v) + cdef void glWindowPos2i (GLint x, GLint y) + cdef void glWindowPos2iv (GLint *v) + cdef void glWindowPos2s (GLshort x, GLshort y) + cdef void glWindowPos2sv (GLshort *v) + cdef void glWindowPos3d (GLdouble x, GLdouble y, GLdouble z) + cdef void glWindowPos3dv (GLdouble *v) + cdef void glWindowPos3f (GLfloat x, GLfloat y, GLfloat z) + cdef void glWindowPos3fv (GLfloat *v) + cdef void glWindowPos3i (GLint x, GLint y, GLint z) + cdef void glWindowPos3iv (GLint *v) + cdef void glWindowPos3s (GLshort x, GLshort y, GLshort z) + cdef void glWindowPos3sv (GLshort *v) + cdef void glGenQueries (GLsizei n, GLuint *ids) + cdef void glDeleteQueries (GLsizei n, GLuint *ids) + cdef GLboolean glIsQuery (GLuint id) + cdef void glBeginQuery (GLenum target, GLuint id) + cdef void glEndQuery (GLenum target) + cdef void glGetQueryiv (GLenum target, GLenum pname, GLint *params) + cdef void glGetQueryObjectiv (GLuint id, GLenum pname, GLint *params) + cdef void glGetQueryObjectuiv (GLuint id, GLenum pname, GLuint *params) + cdef void glBindBuffer (GLenum target, GLuint buffer) + cdef void glDeleteBuffers (GLsizei n, GLuint *buffers) + cdef void glGenBuffers (GLsizei n, GLuint *buffers) + cdef GLboolean glIsBuffer (GLuint buffer) + cdef GLvoid* glMapBuffer (GLenum target, GLenum access) + cdef GLboolean glUnmapBuffer (GLenum target) + cdef void glGetBufferParameteriv (GLenum target, GLenum pname, GLint *params) + cdef void glGetBufferPointerv (GLenum target, GLenum pname, GLvoid* *params) + cdef void glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha) + cdef void glDrawBuffers (GLsizei n, GLenum *bufs) + cdef void glStencilOpSeparate (GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) + cdef void glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask) + cdef void glStencilMaskSeparate (GLenum face, GLuint mask) + cdef void glAttachShader (GLuint program, GLuint shader) + cdef void glBindAttribLocation (GLuint program, GLuint index, GLchar *name) + cdef void glCompileShader (GLuint shader) + cdef GLuint glCreateProgram () + cdef GLuint glCreateShader (GLenum type) + cdef void glDeleteProgram (GLuint program) + cdef void glDeleteShader (GLuint shader) + cdef void glDetachShader (GLuint program, GLuint shader) + cdef void glDisableVertexAttribArray (GLuint index) + cdef void glEnableVertexAttribArray (GLuint index) + cdef void glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) + cdef void glGetActiveUniform (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) + cdef void glGetAttachedShaders (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *obj) + cdef GLint glGetAttribLocation (GLuint program, GLchar *name) + cdef void glGetProgramiv (GLuint program, GLenum pname, GLint *params) + cdef void glGetProgramInfoLog (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog) + cdef void glGetShaderiv (GLuint shader, GLenum pname, GLint *params) + cdef void glGetShaderInfoLog (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog) + cdef void glGetShaderSource (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source) + cdef GLint glGetUniformLocation (GLuint program, GLchar *name) + cdef void glGetUniformfv (GLuint program, GLint location, GLfloat *params) + cdef void glGetUniformiv (GLuint program, GLint location, GLint *params) + cdef void glGetVertexAttribdv (GLuint index, GLenum pname, GLdouble *params) + cdef void glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat *params) + cdef void glGetVertexAttribiv (GLuint index, GLenum pname, GLint *params) + cdef void glGetVertexAttribPointerv (GLuint index, GLenum pname, GLvoid* *pointer) + cdef GLboolean glIsProgram (GLuint program) + cdef GLboolean glIsShader (GLuint shader) + cdef void glLinkProgram (GLuint program) + cdef void glShaderSource (GLuint shader, GLsizei count, GLchar* *string, GLint *length) + cdef void glUseProgram (GLuint program) + cdef void glUniform1f (GLint location, GLfloat v0) + cdef void glUniform2f (GLint location, GLfloat v0, GLfloat v1) + cdef void glUniform3f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2) + cdef void glUniform4f (GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) + cdef void glUniform1i (GLint location, GLint v0) + cdef void glUniform2i (GLint location, GLint v0, GLint v1) + cdef void glUniform3i (GLint location, GLint v0, GLint v1, GLint v2) + cdef void glUniform4i (GLint location, GLint v0, GLint v1, GLint v2, GLint v3) + cdef void glUniform1fv (GLint location, GLsizei count, GLfloat *value) + cdef void glUniform2fv (GLint location, GLsizei count, GLfloat *value) + cdef void glUniform3fv (GLint location, GLsizei count, GLfloat *value) + cdef void glUniform4fv (GLint location, GLsizei count, GLfloat *value) + cdef void glUniform1iv (GLint location, GLsizei count, GLint *value) + cdef void glUniform2iv (GLint location, GLsizei count, GLint *value) + cdef void glUniform3iv (GLint location, GLsizei count, GLint *value) + cdef void glUniform4iv (GLint location, GLsizei count, GLint *value) + cdef void glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, GLfloat *value) + cdef void glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, GLfloat *value) + cdef void glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, GLfloat *value) + cdef void glValidateProgram (GLuint program) + cdef void glVertexAttrib1d (GLuint index, GLdouble x) + cdef void glVertexAttrib1dv (GLuint index, GLdouble *v) + cdef void glVertexAttrib1f (GLuint index, GLfloat x) + cdef void glVertexAttrib1fv (GLuint index, GLfloat *v) + cdef void glVertexAttrib1s (GLuint index, GLshort x) + cdef void glVertexAttrib1sv (GLuint index, GLshort *v) + cdef void glVertexAttrib2d (GLuint index, GLdouble x, GLdouble y) + cdef void glVertexAttrib2dv (GLuint index, GLdouble *v) + cdef void glVertexAttrib2f (GLuint index, GLfloat x, GLfloat y) + cdef void glVertexAttrib2fv (GLuint index, GLfloat *v) + cdef void glVertexAttrib2s (GLuint index, GLshort x, GLshort y) + cdef void glVertexAttrib2sv (GLuint index, GLshort *v) + cdef void glVertexAttrib3d (GLuint index, GLdouble x, GLdouble y, GLdouble z) + cdef void glVertexAttrib3dv (GLuint index, GLdouble *v) + cdef void glVertexAttrib3f (GLuint index, GLfloat x, GLfloat y, GLfloat z) + cdef void glVertexAttrib3fv (GLuint index, GLfloat *v) + cdef void glVertexAttrib3s (GLuint index, GLshort x, GLshort y, GLshort z) + cdef void glVertexAttrib3sv (GLuint index, GLshort *v) + cdef void glVertexAttrib4Nbv (GLuint index, GLbyte *v) + cdef void glVertexAttrib4Niv (GLuint index, GLint *v) + cdef void glVertexAttrib4Nsv (GLuint index, GLshort *v) + cdef void glVertexAttrib4Nub (GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w) + cdef void glVertexAttrib4Nubv (GLuint index, GLubyte *v) + cdef void glVertexAttrib4Nuiv (GLuint index, GLuint *v) + cdef void glVertexAttrib4Nusv (GLuint index, GLushort *v) + cdef void glVertexAttrib4bv (GLuint index, GLbyte *v) + cdef void glVertexAttrib4d (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w) + cdef void glVertexAttrib4dv (GLuint index, GLdouble *v) + cdef void glVertexAttrib4f (GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) + cdef void glVertexAttrib4fv (GLuint index, GLfloat *v) + cdef void glVertexAttrib4iv (GLuint index, GLint *v) + cdef void glVertexAttrib4s (GLuint index, GLshort x, GLshort y, GLshort z, GLshort w) + cdef void glVertexAttrib4sv (GLuint index, GLshort *v) + cdef void glVertexAttrib4ubv (GLuint index, GLubyte *v) + cdef void glVertexAttrib4uiv (GLuint index, GLuint *v) + cdef void glVertexAttrib4usv (GLuint index, GLushort *v) + cdef void glVertexAttribPointer (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLvoid *pointer) + cdef void glUniformMatrix2x3fv (GLint location, GLsizei count, GLboolean transpose, GLfloat *value) + cdef void glUniformMatrix3x2fv (GLint location, GLsizei count, GLboolean transpose, GLfloat *value) + cdef void glUniformMatrix2x4fv (GLint location, GLsizei count, GLboolean transpose, GLfloat *value) + cdef void glUniformMatrix4x2fv (GLint location, GLsizei count, GLboolean transpose, GLfloat *value) + cdef void glUniformMatrix3x4fv (GLint location, GLsizei count, GLboolean transpose, GLfloat *value) + cdef void glUniformMatrix4x3fv (GLint location, GLsizei count, GLboolean transpose, GLfloat *value) + cdef void glColorMaski (GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a) + cdef void glGetBooleani_v (GLenum target, GLuint index, GLboolean *data) + cdef void glGetIntegeri_v (GLenum target, GLuint index, GLint *data) + cdef void glEnablei (GLenum target, GLuint index) + cdef void glDisablei (GLenum target, GLuint index) + cdef GLboolean glIsEnabledi (GLenum target, GLuint index) + cdef void glBeginTransformFeedback (GLenum primitiveMode) + cdef void glEndTransformFeedback () + cdef void glBindBufferBase (GLenum target, GLuint index, GLuint buffer) + cdef void glTransformFeedbackVaryings (GLuint program, GLsizei count, GLchar* *varyings, GLenum bufferMode) + cdef void glGetTransformFeedbackVarying (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) + cdef void glClampColor (GLenum target, GLenum clamp) + cdef void glBeginConditionalRender (GLuint id, GLenum mode) + cdef void glEndConditionalRender () + cdef void glVertexAttribIPointer (GLuint index, GLint size, GLenum type, GLsizei stride, GLvoid *pointer) + cdef void glGetVertexAttribIiv (GLuint index, GLenum pname, GLint *params) + cdef void glGetVertexAttribIuiv (GLuint index, GLenum pname, GLuint *params) + cdef void glVertexAttribI1i (GLuint index, GLint x) + cdef void glVertexAttribI2i (GLuint index, GLint x, GLint y) + cdef void glVertexAttribI3i (GLuint index, GLint x, GLint y, GLint z) + cdef void glVertexAttribI4i (GLuint index, GLint x, GLint y, GLint z, GLint w) + cdef void glVertexAttribI1ui (GLuint index, GLuint x) + cdef void glVertexAttribI2ui (GLuint index, GLuint x, GLuint y) + cdef void glVertexAttribI3ui (GLuint index, GLuint x, GLuint y, GLuint z) + cdef void glVertexAttribI4ui (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w) + cdef void glVertexAttribI1iv (GLuint index, GLint *v) + cdef void glVertexAttribI2iv (GLuint index, GLint *v) + cdef void glVertexAttribI3iv (GLuint index, GLint *v) + cdef void glVertexAttribI4iv (GLuint index, GLint *v) + cdef void glVertexAttribI1uiv (GLuint index, GLuint *v) + cdef void glVertexAttribI2uiv (GLuint index, GLuint *v) + cdef void glVertexAttribI3uiv (GLuint index, GLuint *v) + cdef void glVertexAttribI4uiv (GLuint index, GLuint *v) + cdef void glVertexAttribI4bv (GLuint index, GLbyte *v) + cdef void glVertexAttribI4sv (GLuint index, GLshort *v) + cdef void glVertexAttribI4ubv (GLuint index, GLubyte *v) + cdef void glVertexAttribI4usv (GLuint index, GLushort *v) + cdef void glGetUniformuiv (GLuint program, GLint location, GLuint *params) + cdef void glBindFragDataLocation (GLuint program, GLuint color, GLchar *name) + cdef GLint glGetFragDataLocation (GLuint program, GLchar *name) + cdef void glUniform1ui (GLint location, GLuint v0) + cdef void glUniform2ui (GLint location, GLuint v0, GLuint v1) + cdef void glUniform3ui (GLint location, GLuint v0, GLuint v1, GLuint v2) + cdef void glUniform4ui (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) + cdef void glUniform1uiv (GLint location, GLsizei count, GLuint *value) + cdef void glUniform2uiv (GLint location, GLsizei count, GLuint *value) + cdef void glUniform3uiv (GLint location, GLsizei count, GLuint *value) + cdef void glUniform4uiv (GLint location, GLsizei count, GLuint *value) + cdef void glTexParameterIiv (GLenum target, GLenum pname, GLint *params) + cdef void glTexParameterIuiv (GLenum target, GLenum pname, GLuint *params) + cdef void glGetTexParameterIiv (GLenum target, GLenum pname, GLint *params) + cdef void glGetTexParameterIuiv (GLenum target, GLenum pname, GLuint *params) + cdef void glClearBufferiv (GLenum buffer, GLint drawbuffer, GLint *value) + cdef void glClearBufferuiv (GLenum buffer, GLint drawbuffer, GLuint *value) + cdef void glClearBufferfv (GLenum buffer, GLint drawbuffer, GLfloat *value) + cdef void glClearBufferfi (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil) + cdef GLubyte * glGetStringi (GLenum name, GLuint index) + cdef void glDrawArraysInstanced (GLenum mode, GLint first, GLsizei count, GLsizei primcount) + cdef void glDrawElementsInstanced (GLenum mode, GLsizei count, GLenum type, GLvoid *indices, GLsizei primcount) + cdef void glTexBuffer (GLenum target, GLenum internalformat, GLuint buffer) + cdef void glPrimitiveRestartIndex (GLuint index) + cdef void glFramebufferTexture (GLenum target, GLenum attachment, GLuint texture, GLint level) + cdef void glVertexAttribDivisor (GLuint index, GLuint divisor) + cdef void glMinSampleShading (GLclampf value) + cdef void glBlendEquationi (GLuint buf, GLenum mode) + cdef void glBlendEquationSeparatei (GLuint buf, GLenum modeRGB, GLenum modeAlpha) + cdef void glBlendFunci (GLuint buf, GLenum src, GLenum dst) + cdef void glBlendFuncSeparatei (GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) + cdef GLboolean glIsRenderbuffer (GLuint renderbuffer) + cdef void glBindRenderbuffer (GLenum target, GLuint renderbuffer) + cdef void glDeleteRenderbuffers (GLsizei n, GLuint *renderbuffers) + cdef void glGenRenderbuffers (GLsizei n, GLuint *renderbuffers) + cdef void glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height) + cdef void glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint *params) + cdef GLboolean glIsFramebuffer (GLuint framebuffer) + cdef void glBindFramebuffer (GLenum target, GLuint framebuffer) + cdef void glDeleteFramebuffers (GLsizei n, GLuint *framebuffers) + cdef void glGenFramebuffers (GLsizei n, GLuint *framebuffers) + cdef GLenum glCheckFramebufferStatus (GLenum target) + cdef void glFramebufferTexture1D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) + cdef void glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) + cdef void glFramebufferTexture3D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset) + cdef void glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) + cdef void glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint *params) + cdef void glGenerateMipmap (GLenum target) + cdef void glBlitFramebuffer (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) + cdef void glRenderbufferStorageMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) + cdef void glFramebufferTextureLayer (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer) + cdef void glBindVertexArray (GLuint array) + cdef void glDeleteVertexArrays (GLsizei n, GLuint *arrays) + cdef void glGenVertexArrays (GLsizei n, GLuint *arrays) + cdef GLboolean glIsVertexArray (GLuint array) + cdef void glGetUniformIndices (GLuint program, GLsizei uniformCount, GLchar* *uniformNames, GLuint *uniformIndices) + cdef void glGetActiveUniformsiv (GLuint program, GLsizei uniformCount, GLuint *uniformIndices, GLenum pname, GLint *params) + cdef void glGetActiveUniformName (GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName) + cdef GLuint glGetUniformBlockIndex (GLuint program, GLchar *uniformBlockName) + cdef void glGetActiveUniformBlockiv (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params) + cdef void glGetActiveUniformBlockName (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) + cdef void glUniformBlockBinding (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding) + cdef void glDrawElementsBaseVertex (GLenum mode, GLsizei count, GLenum type, GLvoid *indices, GLint basevertex) + cdef void glDrawRangeElementsBaseVertex (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, GLvoid *indices, GLint basevertex) + cdef void glDrawElementsInstancedBaseVertex (GLenum mode, GLsizei count, GLenum type, GLvoid *indices, GLsizei primcount, GLint basevertex) + cdef void glMultiDrawElementsBaseVertex (GLenum mode, GLsizei *count, GLenum type, GLvoid* *indices, GLsizei primcount, GLint *basevertex) + cdef void glProvokingVertex (GLenum mode) + cdef void glTexImage2DMultisample (GLenum target, GLsizei samples, GLint internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations) + cdef void glTexImage3DMultisample (GLenum target, GLsizei samples, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations) + cdef void glGetMultisamplefv (GLenum pname, GLuint index, GLfloat *val) + cdef void glSampleMaski (GLuint index, GLbitfield mask) + cdef void glBindFragDataLocationIndexed (GLuint program, GLuint colorNumber, GLuint index, GLchar *name) + cdef GLint glGetFragDataIndex (GLuint program, GLchar *name) + cdef void glGenSamplers (GLsizei count, GLuint *samplers) + cdef void glDeleteSamplers (GLsizei count, GLuint *samplers) + cdef GLboolean glIsSampler (GLuint sampler) + cdef void glBindSampler (GLuint unit, GLuint sampler) + cdef void glSamplerParameteri (GLuint sampler, GLenum pname, GLint param) + cdef void glSamplerParameteriv (GLuint sampler, GLenum pname, GLint *param) + cdef void glSamplerParameterf (GLuint sampler, GLenum pname, GLfloat param) + cdef void glSamplerParameterfv (GLuint sampler, GLenum pname, GLfloat *param) + cdef void glSamplerParameterIiv (GLuint sampler, GLenum pname, GLint *param) + cdef void glSamplerParameterIuiv (GLuint sampler, GLenum pname, GLuint *param) + cdef void glGetSamplerParameteriv (GLuint sampler, GLenum pname, GLint *params) + cdef void glGetSamplerParameterIiv (GLuint sampler, GLenum pname, GLint *params) + cdef void glGetSamplerParameterfv (GLuint sampler, GLenum pname, GLfloat *params) + cdef void glGetSamplerParameterIuiv (GLuint sampler, GLenum pname, GLuint *params) + cdef void glQueryCounter (GLuint id, GLenum target) + cdef void glVertexP2ui (GLenum type, GLuint value) + cdef void glVertexP2uiv (GLenum type, GLuint *value) + cdef void glVertexP3ui (GLenum type, GLuint value) + cdef void glVertexP3uiv (GLenum type, GLuint *value) + cdef void glVertexP4ui (GLenum type, GLuint value) + cdef void glVertexP4uiv (GLenum type, GLuint *value) + cdef void glTexCoordP1ui (GLenum type, GLuint coords) + cdef void glTexCoordP1uiv (GLenum type, GLuint *coords) + cdef void glTexCoordP2ui (GLenum type, GLuint coords) + cdef void glTexCoordP2uiv (GLenum type, GLuint *coords) + cdef void glTexCoordP3ui (GLenum type, GLuint coords) + cdef void glTexCoordP3uiv (GLenum type, GLuint *coords) + cdef void glTexCoordP4ui (GLenum type, GLuint coords) + cdef void glTexCoordP4uiv (GLenum type, GLuint *coords) + cdef void glMultiTexCoordP1ui (GLenum texture, GLenum type, GLuint coords) + cdef void glMultiTexCoordP1uiv (GLenum texture, GLenum type, GLuint *coords) + cdef void glMultiTexCoordP2ui (GLenum texture, GLenum type, GLuint coords) + cdef void glMultiTexCoordP2uiv (GLenum texture, GLenum type, GLuint *coords) + cdef void glMultiTexCoordP3ui (GLenum texture, GLenum type, GLuint coords) + cdef void glMultiTexCoordP3uiv (GLenum texture, GLenum type, GLuint *coords) + cdef void glMultiTexCoordP4ui (GLenum texture, GLenum type, GLuint coords) + cdef void glMultiTexCoordP4uiv (GLenum texture, GLenum type, GLuint *coords) + cdef void glNormalP3ui (GLenum type, GLuint coords) + cdef void glNormalP3uiv (GLenum type, GLuint *coords) + cdef void glColorP3ui (GLenum type, GLuint color) + cdef void glColorP3uiv (GLenum type, GLuint *color) + cdef void glColorP4ui (GLenum type, GLuint color) + cdef void glColorP4uiv (GLenum type, GLuint *color) + cdef void glSecondaryColorP3ui (GLenum type, GLuint color) + cdef void glSecondaryColorP3uiv (GLenum type, GLuint *color) + cdef void glVertexAttribP1ui (GLuint index, GLenum type, GLboolean normalized, GLuint value) + cdef void glVertexAttribP1uiv (GLuint index, GLenum type, GLboolean normalized, GLuint *value) + cdef void glVertexAttribP2ui (GLuint index, GLenum type, GLboolean normalized, GLuint value) + cdef void glVertexAttribP2uiv (GLuint index, GLenum type, GLboolean normalized, GLuint *value) + cdef void glVertexAttribP3ui (GLuint index, GLenum type, GLboolean normalized, GLuint value) + cdef void glVertexAttribP3uiv (GLuint index, GLenum type, GLboolean normalized, GLuint *value) + cdef void glVertexAttribP4ui (GLuint index, GLenum type, GLboolean normalized, GLuint value) + cdef void glVertexAttribP4uiv (GLuint index, GLenum type, GLboolean normalized, GLuint *value) + cdef void glDrawArraysIndirect (GLenum mode, GLvoid *indirect) + cdef void glDrawElementsIndirect (GLenum mode, GLenum type, GLvoid *indirect) + cdef void glUniform1d (GLint location, GLdouble x) + cdef void glUniform2d (GLint location, GLdouble x, GLdouble y) + cdef void glUniform3d (GLint location, GLdouble x, GLdouble y, GLdouble z) + cdef void glUniform4d (GLint location, GLdouble x, GLdouble y, GLdouble z, GLdouble w) + cdef void glUniform1dv (GLint location, GLsizei count, GLdouble *value) + cdef void glUniform2dv (GLint location, GLsizei count, GLdouble *value) + cdef void glUniform3dv (GLint location, GLsizei count, GLdouble *value) + cdef void glUniform4dv (GLint location, GLsizei count, GLdouble *value) + cdef void glUniformMatrix2dv (GLint location, GLsizei count, GLboolean transpose, GLdouble *value) + cdef void glUniformMatrix3dv (GLint location, GLsizei count, GLboolean transpose, GLdouble *value) + cdef void glUniformMatrix4dv (GLint location, GLsizei count, GLboolean transpose, GLdouble *value) + cdef void glUniformMatrix2x3dv (GLint location, GLsizei count, GLboolean transpose, GLdouble *value) + cdef void glUniformMatrix2x4dv (GLint location, GLsizei count, GLboolean transpose, GLdouble *value) + cdef void glUniformMatrix3x2dv (GLint location, GLsizei count, GLboolean transpose, GLdouble *value) + cdef void glUniformMatrix3x4dv (GLint location, GLsizei count, GLboolean transpose, GLdouble *value) + cdef void glUniformMatrix4x2dv (GLint location, GLsizei count, GLboolean transpose, GLdouble *value) + cdef void glUniformMatrix4x3dv (GLint location, GLsizei count, GLboolean transpose, GLdouble *value) + cdef void glGetUniformdv (GLuint program, GLint location, GLdouble *params) + cdef GLint glGetSubroutineUniformLocation (GLuint program, GLenum shadertype, GLchar *name) + cdef GLuint glGetSubroutineIndex (GLuint program, GLenum shadertype, GLchar *name) + cdef void glGetActiveSubroutineUniformiv (GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint *values) + cdef void glGetActiveSubroutineUniformName (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name) + cdef void glGetActiveSubroutineName (GLuint program, GLenum shadertype, GLuint index, GLsizei bufsize, GLsizei *length, GLchar *name) + cdef void glUniformSubroutinesuiv (GLenum shadertype, GLsizei count, GLuint *indices) + cdef void glGetUniformSubroutineuiv (GLenum shadertype, GLint location, GLuint *params) + cdef void glGetProgramStageiv (GLuint program, GLenum shadertype, GLenum pname, GLint *values) + cdef void glPatchParameteri (GLenum pname, GLint value) + cdef void glPatchParameterfv (GLenum pname, GLfloat *values) + cdef void glBindTransformFeedback (GLenum target, GLuint id) + cdef void glDeleteTransformFeedbacks (GLsizei n, GLuint *ids) + cdef void glGenTransformFeedbacks (GLsizei n, GLuint *ids) + cdef GLboolean glIsTransformFeedback (GLuint id) + cdef void glPauseTransformFeedback () + cdef void glResumeTransformFeedback () + cdef void glDrawTransformFeedback (GLenum mode, GLuint id) + cdef void glDrawTransformFeedbackStream (GLenum mode, GLuint id, GLuint stream) + cdef void glBeginQueryIndexed (GLenum target, GLuint index, GLuint id) + cdef void glEndQueryIndexed (GLenum target, GLuint index) + cdef void glGetQueryIndexediv (GLenum target, GLuint index, GLenum pname, GLint *params) + cdef void glReleaseShaderCompiler () + cdef void glShaderBinary (GLsizei count, GLuint *shaders, GLenum binaryformat, GLvoid *binary, GLsizei length) + cdef void glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision) + cdef void glDepthRangef (GLclampf n, GLclampf f) + cdef void glClearDepthf (GLclampf d) + cdef void glGetProgramBinary (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary) + cdef void glProgramBinary (GLuint program, GLenum binaryFormat, GLvoid *binary, GLsizei length) + cdef void glProgramParameteri (GLuint program, GLenum pname, GLint value) + cdef void glUseProgramStages (GLuint pipeline, GLbitfield stages, GLuint program) + cdef void glActiveShaderProgram (GLuint pipeline, GLuint program) + cdef GLuint glCreateShaderProgramv (GLenum type, GLsizei count, GLchar* *strings) + cdef void glBindProgramPipeline (GLuint pipeline) + cdef void glDeleteProgramPipelines (GLsizei n, GLuint *pipelines) + cdef void glGenProgramPipelines (GLsizei n, GLuint *pipelines) + cdef GLboolean glIsProgramPipeline (GLuint pipeline) + cdef void glGetProgramPipelineiv (GLuint pipeline, GLenum pname, GLint *params) + cdef void glProgramUniform1i (GLuint program, GLint location, GLint v0) + cdef void glProgramUniform1iv (GLuint program, GLint location, GLsizei count, GLint *value) + cdef void glProgramUniform1f (GLuint program, GLint location, GLfloat v0) + cdef void glProgramUniform1fv (GLuint program, GLint location, GLsizei count, GLfloat *value) + cdef void glProgramUniform1d (GLuint program, GLint location, GLdouble v0) + cdef void glProgramUniform1dv (GLuint program, GLint location, GLsizei count, GLdouble *value) + cdef void glProgramUniform1ui (GLuint program, GLint location, GLuint v0) + cdef void glProgramUniform1uiv (GLuint program, GLint location, GLsizei count, GLuint *value) + cdef void glProgramUniform2i (GLuint program, GLint location, GLint v0, GLint v1) + cdef void glProgramUniform2iv (GLuint program, GLint location, GLsizei count, GLint *value) + cdef void glProgramUniform2f (GLuint program, GLint location, GLfloat v0, GLfloat v1) + cdef void glProgramUniform2fv (GLuint program, GLint location, GLsizei count, GLfloat *value) + cdef void glProgramUniform2d (GLuint program, GLint location, GLdouble v0, GLdouble v1) + cdef void glProgramUniform2dv (GLuint program, GLint location, GLsizei count, GLdouble *value) + cdef void glProgramUniform2ui (GLuint program, GLint location, GLuint v0, GLuint v1) + cdef void glProgramUniform2uiv (GLuint program, GLint location, GLsizei count, GLuint *value) + cdef void glProgramUniform3i (GLuint program, GLint location, GLint v0, GLint v1, GLint v2) + cdef void glProgramUniform3iv (GLuint program, GLint location, GLsizei count, GLint *value) + cdef void glProgramUniform3f (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2) + cdef void glProgramUniform3fv (GLuint program, GLint location, GLsizei count, GLfloat *value) + cdef void glProgramUniform3d (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2) + cdef void glProgramUniform3dv (GLuint program, GLint location, GLsizei count, GLdouble *value) + cdef void glProgramUniform3ui (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2) + cdef void glProgramUniform3uiv (GLuint program, GLint location, GLsizei count, GLuint *value) + cdef void glProgramUniform4i (GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3) + cdef void glProgramUniform4iv (GLuint program, GLint location, GLsizei count, GLint *value) + cdef void glProgramUniform4f (GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) + cdef void glProgramUniform4fv (GLuint program, GLint location, GLsizei count, GLfloat *value) + cdef void glProgramUniform4d (GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3) + cdef void glProgramUniform4dv (GLuint program, GLint location, GLsizei count, GLdouble *value) + cdef void glProgramUniform4ui (GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3) + cdef void glProgramUniform4uiv (GLuint program, GLint location, GLsizei count, GLuint *value) + cdef void glProgramUniformMatrix2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, GLfloat *value) + cdef void glProgramUniformMatrix3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, GLfloat *value) + cdef void glProgramUniformMatrix4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, GLfloat *value) + cdef void glProgramUniformMatrix2dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, GLdouble *value) + cdef void glProgramUniformMatrix3dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, GLdouble *value) + cdef void glProgramUniformMatrix4dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, GLdouble *value) + cdef void glProgramUniformMatrix2x3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, GLfloat *value) + cdef void glProgramUniformMatrix3x2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, GLfloat *value) + cdef void glProgramUniformMatrix2x4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, GLfloat *value) + cdef void glProgramUniformMatrix4x2fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, GLfloat *value) + cdef void glProgramUniformMatrix3x4fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, GLfloat *value) + cdef void glProgramUniformMatrix4x3fv (GLuint program, GLint location, GLsizei count, GLboolean transpose, GLfloat *value) + cdef void glProgramUniformMatrix2x3dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, GLdouble *value) + cdef void glProgramUniformMatrix3x2dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, GLdouble *value) + cdef void glProgramUniformMatrix2x4dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, GLdouble *value) + cdef void glProgramUniformMatrix4x2dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, GLdouble *value) + cdef void glProgramUniformMatrix3x4dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, GLdouble *value) + cdef void glProgramUniformMatrix4x3dv (GLuint program, GLint location, GLsizei count, GLboolean transpose, GLdouble *value) + cdef void glValidateProgramPipeline (GLuint pipeline) + cdef void glGetProgramPipelineInfoLog (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog) + cdef void glVertexAttribL1d (GLuint index, GLdouble x) + cdef void glVertexAttribL2d (GLuint index, GLdouble x, GLdouble y) + cdef void glVertexAttribL3d (GLuint index, GLdouble x, GLdouble y, GLdouble z) + cdef void glVertexAttribL4d (GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w) + cdef void glVertexAttribL1dv (GLuint index, GLdouble *v) + cdef void glVertexAttribL2dv (GLuint index, GLdouble *v) + cdef void glVertexAttribL3dv (GLuint index, GLdouble *v) + cdef void glVertexAttribL4dv (GLuint index, GLdouble *v) + cdef void glVertexAttribLPointer (GLuint index, GLint size, GLenum type, GLsizei stride, GLvoid *pointer) + cdef void glGetVertexAttribLdv (GLuint index, GLenum pname, GLdouble *params) + cdef void glViewportArrayv (GLuint first, GLsizei count, GLfloat *v) + cdef void glViewportIndexedf (GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h) + cdef void glViewportIndexedfv (GLuint index, GLfloat *v) + cdef void glScissorArrayv (GLuint first, GLsizei count, GLint *v) + cdef void glScissorIndexed (GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height) + cdef void glScissorIndexedv (GLuint index, GLint *v) + cdef void glDepthRangeArrayv (GLuint first, GLsizei count, GLclampd *v) + cdef void glDepthRangeIndexed (GLuint index, GLclampd n, GLclampd f) + cdef void glGetFloati_v (GLenum target, GLuint index, GLfloat *data) + cdef void glGetDoublei_v (GLenum target, GLuint index, GLdouble *data) + cdef void glDrawArraysInstancedBaseInstance (GLenum mode, GLint first, GLsizei count, GLsizei primcount, GLuint baseinstance) + cdef void glDrawElementsInstancedBaseInstance (GLenum mode, GLsizei count, GLenum type, void *indices, GLsizei primcount, GLuint baseinstance) + cdef void glDrawElementsInstancedBaseVertexBaseInstance (GLenum mode, GLsizei count, GLenum type, void *indices, GLsizei primcount, GLint basevertex, GLuint baseinstance) + cdef void glDrawTransformFeedbackInstanced (GLenum mode, GLuint id, GLsizei primcount) + cdef void glDrawTransformFeedbackStreamInstanced (GLenum mode, GLuint id, GLuint stream, GLsizei primcount) + cdef void glGetInternalformativ (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params) + cdef void glGetActiveAtomicCounterBufferiv (GLuint program, GLuint bufferIndex, GLenum pname, GLint *params) + cdef void glBindImageTexture (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format) + cdef void glMemoryBarrier (GLbitfield barriers) + cdef void glTexStorage1D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width) + cdef void glTexStorage2D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) + cdef void glTexStorage3D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) diff -Nru pybik-0.5/pybiklib/glarea.py pybik-1.0.1/pybiklib/glarea.py --- pybik-0.5/pybiklib/glarea.py 2012-01-04 06:56:23.000000000 +0000 +++ pybik-1.0.1/pybiklib/glarea.py 2012-12-05 10:42:28.000000000 +0000 @@ -1,4 +1,5 @@ #-*- coding:utf-8 -*- +# cython: profile=False # Pybik -- A 3 dimensional magic cube game. # Copyright © 2009-2012 B. Clausius @@ -16,650 +17,388 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . - # Ported from GNUbik -# Original filename: glarea.c -# Original copyright and license: 2003, 2004 John Darrington, GPL3+ +# Original filename: glarea-common.c +# Original copyright and license: 2003 John Darrington, GPL3+ -import os -from collections import namedtuple +# no unicode_literals for compiled modules +from __future__ import print_function, division -import OpenGL.error -from OpenGL import GLX as glx -import gobject -import gtk -from gtk import gdk -from gtk import gtkgl -from gtk import gdkgl -import gio - -from .debug import * -from . import config -import cube -import drwBlock -import glarea_common -from . import textures -from .confstore import confstore, COLORED, IMAGED, SELECTIONMODE_QUAD, SELECTIONMODE_EXT - - -RDRAG_COLOUR = 0 -RDRAG_FILELIST = 1 -# picture rate in ms. 40ms = 25 frames per sec -picture_rate = 40 - -class CubeArea (gobject.GObject): - __gsignals__ = { - 'texture-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ()), - 'end-animation': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (bool,)), - 'request-rotation': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (int,int,int)), - } +# This line makes cython happy +global __name__, __package__ # pylint: disable=W0604 +#px/__compiled = True +__compiled = False + +# pylint: disable=W0614,W0401 +#px/from gl cimport * +from OpenGL.GL import * +#px/from glu cimport * +from OpenGL.GLU import * +#px/from libc.math cimport cos, sin, tan, atan2, M_PI +from math import cos, sin, tan, atan2, pi as M_PI +#px/from _gldraw cimport * +from gldraw import * +# pylint: enable=W0614,W0401 + +from .debug import debug, DEBUG_DRAW + +debug('Importing module:', __name__) +debug(' from package:', __package__) +debug(' compiled:', __compiled) + + +#px/cdef Matrix rotation_matrix +rotation_matrix = Matrix() + +# jitter8 distribution for antialiasing +# -7-5-3-1 1 3 5 7 +# +----------------+ +# 7 |*1 | +# 5 | *3 | +# 3 | *2 | +# 1 | *5| +# -1 | *0 | +# -3 | *7 | +# -5 | *4 | +# -7 | *6 | +# +----------------+ +jitter1 = [(0, 0)] +jitter2 = [(-1/4, 1/4), (1/4, -1/4)] +jitter3 = [( 0.0033922635, 0.3317967229), + ( 0.2806016275,-0.2495619123), + (-0.2738171062,-0.0868446388)] +# pylint: disable=C0324 +jitter5 = [(0, 0), (-1/5,-2/5), ( 1/5, 2/5), ( 2/5,-1/5), (-2/5, 1/5)] +jitter8 = [( 1/16,-1/16), (-7/16, 7/16), (-3/16, 3/16), ( 3/16, 5/16), + ( 5/16,-5/16), ( 7/16, 1/16), (-1/16,-7/16), (-5/16,-3/16)] +# pylint: enable=C0324 +jitters = [jitter1, jitter2, jitter3, jitter5, jitter8] + +#px/cdef struct Terrain: +class terrain: pass # pylint: disable=W0232, C0321, R0903 + #px+float red + #px+float green + #px+float blue + #px+bint lighting + #px+int width + #px+int height +#px+cdef Terrain terrain + +#px/cdef struct Frustrum: +class frustrum: # pylint: disable=W0232, R0903 + #px+double bounding_sphere_radius + #px+double zoom + #px+double cp_near + #px+double cp_far + #px/double proj_rect[4] + proj_rect = [None]*4 + #px+int antialiasing + #px+int njitter + #px/double proj_rects_jitter[8][4] + proj_rects_jitter = [[None]*4 for __i in range(8)] + #px+bint multisample +#px+cdef Frustrum frustrum + + +### module state + +def init_module(): + terrain.red = 0.0 + terrain.green = 0.0 + terrain.blue = 0.0 + terrain.lighting = False + terrain.width = 1 + terrain.height = 1 - def __init__(self): - gobject.GObject.__init__(self) - - self.widget = None - self.last_mouse_x = -1 - self.last_mouse_y = -1 - self.default_rotation_x = 10. - self.default_rotation_y = 10. - self.rotation_x, self.rotation_y = glarea_common.set_rotation_xy( - self.default_rotation_x, self.default_rotation_y) - self.button_down_background = False - self.render_pending = False - self.setcursor_pending = False - self.animation_in_progress = 0 - self.timer = None - # the time for which the mouse must stay still, for anything to happen. - self.idle_threshold = 10 - self.mouse_xy = -1, -1 - # Structure to hold copy of the last selection taken or None - self.current_selection = None - self.selection_mode = None - self.enable_disable_selection_entered = 0 - self.stop_detected = False - self.motion = False - self.stop_requested = False - self.abort_requested = False - confstore.callbacks.append(self.on_confstore_changed) - - self.cursors = None - self.load_cursors() - - def is_item_selected(self): - return self.current_selection is not None - - def init(self, widget): - self.widget = widget - - # this is the number of frames drawn when a slice of the cube rotates 90 degrees - self.frameQty = confstore.frameQty - - attribs = [ gdkgl.RGBA, - gdkgl.RED_SIZE, 1, - gdkgl.GREEN_SIZE, 1, - gdkgl.BLUE_SIZE, 1, - - gdkgl.DOUBLEBUFFER, - - gdkgl.DEPTH_SIZE , 1, - - gdkgl.ACCUM_RED_SIZE, 1, - gdkgl.ACCUM_GREEN_SIZE, 1, - gdkgl.ACCUM_BLUE_SIZE, 1, - - gdkgl.ATTRIB_LIST_NONE - ] - - drwBlock.glutInit([]) - glconfig = gdkgl.Config(attribs) - if not glconfig: - raise Exception("Cannot get a suitable visual") - gtkgl.widget_set_gl_capability(self.widget, - glconfig, - None, - True, - gdkgl.RGBA_TYPE) - - self.widget.connect("realize", self.on_realize) - self.widget.connect("expose-event", self.on_expose_event) - self.widget.connect("configure-event", self.on_resize) - - target = [ ("text/uri-list", 0, RDRAG_FILELIST), - ("application/x-color", 0, RDRAG_COLOUR), ] - self.widget.drag_dest_set(gtk.DEST_DEFAULT_ALL, target, gdk.ACTION_COPY) - self.widget.connect("drag-data-received", self.on_drag_data_received) - - self.widget.add_events(gdk.KEY_PRESS_MASK | gdk.BUTTON_PRESS_MASK - | gdk.BUTTON_RELEASE_MASK - # | gdk.BUTTON_MOTION_MASK - | gdk.ENTER_NOTIFY_MASK | gdk.LEAVE_NOTIFY_MASK - | gdk.VISIBILITY_NOTIFY_MASK - | gdk.POINTER_MOTION_MASK) - - self.widget.connect("key-press-event", self.on_key_press_event) - - self.widget.connect("motion-notify-event", self.on_motion_notify_event) - self.widget.connect("button-press-event", self.on_button_press_event) - self.widget.connect("button-release-event", self.on_button_release_event) - - # initialise the selection mechanism - self.set_selection_mode(confstore.selection_mode) - self.timer = gobject.timeout_add(self.idle_threshold, self.on_timer_motion) - # Add a handler to for all those occasions when we don't need the - # selection mechanism going - self.widget.connect("enter-notify-event", self.on_enter_leave_notify_event) - self.widget.connect("leave-notify-event", self.on_enter_leave_notify_event) - self.widget.connect("visibility-notify-event", self.on_enter_leave_notify_event) - self.widget.connect("unmap-event", self.on_enter_leave_notify_event) - - def load_cursors(self): - display = gdk.display_get_default() - cursors = [] - # Load 3 cursors from file (n - ne) - for i, (x, y) in enumerate([(8, 0), (11, 0), (15, 0)]): - filename = os.path.join(config.UI_DIR, 'mouse_{}.png'.format(i)) - pixbuf = gdk.pixbuf_new_from_file(filename) - cursors.append((pixbuf, x, y)) - # 1 cursor (nnw) - pixbuf, x, y = cursors[1] - cursors.insert(0, (pixbuf.flip(True), 15-x, y)) - # 12 cursors (ene - nw) - for i in range(4,16): - pixbuf, x, y = cursors[-4] - cursors.append((pixbuf.rotate_simple(gdk.PIXBUF_ROTATE_CLOCKWISE), 15-y, x)) - cursors.append(cursors[0]) - self.cursors = [gdk.Cursor(display, pixbuf, x, y) for pixbuf, x, y in cursors[1:]] - self.cursors.append(gdk.Cursor(gdk.DOT)) - self.cursors.append(gdk.Cursor(gdk.CROSSHAIR)) - - @staticmethod - def set_the_colours(): - for i in xrange(6): - color = gdk.Color(confstore.colors[i].color) - facetype = confstore.colors[i].facetype - if facetype == COLORED: - pattern = confstore.colors[i].pattern - texname = textures.stock_pattern[pattern].texName if pattern >= 0 else -1 - elif facetype == IMAGED: - imagefile = confstore.colors[i].imagefile - try: - pixbuf = textures.create_pixbuf_from_file(imagefile) - texname = textures.create_pattern_from_pixbuf(pixbuf) - except Exception, err: - debug("Cannot create image from file {}: {}".format(imagefile, err)) - texname = -1 - else: - texname = -1 - drwBlock.face_rendering_set(i, red=color.red / 65535.0, - green=color.green / 65535.0, - blue=color.blue / 65535.0, - facetype=facetype, - texname=texname, - distr=confstore.colors[i].imagemode) - - def re_initialize(self): - glcontext = gtkgl.widget_get_gl_context(self.widget) - gldrawable = gtkgl.widget_get_gl_drawable(self.widget) - - if not gldrawable.gl_begin(glcontext): - debug("Cannot initialise gl drawable") - return - - #TODO: Move the initialisation code somewhere else - try: - self.__texInit_done - except AttributeError: - textures.texInit() - self.__texInit_done = True - glarea_common.graphics_area_init(confstore.lighting) - self.set_the_colours() - color = gdk.Color(confstore.background_color) - glarea_common.set_background_color(color.red_float, color.green_float, color.blue_float) - gldrawable.gl_end() - - @staticmethod - def apply_to_glmodel(model): - assert model.dimension - cube.set_cube_dimension(model.dimension) - drwBlock.init_model() - assert model.blocks - cube.cube_set_blocks(model.blocks) - - def on_realize(self, unused_widget): - self.re_initialize() - - def on_expose_event(self, unused_widget, unused_event): - self.render_idle() - - def on_resize(self, widget, event): - height = event.height - width = event.width - glcontext = gtkgl.widget_get_gl_context(widget) - gldrawable = gtkgl.widget_get_gl_drawable(widget) - - if not gdkgl.Drawable.make_current(gldrawable, glcontext): - debug("Cannot set gl drawable current") - return - - try: - glx.glXWaitGL() - glx.glXWaitX() - except OpenGL.error.GLError: - pass - glarea_common.resize(width, height) - - return False - - def on_key_press_event(self, unused_widget, event): - if event.keyval == gtk.keysyms.Right: - self.rotation_x += 1 - elif event.keyval == gtk.keysyms.Left: - self.rotation_x -= 1 - elif event.keyval == gtk.keysyms.Up: - self.rotation_y -= 1 - elif event.keyval == gtk.keysyms.Down: - self.rotation_y += 1 - else: - return False - - self.rotation_x, self.rotation_y = glarea_common.set_rotation_xy( - self.rotation_x, self.rotation_y) - self.render() - return True - - FacetSelection = namedtuple('FacetSelection', 'block face quadrant maxis mslice mdir') - selectionmode_ext_map = { - ( 0,0): 0, ( 0,2): 3, ( 0,4): 1, - ( 1,0): 1, ( 1,2): 3, - ( 2,0): 1, ( 2,2): 2, ( 2,5): 2, - ( 3,0): 0, ( 3,4): 2, - ( 4,0): 0, - ( 5,0): 2, ( 5,5): 2, - ( 6,0): 3, ( 6,3): 0, ( 6,4): 2, - ( 7,0): 3, ( 7,3): 1, - ( 8,0): 2, ( 8,3): 1, ( 8,5): 1, - ( 9,2): 0, ( 9,4): 1, - (10,2): 0, - (11,2): 2, (11,5): 3, - (12,4): 0, - (14,5): 0, - (15,3): 0, (15,4): 3, - (16,3): 0, - (17,3): 2, (17,5): 1, - (18,1): 3, (18,2): 0, (18,4): 0, - (19,1): 3, (19,2): 1, - (20,1): 2, (20,2): 1, (20,5): 3, - (21,1): 0, (21,4): 0, - (22,1): 0, - (23,1): 2, (23,5): 0, - (24,1): 0, (24,3): 3, (24,4): 3, - (25,1): 1, (25,3): 3, - (26,1): 1, (26,3): 2, (26,5): 0, - } - def pick_polygons(self, x, y): - '''Identify the block at screen co-ordinates x,y.''' - - glcontext = gtkgl.widget_get_gl_context(self.widget) - gldrawable = gtkgl.widget_get_gl_drawable(self.widget) - - if not gdkgl.Drawable.make_current(gldrawable, glcontext): - debug("Cannot set gl drawable current") - return - - height = self.widget.allocation.height - - #TODO Fix pick mode 2 and remove pick mode 1 - # CubeArea.update_selection uses (axis, slice, dir) - # and dialogcolors.drag_data_received uses face, so pick_polygons should return 4 values - closest = glarea_common.pick_polygons(confstore.lighting, x, height-y, 1) - #closest2 = glarea_common.pick_polygons(x, height-y, 1, 2) - if closest is None: - return None - - block = closest[0] - face = closest[1] - quadrant = closest[2] - - size = cube.get_cube_dimension() - if self.selection_mode == SELECTIONMODE_EXT and size > 1: - blockidx = [block % size, block/size % size, block/size/size % size] - blockidx = [0 if b==0 else 1 if b= 0 else -1 - #confstore.colors[i].facetype = COLORED - drwBlock.face_rendering_set(i, texname=texname) - def set_imagefile(i): - imagefile = confstore.colors[i].imagefile - #debug('set_imagefile',i,imagefile) - try: - pixbuf = textures.create_pixbuf_from_file(imagefile) - texname = textures.create_pattern_from_pixbuf(pixbuf) - except Exception, err: - debug(_("Cannot create image from file {filename}: {error}").format( - filename=imagefile, error=err)) - else: - #debug('image tex',texname) - drwBlock.face_rendering_set(i, texname=texname) - - if key == 'frameQty': - self.frameQty = confstore.frameQty - elif key == 'lighting': - self.set_lighting(confstore.lighting) - elif key == 'dimension': - pass - elif key == 'selection_mode': - self.set_selection_mode(confstore.selection_mode) - elif key == 'colors': - i = int(subkeys[0]) - if subkeys[1] == 'color': - set_color(i) - elif subkeys[1] == 'pattern': - set_pattern(i) - elif subkeys[1] == 'imagefile': - set_imagefile(i) - elif subkeys[1] == 'facetype': - facetype = confstore.colors[i].facetype - if facetype == COLORED: - set_pattern(i) - elif facetype == IMAGED: - set_imagefile(i) - drwBlock.face_rendering_set(i, facetype=facetype) - elif subkeys[1] == 'imagemode': - imagemode = confstore.colors[i].imagemode - drwBlock.face_rendering_set(i, distr=imagemode) - #set_imagefile(i) - else: - debug('Unknown conf value changed:', subkeys[1]) - self.render() - elif key == 'background_color': - self.set_background_color(gdk.Color(confstore.background_color)) - else: - debug('Unknown conf value changed:', key) - - +#px/cpdef set_lighting(int enable): +def set_lighting(enable): + terrain.lighting = enable + +def set_background_color(red, green, blue): + terrain.red = red + terrain.green = green + terrain.blue = blue + +def set_antialiasing(antialiasing, multisample=None): + if antialiasing is not None: + frustrum.antialiasing = antialiasing + if frustrum.antialiasing < 0: + frustrum.antialiasing = 0 + elif frustrum.antialiasing >= len(jitters): + frustrum.antialiasing = len(jitters) - 1 + frustrum.njitter = len(jitters[frustrum.antialiasing]) + if multisample is not None: + frustrum.multisample = multisample + _update_projection() + +#px/cdef void _set_rotation_matrix(p_Vector M, float radiansx, float radiansy): +def _set_rotation_matrix(M, radiansx, radiansy): + #px+cdef float sx, sy, cx, cy + #px+cdef float m00, m11, m12, m20 + + sx = sin(radiansx/2) + sy = sin(radiansy/2) + cx = cos(radiansx/2) + cy = cos(radiansy/2) + + m00 = 2*cx*cx - 1. + m11 = 2*cy*cy - 1. + m12 = 2*sy*cy + m20 = 2*sx*cx + # pylint: disable=C0321 + M[0][0] = m00; M[1][0] = 0.; M[2][0] = m20 + M[0][1] = m12 * m20; M[1][1] = m11; M[2][1] = -m00 * m12 + M[0][2] = -m11 * m20; M[1][2] = m12; M[2][2] = m00 * m11 + # py lint: enable=C0321 + + M[0][3] = M[1][3] = M[2][3] = 0. + M[3][0] = M[3][1] = M[3][2] = 0. + M[3][3] = 1. + +def set_rotation_xy(x, y): + x %= 360 + # pylint: disable=C0321 + if y < -90: y = -90 + elif y > 90: y = 90 + _set_rotation_matrix(rotation_matrix, M_PI * x / 180.0, M_PI * y / 180.0) + return x, y + +### GL state + +#px/cdef void _init_lighting(): +def _init_lighting(): + #px/cdef float *light_ambient = [.2, .2, .2, 1.] + light_ambient = [.2, .2, .2, 1.] + #px/cdef float *light_diffuse = [1., 1., 1., 1.] + light_diffuse = [1., 1., 1., 1.] + ##px/cdef float *mat_diffuse = [.8, .8, .8, 1.] + #mat_diffuse = [.8, .8, .8, 1.] + # Controls intensity and color of specular reflections + #px/cdef float *mat_specular = [.5, .6, .5, 1.] + mat_specular = [.5, .6, .5, 1.] + # Controls SPREAD of specular reflections (128.0 = small highlight) + #px+cdef float mat_shininess + mat_shininess = 60. + # Directional light, at infinity (parameter 4, w=0.0), shining towards -Z + #px/cdef float *light_position = [0., 0., 1., 0.] + light_position = [0., 0., 1., 0.] + #px/cdef float *lmodel_ambient = [.6, .6, .6, 1.] + lmodel_ambient = [.6, .6, .6, 1.] + + glShadeModel(GL_SMOOTH) + + glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient) + glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse) + glLightfv(GL_LIGHT0, GL_POSITION, light_position) + + glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient) + # Trying to light the insides of the cubies is a waste of time + glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE) + + # This gives a rolling-sheen effect to the specularity. + # Not all stickers on a face light up at once. + glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE) + + glEnable(GL_LIGHT0) + + glShadeModel(GL_FLAT) + + glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular) + #glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse) + glMaterialf(GL_FRONT, GL_SHININESS, mat_shininess) + glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE) + glEnable(GL_COLOR_MATERIAL) + + glEnable(GL_NORMALIZE) + +def init_glarea(): + debug('GL Version:', + #px+ + glGetString(GL_VERSION)) + glClearColor(0., 0., 0., 1.) + glEnable(GL_DEPTH_TEST) + glEnable(GL_CULL_FACE) # Rasterise only the exterior faces, to speed things up + glMatrixMode(GL_MODELVIEW) + glLoadIdentity() + _init_lighting() + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) + glClear(GL_ACCUM_BUFFER_BIT) + glAccum(GL_RETURN, 1.0) + +def resize(width, height): + terrain.width = width + terrain.height = height + glViewport(0, 0, terrain.width, terrain.height) + _update_projection() + +### display functions + +#px/cdef void _init_projection(double* proj_rect): +def _init_projection(proj_rect): + glMatrixMode(GL_PROJECTION) + glLoadIdentity() + glFrustum(proj_rect[0], proj_rect[1], + proj_rect[2], proj_rect[3], + frustrum.cp_near, frustrum.cp_far) + +#px/cdef void _init_modelview(): +def _init_modelview(): + # Update viewer position in modelview matrix + glMatrixMode(GL_MODELVIEW) + glLoadIdentity() + gluLookAt(0, 0, frustrum.bounding_sphere_radius + frustrum.cp_near, + 0, 0, 0, # center + 0.0, 1.0, 0.0) # up + #px/glMultMatrixf(rotation_matrix) + glMultMatrixf(rotation_matrix) + +def display(): + #px+cdef int jitter + + if terrain.lighting: + glEnable(GL_LIGHTING) + else: + glDisable(GL_LIGHTING) + if frustrum.multisample: + glEnable(GL_MULTISAMPLE) + else: + glDisable(GL_MULTISAMPLE) + glClearColor(terrain.red, terrain.green, terrain.blue, 1.) + _init_modelview() + if frustrum.antialiasing: + glClear(GL_ACCUM_BUFFER_BIT) + for jitter in xrange(frustrum.njitter): + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) + _init_projection(frustrum.proj_rects_jitter[jitter]) + glMatrixMode(GL_MODELVIEW) + draw_cube() + glAccum(GL_ACCUM, 1.0/frustrum.njitter) + glAccum(GL_RETURN, 1.0) + else: + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) + _init_projection(frustrum.proj_rect) + glMatrixMode(GL_MODELVIEW) + draw_cube() + if DEBUG_DRAW: + draw_cube_debug() + + +### picking functions + +def pick_polygons(x, y, granularity): + #px+cdef int viewport[4] + #px+cdef unsigned char pixel[3] + + #px/glGetIntegerv(GL_VIEWPORT, viewport) + viewport = glGetIntegerv(GL_VIEWPORT) + if not (0 <= x - viewport[0] < viewport[2] and 0 <= y - viewport[1] < viewport[3]): + return 0 + + glDisable(GL_LIGHTING) + + glMatrixMode(GL_PROJECTION) + glPushMatrix() + glLoadIdentity() + gluPickMatrix(x, y, granularity, granularity, viewport) + glFrustum(frustrum.proj_rect[0], frustrum.proj_rect[1], + frustrum.proj_rect[2], frustrum.proj_rect[3], + frustrum.cp_near, frustrum.cp_far) + glClearColor(0., 0., 0., 1.) + _init_modelview() + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) + + pick_cube() + #px/glReadPixels(x, y, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, pixel) + pixel = glReadPixels(x, y, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, [[[0, 0, 0]]])[0][0] + index = pixel[0]<<4 | pixel[1] | pixel[2]>>4 + + glMatrixMode(GL_PROJECTION) + glPopMatrix() + + return index + +#px/cdef _modelview_to_viewport(int *viewport, Matrix proj, Matrix view, vvect): +def _modelview_to_viewport(viewport, proj, view, vvect): + #px+cdef float u0, u1, u2, v0, v1, v3 + #px+cdef int w0, w1 + + # u = V^T * vvect + u0 = view[0][0]*vvect[0] + view[1][0]*vvect[1] + view[2][0]*vvect[2] + view[3][0] + u1 = view[0][1]*vvect[0] + view[1][1]*vvect[1] + view[2][1]*vvect[2] + view[3][1] + u2 = view[0][2]*vvect[0] + view[1][2]*vvect[1] + view[2][2]*vvect[2] + view[3][2] + #u3 = 1. + + # v = P * u + v0 = proj[0][0] * u0 + proj[1][0] * u1 + proj[2][0] * u2 + proj[3][0] #* u3 + v1 = proj[0][1] * u0 + proj[1][1] * u1 + proj[2][1] * u2 + proj[3][1] #* u3 + #v2 = proj[0][2] * u0 + proj[1][2] * u1 + proj[2][2] * u2 + proj[3][2] * u3 + v3 = proj[0][3] * u0 + proj[1][3] * u1 + proj[2][3] * u2 + proj[3][3] #* u3 + + w0 = int((v0 / v3 + 1) / 2 * viewport[2]) + w1 = int((v1 / v3 + 1) / 2 * viewport[3]) + return w0, w1 + +def get_cursor_angle(point1, point2): + '''The result is the angle (on the screen) + at which the mouse cursor needs to be drawn.''' + #px+cdef int viewport[4] + #px+cdef Matrix view + #px+cdef Matrix proj + #px+cdef float v1,v2, w1,w2, angle + + #px/glGetIntegerv(GL_VIEWPORT, viewport) + viewport = glGetIntegerv(GL_VIEWPORT) + #px/glGetFloatv(GL_PROJECTION_MATRIX, proj) + proj = glGetFloatv(GL_PROJECTION_MATRIX) + #px/glGetFloatv(GL_MODELVIEW_MATRIX, view) + view = glGetFloatv(GL_MODELVIEW_MATRIX) + + v1, v2 = _modelview_to_viewport(viewport, proj, view, point1) + w1, w2 = _modelview_to_viewport(viewport, proj, view, point2) + + angle = atan2((v1-w1), (v2-w2)) * 180.0 / M_PI + return angle, ((point1, point2), ((v1, v2), (w1, w2))) + + diff -Nru pybik-0.5/pybiklib/glarea_common.py pybik-1.0.1/pybiklib/glarea_common.py --- pybik-0.5/pybiklib/glarea_common.py 2012-01-06 16:33:45.000000000 +0000 +++ pybik-1.0.1/pybiklib/glarea_common.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,376 +0,0 @@ -#-*- coding:utf-8 -*- - -# Pybik -- A 3 dimensional magic cube game. -# Copyright © 2009-2012 B. Clausius -# -# 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 . - - -# Ported from GNUbik -# Original filename: glarea-common.c -# Original copyright and license: 2003 John Darrington, GPL3+ - - -global __name__, __file__, __package__ - - -import cython - -#pxd from gl cimport * -#pxd from glu cimport * -#pxd from math cimport * -#pxd from cube_c cimport * -#pxd from drwBlock_c cimport * -#px-5 -from OpenGL.GL import * -from OpenGL.GLU import * -from math import cos, sin, tan, pi as M_PI -from cube import * -from drwBlock import * - -import cube - -from debug import debug - -debug('Importing module:', __name__) -debug(' from package:', __package__) -debug(' compiled:', cython.compiled) - - -#pxd ctypedef float Quarternion[4] -#px- -Quarternion = None - -# Start with the unit quarternion -cython.declare(cube_view = Quarternion) -#px- -cube_view = [0.] * 4 -cube_view[0] = 0. -cube_view[1] = 0. -cube_view[2] = 0. -cube_view[3] = 1. - - -j8 = [ (0.5625, 0.4375), - (0.0625, 0.9375), - (0.3125, 0.6875), - (0.6875, 0.8125), - (0.8125, 0.1875), - (0.9375, 0.5625), - (0.4375, 0.0625), - (0.1875, 0.3125), - ] - - -# Functions for rotation - -#pxd cdef void quarternion_to_matrix(p_Vector M, float* q) -def quarternion_to_matrix(M, q): - cython.declare( - q00 = cython.float, - q01 = cython.float, - q02 = cython.float, - q11 = cython.float, - q12 = cython.float, - q22 = cython.float, - q03 = cython.float, - q13 = cython.float, - q23 = cython.float, - q33 = cython.float, - ) - q00 = q[0] * q[0] - q01 = q[0] * q[1] - q02 = q[0] * q[2] - q03 = q[0] * q[3] - q11 = q[1] * q[1] - q12 = q[1] * q[2] - q13 = q[1] * q[3] - q22 = q[2] * q[2] - q23 = q[2] * q[3] - q33 = q[3] * q[3] - - M[0][0] = q33 + q00 - q11 - q22 - M[1][1] = q33 - q00 + q11 - q22 - M[2][2] = q33 - q00 - q11 + q22 - M[3][3] = q33 + q00 + q11 + q22 - - M[0][1] = 2*(q01 - q23); M[0][2] = 2*(q02 + q13); M[1][2] = 2*(q12 - q03) - M[1][0] = 2*(q01 + q23); M[2][0] = 2*(q02 - q13); M[2][1] = 2*(q12 + q03) - - M[0][3] = M[1][3] = M[2][3] = 0.0 - M[3][0] = M[3][1] = M[3][2] = 0.0 - -def set_rotation_xy(x, y): - cython.declare( - radiansx = cython.float, - radiansy = cython.float, - sx = cython.float, - sy = cython.float, - cx = cython.float, - cy = cython.float) - x %= 180 - if y < -45: y = -45 - elif y > 45: y = 45 - radiansx = -M_PI * x / 180.0 - radiansy = -M_PI * y / 180.0 - sx = sin(radiansx) - sy = sin(radiansy) - cx = cos(radiansx) - cy = cos(radiansy) - cube_view[0] = sy * cx - cube_view[1] = cy * sx - cube_view[2] = -sy * sx - cube_view[3] = cy * cx - return x, y - - -# display functions - -cython.declare( - fovy = cython.float, - cp_near = cython.float, - cp_far = cython.float, - bounding_sphere_radius = cython.float) -fovy = 33.0 # field of view angle -cp_near = -1 -cp_far = -1 -bounding_sphere_radius = 0 - - -# Wrapper to set the modelview matrix -#pxd cdef void modelViewInit() -def modelViewInit(): - cython.declare( - m = Matrix) - #px- - m = Matrix() - - # Update viewer position in modelview matrix - glMatrixMode(GL_MODELVIEW) - glLoadIdentity() - gluLookAt(0, 0, bounding_sphere_radius + cp_near, - 0, 0, 0, # center - 0.0, 1.0, 0.0) # up - - quarternion_to_matrix(m, cube_view) - glMultMatrixM(m) - - # - # DM 3-Jan-2004 - # - # Add a couple of 90 degree turns to get the top and right faces in their - # logical positions when the program starts up. - glRotatef(90.0, 1, 0, 0) - glRotatef(-90.0, 0, 0, 1) - -#pxd cdef inline int* glGetViewport(int* v): -#pxd glGetIntegerv(GL_VIEWPORT, v) -#pxd return v -#px- -def glGetViewport(unused_v): return glGetIntegerv(GL_VIEWPORT) - -# accFrustum and accPerspective are taken from p397 of the Red Book -#pxd cdef void accFrustum(double rad, double zNear, double zFar, double pixdx, double pixdy) -def accFrustum(rad, zNear, zFar, pixdx, pixdy): - cython.declare( - viewport_ = cython.int[4], - viewport = cython.p_int, - dx = cython.double, - dy = cython.double, - wsize = cython.double) - #px- - viewport_ = None - - viewport = glGetViewport(viewport_) - wsize = 2*rad - dx = -pixdx * wsize / viewport[2] - dy = -pixdy * wsize / viewport[3] - - glFrustum(dx-rad, dy+rad, dy-rad, dy+rad, zNear, zFar) - -#pxd cdef void projection_init(int jitter) -def projection_init(jitter): - global bounding_sphere_radius, cp_near, cp_far - bounding_sphere_radius = 2 * cube.get_cube_dimension() - cp_near = bounding_sphere_radius / tan(fovy * M_PI / 360.0) - cp_far = cp_near + 2*bounding_sphere_radius - - glEnable(GL_DEPTH_TEST) - - glMatrixMode(GL_PROJECTION) - glLoadIdentity() - - accFrustum(bounding_sphere_radius, cp_near, cp_far, j8[jitter][0], j8[jitter][1]) - -def graphics_area_init(lighting): - lighting_init(lighting) - glClearColor(0., 0., 0., 0.) - projection_init(0) - modelViewInit() - -def display(): - glClearColor(background_color.red, background_color.green, background_color.blue, 1.) - projection_init(0) - modelViewInit() - glClear(GL_ACCUM_BUFFER_BIT) - - for jitter in xrange(8): - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) - - projection_init(jitter) - modelViewInit() - - draw_cube() - glAccum(GL_ACCUM, 1.0/8.0) - glAccum(GL_RETURN, 1.0) - -#pxd cdef enum: -#pxd BUFSIZE = 512 -#pxd ctypedef GLuint SelectBuf[BUFSIZE] -#px-2 -BUFSIZE = 512 -SelectBuf = lambda: [0]*BUFSIZE -cython.declare( - selectBuf = SelectBuf - ) -#px- -selectBuf = SelectBuf() - -#pxd cdef void glSelectBuffer_() -def glSelectBuffer_(): - #px- - glSelectBuffer(BUFSIZE); return - glSelectBuffer(BUFSIZE, selectBuf) -#pxd ctypedef unsigned char *p_uchar -#pxd cdef inline p_uchar glReadPixel(int x, int y, p_uchar pixel): -#pxd glReadPixels(x, y, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, pixel); return pixel -#px-3 -p_uchar = cython.p_char -def glReadPixel(x, y, pixel): - return glReadPixels(x, y, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, [[[0, 0, 0]]])[0][0] - -def pick_polygons(lighting, x, y, granularity, pick_mode=1): - cython.declare( - viewport_ = cython.int[4], - viewport = cython.p_int, - pixel = cython.uchar[3], - pixel_ = p_uchar) - #px-2 - viewport_ = None - pixel = [0]*3 - - viewport = glGetViewport(viewport_) - if x < 0 or y < 0 or x >= viewport[2] or y >= viewport[3]: - return None - - if lighting: - set_lighting(False) - - glMatrixMode(GL_PROJECTION) - glPushMatrix() - glLoadIdentity() - - gluPickMatrix(x, y, granularity, granularity, viewport) - gluPerspective(fovy, 1, cp_near, cp_far) - - glClearColor(0., 0., 0., 0.) - modelViewInit() - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) - if pick_mode == 1: - pick_cube() - else: - pick2_cube() - glMatrixMode(GL_PROJECTION) - glPopMatrix() - - pixel_ = glReadPixel(x, y, pixel) - - if lighting: - set_lighting(True) - - if pixel_[2] == 0: - return None - if pick_mode == 1: - return (((pixel_[0]-68)<<8) | pixel_[1]) >> 3, pixel_[1] & 0x7, pixel_[2] / 0x55 - else: - return pixel_[0], pixel_[1], pixel_[2] - - -#pxd cdef void lighting_init(bint lighting) -def lighting_init(lighting): - cython.declare( - light_ambient = cython.float[4], - mat_diffuse = cython.float[4], - mat_specular = cython.float[4], - mat_shininess = cython.float, - light_position = cython.float[4]) - #px-4 - light_ambient = [0]*4 - mat_diffuse = [0]*4 - mat_specular = [0]*4 - light_position = [0]*4 - - init_vector(light_ambient, [0.6, 0.6, 0.6, 1.0]) - init_vector(mat_diffuse, [0.8, 0.8, 0.8, 1.0]) - init_vector(mat_specular, [0.2, 0.2, 0.2, 1.0]) - mat_shininess = 1.0 - init_vector(light_position, [-1.0, 0.5, 0.0, 0.0]) - - glShadeModel(GL_SMOOTH) - glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE) - - glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular) - glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse) - glMaterialf(GL_FRONT, GL_SHININESS, mat_shininess) - - glLightfv(GL_LIGHT0, GL_POSITION, light_position) - glLightfv(GL_LIGHT1, GL_AMBIENT, light_ambient) - - if lighting: - glEnable(GL_LIGHTING) - else: - glDisable(GL_LIGHTING) - glEnable(GL_COLOR_MATERIAL) - glEnable(GL_LIGHT0) - glEnable(GL_LIGHT1) - -#pxd cpdef set_lighting(int enable) -def set_lighting(enable): - if enable: - glEnable(GL_LIGHTING) - else: - glDisable(GL_LIGHTING) - -#pxd cdef struct _Color: -#pxd float red -#pxd float green -#pxd float blue -#px-2 -class _Color: pass -background_color = _Color() -cython.declare(background_color = _Color) - -def set_background_color(red, green, blue): - background_color.red = red - background_color.green = green - background_color.blue = blue - -#pxd cpdef resize(int width, int height) -def resize(width, height): - cython.declare( - min_dim = cython.int) - min_dim = min(width, height) - # Ensure that cube is always the same proportions - glViewport((width-min_dim) / 2, (height-min_dim) / 2, min_dim, min_dim) - diff -Nru pybik-0.5/pybiklib/gldraw.py pybik-1.0.1/pybiklib/gldraw.py --- pybik-0.5/pybiklib/gldraw.py 1970-01-01 00:00:00.000000000 +0000 +++ pybik-1.0.1/pybiklib/gldraw.py 2013-02-01 08:15:41.000000000 +0000 @@ -0,0 +1,381 @@ +#-*- coding:utf-8 -*- +# cython: profile=False + +# Pybik -- A 3 dimensional magic cube game. +# Copyright © 2009-2012 B. Clausius +# +# 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 . + +# Ported from GNUbik +# Original filename: cube.c, drwBlock.c +# Original copyright and license: 1998, 2003, 2004 Dale Mellor, John Darrington, GPL3+ + +# no unicode_literals for compiled modules, because it leads to compile errors in numpy +from __future__ import print_function, division + +# This line makes cython happy +global __name__, __package__ # pylint: disable=W0604 +#px/__compiled = True +__compiled = False + +__all__ = ['draw_cube', 'pick_cube', 'draw_cube_debug', 'Matrix'] + +from .debug import debug, DEBUG_PICK # pylint: disable=W0614,W0401 + +#pxd/from gl cimport * #: +from OpenGL.GL import * # pylint: disable=W0614,W0401 + +#px/cimport numpy as np +import numpy as np + + +debug('Importing module:', __name__) +debug(' from package:', __package__) +debug(' compiled:', __compiled) + + +#px/cdef enum: +if True: + MAX_BLOCKS = 1000 + MAX_FACES = 6 + MAX_FACES_PER_BLOCK = 6 + _TILED = 0 + _MOSAIC = 1 + +#pxd/ctypedef float Vector[4] +Vector = lambda: [0] * 4 +#pxd/ctypedef Vector* p_Vector +p_Vector = None +#pxd/ctypedef Vector Matrix[4] +Matrix = lambda: [Vector() for unused_i in range(4)] + +#px/cdef struct Block: +class Block: # pylint: disable=R0903 +#px- + def __init__(self): + # The position from the centre of the cube, and the rotation from the + # 'natural' position. + #px/Matrix transformation + self.transformation = Matrix() # Matrix + + # only used when animation.running==True otherwise the value is meaningless + #px/bint in_motion + self.in_motion = None + + #px/int cnt_faces + self.cnt_faces = None + #px/int idx_label[MAX_FACES_PER_BLOCK] + self.idx_label = [None]*MAX_FACES_PER_BLOCK + #px/int cnt_label[MAX_FACES_PER_BLOCK] + self.cnt_label = [None]*MAX_FACES_PER_BLOCK + #px/int faceno[MAX_FACES_PER_BLOCK] + self.faceno = [None]*MAX_FACES_PER_BLOCK + + #px/int idx_quads + self.idx_quads = None + #px/int cnt_quads + self.cnt_quads = None + #px/int idx_triangles + self.idx_triangles = None + #px/int cnt_triangles + self.cnt_triangles = None + +#px/cdef struct Cube: +class cube: # pylint: disable=W0232, R0903 + #px+unsigned int size + #px+unsigned int number_blocks + #px/Block blocks[MAX_BLOCKS] + blocks = [Block() for __block in xrange(MAX_BLOCKS)] + + #px+float *model_data_label + #px+float *model_data_lnormal + #px+float *model_data_pick + #px+GLubyte *model_data_pickcolor + #px+int cnt_pick + + #px+float *model_data_texpos_tiled + #px+float *model_data_texpos_mosaic +#px+cdef Cube cube + +#px/cdef float color_bevel[3] +color_bevel = [None] * 3 + +#px/cdef struct Face: +class Face: pass # pylint: disable=W0232, C0321, R0903 + #px+float color[3] + #px+int texName + #px+int distr +#px/cdef Face face_rendering[MAX_FACES] +face_rendering = [Face() for __i in range(MAX_FACES)] + +#px/cdef struct Animation_Struct: +class animation: # pylint: disable=W0232, R0903 + #px+bint running + #px+float angle, angle_max + #px/float rotation[3] + rotation = [None] * 3 +#px+cdef Animation_Struct animation + + +def init_module(): + #px+cdef int i + + cube.size = cube.number_blocks = 0 + #cube.blocks + + #cube.model_data_label + #cube.model_data_lnormal + #cube.model_data_pick + #cube.model_data_pickcolor + cube.cnt_pick = 0 + + #cube.model_data_texpos_tiled + #cube.model_data_texpos_mosaic + + for i in xrange(3): + color_bevel[i] = .1 + + for i in xrange(MAX_FACES): + #px- + face_rendering[i].color = [0]*3 + set_face_rendering(i, red=1., green=1., blue=1., imagemode=_TILED) + face_rendering[i].texName = -1 + + animation.running = 0 + animation.angle = animation.angle_max = 0 + for i in xrange(3): + animation.rotation[i] = 0. + +#px/cpdef set_animation_block(int block_id, bint selected): +def set_animation_block(block_id, selected): + cube.blocks[block_id].in_motion = selected + +def set_transformations(blocks): + #px+cdef int b,i,j + for b in range(cube.number_blocks): + for i in range(4): + for j in range(4): + cube.blocks[b].transformation[i][j] = float(blocks[b][i][j]) + +#px/cpdef start_animate(float angle_max, float axisx, float axisy, float axisz): +def start_animate(angle_max, axisx, axisy, axisz): + animation.angle = 0.0 + animation.angle_max = angle_max + animation.running = 1 + animation.rotation[0] = axisx + animation.rotation[1] = axisy + animation.rotation[2] = axisz + +#px/cpdef step_animate(float increment): +def step_animate(increment): + animation.angle -= increment + return abs(animation.angle) < animation.angle_max + +def end_animate(): + animation.running = 0 + +#pxd/cdef void draw_cube(): +def draw_cube(): + if DEBUG_PICK: + pick_cube() + return + + #px+cdef int i + #px+cdef p_Vector M + + for i in range(cube.number_blocks): + glPushMatrix() + if animation.running and cube.blocks[i].in_motion: + glRotatef(animation.angle, + animation.rotation[0], animation.rotation[1], animation.rotation[2]) + #px/M = cube.blocks[i].transformation + M = cube.blocks[i].transformation + #px/glMultMatrixf(M) + glMultMatrixf(M) + draw_block(i) + glPopMatrix () + +#px/cdef void draw_block(int block_id): +def draw_block(block_id): + #px+cdef int i + + glEnableClientState(GL_VERTEX_ARRAY) + glEnableClientState(GL_NORMAL_ARRAY) + glVertexPointer(3, GL_FLOAT, 0, cube.model_data_label) + glNormalPointer(GL_FLOAT, 0, cube.model_data_lnormal) + glColor3fv(color_bevel) + glDrawArrays(GL_QUADS, cube.blocks[block_id].idx_quads, cube.blocks[block_id].cnt_quads) + glDrawArrays(GL_TRIANGLES, cube.blocks[block_id].idx_triangles, cube.blocks[block_id].cnt_triangles) + + for i in range(cube.blocks[block_id].cnt_faces): + faceno = cube.blocks[block_id].faceno[i] + # render the colors (ie the little sticky labels) + glColor3fv(face_rendering[faceno].color) + if face_rendering[faceno].texName != -1: + glEnableClientState(GL_TEXTURE_COORD_ARRAY) + glEnable(GL_TEXTURE_2D) + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL) + glBindTexture(GL_TEXTURE_2D, face_rendering[faceno].texName) + if face_rendering[faceno].distr == _MOSAIC: + glTexCoordPointer(2, GL_FLOAT, 0, cube.model_data_texpos_mosaic) + else: # TILED + glTexCoordPointer(2, GL_FLOAT, 0, cube.model_data_texpos_tiled) + glDrawArrays(GL_QUADS, cube.blocks[block_id].idx_label[i], cube.blocks[block_id].cnt_label[i]) + glDisableClientState(GL_TEXTURE_COORD_ARRAY) + glDisable(GL_TEXTURE_2D) + else: + glDrawArrays(GL_QUADS, cube.blocks[block_id].idx_label[i], cube.blocks[block_id].cnt_label[i]) + + glDisableClientState(GL_VERTEX_ARRAY) + glDisableClientState(GL_NORMAL_ARRAY) + +#pxd/cdef void pick_cube(): +def pick_cube(): + #px+cdef int block_id, face + + glEnableClientState(GL_VERTEX_ARRAY) + glEnableClientState(GL_COLOR_ARRAY) + glVertexPointer(3, GL_FLOAT, 0, cube.model_data_pick) + glColorPointer(3, GL_UNSIGNED_BYTE, 0, cube.model_data_pickcolor) + glDrawArrays(GL_TRIANGLES, 0, cube.cnt_pick) + glDisableClientState(GL_VERTEX_ARRAY) + glDisableClientState(GL_COLOR_ARRAY) + +def set_model(model): + #px+cdef int block + + # The number of blocks per side of the cube. + cube.size = model.sizes[0] + cube.number_blocks = len(model.blocks) + assert cube.number_blocks <= MAX_BLOCKS + + #### Create the raw GL data #### + #px+cdef np.ndarray[float, mode="c"] glvertices + #px+cdef np.ndarray[float, mode="c"] glnormals + #px+cdef np.ndarray[GLubyte, mode="c"] glcolors + #px+cdef np.ndarray[float, mode="c"] gltexpostiled, gltexposmosaic + #px+cdef int idx_vbevelq, idx_vbevelt + ( glvertices, glnormals, glcolors, gltexpostiled, gltexposmosaic, + blockinfos, + idx_vbevelq, idx_vbevelt + ) = model.gl_data() + + #px/cube.model_data_label = &glvertices[0] + cube.model_data_label = glvertices[0:] + #px/cube.model_data_lnormal = &glnormals[0] + cube.model_data_lnormal = glnormals[0:] + #px/cube.model_data_texpos_tiled = &gltexpostiled[0] + cube.model_data_texpos_tiled = gltexpostiled[0:] + #px/cube.model_data_texpos_mosaic = &gltexposmosaic[0] + cube.model_data_texpos_mosaic = gltexposmosaic[0:] + + #px+cdef int idx + lidx = 0 + qidx = idx_vbevelq // 3 + tidx = idx_vbevelt // 3 + for block in range(cube.number_blocks): + cube.blocks[block].cnt_faces = len(blockinfos[block][0]) + for i, (cnt, faceno) in enumerate(blockinfos[block][0]): + cube.blocks[block].idx_label[i] = lidx + cube.blocks[block].cnt_label[i] = cnt + cube.blocks[block].faceno[i] = faceno + lidx += cnt + cube.blocks[block].idx_quads = qidx + cube.blocks[block].cnt_quads = blockinfos[block][1] + qidx += blockinfos[block][1] + cube.blocks[block].idx_triangles = tidx + cube.blocks[block].cnt_triangles = blockinfos[block][2] + tidx += blockinfos[block][2] + +#px/cpdef set_pick_model(np.ndarray[float, mode="c"] glvertices, np.ndarray[GLubyte, mode="c"] glcolors): +def set_pick_model(glvertices, glcolors): + #px/cube.model_data_pick = &glvertices[0] + cube.model_data_pick = glvertices + #px/cube.model_data_pickcolor = &glcolors[0] + cube.model_data_pickcolor = glcolors + cube.cnt_pick = len(glvertices) // 3 + +#pxd/cdef void draw_cube_debug(): +def draw_cube_debug(): + #px+cdef float offset + offset = 1.4 * cube.size + + # X axis + glPushMatrix() + glTranslatef(-offset, -offset, -1.*cube.size) + glBegin(GL_LINES) + glColor3f(1., 0., 0.) + glVertex3f(0, 0, 0) + glVertex3f(2*cube.size, 0, 0) + glEnd() + + glRasterPos3d(offset*1.1, 0, 0) + glPopMatrix() + + # Y axis + glPushMatrix() + glTranslatef(-offset, -offset, -1.*cube.size) + glBegin(GL_LINES) + glColor3f(0., 1., 0.) + glVertex3f(0, 0, 0) + glVertex3f(0, 2*cube.size, 0) + glEnd() + + glRasterPos3d(0.1*offset, offset, 0) + glPopMatrix() + + # Z axis + glPushMatrix() + glTranslatef(-offset, -offset, -1.*cube.size) + glBegin(GL_LINES) + glColor3f(0., 0., 1.) + glVertex3f(0, 0, 0) + glVertex3f(0, 0, 2*cube.size) + glEnd() + + glRasterPos3d(0.1*offset, 0, offset) + glPopMatrix () + +def draw_dot(x, y): + #px/cdef float *pixel = [1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,1.,] + pixel = [1.] * 16 + glWindowPos2i(x, y) + glDrawPixels(4, 4, GL_GREEN, GL_FLOAT, pixel) + +def draw_select_debug(modelview_points, viewport_points): + glDisable(GL_DEPTH_TEST) + glColor3f(1., 1., 1.) + glBegin(GL_LINES) + for point in modelview_points: + glVertex3f(point[0], point[1], point[2]) + glEnd() + for point in viewport_points: + draw_dot(point[0], point[1]) + glEnable(GL_DEPTH_TEST) + + +def set_face_rendering(faceidx, red=-1, green=-1, blue=-1, imagemode=-1): + # pylint: disable=C0321 + if red >= 0: face_rendering[faceidx].color[0] = red + if green >= 0: face_rendering[faceidx].color[1] = green + if blue >= 0: face_rendering[faceidx].color[2] = blue + if imagemode >= 0: face_rendering[faceidx].distr = imagemode + +#px/cpdef set_face_texture(int faceidx, int texname): +def set_face_texture(faceidx, texname): + prevtexname = face_rendering[faceidx].texName + face_rendering[faceidx].texName = texname + return prevtexname + + diff -Nru pybik-0.5/pybiklib/main.py pybik-1.0.1/pybiklib/main.py --- pybik-0.5/pybiklib/main.py 2012-01-06 16:33:58.000000000 +0000 +++ pybik-1.0.1/pybiklib/main.py 2013-01-31 09:53:39.000000000 +0000 @@ -16,182 +16,306 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . - # Ported from GNUbik # Original filename: main.c # Original copyright and license: 1998, 2003--2004 John Darrington, GPL3+ +from __future__ import print_function, division, unicode_literals -import sys -import argparse -argparse._ = _ -# These strings are defined in the module argparse -# and repeated here so that they are included in the translation template. -if False: - #Translators: Strings from file main.py are visible only on the commandline and/or in the man-page - _('usage: ') - _('optional arguments') +import sys, os +from collections import namedtuple from . import debug, config +N_ = lambda s: s -def import_ext(pure_python): - if not pure_python: + +def format_opts(opts): + opts = ((o + o.strip('--')[0].upper() if o.endswith('=') else o) for o in opts) + return ' ' + ', '.join(opts) + +def format_help(text, indent=0): + try: + width = int(os.environ['COLUMNS']) - 2 + except (KeyError, ValueError): + width = 78 + width -= indent + def split(text): + lines = text.split('\n') + for line in lines: + res = None + words = line.split(' ') + for word in words: + if res is None: + res = word + elif len(res + word) + 1 <= width: + res = ' '.join((res, word)) + else: + yield res + res = word + yield res + return '\n'.ljust(indent+1).join(split(text)) + +def print_usage(unused_value, unused_opts): + print('Usage:', sys.argv[0], '[options]') + for args, unused_func, text in arg_info: + if args is None: + print() + print(format_help(text)) + else: + opts = format_opts(args) + if len(opts) > 18: + text = '\n' + text + else: + opts = opts.ljust(20) + text = format_help(text, 20) + print(opts + text) + sys.exit(0) + +def print_version(*unused_args): + print(config.APPNAME, config.VERSION) + print() + print(config.COPYRIGHT.replace('©', '(C)')) #XXX: help2man cannot handle unicode + print() + print(config.wrap(config.LICENSE_INFO)) + print() + print(config.wrap(config.LICENSE_NOT_FOUND)) + sys.exit(0) + +debug_level_names = [__a[6:].lower() for __a in debug.__all__ if __a.startswith('DEBUG_')] + +arg_info = [ + (None, None, config.LONG_DESCRIPTION.replace('ő', 'o')), #XXX: help2man cannot handle unicode + (None, None, 'Pybik can be fully controlled and configured via the graphical user interface.' + ' The options listed here are intended primarily for testing and debugging.'), + (None, None, 'Options:'), + (['-h', '--help'], print_usage, + 'Show help message and exit'), + (['--version'], print_version, + 'Show version number and exit'), + (['--config-file='], lambda value, opts: opts.setdefault('config-file', value), + 'Specify the configuration file to use instead of the default location'), + (['--defaultconfig'], lambda value, opts: opts.setdefault('defaultconfig', True), + 'Print default settings to stdout and exit'), + (['--pyside'], lambda value, opts: opts.setdefault('pyside', True), + 'Use PySide, cannot combined with --pyqt4'), + (['--pyqt4'], lambda value, opts: opts.setdefault('pyqt4', True), + 'Use PyQt4, cannot be combined with --pyside,' + ' is neither --pyside nor --pyqt4 is given, the application' + ' first imports PySide and if that fails it imports PyQt4'), + (['--pure-python'], lambda value, opts: opts.setdefault('pure-python', True), + 'Use python module for rendering (very slow)'), + (['--debug='], lambda value, opts: opts.setdefault('debug', value), + 'Enable debug output, D is a comma-separated list of debug flags:\n{0}' + .format(' '.join(debug_level_names))), + (None, None, 'Qt-Options, for a full list refer to the Qt-Reference,' + ' but not all options make sense for this application:'), + (['-style S'], None, + 'sets the application GUI style. Possible values are' + ' motif, windows, and platinum.'), + (['-widgetcount'], None, + 'prints debug message at the end about number of widgets left' + ' undestroyed and maximum number of widgets existed at the same time'), + (['-reverse'], None, + "sets the application's layout direction to left-to-right"), + (['-graphicssystem G'], None, + 'sets the backend to be used for on-screen widgets and pixmaps.' + ' Available options are raster and opengl.'), + ] + +def parse_args(args): + arg_functs = {o: f for opts, f, h in arg_info for o in opts or [] if f is not None} + opts = {} + ui_args = [] + for arg in args: try: - import cube_c - sys.modules['pybiklib.cube'] = cube_c - sys.modules['cube_c'] = cube_c + index = arg.index('=') + except ValueError: + value = None + else: + arg, value = arg[:index+1], arg[index+1:] + try: + func = arg_functs[arg] + except KeyError: + ui_args.append(arg) + else: + func(value, opts) + + if 'pyside' in opts: + if 'pyqt4' in opts: + print('You cannot use both --pyside and --pyqt4') + sys.exit(1) + else: + pythonqt = 'pyside' + else: + if 'pyqt4' in opts: + pythonqt = 'pyqt4' + else: + pythonqt = None + + debug_flags = opts.get('debug', None) + if debug_flags is not None: + debug_flags = [f for f in debug_flags.split(',') if f] + for d in debug_flags: + if d not in debug_level_names: + print('unknown debug option:', d) + sys.exit(1) + + Opts = namedtuple('Opts', 'debug_flags pythonqt pure_python ui_args config_file defaultconfig') + return Opts(debug_flags, pythonqt, opts.get('pure-python', False), ui_args, + opts.get('config-file', config.USER_SETTINGS_FILE), opts.get('defaultconfig', False)) + +def import_ext(pythonqt, pure_python): + if pythonqt != 'pyqt4': + debug.debug('Importing PySide') + try: + import PySide, PySide.QtCore, PySide.QtGui, PySide.QtOpenGL except ImportError as e: - print e - print 'Unable to import module cube_c, using slow fallback.' - pure_python = True + debug.debug(' Failed') + if pythonqt == 'pyside': + print('PySide not found.', e) + sys.exit(1) + pythonqt = 'pyqt4' + if pythonqt == 'pyqt4': + debug.debug('Importing PyQt4') + try: + import sip + sip.setapi('QString', 2) + sip.setapi('QVariant', 2) + import PyQt4 + import PyQt4.QtCore + import PyQt4.QtGui + import PyQt4.QtOpenGL + except ImportError as e: + debug.debug(' Failed') + print('Python bindings for Qt4 not found.', e) + sys.exit(1) + sys.modules[b'PySide'] = PyQt4 + sys.modules[b'PySide.QtCore'] = PyQt4.QtCore + sys.modules[b'PySide.QtGui'] = PyQt4.QtGui + sys.modules[b'PySide.QtOpenGL'] = PyQt4.QtOpenGL + # Monkey patch QtCore + # pylint: disable=E1101 + PyQt4.QtCore.Signal = PyQt4.QtCore.pyqtSignal + PyQt4.QtCore.Slot = PyQt4.QtCore.pyqtSlot + PyQt4.QtCore.Qt.CursorShape.CrossCursor = PyQt4.QtCore.Qt.CrossCursor + PyQt4.QtCore.Qt.TransformationMode.SmoothTransformation = \ + PyQt4.QtCore.Qt.SmoothTransformation + # Monkey patch QtOpenGL + PyQt4.QtOpenGL.QGLContext.BindOption.LinearFilteringBindOption = \ + PyQt4.QtOpenGL.QGLContext.LinearFilteringBindOption + PyQt4.QtOpenGL.QGLContext.BindOption.MipmapBindOption = PyQt4.QtOpenGL.QGLContext.MipmapBindOption + # pylint: enable=E1101 + + if debug.DEBUG: + import PySide, PySide.QtCore, PySide.QtGui, PySide.QtOpenGL # pylint: disable=W0404 + debug.debug('Qt modules:', PySide.__name__, PySide.QtCore.__name__, + PySide.QtGui.__name__, PySide.QtOpenGL.__name__) + if not pure_python: try: - import drwBlock_c - sys.modules['pybiklib.drwBlock'] = drwBlock_c - sys.modules['drwBlock_c'] = drwBlock_c + import _gldraw + sys.modules[b'pybiklib.gldraw'] = _gldraw + sys.modules[b'_gldraw'] = _gldraw except ImportError as e: - del sys.modules['pybiklib.cube'] - del sys.modules['cube_c'] - print e - print 'Unable to import module drwBlock_c, using slow fallback.' + print(e) + print('Unable to import module _gldraw, using slow fallback.') pure_python = True if not pure_python: try: - import glarea_common_c - sys.modules['pybiklib.glarea_common'] = glarea_common_c + import _glarea + sys.modules[b'pybiklib.glarea'] = _glarea except ImportError as e: - del sys.modules['pybiklib.cube'] - del sys.modules['cube_c'] - del sys.modules['pybiklib.drwBlock'] - del sys.modules['drwBlock_c'] - print e - print 'Unable to import module glarea_common_c, using slow fallback.' - else: - return - try: - import cython - debug.debug('cython found') - cython.float[5] - debug.debug('cython types support indexing') - except (ImportError, TypeError): - debug.debug('cython not found or types do not support indexing: simulate') - def _ctype(type_): - class _CType (object): - def __call__(self, *args): - return type_(*args) - def __getitem__(self, n): - return lambda: [None]*n - return _CType() - - sys.modules['cython'] = cython = type(sys)('cython') - cython.compiled = False - def declare(*args, **kwags): - if len(args) == 1: - return args[0]() - if len(args) == 2: - return args[0](args[1]) - cython.declare = declare - def struct(**kwargs): - class _Struct (object): - def __init__(self): - for k in kwargs: - setattr(self, k, None) - return _Struct - cython.struct = struct - def locals(**kwargs): - return lambda func: func - cython.locals = locals - cython.NULL = None - cython.int = _ctype(int) - cython.p_int = object - cython.float = _ctype(float) - cython.p_float = object - cython.double = _ctype(float) - cython.short = _ctype(int) - cython.uchar = _ctype(int) - cython.p_char = object - + del sys.modules[b'pybiklib.gldraw'] + del sys.modules[b'_gldraw'] + print(e) + print('Unable to import module _glarea, using slow fallback.') + if pure_python: + try: + from OpenGL import GL as unused_GL + except ImportError as e: + print('Python bindings for OpenGL not found.', e) + sys.exit(1) + -def run(): - options = app_opts() +def run_app(root_dir, args, config_file): + import gettext + from PySide.QtCore import QLocale, QTranslator, QTimer + from PySide.QtGui import QApplication, QPalette, QColor - debug.install(debug, options.debug_modes) - debug.debug('debug output enabled:') - debug.debug(' ', *[m for m, v in options.debug_modes.items() if v is True]) - debug.debug(' ', *['%s=%d'%(m, v) for m, v in options.debug_modes.items() if type(v) is int]) - debug.debug(config.PACKAGE, config.VERSION) - - import_ext(options.pure_python) - - import application - app = application.Application() - if options.frameQty is not None: - app.cube_area.frameQty = options.frameQty - app.first_new_game(options.cube_dimension, options.solved) - app.run_main_loop() - - -debug_level_names = [__a[6:].lower() - for __a in debug.__all__ - if __a.startswith('DEBUG_') and __a != 'DEBUG_LEVEL'] - -def arg_parser(): - '''Create parser for pybik arguments. - Used for command line and to create man page - ''' - parser = argparse.ArgumentParser( - description=unicode(config.get_description(),'utf-8'), - add_help=False, - ) - - parser.add_argument('-h', '--help', action='help', - help=unicode(_("Show help message and exit"),'utf-8')) - parser.add_argument('--version', action='version', version=config.VERSION, - help=unicode(_("Show version number and exit"),'utf-8')) - parser.add_argument("-s", "--solved", action="store_true", default=False, - help=unicode(_("Start with the cube already solved"),'utf-8')) - parser.add_argument("--size", type=int, dest='cube_dimension', - help=unicode(_("Start with a N x N x N sized cube"),'utf-8'), metavar="N") - parser.add_argument("--animation", type=int, dest='frameQty', - help=unicode(_("Show N intermediate positions in animations"),'utf-8'), metavar="N") - parser.add_argument("--pure-python", action="store_true", default=False, - help=unicode(_("Use python module for rendering (very slow)"),'utf-8')) - parser.add_argument("--debug", type=str, dest='debug_level', default=-1, - help=unicode(_("Enable debug output, D is an integer or" - " a comma-separated list of [{0}]"),'utf-8') - .format(','.join(debug_level_names)), - metavar="D") - return parser - -def app_opts(): - '''Returns parsed args from command line''' - parser = arg_parser() - args = parser.parse_args() + # initialize QApplication + app = QApplication(args) + args = app.arguments()[1:] + if args: + print('Unknown arguments:', ' '.join(args)) + sys.exit(1) + app.setOrganizationName(config.PACKAGE) + app.setApplicationName(config.APPNAME) + app.setApplicationVersion(config.VERSION) + + # Workaround for whatsThis-Text (white text on light background) + palette = app.palette() + colorfg = palette.color(QPalette.Active, QPalette.ToolTipText) + colorbg = palette.color(QPalette.Active, QPalette.ToolTipBase) + valuefg = colorfg.value() + valuebg = (valuefg + 255) // 2 if valuefg < 128 else valuefg // 2 + colorbg = QColor.fromHsv(colorbg.hue(), colorbg.saturation(), valuebg) + palette.setColor(QPalette.Active, QPalette.ToolTipBase, colorbg) + app.setPalette(palette) + + # initialize translation + language = QLocale.system().name() + # standard Qt translation, used for e.g. standard buttons and shortcut names + translator = QTranslator() + translator.load('qt_' + language, config.QT_LOCALE_DIR) + app.installTranslator(translator) + # the rest of the app use gettext for translation + if root_dir == sys.prefix: + # normal installation + LOCALEDIR = None + else: + # different root, e.g. /usr/local, source directory + LOCALEDIR = config.LOCALE_DIR + t = gettext.translation(config.PACKAGE, LOCALEDIR, languages=[language], fallback=True) + t.install(unicode=True, names=['ngettext']) - debug_level = args.debug_level - debug_level_names_u = [a.upper() for a in debug_level_names] + # initialize settings + from .settings import settings try: - debug_level = int(debug_level) - debug_level_max = sum([1< +# +# 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 . + +from __future__ import print_function, division, unicode_literals + +import sys, os, subprocess + + +rotation_symbolic_compact_to_idxrot = { + "":"", "ff":"FF", "ll":"LL", "uu":"UU", + "f":"F", "f'":"B", "fuu":"UUB", "fll":"UUF", + "ffu":"ULL", "u":"U", "u'":"D", "ffu'":"UFF", + "fu":"UL", "f'u":"UR", "fu'":"FD", "f'u'":"LB", + "f'l'":"DB", "uf":"UF", "fl":"LD", "lu":"UB", + "l'":"R", "ffl'":"UUL", "l":"L", "ffl":"UUR", + } + +def indices_compact_to_index(indices, size): + indices = tuple(indices) + for b in range(size * size * size): + bindices = (b % size, b // size % size, b // size // size) + if bindices == indices: + return b + raise ValueError('Invalid block indices:', indices) + +def index_compact_to_indices(index, size): + return index % size, index // size % size, index // size // size + +def block_compact_to_index_rot(block, size): + # every block is stored as 4-tuple (x,y,z,sym), where sym is a symbolic rotation + block = block.strip().split(',') + x, y, z, rot = block + x, y, z = int(x), int(y), int(z) + x, y, z = y, size-1 - z, size-1 - x + indices = x, y, z + try: + rot = rotation_symbolic_compact_to_idxrot[rot] + except KeyError: + raise ValueError('Invalid block rotation:', rot) + index = indices_compact_to_index(indices, size) + return '{}-{}'.format(index, rot) + +def blocks_compact_to_index_rot(blocks, size): + def blocks_perm(index): + x, y, z = index_compact_to_indices(index, size) + x, y, z = size-1 - z, x, size-1 - y + index = indices_compact_to_index((x, y, z), size) + return blocks[index] + blocks = blocks.strip().split(' ') + for i, block in enumerate(blocks): + blocks[i] = block_compact_to_index_rot(block, size) + blocks = [blocks_perm(i) for i, unused_b in enumerate(blocks)] + return ' '.join(blocks) + +def parse_initial_state(state): + msf, blocks = state.split(':', 1) + model, size, bformat = msf.split(' ', 2) + if model != 'Cube': + print('Unknown model:', repr(model)) + print(' Fallback:', 'Cube', 3, 'solved') + return 'Cube', 3, 'solved' + try: + size = int(size) + except ValueError: + print('Unknown size:', repr(size)) + print(' Fallback:', 'Cube', 3, 'solved') + return 'Cube', 3, 'solved' + if bformat == 'identity': + blocks = 'solved' + elif bformat == 'blocks_compact': + blocks = 'idx-rot: ' + blocks_compact_to_index_rot(blocks, size) + else: + blocks = 'solved' + return model, size, blocks + +def gconf_0_5_to_settings_1_0(settings_file): + path_to_face = {#'/apps/pybik': None, + #'/apps/pybik/colors:': None, + '/apps/pybik/colors/0:': 0, + '/apps/pybik/colors/1:': 1, + '/apps/pybik/colors/2:': 2, + '/apps/pybik/colors/3:': 3, + '/apps/pybik/colors/4:': 4, + '/apps/pybik/colors/5:': 5, + } + path = '/apps/pybik' + try: + process = subprocess.Popen(['gconftool', '--recursive-list', path], stdout=subprocess.PIPE) + except OSError: + return + lines = process.communicate()[0] + settings_dir = os.path.dirname(settings_file) + if settings_dir and not os.path.exists(settings_dir): + os.makedirs(settings_dir) + with open(settings_file, 'w') as settings: + face = 0 + for line in lines.splitlines(): + line = line.strip() + face = path_to_face.get(line, face) + if '=' not in line: + facetype = None + pattern = None + imagefile = None + imagemode = None + continue + key, value = line.split('=', 1) + key = key.strip() + value = value.strip() + # pylint: disable=C0321 + if key == 'saved_pos': print('game.position =', value, file=settings) + elif key == 'selection_mode': + value = 'quadrant' if value == '0' else 'simple' + print('draw.selection =', repr(value), file=settings) + elif key == 'saved_moves': print('game.moves =', repr('native: '+value), file=settings) + elif key == 'lighting': print('draw.lighting =', value=='true', file=settings) + elif key == 'background_color': print('theme.bgcolor =', repr(value), file=settings) + elif key == 'saved_state': + mtype, size, blocks = parse_initial_state(value) + print('game.type =', repr(mtype), file=settings) + print('game.size =', (size, size, size), file=settings) + print('game.blocks =', repr(blocks), file=settings) + elif key == 'color': print('theme.face.%s.color =' % face, repr(value), file=settings) + elif key == 'facetype': + facetype = value + if facetype == '1' and pattern is not None: + print('theme.face.%s.image =' % face, repr(pattern), file=settings) + if facetype == '2' and imagefile is not None: + print('theme.face.%s.image =' % face, repr(imagefile), file=settings) + if facetype == '2' and imagemode is not None: + print('theme.face.%s.mode =' % face, repr(imagemode), file=settings) + elif key == 'pattern': + if value == '0': pattern = 'BEAMED EIGHTH NOTES.png' + elif value == '1': pattern = 'diagonal-lines.png' + elif value == '2': pattern = 'WHITE SMILING FACE.png' + elif value == '3': pattern = 'BLACK SMILING FACE.png' + elif value == '4': pattern = 'squares.png' + elif value == '5': pattern = 'WHITE SUN WITH RAYS.png' + if facetype == '1': + print('theme.face.%s.image =' % face, repr(pattern), file=settings) + elif key == 'imagefile': + imagefile = value + if facetype == '2': + print('theme.face.%s.image =' % face, repr(imagefile), file=settings) + elif key == 'imagemode': + imagemode = 'tiled' if value != '1' else 'mosaic' + if facetype == '2': + print('theme.face.%s.mode =' % face, repr(imagemode), file=settings) + +def main(): + if len(sys.argv) != 2: + sys.exit(1) + gconf_0_5_to_settings_1_0(sys.argv[1]) + + +if __name__ == '__main__': + main() + + diff -Nru pybik-0.5/pybiklib/model.py pybik-1.0.1/pybiklib/model.py --- pybik-0.5/pybiklib/model.py 1970-01-01 00:00:00.000000000 +0000 +++ pybik-1.0.1/pybiklib/model.py 2013-01-06 04:23:35.000000000 +0000 @@ -0,0 +1,900 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright © 2012-2013 B. Clausius +# +# 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 . + +from __future__ import print_function, division, unicode_literals + +import os +from math import sin, cos, pi, sqrt +import re +import cPickle as pickle + +import numpy as np + +from .debug import DEBUG, DEBUG_NOLABEL, DEBUG_NOBEVEL, DEBUG_INNER +from .config import MODELS_DIR + +N_ = lambda t: t +try: + _ +except NameError: + _ = N_ + +use_modeldata = True +modeldata_cache = {} + + +class Face (object): + def __init__(self, symbol, vindices=None, vertices=None): + self.symbol = symbol + self.vindices = vindices + self.vertices = vertices + self.normal = None + self.scaled = None # Face with indices for beveled_vertices + self.faces = None # adjacent faces + + def __repr__(self): + return 'Face({}, {})'.format(self.symbol, self.vindices) + + def edges(self): + vertices = self.vertices if self.vindices is None else self.vindices + v1 = vertices[0] + for v2 in vertices[1:]: + yield v1, v2 + v1 = v2 + yield v1, vertices[0] + + def center(self, vertices=None): + if vertices is None: + vertices = self.vertices + if self.vindices is not None: + vertices = [vertices[vi] for vi in self.vindices] + return [sum(_i)/len(_i) for _i in zip(*vertices)] + + def create_scaled(self, vertices, factor, new_vertices): + bf = [] + for vi in self.vindices: + # Scale orthogonal to the center + bv = [(v-c)*factor+c for v, c in zip(vertices[vi], self.center(vertices))] + bf.append(len(new_vertices)) + new_vertices.append(bv) + self.scaled = Face(self.symbol, bf) + + def translated(self, vertices, offset, factor=1): + tf = [] + if vertices is None: + for v in self.vertices: + tv = [xv+xo*factor for xv, xo in zip(v, offset)] + tf.append(tv) + else: + for vi in self.vindices: + tv = [xv+xo*factor for xv, xo in zip(vertices[vi], offset)] + tf.append(tv) + return Face(self.symbol, vertices=tf) + + def roll(self, n): + if self.vindices is not None: + vlen = len(self.vindices) + self.vindices = [self.vindices[(i-n)%vlen] for i in range(vlen)] + elif self.vertices is not None: + vlen = len(self.vertices) + self.vertices = [self.vertices[(i-n)%vlen] for i in range(vlen)] + + def init_adjacent_faces(self, faces): + self.faces = [] + for edge in self.edges(): + edge = tuple(reversed(edge)) + for f in faces: + for e in f.edges(): + if e == edge: + break + else: + continue + self.faces.append(f.symbol) + break + else: + assert False, 'No adjacent face for edge: ' + str((self, edge, faces)) + assert len(self.faces) == len(self.vindices) + + def flip(self): + self.vertices.reverse() + + +class Block (object): + def __init__(self, model, index, data=None): + if data is not None: + self.__dict__.update(data) + return + self.index = index + self.indices = (index % model.sizes[0], + index // model.sizes[0] % model.sizes[1], + index // model.sizes[0] // model.sizes[1]) + self.coords = [float(2*idx - model.sizes[i] + 1) for i, idx in enumerate(self.indices)] + self.coords.append(1.) + self.symbol_to_move = {} + self.visible_faces = [] + self.visible_glfaces = [] + for symbol in model.faces: + mdir = symbol not in model.symbols + maxis = model.symbols.index(model.invers_symbols[symbol] if mdir else symbol) + mslice = self.axis_to_slice(maxis) + self.symbol_to_move[symbol] = (maxis, mslice, mdir) + if mslice == (model.sizes[maxis]-1 if mdir else 0): + self.visible_faces.append(symbol) + self.inplace_rotations = [] + + def init_inplace_rotations(self, model): + for (blocknum, rotsym), blocknum2 in model.rotated_position.items(): + if blocknum == blocknum2 == self.index and rotsym: + self.inplace_rotations.append(rotsym) + self.inplace_rotations = sorted(self.inplace_rotations, key=len)[:2] + + def __repr__(self): + return 'Block({}, {}, {}, {})'.format(self.index, self.indices, self.coords, self.visible_faces) + + def axis_to_slice(self, maxis): + return self.indices[maxis] + + +class Geometry (object): + def __init__(self, vertices=None, faces=None, bevel_factor=None): + self.vertices = vertices + self.faces = faces + self.beveled_vertices = [] # list of vertex positions + + for f in self.faces.values(): + f.normal = f.center(self.vertices) + f.create_scaled(self.vertices, bevel_factor, self.beveled_vertices) + f.init_adjacent_faces(self.faces.values()) + + def create_permutation(self, matrix): + m = np.matrix(matrix) + indices = {} + for i, v in enumerate(self.vertices): + rv = (m * np.matrix(v+[0]).T).T.tolist()[0][:-1] + ri = self.vertices.index(rv) + indices[i] = ri + symbols = {} + for sym, f in self.faces.items(): + rvindices = [indices[i] for i in f.vindices] + for rsym, rf in self.faces.items(): + if set(rvindices) == set(rf.vindices): + symbols[rsym.lower()] = sym.lower() + return symbols + + +class EmptyModel (object): + type = 'Empty' + mformat = u'Empty' + symbols = b'' + symbolsI = b'' + faces = b'' + + sizes = [0, 0, 0] + size = None + bounding_sphere_radius = 1. + blocks = [] + + def __init__(self, *unused_args): + # The arrays should never be empty. For empty numpy-arrays it is + # not possible to get the C-address in module gldraw (compiled mode). + # The fields can only become empty when certain debugging options are active. + glvertices = np.array([0], dtype='f') + glnormals = np.array([0], dtype='f') + glcolors = np.array([0], dtype=np.ubyte) + gltexpostiled = np.array([0], dtype='f') + gltexposmosaic = np.array([0], dtype='f') + self.gldata = [glvertices, glnormals, glcolors, gltexpostiled, gltexposmosaic] + + def gl_data(self): + return tuple(self.gldata) + ([], 0, 0) + + def gl_pick_data(self, unused_selection_mode): + # pylint: disable=W0201 + self.gl_pick_vertices = np.array([0], dtype='f') + self.gl_pick_colors = np.array([0], dtype=np.ubyte) + return self.gl_pick_vertices, self.gl_pick_colors + + +class BrickModel (object): + type = N_('Brick') + mformat = _(u'{0}×{1}×{2}-Brick') + symmetry = 180., 180., 180. + + axes = [(-1,0,0), (0,-1,0), (0,0,-1)] # pylint: disable=C0324 + symbols = b'LDB' + symbolsI = b'RUF' + faces = b'UDLRFB' + epsilon = 0.00001 + + #### geometry of the cube #### + # vertex standard + # indices orientation face symbols + # 2------3 +---+ + # |\ |\ y | U | + # | 6------7 | +---+---+---+---+ + # | | | | o--x | L | F | R | B | + # 0-|----1 | \ +---+---+---+---+ + # \| \| z | D | + # 4------5 +---+ + + geom = Geometry( + # vertex-positions, used for unbeveled faces and picking + vertices=[[-1,-1,-1], [1,-1,-1], [-1, 1,-1], [1, 1,-1], + [-1,-1, 1], [1,-1, 1], [-1, 1, 1], [1, 1, 1]], + # vertex-indices for unbeveled faces, used for picking + faces={b'U': Face(b'U', [2,6,7,3]), b'D': Face(b'D', [4,0,1,5]), + b'L': Face(b'L', [2,0,4,6]), b'R': Face(b'R', [7,5,1,3]), + b'F': Face(b'F', [6,4,5,7]), b'B': Face(b'B', [3,1,0,2])}, + bevel_factor=0.9 + ) + texpos_tiled = [(0, 0), (0, 1), (1, 1), (1, 0)] + face_axes = {b'U': (0, 2), b'D': (0, 2), + b'L': (2, 1), b'R': (2, 1), + b'F': (0, 1), b'B': (0, 1)} + + def __init__(self, size, mirror_distance): + self.sizes = self.norm_sizes(size) # tuple of lenght 3 + assert len(self.sizes) == 3 + for _size in self.sizes: + assert 1 <= _size <= 10 + self.size = size # derived classes can assign a different value + self.mirror_distance = mirror_distance and mirror_distance * max(self.sizes) + + #TODO: The bounding_sphere_radius is optimised for the far clipping plane, + # for the near clipping plane the radius without the mirror_distance + # would be sufficient. + s = max(self.sizes) + sm = s + (self.mirror_distance or 0) + self.bounding_sphere_radius = sqrt(2*s*s + sm*sm) + + self.invers_symbols = {} + for sym, isym in zip(self.symbols, self.symbolsI): + self.invers_symbols[sym] = isym + self.invers_symbols[isym] = sym + self.axesI = [tuple(-x for x in a) for a in self.axes] + + self.normal_rotation_symbols = {} + self.rotation_matrices = {} + self._init_rotations() + self.face_permutations = self._create_permutations() + + if use_modeldata: + global modeldata_cache + try: + modeldata = modeldata_cache[(self.type, self.sizes)] + except KeyError: + datafilename = self.get_datafilename(self.sizes) + datafilename = os.path.join(MODELS_DIR, datafilename) + with open(datafilename, 'rb') as datafile: + modeldata = pickle.load(datafile) + modeldata_cache = modeldata + modeldata = modeldata_cache[(self.type, self.sizes)] + self.blocks = [Block(None, None, data=data) for data in modeldata[b'blocks']] + self.rotated_position = modeldata[b'rotated_position'] + self.gl_never_visible_face = self._gl_never_visible_face_cached + else: + nblocks = self.sizes[0] * self.sizes[1] * self.sizes[2] + self.blocks = [Block(self, i) for i in range(nblocks)] + self.rotated_position = self._create_rotated_position() + for block in self.blocks: + block.init_inplace_rotations(self) + self.gl_never_visible_face = self._gl_never_visible_face_create_cache + + self.pick_vector = {} + for maxis, axis in enumerate(self.axes): + for symbol, face in self.geom.faces.items(): + self.pick_vector[maxis, False, symbol] = np.cross(axis, face.normal).tolist() + self.pick_vector[maxis, True, symbol] = np.cross(face.normal, axis).tolist() + + self.pick_data = [()] # list of (maxis, mslice, mdir, face, center, block, symbol) + + # List of numpy-arrays + # the gldraw module uses C-pointers to the data, so it is essential + # that the arrays do not get lost + self.gldata = [] + + @classmethod + def norm_sizes(cls, sizes): + return sizes + + @classmethod + def displaystring(cls, size): + return cls.mformat.format(*size) + + def __unicode__(self): + return self.displaystring(self.sizes) + + @classmethod + def _create_rotation(cls, axis, angle): + angle = angle / 180. * pi + sa = sin(angle) + ca = cos(angle) + e_ca = 1 - ca + n1 = axis[0] + n2 = axis[1] + n3 = axis[2] + m = np.matrix([ + [n1*n1*e_ca + ca, n1*n2*e_ca - n3*sa, n1*n3*e_ca + n2*sa, 0.], + [n2*n1*e_ca + n3*sa, n2*n2*e_ca + ca, n2*n3*e_ca - n1*sa, 0.], + [n3*n1*e_ca - n2*sa, n3*n2*e_ca + n1*sa, n3*n3*e_ca + ca, 0.], + [0., 0., 0., 1.], + ]) + #XXX: try to keep the matrix clean + mx, my = m.shape + for y in range(my): + for x in range(mx): + if abs(m.A[y][x]) < cls.epsilon: + m.A[y][x] = 0. + return m + + @classmethod + def _matrix_equal(cls, m1, m2): + assert m1.shape == m2.shape, (m1, m2) + mx, my = m1.shape + for y in range(my): + for x in range(mx): + if abs(m1.A[y][x] - m2.A[y][x]) > cls.epsilon: + return False + return True + + def _init_rotations(self): + prim = [(sym, self._create_rotation(axis, angle)) + for axis, sym, angle in zip(self.axes + self.axesI, + self.symbols + self.symbolsI, + self.symmetry + self.symmetry)] + self.normal_rotation_symbols[b''] = b'' + transform = [(b'', np.matrix(np.identity(4)))] + for sp, p in prim: + transform.append((sp, p)) + for sm, m in transform: + for sp, p in prim: + n = m * p + sn = sm + sp + for st, t in transform: + if self._matrix_equal(t, n): + self.normal_rotation_symbols[sn] = st + break + else: + self.normal_rotation_symbols[sn] = sn + transform.append((sn, n)) + for sm, m in transform: + self.rotation_matrices[sm] = m.A.tolist() + + def _create_permutations(self): + face_permutations = {} + for msym, matrix in self.rotation_matrices.items(): + face_permutations[msym] = self.geom.create_permutation(matrix) + return face_permutations + + def _create_rotated_position(self): + rotated_position = {} + for b, block in enumerate(self.blocks): + for sym, rotation in self.rotation_matrices.items(): + coords = (np.matrix([block.coords]) * rotation).A.tolist()[0] + for p, pos in enumerate(self.blocks): + if pos.coords == coords: + rotated_position[b, sym] = p + break + else: + assert False, 'not a permutation' + return rotated_position + + @classmethod + def get_datafilename(cls, sizes): + x, y, unused_z = sizes + if x <= 2: + return b'mdata_01-02' + else: + return b'mdata_{:02}_{}'.format(x, 0 if x<=5 else y%2 if x<=8 else y%3) + + def get_savedata(self): + blocks = [block.__dict__ for block in self.blocks] + return {b'blocks': blocks, b'rotated_position': self.rotated_position} + + def norm_symbol(self, sym): + try: + return self.normal_rotation_symbols[sym] + except KeyError: + new_sym = '' + for c in sym: + try: + new_sym = self.normal_rotation_symbols[new_sym+c] + except KeyError: + raise ValueError('invalid symbol:', sym) + return new_sym + + def block_indices_to_index(self, indices): + indices = tuple(indices) + for b, block in enumerate(self.blocks): + if block.indices == indices: + return b + raise ValueError('Invalid block indices:', indices) + + def rotation_symbolic_to_matrix(self, block, sym): + m = self.rotation_matrices[sym][:] + m[3] = self.blocks[block].coords + return m + + def block_symbolic_to_block_index(self, symblock): + indices = [1] * len(self.axes) + for match in re.finditer(r'(.)(\d*)', symblock): + blockface, blockslice = match.groups() + blockface = blockface.upper() + blockslicenum = int(blockslice)-1 if blockslice else 0 + if blockface in self.symbolsI: + axis = self.symbolsI.index(blockface) + blockslicenum = self.sizes[axis]-1 - blockslicenum + blockface = self.invers_symbols[blockface] + else: + axis = self.symbols.index(blockface) + indices[axis] = blockslicenum + return self.block_indices_to_index(indices) + + def block_index_to_block_symbolic(self, blockpos, rotsym): + def axisidx_to_sym(axis, idx): + if idx <= self.sizes[axis] // 2: + sym = self.symbols[axis] + else: + idx = self.sizes[axis]-1 - idx + sym = self.symbolsI[axis] + sym = sym.lower() + if idx == 0: + # skip idx for corners + return sym, self.face_symbolic_to_face_color(sym, rotsym) + elif idx == 1 and self.sizes[axis] == 3: + # for size == 3 there is only one edge + return '', '' + else: + # symbol with index to distinguish edge, but no color because the face is not visible + return sym + str(idx+1), '?' + x, y, z = self.blocks[blockpos].indices + symx, colorsymx = axisidx_to_sym(0, x) + symy, colorsymy = axisidx_to_sym(1, y) + symz, colorsymz = axisidx_to_sym(2, z) + return symx + symy + symz, colorsymx + colorsymy + colorsymz + + def face_symbolic_to_face_color(self, face, rot): + for k, v in self.face_permutations[rot].items(): + if v == face: + return k + else: + assert False, (face, rot) + + def rotate_symbolic(self, axis, rdir, block, sym): + rsym = (self.symbols if not rdir else self.symbolsI)[axis] + block = self.rotated_position[block, rsym] + sym = self.norm_symbol(sym + rsym) + return block, sym + + def rotate_move(self, complete_move, move): + caxis, unused_cslice, cdir = complete_move + maxis, mslice, mdir = move + caxissym = (self.symbols if cdir else self.symbolsI)[caxis] + maxissym = (self.symbols if not mdir else self.symbolsI)[maxis] + raxissym = self.face_permutations[caxissym][maxissym.lower()].upper() + rdir = raxissym not in self.symbols + raxis = self.symbols.index(self.invers_symbols[raxissym] if rdir else raxissym) + if mdir != rdir: + mslice = self.sizes[raxis] - 1 - mslice + return raxis, mslice, rdir + + @staticmethod + def get_selected_move(block, face, edgeno): + '''block: a block in the rotation slice + face -> edgeno is the direction of slice rotation + ''' + edgeno = (edgeno - 1) % 4 + rotation_symbol = face.faces[edgeno] + return block.symbol_to_move[rotation_symbol] + + def compare_move_to_pick(self, maxis, unused_mslice, mdir, face, faceedge): + axis = self.axes[maxis] + if mdir: + vpick = np.cross(axis, face.normal).tolist() + else: + vpick = np.cross(face.normal, axis).tolist() + #TODO: rather test whether face.center+pick_vector intersects with the edge + return vpick == faceedge.normal + + @staticmethod + def get_selected_move_center(block, face): + maxis, mslice, mdir = block.symbol_to_move[face.symbol] + return maxis, mslice, not mdir + + def _gl_never_visible_face_cached(self, block, face): # pylint: disable=R0201 + return face not in block.visible_glfaces + + def _gl_never_visible_face_create_cache(self, block, face): + if not self._gl_never_visible_face_calculated(block, face): + block.visible_glfaces.append(face) + # create the cache and discard the real gl face + return True + + def _gl_never_visible_face_calculated(self, block, face): + if max(self.sizes) == 2 and self.sizes.count(2) >= 2: + #FIXME: the algorithm to detect invisible faces is wrong, + # deactivate the test for the cubes that are most affected. + return False + vertices = self.geom.beveled_vertices + c = block.coords + sqr0 = self.sizes[0] * self.sizes[0] + sqr1 = self.sizes[1] * self.sizes[1] + sqr2 = self.sizes[2] * self.sizes[2] + for vi in face: + v = [vk+ck for vk, ck in zip(vertices[vi], c)] + if (v[0]*v[0] + v[1]*v[1] > min(sqr0, sqr1) or + v[0]*v[0] + v[2]*v[2] > min(sqr0, sqr2) or + v[1]*v[1] + v[2]*v[2] > min(sqr1, sqr2)): + return False + return True + + def texpos_tiled_to_mosaic(self, block, face, texpos_tiled): + axisx, axisy = self.face_axes[face.symbol] + sizex, sizey = self.sizes[axisx], self.sizes[axisy] + tptx, tpty = texpos_tiled + + vertices = [self.geom.vertices[vi] for vi in face.vindices] + subx = [(c1-c0)/2 for c0, c1 in zip(vertices[0], vertices[-1])] + suby = [(c1-c0)/2 for c0, c1 in zip(vertices[0], vertices[1])] + coords = block.coords[:3] + tpmx = sum(tc*bc for tc, bc in zip(subx, coords)) + tpmy = sum(tc*bc for tc, bc in zip(suby, coords)) + + texx = ((sizex-1 + tpmx) / 2. + tptx) / sizex + texy = ((sizey-1 + tpmy) / 2. + tpty) / sizey + return texx, texy + + def gl_label_quads(self, block, visible): + if DEBUG: + if DEBUG_INNER: + for i in range(3): + if block.indices[i] in [0, self.sizes[i]-1]: + return + if DEBUG_NOLABEL and visible: + return + if DEBUG_NOBEVEL and not visible: + return + for faceno, symbol in enumerate(self.faces): + face = self.geom.faces[symbol] + if (symbol in block.visible_faces) != visible: + continue + f = face.scaled + if self.gl_never_visible_face(block, f.vindices): + continue + for i, vi in enumerate(f.vindices): + v = self.geom.beveled_vertices[vi] + texpos_tiled = self.texpos_tiled[i] + texpos_mosaic = self.texpos_tiled_to_mosaic(block, face, texpos_tiled) + yield (v, face.normal, faceno, texpos_tiled, texpos_mosaic) + if self.mirror_distance is not None and visible: + f = f.translated(self.geom.beveled_vertices, face.normal, self.mirror_distance) + f.flip() + for i, v in enumerate(f.vertices): + tptx, tpty = self.texpos_tiled[i] + texpos_tiled = 1. - tptx, tpty + texpos_mosaic = self.texpos_tiled_to_mosaic(block, face, texpos_tiled) + yield (v, face.normal, faceno, texpos_tiled, texpos_mosaic) + + def gl_beveled_quads(self, block): + '''For every edge create a face''' + if DEBUG: + if DEBUG_INNER: + for i in range(3): + if block.indices[i] in [0, self.sizes[i]-1]: + return + if DEBUG_NOBEVEL: + return + for symbol, f in self.geom.faces.items(): + for symbol2, (vi, vi2) in zip(f.faces, f.edges()): + if symbol >= symbol2: # find the corners only once, no matter in which order + continue + f2 = self.geom.faces[symbol2] + # f and f2 have a common edge (vi,vi2) + # we now need the vertices and normals of the adjacent labels. + # remember, the face must be counterclockwise! + bvi1 = f.scaled.vindices[f.vindices.index(vi2)] + bvi2 = f.scaled.vindices[f.vindices.index(vi)] + bvi3 = f2.scaled.vindices[f2.vindices.index(vi)] + bvi4 = f2.scaled.vindices[f2.vindices.index(vi2)] + if self.gl_never_visible_face(block, [bvi1, bvi2, bvi3, bvi4]): + continue + n = Face('', [bvi1, bvi2, bvi3, bvi4]).center(self.geom.beveled_vertices) + yield self.geom.beveled_vertices[bvi1], n + yield self.geom.beveled_vertices[bvi2], n + yield self.geom.beveled_vertices[bvi3], n + yield self.geom.beveled_vertices[bvi4], n + + def gl_beveled_triangles(self, block): + '''For every corner create a face''' + if DEBUG: + if DEBUG_INNER: + for i in range(3): + if block.indices[i] in [0, self.sizes[i]-1]: + return + if DEBUG_NOBEVEL: + return + for vi in range(len(self.geom.vertices)): + bf = [] # one beveled face for each vertex + for face_first in self.geom.faces.values(): + if vi in face_first.vindices: + # we now have one adjacent face, this code should be reached if the model is valid + break + else: + face_first = None + assert False + face = face_first + while True: + ivi = face.vindices.index(vi) + bvi = face.scaled.vindices[ivi] + bf.insert(0, bvi) # we need counterclockwise order + symbol = face.faces[ivi] + face = self.geom.faces[symbol] + ## we now have the clockwise next face + if face_first.symbol == face.symbol: + break + if self.gl_never_visible_face(block, bf): + continue + n = Face('', bf).center(self.geom.beveled_vertices) + for vi in bf: + yield self.geom.beveled_vertices[vi], n + + def gl_pick_triangles(self, selection_mode): + def edge_center(v1, v2): + return [(_v1 + _v2) / 2 for _v1, _v2 in zip(v1, v2)] + for block in self.blocks: + cnt_faces = 0 + for i in range(3): + if block.indices[i] in [0, self.sizes[i]-1]: + cnt_faces += 1 + for face, symbol in enumerate(self.faces): + f = self.geom.faces[symbol] + assert f.symbol == symbol + if symbol not in block.visible_faces: + continue + cnt_n = 0 + for _sym in f.faces: + if _sym in block.visible_faces: + cnt_n += 1 + ft = f.translated(self.geom.vertices, block.coords) + vc = ft.center() + if self.mirror_distance is None: + ftt = ft + else: + ftt = ft.translated(None, f.normal, self.mirror_distance) + vct = ftt.center() + + if selection_mode == 1 and cnt_n == 0: + maxis, mslice, mdir = self.get_selected_move_center(block, f) + color = len(self.pick_data) + self.pick_data.append((maxis, mslice, mdir, face, True, block, symbol, None, None)) + for i in (0,1,2, 2,3,0): # pylint: disable=C0324 + yield color, ft.vertices[i] + if self.mirror_distance is not None: + color = len(self.pick_data) + self.pick_data.append((maxis, mslice, not mdir, face, True, block, symbol, None, None)) + for i in (0,2,1, 2,0,3): # pylint: disable=C0324 + yield color, ftt.vertices[i] + elif selection_mode == 1 and cnt_n == 1 and cnt_faces == 2: + for edgeno, symboledge in enumerate(f.faces): # find the other face on the block + if symboledge in block.visible_faces: + break + else: + edgeno = symboledge = None + assert False + maxis, mslice, mdir = self.get_selected_move(block, f, edgeno) + if DEBUG: + assert self.compare_move_to_pick(maxis, mslice, mdir, f, self.geom.faces[symboledge]) + ec = edge_center(*list(ft.edges())[edgeno]) + color = len(self.pick_data) + self.pick_data.append((maxis, mslice, mdir, face, False, block, symbol, vc, ec)) + for i in (0,1,2, 2,3,0): # pylint: disable=C0324 + yield color, ft.vertices[i] + if self.mirror_distance is not None: + for i in (0,2,1, 2,0,3): # pylint: disable=C0324 + yield color, ftt.vertices[i] + elif selection_mode == 1 and cnt_n == 2 and cnt_faces == 3: + # find the two other faces on the block + for i1, symboledge1 in enumerate(f.faces): # find the other face on the block + i2 = (i1 + 1) % 4 + symboledge2 = f.faces[i2] + visible_faces = block.visible_faces + if symboledge1 in visible_faces and symboledge2 in visible_faces: + break + else: + i1 = symboledge1 = None + assert False + symboledges = (i1, symboledge1, i1-1), (i2, symboledge2, i2) + for edgeno, symboledge, offset in symboledges: + maxis, mslice, mdir = self.get_selected_move(block, f, edgeno) + if DEBUG: + assert self.compare_move_to_pick(maxis, mslice, mdir, f, self.geom.faces[symboledge]) + ec = edge_center(*list(ft.edges())[edgeno]) + color = len(self.pick_data) + self.pick_data.append((maxis, mslice, mdir, face, False, block, symbol, vc, ec)) + for i in (0, 1, 2): + yield color, ft.vertices[(i+offset)%4] + if self.mirror_distance is not None: + for i in (0, 2, 1): + yield color, ftt.vertices[(i+offset)%4] + else: + for edgeno, (edge, edget) in enumerate(zip(ft.edges(), ftt.edges())): + maxis, mslice, mdir = self.get_selected_move(block, f, edgeno) + ec = edge_center(*edge) + color = len(self.pick_data) + self.pick_data.append((maxis, mslice, mdir, face, False, block, symbol, vc, ec)) + # pylint: disable=C0321 + yield color, vc; yield color, edge[0]; yield color, edge[1] + if self.mirror_distance is not None: + yield color, vct; yield color, edget[1]; yield color, edget[0] + + def gl_data(self): + vertices = [] + normals = [] + colors = [] + texpost = [] + texposm = [] + # list of (labelinfo, bevelqinfo, beveltinfo) + blockinfos = [[[], 0, 0] for unused_b in self.blocks] + + # label vertices + for iblock, block in enumerate(self.blocks): + cnt = 0 + facesinfo = [] + last_faceno = -1 + for v, n, f, tpt, tpm in self.gl_label_quads(block, True): + vertices += v + normals += n + texpost += tpt + texposm += tpm + if last_faceno != f: + cnt = 1 + facesinfo.append((cnt, f)) + last_faceno = f + else: + cnt += 1 + facesinfo[-1] = (cnt, f) + blockinfos[iblock][0][:] = facesinfo + # beveled edges + idx_vbevelq = len(vertices) + for iblock, block in enumerate(self.blocks): + cnt = 0 + for v, n in self.gl_beveled_quads(block): + vertices += v + normals += n + cnt += 1 + for v, n, f, tpt, tpm in self.gl_label_quads(block, False): + vertices += v + normals += n + cnt += 1 + blockinfos[iblock][1] = cnt + # beveled corners + idx_vbevelt = len(vertices) + for iblock, block in enumerate(self.blocks): + cnt = 0 + for v, n in self.gl_beveled_triangles(block): + vertices += v + normals += n + cnt += 1 + blockinfos[iblock][2] = cnt + + # The arrays should never be empty. For empty numpy-arrays it is + # not possible to get the C-address in module gldraw (compiled mode). + # The fields can only become empty when certain debugging options are active. + glvertices = np.array(vertices or [0], dtype='f') + glnormals = np.array(normals or [0], dtype='f') + glcolors = np.array(colors or [0], dtype=np.ubyte) + gltexpostiled = np.array(texpost or [0], dtype='f') + gltexposmosaic = np.array(texposm or [0], dtype='f') + self.gldata.append(glvertices) + self.gldata.append(glnormals) + self.gldata.append(glcolors) + self.gldata.append(gltexpostiled) + self.gldata.append(gltexposmosaic) + if DEBUG: + assert idx_vbevelq * 2 == len(texpost) * 3 == len(texposm) * 3 + assert sum([cnt for _bi in blockinfos for cnt, unused_faceno in _bi[0]]) * 3 == idx_vbevelq + + return (glvertices, glnormals, glcolors, gltexpostiled, gltexposmosaic, + blockinfos, + idx_vbevelq, idx_vbevelt + ) + + def gl_pick_data(self, selection_mode): + # Pick TRIANGLES vertices + vertices = [] + colors = [] + for col, v in self.gl_pick_triangles(selection_mode): + vertices += v + color = [(col>>4) & 0xf0, (col) & 0xf0, (col<<4) & 0xf0] + colors += color + glvertices = np.array(vertices or [0], dtype='f') + glcolors = np.array(colors or [0], dtype=np.ubyte) + # pylint: disable=W0201 + self.gl_pick_vertices = glvertices + self.gl_pick_colors = glcolors + assert len(glvertices) == len(glcolors) + return glvertices, glcolors + + +class TowerModel (BrickModel): + type = N_('Tower') + mformat = _(u'{0}×{1}-Tower') + symmetry = 180., 90., 180. + + def __init__(self, size, mirror_distance): + BrickModel.__init__(self, size, mirror_distance) + self.size = size[:2] + + @classmethod + def norm_sizes(cls, sizes): + x, y, unused_z = sizes + return x, y, x + + +class CubeModel (BrickModel): + type = N_('Cube') + mformat = _(u'{0}×{0}×{0}-Cube') + symmetry = 90., 90., 90. + + def __init__(self, size, mirror_distance): + BrickModel.__init__(self, size, mirror_distance) + self.size = size[0], + + @classmethod + def norm_sizes(cls, sizes): + x, unused_y, unused_z = sizes + return x, x, x + + +empty_model = EmptyModel() +models = [CubeModel, TowerModel, BrickModel] + +def from_string(modelstr): + if modelstr == '*': + return '*', '*', (), None + re_model = r'''^(\w+) + (?: \s+(\w+) + (?: \s*(\W) + \s*(\w+) + (?: \s*\3 + \s*(\w+) + )?)? + (?:\s+with + \s+(.+) + )?)?\s*$''' + match = re.match(re_model, modelstr, re.X) + if match is None: + raise ValueError('Invalid model: ' + modelstr) + mtype, width, height, depth, exp = match.group(1, 2, 4, 5, 6) + for Model in models: + if mtype == Model.type: + break + else: + Model = None + raise ValueError('Unknown model type %r' % mtype) + def convert_if_int(value): + if value is None: + return value + try: + return int(value) + except ValueError: + return value + sizes = tuple(convert_if_int(s) for s in (width, height, depth)) + return modelstr, Model, sizes, exp + + diff -Nru pybik-0.5/pybiklib/move_queue.py pybik-1.0.1/pybiklib/move_queue.py --- pybik-0.5/pybiklib/move_queue.py 2011-12-20 12:08:53.000000000 +0000 +++ pybik-1.0.1/pybiklib/move_queue.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,268 +0,0 @@ -#-*- coding:utf-8 -*- - -# Pybik -- A 3 dimensional magic cube game. -# Copyright © 2009-2011 B. Clausius -# -# 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 . - - -# Ported from GNUbik -# Original filename: move-queue.c -# Original copyright and license: 2004 Dale Mellor, GPL3+ - - -import re - -from .debug import * - - -# A structure containing information about a movement taking place. -class MoveData(object): - def __init__(self, maxis, mslice, mdir): - self.axis = maxis # int 0... - self.slice = mslice # int 0...dim-1 or -1 for all slices - self.dir = mdir # 0 or 1. - def copy(self): - return MoveData(self.axis, self.slice, self.dir) - def __str__(self): - return 'MoveData(maxis={}, mslice={}, mdir={})'.format(self.axis, self.slice, self.dir) - __repr__ = __str__ - - -class MoveQueue(object): - class MoveQueueItem(MoveData): - def __init__(self, data, mark_after=False, code=None, markup=None): - if data: - MoveData.__init__(self, data.axis, data.slice, data.dir) - else: - MoveData.__init__(self, 0, 0, 0) - self.mark_after = mark_after - self.code = code - self.markup = markup - def copy(self): - return MoveQueue.MoveQueueItem(self, - mark_after=self.mark_after, - code=self.code, - markup=self.markup) - - def __init__(self): - self.current_place = 0 # Number of steps of current from head. - self.moves = [] - self.converter = FormatFlubrd - def at_start(self): - return self.current_place == 0 - def at_end(self): - return self.current_place == self.queue_length - @property - def head(self): - return self.moves and self.moves[0] or None - @property - def tail(self): - return self.moves and self.moves[-1] or None - @property - def _prev(self): - return self.moves[self.current_place-1] - @property - def _current(self): - return self.moves[self.current_place] - @property - def queue_length(self): - return len(self.moves) - def __str__(self): - return 'MoveQueue(len=%s)' % self.queue_length - - # Routine to push a new MoveData object onto the _back_ of the given queue. A - # new, locally-managed copy is made of the incumbent datum. Return 1 (one) if - # the operation is successful; 0 (zero) indicates that there was insufficient - # memory to grow the queue. - def push(self, move_data, mark_after=False, code=None, markup=None): - new_element = self.MoveQueueItem(move_data, - mark_after=mark_after, code=code, markup=markup) - self.moves.append(new_element) - return 1 - - # Procedure to copy the incumbent datum to the current place in the queue, and - # drop all subsequent queue entries (so that the current element becomes the - # tail). If current points past the end of the tail (including the case when - # there are no data in the queue), then a regular push operation is performed - # at the tail, and in this case zero may be returned if there is insufficient - # memory to grow the queue. In all other cases 1 (one) will be returned. - def push_current(self, move_data): - # If there are no data in the queue, then perform a standard push - # operation. Also do this if we are at the tail. - if not self.at_end(): - self.moves[self.current_place:] = [] - self.push(move_data) - return 1 - - def prev(self): - return None if self.at_start() else self._prev - # Routine to get the data at the 'current' position in the queue. If there are - # no data in the queue, None will be returned. - def current(self): - return None if self.at_end() else self._current - - # Routine to retard the current pointer (move it towards the _head_ of the queue). - def retard(self): - if not self.at_start(): - self.current_place -= 1 - - def rewind_start(self): - self.current_place = 0 - - # Remove the current object and all those that come afterwards. - def truncate(self): - self.moves[self.current_place:] = [] - - def truncate_before(self): - self.moves[:self.current_place] = [] - self.current_place = 0 - - def reset(self): - self.current_place = 0 - self.moves[:] = [] - - def advance(self): - if self.at_end(): - return False - self.current_place += 1 - return not self.at_end() - - def invert(self): - self.moves.reverse() - for move in self.moves: - move.dir = 1 - move.dir - move.code = None - move.markup = None - if not (self.at_start() or self.at_end()): - self.current_place = len(self.moves) - self.current_place - - def mark_current(self, mark=True): - if not self.at_start(): - self._prev.mark_after = mark - if self._prev.code is not None: - self._prev.code = self._prev.code.replace(' ','') - #FIXME: recreate self._prev.markup - if mark: - self._prev.code += ' ' - - @debug_func - def format(self, size): - #TODO: arg to use explicit converter - code = '' - markup = '' - pos = 0 - for i, move in enumerate(self.moves): - if move.code is None: - move.code, move.markup = self.converter.format(move, size) - code += move.code - markup += move.markup - if i < self.current_place: - pos = len(code) - return code, pos, markup - - @debug_func - def parse_iter(self, code, pos, size): - #TODO: arg to use explicit converter - code = code.lstrip(' ') - queue_pos = self.current_place - move_code = '' - for i, c in enumerate(code): - if move_code and self.converter.isstart(c): - data, mark, markup_code = self.converter.parse(move_code, size) - #FIXME: if data is None an invalid move should be pushed - self.push(data, mark, move_code, markup_code) - yield data, queue_pos - if i == pos: - queue_pos = self.queue_length - move_code = c - else: - move_code += c - if i < pos: - queue_pos = self.queue_length + 1 - if move_code: - data, mark, markup_code = self.converter.parse(move_code, size) - self.push(data, mark, move_code, markup_code) - if len(code)-len(move_code) < pos: - queue_pos = self.queue_length - yield data, queue_pos - - def parse(self, code, pos, size): - qpos = 0 - for res in self.parse_iter(code, pos, size): - qpos = res[1] - return qpos - - -class FormatFlubrd: - map_face_flubrd = 'flubrd' - re_flubrd = re.compile("(.)(\d*)(['-]?)([^ ]*)( *)(.*)") - - @classmethod - def isstart(cls, char): - return char.lower() in cls.map_face_flubrd - - @staticmethod - def _format_markup(mface, mslice, mdir, err1, mark, err2): - if err1: err1 = '%s' % err1 - if err2: err2 = '%s' % err2 - return ''.join((mface, mslice, mdir, err1, mark, err2)) - - @staticmethod - def intern_to_normal_move(maxis, mslice, mdir, size): - if mslice == -1: - return maxis+3 if mdir else maxis, 0, 0, True - elif mslice*2 > size-1: - return maxis+3, size-mslice-1, 1-mdir, False - else: - return maxis, mslice, mdir, False - - @classmethod - def format(cls, move, size): - mface, mslice, mdir, whole_cube = cls.intern_to_normal_move(move.axis, move.slice, move.dir, size) - mface = cls.map_face_flubrd[mface] - if whole_cube: - mface = mface.upper() - mslice = str(mslice+1) if mslice else '' - mdir = '-' if mdir else "" - mark = ' ' if move.mark_after else '' - move_code = mface + mslice + mdir + mark - markup_code = cls._format_markup(mface, mslice, mdir, '', mark, '') - return move_code, markup_code - - @staticmethod - def normal_to_intern_move(mface, mslice, mdir, whole_cube, size): - if mface < 3: - return mface, (-1 if whole_cube else mslice), mdir - else: - return mface-3, (-1 if whole_cube else size-mslice-1), 1-mdir - - @classmethod - def parse(cls, move_code, size): - #debug('move_code: '+move_code) - mface, mslice, mdir, err1, mark, err2 = cls.re_flubrd.match(move_code).groups() - markup_code = cls._format_markup(mface, mslice, mdir, err1, mark, err2) - whole_cube = mface.isupper() - mface = cls.map_face_flubrd.find(mface.lower()) - mslice = int(mslice or 1) - 1 - mdir = int(bool(mdir)) - mark = bool(mark) - if mface >= 0 and 0 <= mslice < size: - # move finished, normalize it - maxis, mslice, mdir = cls.normal_to_intern_move(mface, mslice, mdir, whole_cube, size) - return MoveData(maxis, mslice, mdir), mark, markup_code - else: - debug('Error parsing formula') - return None, False, move_code - diff -Nru pybik-0.5/pybiklib/moves.py pybik-1.0.1/pybiklib/moves.py --- pybik-0.5/pybiklib/moves.py 1970-01-01 00:00:00.000000000 +0000 +++ pybik-1.0.1/pybiklib/moves.py 2012-12-04 16:23:28.000000000 +0000 @@ -0,0 +1,300 @@ +#-*- coding:utf-8 -*- + +# Pybik -- A 3 dimensional magic cube game. +# Copyright © 2009-2012 B. Clausius +# +# 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 . + +# Ported from GNUbik +# Original filename: move-queue.c +# Original copyright and license: 2004 Dale Mellor, GPL3+ + +from __future__ import print_function, division, unicode_literals + +import re +from collections import namedtuple + +from .debug import * # pylint: disable=W0401, W0614 + + +# A structure containing information about a movement taking place. +class MoveData (namedtuple('_MoveData', 'axis slice dir')): # pylint: disable=W0232 + # axis = 0... + # slice = 0...dim-1 or -1 for all slices + # dir = 0 or 1 + def inverted(self): + return self._replace(dir=not self.dir) # pylint: disable=E1101 + +class MoveQueue(object): + class MoveQueueItem(object): + def __init__(self, data, mark_after=False, code=None, markup=None): + self.data = MoveData(*data) or MoveData(0, 0, 0) + self.mark_after = mark_after + self.code = code + self.markup = markup + axis = property(lambda self: self.data.axis) + slice = property(lambda self: self.data.slice) + dir = property(lambda self: self.data.dir) + def copy(self): + return MoveQueue.MoveQueueItem(self.data, + mark_after=self.mark_after, + code=self.code, + markup=self.markup) + def invert(self): + self.data = self.data.inverted() + def rotate_by(self, model, totalmove): + rmove = model.rotate_move(totalmove.data, self.data) + self.data = MoveData(*rmove) + self.code = None + self.markup = None + + def __init__(self): + self.current_place = 0 # Number of steps of current from head. + self.moves = [] + self.converter = FormatFlubrd + def copy(self): + movequeue = MoveQueue() + movequeue.current_place = self.current_place + movequeue.moves = [m.copy() for m in self.moves] + movequeue.converter = self.converter + return movequeue + + def at_start(self): + return self.current_place == 0 + def at_end(self): + return self.current_place == self.queue_length + @property + def _prev(self): + return self.moves[self.current_place-1] + @property + def _current(self): + return self.moves[self.current_place] + @property + def queue_length(self): + return len(self.moves) + def __str__(self): + return 'MoveQueue(len=%s)' % self.queue_length + + # Routine to push a new MoveData object onto the _back_ of the given queue. A + # new, locally-managed copy is made of the incumbent datum. Return 1 (one) if + # the operation is successful; 0 (zero) indicates that there was insufficient + # memory to grow the queue. + def push(self, move_data, mark_after=False, code=None, markup=None): + new_element = self.MoveQueueItem(move_data, + mark_after=mark_after, code=code, markup=markup) + self.moves.append(new_element) + + # Procedure to copy the incumbent datum to the current place in the queue, and + # drop all subsequent queue entries (so that the current element becomes the + # tail). If current points past the end of the tail (including the case when + # there are no data in the queue), then a regular push operation is performed + # at the tail. In all other cases 1 (one) will be returned. + def push_current(self, move_data): + # If there are no data in the queue, then perform a standard push + # operation. Also do this if we are at the tail. + if not self.at_end(): + self.moves[self.current_place:] = [] + self.push(move_data) + + # Routine to get the data at the 'current' position in the queue. If there are + # no data in the queue, None will be returned. + def current(self): + return None if self.at_end() else self._current.data + + # Routine to retard the current pointer (move it towards the _head_ of the queue). + def retard(self): + if not self.at_start(): + self.current_place -= 1 + + def rewind_start(self): + self.current_place = 0 + + def forward_end(self): + self.current_place = self.queue_length + + # Remove the current object and all those that come afterwards. + def truncate(self): + self.moves[self.current_place:] = [] + + def truncate_before(self): + self.moves[:self.current_place] = [] + self.current_place = 0 + + def reset(self): + self.current_place = 0 + self.moves[:] = [] + + def advance(self): + if not self.at_end(): + self.current_place += 1 + + def invert(self): + # a mark at the end of the moves is discarded because a mark at start is not supported + mark = False + for move in self.moves: + move.invert() + move.code = None + move.markup = None + move.mark_after, mark = mark, move.mark_after + self.moves.reverse() + if not (self.at_start() or self.at_end()): + self.current_place = len(self.moves) - self.current_place + + def normalize_complete_rotations(self, model): + totalmoves = [] + new_moves = [] + for i, move in enumerate(self.moves): + if i == self.current_place: + self.current_place = len(new_moves) + if move.slice < 0: + totalmoves.append(move) + else: + for totalmove in reversed(totalmoves): + move.rotate_by(model, totalmove) + new_moves.append(move) + self.moves = new_moves + totalmoves + + def is_mark_current(self): + return self.at_start() or self._prev.mark_after + + def is_mark_after(self, pos): + return self.moves[pos].mark_after + + def mark_current(self, mark=True): + if not self.at_start(): + self._prev.mark_after = mark + if self._prev.code is not None: + self._prev.code = self._prev.code.replace(' ','') + #FIXME: recreate self._prev.markup + if mark: + self._prev.code += ' ' + + def mark_and_extend(self, other): + if not other.moves: + return -1 + self.mark_current() + self.truncate() + self.moves += other.moves + return self.current_place + other.current_place + + def format(self, model): + #TODO: arg to use explicit converter + code = '' + markup = '' + pos = 0 + for i, move in enumerate(self.moves): + if move.code is None: + move.code, move.markup = self.converter.format(move, model) + code += move.code + markup += move.markup + if i < self.current_place: + pos = len(code) + return code, pos, markup + + def parse_iter(self, code, pos, model): + #TODO: arg to use explicit converter + code = code.lstrip(' ') + queue_pos = self.current_place + move_code = '' + for i, c in enumerate(code): + if move_code and self.converter.isstart(c, model): + data, mark, markup_code = self.converter.parse(move_code, model) + if data is not None: + #FIXME: invalid chars at start get lost, other invalid chars are just ignored + self.push(data, mark, move_code, markup_code) + yield data, queue_pos + if i == pos: + queue_pos = self.queue_length + move_code = c + else: + move_code += c + if i < pos: + queue_pos = self.queue_length + 1 + if move_code: + data, mark, markup_code = self.converter.parse(move_code, model) + if data is not None: + self.push(data, mark, move_code, markup_code) + if len(code)-len(move_code) < pos: + queue_pos = self.queue_length + yield data, queue_pos + + def parse(self, code, pos, model): + qpos = 0 + for res in self.parse_iter(code, pos, model): + qpos = res[1] + return qpos + + +class FormatFlubrd: # pylint: disable=W0232 + re_flubrd = re.compile("(.)(\d*)(['-]?)([^ ]*)( *)(.*)") + + @classmethod + def isstart(cls, char, model): + return char.upper() in model.faces + + @staticmethod + def _format_markup(mface, mslice, mdir, err1, mark, err2): + if err1: + err1 = '%s' % err1 + if err2: + err2 = '%s' % err2 + return ''.join((mface, mslice, mdir, err1, mark, err2)) + + @staticmethod + def intern_to_normal_move(maxis, mslice, mdir, model): + if mslice == -1: + return model.symbolsI[maxis] if mdir else model.symbols[maxis], 0, 0, True + elif mslice*2 > model.sizes[maxis]-1: + return model.symbolsI[maxis], model.sizes[maxis]-1 - mslice, 1-mdir, False + else: + return model.symbols[maxis], mslice, mdir, False + + @classmethod + def format(cls, move, model): + mface, mslice, mdir, whole_cube = cls.intern_to_normal_move(move.axis, move.slice, move.dir, model) + mface = mface.upper() if whole_cube else mface.lower() + mslice = str(mslice+1) if mslice else '' + mdir = '-' if mdir else "" + mark = ' ' if move.mark_after else '' + move_code = mface + mslice + mdir + mark + markup_code = cls._format_markup(mface, mslice, mdir, '', mark, '') + return move_code, markup_code + + @staticmethod + def normal_to_intern_move(mface, mslice, mdir, whole_cube, model): + if mface in model.symbols: + return model.symbols.index(mface), (-1 if whole_cube else mslice), mdir + elif mface in model.symbolsI: + maxis = model.symbolsI.index(mface) + return maxis, (-1 if whole_cube else model.sizes[maxis]-1 - mslice), 1-mdir + else: + return None, None, None + + @classmethod + def parse(cls, move_code, model): + #debug('move_code: '+move_code) + mface, mslice, mdir, err1, mark, err2 = cls.re_flubrd.match(move_code).groups() + markup_code = cls._format_markup(mface, mslice, mdir, err1, mark, err2) + whole_cube = mface.isupper() + mface = mface.upper() + mslice = int(mslice or 1) - 1 + mdir = int(bool(mdir)) + mark = bool(mark) + # move finished, normalize it + maxis, mslice2, mdir = cls.normal_to_intern_move(mface, mslice, mdir, whole_cube, model) + if maxis is not None and 0 <= mslice < model.sizes[maxis]: + return MoveData(maxis, mslice2, mdir), mark, markup_code + debug('Error parsing formula') + return None, False, move_code + diff -Nru pybik-0.5/pybiklib/plugins.py pybik-1.0.1/pybiklib/plugins.py --- pybik-0.5/pybiklib/plugins.py 2012-01-06 16:34:10.000000000 +0000 +++ pybik-1.0.1/pybiklib/plugins.py 2012-12-13 19:11:29.000000000 +0000 @@ -16,132 +16,136 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . - # Ported from GNUbik # Original filename: guile-hooks.c # Original copyright and license: 2004 Dale Mellor, GPL3+ +from __future__ import print_function, division, unicode_literals import os import sys import imp -import re -from collections import namedtuple +from collections import namedtuple, OrderedDict -from .debug import * +from .debug import * # pylint: disable=W0401, W0614 from . import config -from . import move_queue +from .moves import MoveQueue +from . import model +FILE_VERSION = '1.1' -class PluginHelper (object): + +class PluginState (object): def __init__(self, app): - self.app = app - # When a script runs, the first cube movement that is requested by the script - # must flush the move queue after the place of current insertion; further move - # requests must be appended to the end of the move queue. This variable is used - # to track the first request. - self.moved = False - plugin_funcs = [ - ('register_script', self.plugin_register_script), - ("cube_state", self.plugin_cube_state), - ("rotate_animated", self.plugin_rotate_animated), - ('rotate_flubrd', self.plugin_rotate_flubrd), - ("run_moves", self.plugin_run_moves), - ("error_dialog", self.plugin_error_dialog), - ('random', lambda x:app.current_movement.current_cube_state.rand.randrange(x)), - ] - module = sys.modules['pybikplugin'] = type(sys)('pybikplugin') - for name, func in plugin_funcs: - setattr(module, name, func) - - def __del__(self): - self.app = None - - def call(self, func): - if not callable(func): - return False - self.moved = False - func() - return self.moved - - def plugin_register_script(self, path, func): - self.scripts.append((path, func)) - - def plugin_cube_state(self): - '''Function callable from plugin which returns a structure - reflecting the current state of the cube.''' - return self.app.current_movement.current_cube_state.copy() - - def _start_moves_if_first(self): - '''The first time a script makes a move on the cube, the move_queue must be - truncated to the current place, and the place is marked so that the viewer - can rewind the effects of the script. This script performs the necessary - preparations.''' - if not self.moved: - self.moved = 1 - self.app.current_movement.all_moves.truncate() - self.app.current_movement.all_moves.mark_current(True) - - def plugin_rotate_animated(self, moves): - '''Function which, when called from plugins, causes one - side of the cube to rotate on-screen.''' - self._start_moves_if_first() - for maxis, mslice, mdir in moves: - data = move_queue.MoveData(maxis, mslice, mdir) - self.app.current_movement.all_moves.push(data) + self.initial_state = None + self.current_state = app.gamestate.current_cube_state.copy() + self.moves = MoveQueue() + self.error_dialog = app.error_dialog + self.set_progress = app.set_progress + self.end_progress = app.end_progress + + def add_moves(self, moves): + for move in moves: + self.current_state.rotate_slice(move) + self.moves.push(move) - def plugin_rotate_flubrd(self, code, size): - self._start_moves_if_first() + def add_flubrd(self, code): #TODO: here flubrd should be used, not the one in all_moves, # the converter in all_moves may be configurable in the future - moves = [] - for move_data, unused_pos in self.app.current_movement.all_moves.parse_iter(code, len(code), size): - moves.append((move_data.axis, move_data.slice, move_data.dir)) - return moves - - def plugin_run_moves(self): - '''Function allowing a script to apply all its moves in one go to the cube, - without creating animations on the display.''' - self.app.current_movement.do_fast_forward() - - def plugin_error_dialog(self, message): - '''Function to allow a plugin to display a message to the user.''' - self.app.error_dialog(message) + for move_data, unused_pos in self.moves.parse_iter(code, len(code), self.current_state.model): + self.current_state.rotate_slice(move_data) + + def random(self, count=-1): + self.current_state.set_solved() + self.current_state.randomize(count) + self.initial_state = self.current_state.copy() + self.moves.reset() + + def test_model(self, models, show_error=True): + cube = self.current_state + for unused_modelstr, Model, sizes, exp in models: + if Model == '*': + return True + if Model is None: + continue + if cube.type != Model.type: + continue + sizedict = {} + for size1, size2 in zip(sizes, cube.model.sizes): + if size1 is None: + continue + if type(size1) is int: + if size1 != size2: + break + else: + sizedict[size1] = size2 + else: + try: + if exp is None or eval(exp, {}, sizedict): + return True + except ValueError: + continue + if not show_error: + return False + models = [model_[0] for model_ in models if model_[1] is not None] + if not models: + self.error_dialog(_('This algorithm does not work for any model.\n')) + elif len(models) == 1: + self.error_dialog(_('This algorithm only works for:\n') + ' ' + models[0]) + else: + self.error_dialog( + _('This algorithm only works for:\n') + + '\n'.join([' • ' + m for m in models]) + ) + return False - def _load_py_plugin(self, dirname, modulename): - file_, path, desc = imp.find_module(modulename, [dirname]) - try: - module = imp.load_module(modulename, file_, path, desc) - debug(' import', modulename) - except Exception as e: - debug(e) - finally: - if file_: - file_.close() - - def _load_plugins_from_directory(self, dirname): - if os.path.isdir(dirname): - debug('Plugins from', dirname) - sys.path.insert(0, dirname) - for filename in sorted(os.listdir(dirname), key=str.lower): - debug(' script:', filename) - name, ext = os.path.splitext(filename) - if ext == '.py': - self._load_py_plugin(dirname, name) - elif ext == '.script': - self._load_text_plugin(os.path.join(dirname, filename)) + +class PluginHelper (object): + def __init__(self): + self.scripts = OrderedDict() + self.error_messages = [] + + def call(self, app, index): + plugin_state = PluginState(app) + all_models = [] + for models, func in self.scripts.values()[index]: + if plugin_state.test_model(models, show_error=False): + func(plugin_state) + break + all_models += models + else: + plugin_state.test_model(all_models, show_error=True) + return plugin_state.initial_state, plugin_state.moves + + def load_plugins_from_directory(self, dirname): + if not os.path.isdir(dirname): + debug('Plugins path does not exist:', dirname) + return + debug('Loading Plugins from', dirname) + sys.path.insert(0, dirname) + for filename in sorted(os.listdir(dirname), key=unicode.lower): + unused_name, ext = os.path.splitext(filename) + if ext != '.algorithm': + continue + debug(' algorithm:', filename) + try: + self.load_text_plugin(os.path.join(dirname, filename)) + except Exception as e: # pylint: disable=W0703 + self.error_messages.append('Error loading {}:\n{}'.format(os.path.basename(filename), e)) + sys.excepthook(*sys.exc_info()) def load_plugins(self): '''This function initializes the plugins for us, and once the plugins have all been imported, it returns the requested menu structure to the caller.''' - self.scripts = [] - self._load_plugins_from_directory(config.SCRIPT_DIR) - script_dir = os.path.join(config.get_data_home(), 'scripts') - self._load_plugins_from_directory(script_dir) + self.scripts.clear() + del self.error_messages[:] + self.load_plugins_from_directory(config.SCRIPT_DIR) + self.load_plugins_from_directory(config.USER_SCRIPT_DIR) debug(' found', len(self.scripts)) - return self.scripts + return [(path, i) for i, path in enumerate(self.scripts.keys())] - def _load_text_plugin(self, filename): + @staticmethod + def parse_text_plugin(filename): with open(filename) as fp: lines = fp.readlines() paras = [] @@ -150,7 +154,7 @@ para = {} key = None for line in lines: - line = line.rstrip() + line = unicode(line, 'utf-8').rstrip() if not line: # end para if para: @@ -170,38 +174,47 @@ para[key] = [value] if value else [] if para: paras.append(para) + return paras - if not paras: - return - - # evaluate header - header = paras[0].copy() + @staticmethod + def eval_model(modelstrings): + model_infos = [] + for modelstr in modelstrings: + try: + model_info = model.from_string(modelstr) + except ValueError as e: + debug('Error in model %s:' % modelstr, e) + else: + model_infos.append(model_info) + return model_infos + + @classmethod + def eval_header(cls, header): value = header.get('File-Version', []) - if value != ['1.0']: - debug('Wrong file version:', '\n'.join(value)) - return + if len(value) == 0: + value = FILE_VERSION + debug('No file version found, assume version', value) + elif len(value) == 1: + value = value[0] + else: + debug('Multiple version numbers found:\n ', '\n '.join(value)) + value = value[0] + debug('assume version', value) + if value != FILE_VERSION: + debug('Wrong file version:', value) + return None, None models = header.get('Model', []) - if not models: - debug('Field "Model" not specified') - return - def split_model(model): - type_ = model.split(' ', 1) - if len(type_) != 2 or type_[0] != 'Cube': - return 'unknown', 'unknown', None - type_, size = type_ - try: - size = int(size) - except ValueError: - return 'unknown', 'unknown', None - return model, type_, size - models = [split_model(m) for m in models] + models = cls.eval_model(models) + ref_blocks = header.get('Ref-Blocks', None) if ref_blocks: ref_blocks = ' '.join(ref_blocks).split() - - # evaluate solutions + return models, ref_blocks + + @classmethod + def eval_paras(cls, models, ref_blocks, paras): for para in paras: - value = para.get('Path', []) + value = para.get('Path', ()) if len(value) != 1 or not value[0]: debug(' skip Path:', value) para.clear() @@ -224,6 +237,9 @@ value = [split_path(v)[1] for v in value] para['Depends'] = value + value = para.get('Model', None) + para['Model'] = models if value is None else cls.eval_model(value) + value = para.get('Ref-Blocks', None) if value: value = ' '.join(value).split() @@ -231,7 +247,7 @@ value = para.get('Solution', None) def split_solution(value): - value = value.split('#',1)[0] + value = value.split('#', 1)[0] value = value.split(',', 1) if len(value) != 2: return None @@ -243,78 +259,109 @@ value = [split_solution(v) for v in value if v] para['Solution'] = value + value = para.get('Moves', None) or None + if value is not None: + value = ' '.join(value) + para['Moves'] = value + + value = para.get('Module', None) or None + if value is not None: + value = value[0] + para['Module'] = value + + def load_text_plugin(self, filename): + paras = self.parse_text_plugin(filename) + if not paras: + return + + # evaluate header + models, ref_blocks = self.eval_header(paras[0]) + if models is None: + return + + # evaluate solutions + self.eval_paras(models, ref_blocks, paras) + scripts = [] for para in paras: if not para: continue sep, path = para['Path'] - params = namedtuple('ScriptParams', 'depends ref_blocks solution scripts models')( - depends=para['Depends'], + models = para['Model'] + depends = para['Depends'] + solution = para['Solution'] + moves = para['Moves'] + module = para['Module'] + if depends or solution is not None: + if moves is not None: + debug(' solution can not have moves:', path) + if module is not None: + debug(' solution can not have a module field:', path) + params = ScriptParams( + depends=depends, ref_blocks=para['Ref-Blocks'], - solution=para['Solution'], + solution=solution, scripts=scripts, models=models, + sep_path=(sep, path), ) - scripts.append((path, sep!='@', ScriptFactory(self, params))) + scripts.append((path, sep!='@', models, ScriptFactory(self, params))) + elif moves is not None: + if module is not None: + debug(' Moves can not have a module field:', path) + def play_moves(moves, models): + def func(game): + if game.test_model(models): + game.add_flubrd(moves) + return func + scripts.append((path, True, models, play_moves(moves, models))) + elif module is not None: + dirname = os.path.dirname(filename) + modulename, funcname = module.split(' ', 1) + mfile, mpath, mdesc = imp.find_module(modulename, [dirname]) + moduleobj = imp.load_module(modulename, mfile, mpath, mdesc) + modulefunc = getattr(moduleobj, funcname) + scripts.append((path, True, models, modulefunc)) + else: + debug(' skip Path without algorithm:', path) - self.scripts += [(path, func) for path, visible, func in scripts if visible] + for path, visible, models, func in scripts: + if visible: + funclist = self.scripts.setdefault(path, []) + funclist.append((models, func)) +ScriptParams = namedtuple('ScriptParams', 'depends ref_blocks solution scripts models sep_path') + class ScriptFactory (object): def __init__(self, plugin, params): self.solved_face_colors = {} self.plugin = plugin self.params = params - def __call__(self): - cube = self.plugin.plugin_cube_state() - for model, type_, dimension in self.params.models: - if cube.type == type_ and cube.dimension == dimension: - break - else: - self.plugin.plugin_error_dialog( - _('This script only works for:') + - ''.join('\n '+m for m,t,d in self.params.models)) + def __call__(self, plugin_state): + if not plugin_state.test_model(self.params.models): return depends = list(reversed(self.params.depends)) - scripts = {path: func for path, visible, func in self.params.scripts} + scripts = {path: func for path, visible, models, func in self.params.scripts} for depend in depends: instance = scripts[depend] depends += instance.params.depends for depend in reversed(depends): instance = scripts[depend] - self.execute(cube, instance.params.ref_blocks, instance.params.solution) - self.execute(cube, self.params.ref_blocks, self.params.solution) - - def get_color(self, cube, face, block): - facenum = 'udlrfb'.index(face) - f, l, u = 1, 1, 1 - for match in re.finditer(r'(.)(\d*)', block): - blockface, blockslice = match.groups() - blockslicenum = int(blockslice) if blockslice else 1 - if blockface == 'u': u = blockslicenum - 1 - elif blockface == 'd': u = cube.dimension - blockslicenum - elif blockface == 'l': l = blockslicenum - 1 - elif blockface == 'r': l = cube.dimension - blockslicenum - elif blockface == 'f': f = blockslicenum - 1 - elif blockface == 'b': f = cube.dimension - blockslicenum - if face in 'ud': index = f + cube.dimension * l - if face in 'lr': index = f + cube.dimension * u - if face in 'fb': index = l + cube.dimension * u - - return cube.faces[facenum][index] + self.execute(plugin_state, instance.params) + self.execute(plugin_state, self.params) - @debug_func - def test_face(self, cube, position, condition, face): + def test_face(self, cube, blocksym, condition, face): try: color2 = self.solved_face_colors[condition[face]] except KeyError: return True - color1 = self.get_color(cube, position[face], position) + blocknum = cube.model.block_symbolic_to_block_index(blocksym) + color1 = cube.get_colorsymbol(blocknum, blocksym[face]) return color1 == color2 - @debug_func def test_basic_condition(self, cube, position, condition): assert len(position) == len(condition) for i in xrange(len(position)): @@ -322,13 +369,13 @@ return False return True - def opposite(self, face): + @staticmethod + def opposite(face): return { 'f': 'b', 'b': 'f', 'l': 'r', 'r': 'l', 'u': 'd', 'd': 'u', }[face] - @debug_func def test_pattern_condition(self, cube, position, condition): if '?' in condition: conditions = (condition.replace('?', face, 1) @@ -339,11 +386,11 @@ else: return self.test_basic_condition(cube, position, condition) - def rotated_conditions(self, condition): + @staticmethod + def rotated_conditions(condition): for i in range(len(condition)): yield condition[i:] + condition[:i] - @debug_func def test_prefix_condition(self, cube, position, condition): if condition.startswith('!*'): return not self.test_or_conditions(cube, position, self.rotated_conditions(condition[2:])) @@ -358,50 +405,53 @@ else: return self.test_pattern_condition(cube, position, condition) - @debug_func def test_or_conditions(self, cube, position, conditions): for prefix_cond in conditions: if self.test_prefix_condition(cube, position, prefix_cond): return True return False - @debug_func def test_and_conditions(self, cube, conditions): for position, or_cond in conditions: if not self.test_or_conditions(cube, position, or_cond.split('|')): return False return True - def execute(self, cube, ref_blocks, rules): + def execute(self, plugin_state, params): + rules = params.solution if rules is None: return + cube = plugin_state.current_state count = 0 pos = 0 while pos < len(rules): self.solved_face_colors.clear() - for block in ref_blocks: + for block in params.ref_blocks: + blocknum = cube.model.block_symbolic_to_block_index(block) for face in block: - self.solved_face_colors[face] = self.get_color(cube, face, block) + self.solved_face_colors[face] = cube.get_colorsymbol(blocknum, face) conditions, moves = rules[pos] if self.test_and_conditions(cube, conditions): - debug('positive: {}. {!r}, {!r}'.format( - pos, ' '.join('='.join(c) for c in conditions), moves)) + if DEBUG_ALG: + print('{}: accept: {:2}. {}, {}'.format( + params.sep_path[0].join(params.sep_path[1]), + pos+1, + ' '.join('='.join(c) for c in conditions), + moves)) if moves == '@@solved': return if count > 4 * len(rules): # this value is just guessed - self.plugin.plugin_error_dialog( + plugin_state.error_dialog( 'An infinite loop was detected. ' 'This is probably an error in the solution.') return count += 1 - moves_ = self.plugin.plugin_rotate_flubrd(moves, cube.dimension) - for move in moves_: - cube._rotate_slice(*move) + plugin_state.add_flubrd(moves) pos = 0 else: pos += 1 - self.plugin.plugin_error_dialog( + plugin_state.error_dialog( 'No matching rules found. ' 'This is probably an error in the solution.') diff -Nru pybik-0.5/pybiklib/pybik.py pybik-1.0.1/pybiklib/pybik.py --- pybik-0.5/pybiklib/pybik.py 2011-12-25 15:43:56.000000000 +0000 +++ pybik-1.0.1/pybiklib/pybik.py 2012-11-12 09:47:57.000000000 +0000 @@ -2,7 +2,7 @@ #-*- coding:utf-8 -*- # Pybik -- A 3 dimensional magic cube game. -# Copyright © 2009, 2011 B. Clausius +# Copyright © 2009, 2011-2012 B. Clausius # # 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 @@ -17,43 +17,16 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +from __future__ import print_function, division, unicode_literals -import sys, os -import gettext - -import pygtk -pygtk.require('2.0') - -lib_dir = os.path.dirname(os.path.realpath(__file__)) -src_dir, sub_dir = os.path.split(lib_dir) -root_dir = os.path.dirname(os.path.realpath(os.path.dirname(__file__))) - -if sub_dir == 'pybiklib': - sys.path[0] = src_dir - print 'Running from source directory' - -try: - from pybiklib import config -except ImportError: - print 'Pybik is not properly installed.' - sys.exit(1) - -if sub_dir == 'pybiklib': - # running from source - LOCALEDIR = os.path.join(src_dir, 'build', 'mo') -elif root_dir == sys.prefix: - # normal installation - LOCALEDIR = None -else: - # different root, e.g. /usr/local - LOCALEDIR = config.LOCALE_DIR -gettext.install(config.PACKAGE, LOCALEDIR, names=['ngettext']) +import os import pybiklib.main +root_dir = os.path.dirname(os.path.realpath(os.path.dirname(__file__))) def main(): - pybiklib.main.run() + pybiklib.main.run(root_dir) if __name__ == '__main__': main() diff -Nru pybik-0.5/pybiklib/settings.py pybik-1.0.1/pybiklib/settings.py --- pybik-0.5/pybiklib/settings.py 1970-01-01 00:00:00.000000000 +0000 +++ pybik-1.0.1/pybiklib/settings.py 2012-12-13 17:23:08.000000000 +0000 @@ -0,0 +1,343 @@ +#-*- coding:utf-8 -*- + +# Pybik -- A 3 dimensional magic cube game. +# Copyright © 2009, 2011-2012 B. Clausius +# +# 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 . + +from __future__ import print_function, division, unicode_literals + +import sys, os +from ast import literal_eval +import errno + +from PySide.QtCore import * # pylint: disable=W0614,W0401 + +from .debug import debug +from . import config +from . import model + + +def tuple_validator(lenght, itemtype, value, valuerange=None): + if type(value) is not tuple: + return False + if len(value) != lenght: + return False + for v in value: + if type(v) is not itemtype: + return False + if valuerange is not None and not valuerange[0] <= v <= valuerange[1]: + return False + return True + +class KeyStore (QObject): + schema = { + # key: (default, range/enum/validator) + # None: value without restriction + # tuple: contains two values (min, max) + # list: contains strings for the enum text, + # the index is the enum value + # function: returns True, if value is valid + 'window.size': ((480, 360),lambda v: tuple_validator(2, int, v)), + 'window.divider': (300, lambda v: type(v) is int), + 'window.toolbar': (True, lambda v: type(v) is bool), + 'window.editbar': (True, lambda v: type(v) is bool), + 'window.statusbar': (True, lambda v: type(v) is bool), + 'draw.default_rotation':((-30.,39.),lambda v: tuple_validator(2, float, v)), + 'draw.lighting': (False, lambda v: type(v) is bool), + 'draw.selection': (1, ['quadrant', 'simple']), + 'draw.speed': (30, (1, 100)), + 'game.type': (0, [m.type for m in model.models]), + 'game.size': ((3,4,2), lambda v: tuple_validator(3, int, v, (1, 10))), + 'game.blocks': ('solved', lambda v: type(v) is unicode), + 'game.moves': ('', lambda v: type(v) is unicode), + 'game.position': (0, lambda v: type(v) is int and v >= 0), + 'theme.face.0.color': ('#a81407', lambda v: type(v) is unicode), + 'theme.face.1.color': ('#d94b1c', lambda v: type(v) is unicode), + 'theme.face.2.color': ('#f0c829', lambda v: type(v) is unicode), + 'theme.face.3.color': ('#e3e3e3', lambda v: type(v) is unicode), + 'theme.face.4.color': ('#1d6311', lambda v: type(v) is unicode), + 'theme.face.5.color': ('#00275e', lambda v: type(v) is unicode), + 'theme.face.#.image': ('', lambda v: type(v) is unicode), + 'theme.face.#.mode': (0, ['tiled', 'mosaic']), + 'theme.bgcolor': ('#B99553', lambda v: type(v) is unicode), + 'draw.accels': ([('r', 'KP+6'), ('r-', 'Shift+KP+Right'), + ('l', 'KP+4'), ('l-', 'Shift+KP+Left'), + ('u', 'KP+8'), ('u-', 'Shift+KP+Up'), + ('d', 'KP+2'), ('d-', 'Shift+KP+Down'), + ('f', 'KP+5'), ('f-', 'Shift+KP+Clear'), + ('b', 'KP+0'), ('b-', 'Shift+KP+Ins'), + ('R', 'Ctrl+KP+8'), ('L', 'Ctrl+KP+2'), + ('U', 'Ctrl+KP+4'), ('D', 'Ctrl+KP+6'), + ('F', 'Ctrl+KP+5'), ('B', 'Ctrl+KP+0'), + ], lambda v: type(v) is list), + 'draw.zoom': (1.0, (0.1, 100.0)), + 'draw.accum': (0, ['disabled', 'ugly', 'low', 'medium', 'high']), + 'draw.samples': (3, ['disabled', 'ugly', 'low', 'medium', 'high', 'higher']), + 'draw.mirror_faces': (False, lambda v: type(v) is bool), + 'draw.mirror_distance': (2.1, (0.1, 10.0)), + 'action.edit_moves': ('Ctrl+L', lambda v: type(v) is unicode), + 'action.edit_model': ('', lambda v: type(v) is unicode), + 'action.selectmodel': ('', lambda v: type(v) is unicode), + 'action.initial_state': ('', lambda v: type(v) is unicode), + 'action.reset_rotation':('', lambda v: type(v) is unicode), + 'action.invert_moves': ('', lambda v: type(v) is unicode), + 'action.reload_scripts':('', lambda v: type(v) is unicode), + 'action.preferences': ('', lambda v: type(v) is unicode), + 'action.normalize_complete_rotations':('',lambda v: type(v) is unicode), + } + + changed = Signal(str) + error = Signal(str) + + def __init__(self, filename): + QObject.__init__(self) + self.filename = filename + self.keystore = {} + self.read_settings() + self.write_timer = QTimer(self) + self.write_timer.setSingleShot(True) + self.write_timer.setInterval(5000) + self.write_timer.timeout.connect(self.write_settings) + + def get_default(self, key): + return self.schema[key][0] + def get_range(self, key): + return self.schema[key][1] + + def get_value(self, key): + try: + return self.keystore[key] + except KeyError: + return self.get_default(key) + + def get_nick(self, key): + value = self.get_value(key) + valuerange = self.get_range(key) + if not isinstance(valuerange, list): + raise ValueError('{} is not an enum'.format(key)) + return valuerange[value] + + def set_value(self, key, value): + self.keystore[key] = value + self.changed.emit(key) + if not self.write_timer.isActive(): + self.write_timer.start() + + def set_nick(self, key, nick): + valuerange = self.get_range(key) + if not isinstance(valuerange, list): + raise ValueError('{} is not an enum'.format(key)) + value = valuerange.index(nick) + return self.set_value(key, value) + + def del_value(self, key): + try: + del self.keystore[key] + except KeyError: + pass # already the default value + self.changed.emit(key) + if not self.write_timer.isActive(): + self.write_timer.start() + + @classmethod + def _str_to_uni(cls, value): + # pylint: disable=C0321 + if type(value) is str: return value.decode('utf-8') + if type(value) is list: return [cls._str_to_uni(v) for v in value] + if type(value) is tuple: return tuple(cls._str_to_uni(v) for v in value) + return value + + @classmethod + def _uni_to_str(cls, value): + # pylint: disable=C0321 + if type(value) is unicode: return value.encode('utf-8') + if type(value) is list: return [cls._uni_to_str(v) for v in value] + if type(value) is tuple: return tuple(cls._uni_to_str(v) for v in value) + return value + + def read_settings(self): + if not self.filename: + return + keys = self.schema.keys() + dirname = os.path.dirname(self.filename) + if dirname and not os.path.exists(dirname): + os.makedirs(dirname) + + # Only convert from gconf to standard location + write_version_file = False + if self.filename == config.USER_SETTINGS_FILE and not os.path.exists(config.USER_VERSION_FILE): + write_version_file = True + try: + if not os.path.exists(self.filename): + from . import migration + migration.gconf_0_5_to_settings_1_0(self.filename) + except Exception: # pylint: disable=W0703 + # Never fail, but report error + sys.excepthook(*sys.exc_info()) + + # read settings + try: + with open(self.filename) as settings_file: + lines = settings_file.readlines() + except IOError as e: + if e.errno == errno.ENOENT: + lines = [] + else: + raise + for line in lines: + # parse the line, discard invalid keys + try: + key, strvalue = line.split('=', 1) + except ValueError: + continue + key = key.strip() + strvalue = strvalue.strip() + if key not in keys: + continue + try: + value = literal_eval(strvalue) + except (ValueError, SyntaxError): + continue + + value = self._str_to_uni(value) + + # translate enums and validate values + valuerange = self.get_range(key) + if isinstance(valuerange, list): + try: + value = valuerange.index(value) + except ValueError: + continue + elif isinstance(valuerange, tuple): + if not valuerange[0] <= value <= valuerange[1]: + continue + elif valuerange is not None: + if not valuerange(value): + continue + + self.keystore[key] = value + + if write_version_file: + with open(config.USER_VERSION_FILE, 'w') as version_file: + version_file.write(config.VERSION) + + def dump(self, file, all=False): # pylint: disable=W0622 + keydict = self.schema if all else self.keystore + for key in sorted(keydict.keys()): + if '#' in key: + continue + value = self.get_value(key) + # translate enums + valuerange = self.get_range(key) + if isinstance(valuerange, list): + value = valuerange[value] + value = self._uni_to_str(value) + print(key, '=', repr(value), file=file) + + def write_settings(self): + if not self.filename: + return + try: + with open(self.filename, 'w') as settings_file: + self.dump(settings_file) + except EnvironmentError as e: + error_message = _('Settings can not be written to file: ' + '{error_message}').format(error_message=e) + debug(error_message) + self.error.emit(error_message) + + +class Settings (object): + keystore = None + + def __init__(self, key=''): + object.__setattr__(self, '_key', key) + object.__setattr__(self, '_array_len', 0) + + def load(self, filename): + self.__class__.keystore = KeyStore(filename) + keys = self.keystore.schema.keys() + deferred = [] + + for key in keys: + subkeys = key.split('.') + settings_parent = self + for subkey in subkeys[:-1]: + if subkey == '#': + deferred.append(key) + break + if subkey.isdigit(): + subkey = str(int(subkey)) + try: + settings_child = getattr(settings_parent, subkey) + except KeyError: + settings_child = Settings(settings_parent._key + subkey + '.') + object.__setattr__(settings_parent, subkey, settings_child) + assert isinstance(settings_child, Settings) + settings_parent = settings_child + else: + object.__setattr__(settings_parent, subkeys[-1]+'_range', self.keystore.get_range(key)) + changed = False + for key in deferred: + subkeys = key.split('.') + settings_parent = self + for i, subkey in enumerate(subkeys): + if subkey == '#': + for subkey in settings_parent.__dict__.keys(): + if subkey[0] == '_': + continue + expanded = '.'.join(subkeys[:i] + [subkey] + subkeys[i+1:]) + if expanded not in self.keystore.schema: + changed = True + self.keystore.schema[expanded] = self.keystore.schema[key] + break + settings_parent = getattr(settings_parent, subkey) + if changed: + self.load(filename) + + def close(self): + self.keystore.write_timer.stop() + self.keystore.write_settings() + + def __getattr__(self, key): + if key.endswith('_nick'): + return self.keystore.get_nick(self._key + key[:-5]) + return self.keystore.get_value(self._key + key) + + def __getitem__(self, key): + return getattr(self, str(key)) + + def __setattr__(self, key, value): + if key.endswith('_nick'): + key = self._key + key[:-5] + func = self.keystore.set_nick + else: + key = self._key + key + func = self.keystore.set_value + if key in self.keystore.schema.keys(): + func(key, value) + else: + raise AttributeError('use object.__setattr__ to set attributes') + + def __delattr__(self, key): + _key = self._key + key + if _key in self.keystore.schema.keys(): + self.keystore.del_value(_key) + else: + raise AttributeError('use object.__delattr__ to delete attributes') + + +settings = Settings() + diff -Nru pybik-0.5/pybiklib/state.py pybik-1.0.1/pybiklib/state.py --- pybik-0.5/pybiklib/state.py 2011-12-29 20:56:29.000000000 +0000 +++ pybik-1.0.1/pybiklib/state.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,160 +0,0 @@ -#-*- coding:utf-8 -*- - -# Pybik -- A 3 dimensional magic cube game. -# Copyright © 2009-2011 B. Clausius -# -# 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 . - - -# Ported from GNUbik -# Original filename: ui.c -# Original copyright and license: GPL3+ -# 1998, 2003 John Darrington -# 2004 John Darrington, Dale Mellor - - -from .debug import * - -from . import cube_form -from . import move_queue - - -# The move taking place NOW -class CurrentMovement: - def __init__(self): - self.mark_before = False - self.initial_cube_state = cube_form.CubeState() - self.current_cube_state = cube_form.CubeState() - self.all_moves = move_queue.MoveQueue() - - def set_saved_game(self, dimension, saved_state, saved_moves, saved_pos): - self.initial_cube_state.set_solved(dimension=dimension) - try: - self.initial_cube_state.parse_block(saved_state) - except Exception as e: - debug('Error parsing saved cube state: ', e) - self.current_cube_state = self.initial_cube_state.copy() - else: - self.current_cube_state = self.initial_cube_state.copy() - self.all_moves.reset() - pos = self.all_moves.parse(saved_moves, saved_pos, dimension) - self.do_fast_forward(to_pos=pos) - - def get_saved_game(self): - dimension = self.initial_cube_state.dimension - saved_state = self.initial_cube_state.format_block_compact() - saved_moves, saved_pos, unused_markup = self.all_moves.format(dimension) - return dimension, saved_state, saved_moves, saved_pos - - def set_solved(self, dimension): - self.initial_cube_state.set_solved(dimension=dimension) - self.current_cube_state = self.initial_cube_state.copy() - - def set_random(self, dimension): - self.initial_cube_state.set_solved(dimension=dimension) - self.initial_cube_state.randomize_and_apply() - self.current_cube_state = self.initial_cube_state.copy() - - ### Funktions to control the cube for use in callbacks and scripts - - def request_back(self): - '''One step back in the sequence of moves''' - if self.all_moves.at_start(): - return None - self.all_moves.retard() - move_data = self.all_moves.current().copy() - self.current_cube_state.rotate_slice_back(move_data) - move_data.dir = not move_data.dir - self.mark_before = move_data.mark_after - return move_data - - # Internal functionality for the following two functions. - def _request_play(self, one_move): - move_data = self.all_moves.current() - if move_data: - self.mark_before = self.all_moves.at_start() or self.all_moves.prev().mark_after - self.current_cube_state.rotate_slice(move_data) - self.all_moves.advance() - return move_data - - def request_play(self): - '''Play the current sequence of moves to the end''' - move_data = self._request_play(0) - return move_data - - def request_next(self): - '''One step forward in the sequence of moves''' - return self._request_play(1) - - def request_rotation(self, maxis, mslice, mdir): - '''Make one new move. - - The usual rotation request, called when user uses mouse to rotate the cube by - hand. The move is put into the `current' place, and all the moves in - all_moves afterwards are zapped.''' - move_data = move_queue.MoveData(maxis, mslice, mdir) - self.all_moves.push_current(move_data) - - def request_mark_move_queue(self, mark): - '''Set a marker at the current position in the sequence of moves''' - self.all_moves.mark_current(mark) - - def do_rewind_to_mark(self): - if self.all_moves.at_start(): - return False - move_data = self.all_moves.prev() - while True: - self.all_moves.retard() - self.current_cube_state.rotate_slice_back(move_data) - if self.all_moves.at_start(): - break - move_data = self.all_moves.prev() - if move_data.mark_after: - break - return True - - def do_fast_forward(self, to_pos=-1): - '''Go to end of the sequence of moves. - - All the moves take place on the cube, not via the animation - routines, so the effect is to show the result instantaneously.''' - move_data = self.all_moves.current() - while move_data: - if to_pos == self.all_moves.current_place: - break - self.current_cube_state.rotate_slice(move_data) - self.all_moves.advance() - if to_pos < 0 and move_data.mark_after: - break - move_data = self.all_moves.current() - - def set_from_formula(self, code, pos): - self.current_cube_state = self.initial_cube_state.copy() - self.all_moves.rewind_start() - self.all_moves.reset() - pos = self.all_moves.parse(code, pos, self.current_cube_state.dimension) - self.do_fast_forward(to_pos=pos) - - def set_as_initial_state(self): - self.initial_cube_state = self.current_cube_state.copy() - self.all_moves.truncate_before() - - def invert_moves(self): - self.current_cube_state = self.initial_cube_state.copy() - self.all_moves.invert() - pos = self.all_moves.current_place - self.all_moves.rewind_start() - self.do_fast_forward(to_pos=pos) - - diff -Nru pybik-0.5/pybiklib/textures.py pybik-1.0.1/pybiklib/textures.py --- pybik-0.5/pybiklib/textures.py 2012-01-06 17:00:19.000000000 +0000 +++ pybik-1.0.1/pybiklib/textures.py 2012-12-04 16:44:48.000000000 +0000 @@ -16,183 +16,55 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . - # Ported from GNUbik # Original filename: textures.c # Original copyright and license: 2003 John Darrington, GPL3+ +from __future__ import print_function, division, unicode_literals -from OpenGL import GL as gl -from gtk import gdk - -SWATCH_WIDTH = 256 -SWATCH_HEIGHT = 256 -SWATCH_WIDTH_SMALL = 64 -SWATCH_HEIGHT_SMALL = 64 -SWATCH_WIDTH_SMALLEST = 32 -SWATCH_HEIGHT_SMALLEST = 32 - - -class PatternParameters: - def __init__(self, texName=0, data=[], texFunc=0): - self.texName = texName # uint - self.data = data # byte[] ? - self.texFunc = texFunc # int This is the function to be passed to glTexEnv - - -checkImageWidth = 64 -checkImageHeight = 64 - -Image = [[[[0]*4 for __i in xrange(checkImageWidth)] - for __j in xrange(checkImageHeight)] for __k in xrange(6)] -xbm = [[0] * (checkImageHeight*checkImageWidth/8) for __i in xrange(6)] - -stock_pattern = [PatternParameters() for __i in xrange(6)] - - -def texMakePatterns (): - #int i, j, c - k = 0 - x = 0 - shift = 0 - - # Stripy pattern - for i in xrange(checkImageHeight): - for j in xrange(checkImageWidth): - c = ((i&0x04) == 0) * 255 - Image[k][i][j][0] = c - Image[k][i][j][1] = c - Image[k][i][j][2] = c - Image[k][i][j][3] = 255 - xbm[k][x] |= (c&0x01) << shift - shift += 1 - if shift >= 8: - shift = 0 - x += 1 - - - # Diagonal Striped - k = 1 - shift = 0 - x = 0 - for i in xrange(checkImageHeight): - for j in xrange(checkImageWidth): - c = (((i+j)&0x08) == 0) * 255 - Image[k][i][j][0] = c - Image[k][i][j][1] = c - Image[k][i][j][2] = c - Image[k][i][j][3] = 255 - xbm[k][x] |= (c&0x01) << shift - shift += 1 - if shift >= 8: - shift = 0 - x += 1 - - - # Checked patterns - for k in xrange(2, 6): - mask = 0x01 << k - shift = 0 - x = 0 - for i in xrange(checkImageHeight): - for j in xrange(checkImageWidth): - c = (((i&mask) == 0) ^ ((j&mask) == 0)) * 255 - Image[k][i][j][0] = c - Image[k][i][j][1] = c - Image[k][i][j][2] = c - Image[k][i][j][3] = 255 - xbm[k][x] |= (c&0x01) << shift - shift += 1 - if shift >= 8: - shift = 0 - x += 1 - - -def texInit (): - texMakePatterns () - gl.glPixelStorei (gl.GL_UNPACK_ALIGNMENT, 1) - - texName = gl.glGenTextures (6) - #debug(texName) - - gl.glTexEnvi (gl.GL_TEXTURE_ENV, gl.GL_TEXTURE_ENV_MODE, gl.GL_MODULATE) - for i in xrange(6): - stock_pattern[i].texName = texName[i] - - gl.glBindTexture (gl.GL_TEXTURE_2D, texName[i]) - gl.glTexParameteri (gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_S, gl.GL_CLAMP) - gl.glTexParameteri (gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_T, gl.GL_CLAMP) - gl.glTexParameteri (gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_NEAREST) - gl.glTexParameteri (gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER, gl.GL_NEAREST) - - gl.glTexImage2D (gl.GL_TEXTURE_2D, 0, gl.GL_RGBA, checkImageWidth, - checkImageHeight, 0, gl.GL_RGBA, gl.GL_UNSIGNED_BYTE, - Image[i]) - - stock_pattern[i].data = xbm[i] - stock_pattern[i].texFunc = gl.GL_MODULATE - - -# Create a texture from a gdk_pixbuf. -# Returns NULL if it cannot be created. -def create_pattern_from_pixbuf (pixbuf): - gl.glPixelStorei (gl.GL_UNPACK_ALIGNMENT, 1) - texName = gl.glGenTextures(1) - #debug('texName',texName) - - gl.glBindTexture (gl.GL_TEXTURE_2D, texName) - gl.glTexParameteri (gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_S, gl.GL_CLAMP) - gl.glTexParameteri (gl.GL_TEXTURE_2D, gl.GL_TEXTURE_WRAP_T, gl.GL_CLAMP) - gl.glTexParameteri (gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_NEAREST) - gl.glTexParameteri (gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER, gl.GL_NEAREST) - - #int width - #int height - #guchar * pixels - - #gboolean has_alpha - #int channels - - #GLenum format - #GdkColorspace colourSpace - - #domain = g_quark_from_string ("rubik_texture") - - width = pixbuf.get_width () - height = pixbuf.get_height () - colourSpace = pixbuf.get_colorspace () - - - channels = pixbuf.get_n_channels () - has_alpha = pixbuf.get_has_alpha () - - # This seems to cover all the cases that gdk_pixbuf - # supports at the moment - if colourSpace == gdk.COLORSPACE_RGB: - if channels == 4 and has_alpha: - format_ = gl.GL_RGBA - elif channels == 3 and not has_alpha: - format_ = gl.GL_RGB - else: - raise Exception(_("Pixbuf has wrong number of channels")) - #return 0 - else: - raise Exception(_("Pixbuf has unknown color space: {0}").format(colourSpace)) - #return 0 +import os +from glob import glob - pixels = pixbuf.get_pixels () +# pylint: disable=W0614,W0401 +from PySide.QtCore import Qt +from PySide.QtGui import * +# pylint: enable=W0614,W0401 - gl.glTexImage2D (gl.GL_TEXTURE_2D, 0, 3, width, height, 0, - format_, gl.GL_UNSIGNED_BYTE, pixels) +from . import config - return texName - -def create_pixbuf_from_file(filename): - unscaled_pixbuf = gdk.pixbuf_new_from_file(filename) - - # We must scale the image, because Mesa/OpenGL insists on it being of size - # 2^n ( where n is integer ) - pixbuf = unscaled_pixbuf.scale_simple(SWATCH_WIDTH, SWATCH_HEIGHT, gdk.INTERP_NEAREST) - return pixbuf +class Textures (object): + max_size = 256 + stock_dir = os.path.join(config.UI_DIR, 'images') + def __init__(self): + self.stock_files = sorted(os.path.basename(f) for f in glob(os.path.join(self.stock_dir, '*'))) + self.stock_pixbuf = {None:None} + + def get_stock_pixbuf(self, name): + try: + return self.stock_pixbuf[name] + except KeyError: + if name not in self.stock_files: + return None + filename = os.path.join(self.stock_dir, name) + self.stock_pixbuf[name] = pixbuf = self.create_pixbuf_from_file(filename) + return pixbuf + + @classmethod + def create_pixbuf_from_file(cls, filename): + image = QImage(filename) + # We must scale the image, because Mesa/OpenGL insists on it being of size + # 2^n ( where n is integer ) + width = image.width() + height = image.height() + scaled_width = cls.max_size + while scaled_width > width: + scaled_width //= 2 + scaled_height = cls.max_size + while scaled_height > height: + scaled_height //= 2 + return image.scaled(scaled_width, scaled_height, + transformMode=Qt.TransformationMode.SmoothTransformation) + +textures = Textures() diff -Nru pybik-0.5/setup.py pybik-1.0.1/setup.py --- pybik-0.5/setup.py 2012-01-06 16:31:51.000000000 +0000 +++ pybik-1.0.1/setup.py 2013-02-01 20:19:31.000000000 +0000 @@ -1,7 +1,7 @@ #!/usr/bin/python # -*- coding: utf-8 -*- -# Copyright © 2009, 2011-2012 B. Clausius +# Copyright © 2009, 2011-2013 B. Clausius # # 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 @@ -16,6 +16,9 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +# pylint: disable=W0201 +from __future__ import print_function, division + from glob import glob import os import sys @@ -27,27 +30,450 @@ import distutils.cmd from distutils.extension import Extension -from distutils.errors import DistutilsOptionError - from distutils.dir_util import remove_tree -from distutils.log import warn, info, error, fatal, debug +from distutils.file_util import move_file +from distutils.dep_util import newer, newer_group +from distutils.log import warn, info, error, debug + +import distutils.dist import distutils.command.build import distutils.command.build_ext +import distutils.command.build_scripts import distutils.command.install import distutils.command.install_data +import distutils.command.install_lib import distutils.command.clean +import distutils.command.sdist -#from Pyrex.Distutils.extension import Extension -#from Pyrex.Distutils import build_ext #from Cython.Distutils import build_ext from pybiklib import config -############ This code is taken from python-distutils-extra -class build_i18n(distutils.cmd.Command): +def po_isempty(pofilename): + try: + import polib + except ImportError: + print('polib not found, assuming the file %s contains translations' % pofilename) + return False + for entry in polib.pofile(pofilename): + if entry.translated() and entry.msgid != entry.msgstr: + return False + return True + + +class Distribution (distutils.dist.Distribution): + def __init__(self, attrs=None): + self.bug_contact = None + self.qt_ui_files = None + distutils.dist.Distribution.__init__(self, attrs=attrs) + +class build(distutils.command.build.build): + """Adds extra commands to the build target.""" + user_options = distutils.command.build.build.user_options + [ + ('inplace', 'i', 'ignore build-lib and put compiled modules into the source directory'), + ('use-generated-code', None, 'Use generated Code included in distributed source' + ' to avoid build-dependencies'), + ('parallel=', None, 'Build in parallel with the given number of processes or "auto"'), + ('arch-only', None, 'Build only architecture dependent files'), + ('indep-only', None, 'Build only architecture independent files'), + ('pyside', None, 'Use PySide to compile ui files (default)'), + ('pyqt4', None, 'Use PyQt4 to compile ui files'), + ] + boolean_options = distutils.command.build.build.boolean_options + [ + 'inplace', 'use-generated-code', 'arch-only', 'indep-only', + 'pyside', 'pyqt4', + ] + negative_opt = {'pyqt4' : 'pyside'} + + def has_pure_modules(self): + return self.indep_only and not self.inplace and distutils.command.build.build.has_pure_modules(self) + + _commands_dict = dict(distutils.command.build.build.sub_commands) + # pylint: disable=W0212 + sub_commands = [('build_py', has_pure_modules), + ('build_ext', lambda self: self.arch_only and self._commands_dict['build_ext'](self)), + ('build_scripts', lambda self: self.indep_only and self._commands_dict['build_scripts'](self)), + ('build_ui', lambda self: self.indep_only), + ('build_models', lambda self: self.indep_only), + ('build_i18n', lambda self: self.indep_only), + ('build_man', lambda self: self.indep_only and not self.inplace), + ] + # pylint: enable=W0212 + + def initialize_options(self): + distutils.command.build.build.initialize_options(self) + self.inplace = 0 + self.use_generated_code = False + self.parallel = None + self.arch_only = False + self.indep_only = False + self.pyside = True + + def finalize_options(self): + distutils.command.build.build.finalize_options(self) + if not self.arch_only and not self.indep_only: + self.arch_only = self.indep_only = True + + +class build_csrc (distutils.command.build_ext.build_ext): + user_options = distutils.command.build_ext.build_ext.user_options + [ + ('cython-opts=', None, 'Cython options'), + ('use-generated-code', None, 'Use generated Code included in distributed source' + ' to avoid build-dependencies'), + ] + boolean_options = distutils.command.build_ext.build_ext.boolean_options + [ + 'use-generated-code' + ] + + def initialize_options(self): + distutils.command.build_ext.build_ext.initialize_options(self) + self.inplace = None + self.cython_opts = '' + self.use_generated_code = None + + def finalize_options(self): + distutils.command.build_ext.build_ext.finalize_options(self) + self.set_undefined_options('build', + ('inplace', 'inplace'), + ('use_generated_code', 'use_generated_code'), + ) + self.cython_opts = self.cython_opts.split() + self.cython_opts.insert(0, 'cython') + + def compare_file(self, filename1, filename2): + if self.force or not os.path.exists(filename2): + return False + with open(filename1) as file1, open(filename2) as file2: + return file1.read() == file2.read() + + @staticmethod + def run_py2pyx(py_file, pyx_file, pxd_file): + info('py2pyx: %s --> %s, %s' % (py_file, pyx_file, pxd_file)) + from tools.py2pyx import create_pyx, Py2pyxParseError + try: + create_pyx(py_file, pyx_file, pxd_file) + except Py2pyxParseError as e: + error("error: %s", e) + sys.exit(1) + + def run_cython(self, infile, outfile): + info('cython: %s --> %s' % (infile, outfile)) + self.spawn(self.cython_opts + ['-o', outfile, infile]) + + def build_pyx(self, py_file): + base = os.path.join(self.build_temp, os.path.splitext(py_file)[0]) + basename = os.path.basename(base) + dirname = os.path.dirname(base) + pyx_file = os.path.join(dirname, '_%s.pyx' % basename) + pxd_file = os.path.join(dirname, '_%s.pxd' % basename) + if self.use_generated_code: + return pyx_file, pxd_file + pxd_file_tmp = pxd_file + '.tmp' + self.mkpath(os.path.dirname(pyx_file)) + self.make_file([py_file], pyx_file, self.run_py2pyx, (py_file, pyx_file, pxd_file_tmp)) + if os.path.exists(pxd_file_tmp): + if self.compare_file(pxd_file_tmp, pxd_file): + os.remove(pxd_file_tmp) + info("unchanged file '%s'", pxd_file) + else: + if os.path.exists(pxd_file): + os.remove(pxd_file) + move_file(pxd_file_tmp, pxd_file) + return pyx_file, pxd_file + + def build_extension(self, extension): + sources = extension.sources + ext_path = self.get_ext_fullpath(extension.name) + depends = sources + extension.depends + if self.force or newer_group(depends, ext_path, 'newer'): + info("building C-Code for '%s' extension", extension.name) + else: + debug("skipping '%s' extension (up-to-date)", extension.name) + return + + # generate pxd- and pyx-files from py-files with #px annotations + pyx_files = [] + pyx_files_dep = [] + for in_file in depends: + base, ext = os.path.splitext(in_file) + if ext == '.py': + pyx_file, pxd_file = self.build_pyx(in_file) + if in_file in extension.sources: + pyx_files.append(pyx_file) + pyx_files_dep.append(pxd_file) + elif ext in ('.pxi','.pxd'): + out_file = os.path.join(self.build_temp, in_file) + if not self.use_generated_code: + self.mkpath(os.path.dirname(out_file)) + self.copy_file(in_file, out_file) + pyx_files_dep.append(out_file) + else: + if in_file in extension.sources: + pyx_files.append(in_file) + else: + pyx_files_dep.append(in_file) + # generate C-files with cython + c_files = [] + for in_file in pyx_files: + base, ext = os.path.splitext(in_file) + if ext == '.pyx': + out_file = base + '.c' + if not self.use_generated_code: + self.make_file(pyx_files+pyx_files_dep, out_file, + self.run_cython, (in_file, out_file)) + c_files.append(out_file) + else: + c_files.append(in_file) + for c_file in c_files: + inplace_file = os.path.join('csrc', os.path.basename(c_file)) + if self.use_generated_code: + self.mkpath(os.path.dirname(c_file)) + self.copy_file(inplace_file, c_file) + elif self.inplace: + # copy C-files to the place where they are expected by the use_generated_code option + self.mkpath(os.path.dirname(inplace_file)) + self.copy_file(c_file, inplace_file) + # exclude Cython-files from dependencies + c_files_dep = [] + for in_file in pyx_files_dep: + base, ext = os.path.splitext(in_file) + if ext not in ('.pxi', '.pxd'): + c_files_dep.append(in_file) + extension.depends = c_files_dep + extension.sources = c_files + + +class build_ext (build_csrc): + def build_extension(self, extension): + # build C-code + build_csrc.build_extension(self, extension) + # build extension module from C-code + distutils.command.build_ext.build_ext.build_extension(self, extension) + #HACK: Due to build_csrc.compare_file the C compiler may not run, even though + # the dependencies expect this. Therefore update the timestamp manually. + ext_path = self.get_ext_fullpath(extension.name) + try: + os.utime(ext_path, None) + except OSError: + pass + + +class build_scripts (distutils.command.build_scripts.build_scripts): + user_options = distutils.command.build_scripts.build_scripts.user_options + [ + ('inplace', 'i', 'ignore build-lib and put compiled modules into the source directory'), + ('build-temp=', 't', "temporary build directory"), + ] + boolean_options = distutils.command.build.build.boolean_options + ['inplace'] + + def initialize_options(self): + distutils.command.build_scripts.build_scripts.initialize_options(self) + self.inplace = None + self.build_temp = None + + def finalize_options(self): + distutils.command.build_scripts.build_scripts.finalize_options(self) + self.set_undefined_options('build', + ('inplace', 'inplace'), + ('build_temp', 'build_temp'), + ) + + def run(self): + build_dir = self.build_dir + self.build_dir = self.build_temp + distutils.command.build_scripts.build_scripts.run(self) + self.build_dir = build_dir + for script in self.scripts: + outfile = os.path.basename(script) + script = os.path.join(self.build_temp, outfile) + script = os.path.join(self.build_temp, outfile) + if not os.path.exists(script): + continue + if not self.inplace: + self.mkpath(self.build_dir) + outfile = os.path.join(self.build_dir, outfile) + outfile, ext = os.path.splitext(outfile) + if ext != '.py': + outfile += ext + self.copy_file(script, outfile) + + +class build_ui(distutils.cmd.Command): + description = "Compile Qt user interfaces files (.ui) and resources to python modules." + + user_options = [ + ('indent=', 'I', 'set indent width to N spaces, tab if N is 0 (default: 4)'), + ('ui-execute', 'x', 'generate extra code to test and display the class'), + ('from-imports','F', 'generate imports relative to "."'), + ('build-lib=', 'b', 'directory for compiled UI modules'), + ('inplace', 'i', 'ignore build-lib and put compiled UI modules into the source ' + 'directory alongside your pure Python modules'), + ('force', 'f', 'forcibly build everything (ignore file timestamps)'), + ('use-generated-code', None, 'Use generated Code included in distributed source' + ' to avoid build-dependencies'), + ('pyside', None, 'Use PySide to compile ui files (default)'), + ('pyqt4', None, 'Use PyQt4 to compile ui files'), + ] + boolean_options = ['from-imports', 'ui-execute', 'inplace', 'force', 'use-generated-code', + 'pyside', 'pyqt4'] + negative_opt = {'pyqt4' : 'pyside'} + + def initialize_options(self): + self.qt_ui_files = None + self.indent = 4 + self.ui_execute = False + self.from_imports = False + self.build_lib = None + self.inplace = None + self.force = None + self.use_generated_code = None + self.pyside = None + + def finalize_options(self): + self.qt_ui_files = self.distribution.qt_ui_files + self.set_undefined_options('build', + ('build_lib', 'build_lib'), + ('inplace', 'inplace'), + ('force', 'force'), + ('use_generated_code', 'use_generated_code'), + ('pyside', 'pyside'), + ) + + def run(self): + for package_dir, ui_files in self.qt_ui_files: + if self.use_generated_code: + if not self.inplace: + self.copy_tree(package_dir, os.path.join(self.build_lib, package_dir)) + else: + if not self.inplace: + package_dir = os.path.join(self.build_lib, package_dir) + self.mkpath(package_dir) + init_file = os.path.join(package_dir, '__init__.py') + if self.force and os.path.exists(init_file): + os.remove(init_file) + if not os.path.exists(init_file): + self.execute(lambda: open(init_file, 'w').close(), [], 'generating '+init_file) + for ui_file in ui_files: + filebase = os.path.splitext(os.path.basename(ui_file))[0] + py_file = os.path.join(package_dir, filebase + '.py') + self.make_file(ui_file, py_file, self.compile_ui, [ui_file, py_file]) + + def compile_ui(self, ui_file, py_file): + self._wrapuic(self.pyside) + with open(ui_file, 'r') as fi, open(py_file, 'wt') as fo: + try: + self.compileUi(fi, fo, execute=self.ui_execute, indent=self.indent, + from_imports=self.from_imports) + except Exception, err: + warn("Failed %s: %r", ui_file, err) + sys.exit(1) + if not self.pyside: + with open(py_file, 'rt') as f: + lines = f.readlines() + with open(py_file, 'wt') as f: + skiplines = False + for line in lines: + if skiplines: + if line.startswith('class'): + skiplines = False + f.write('\n') + else: + continue + if line.startswith('from PyQt4'): + line = line.replace('PyQt4', 'PySide') + skiplines = True + line = re.sub(r'\b_fromUtf8\(("[^"]*")\)', r'\1', line) + line = re.sub(r'\bsetMargin\(0\)', r'setContentsMargins(0, 0, 0, 0)', line) + f.write(line) + + _wrappeduic = False + def _wrapuic(self, pyside): + """Wrap uic to use gettext's _() in place of tr()""" + if self._wrappeduic: + return + + if pyside: + try: + from pysideuic import compileUi + from pysideuic.Compiler import qtproxies + except ImportError: + self.warn("You need to have pyside-tools installed in order to compile .ui files.") + sys.exit(1) + else: + try: + from PyQt4.uic import compileUi + from PyQt4.uic.Compiler import qtproxies, compiler, indenter + except ImportError: + self.warn("You need to have PyQt4 installed in order to compile .ui files.") + sys.exit(1) + self.compileUi = compileUi + + class _i18n_string(qtproxies.i18n_string): # pylint: disable=R0903 + """Provide a translated text.""" + def __str__(self): + return '_(%s)' % repr(self.string) + qtproxies.i18n_string = _i18n_string + + self.__class__._wrappeduic = True + + +class build_models(distutils.cmd.Command): + description = "Create data for Pybik models and write it to python modules." + + user_options = [ + ('inplace', 'i', 'ignore build-lib and put compiled UI modules into the source ' + 'directory alongside your pure Python modules'), + ('force', 'f', 'forcibly build everything (ignore file timestamps)'), + ('parallel=', None,'Build in parallel with the given number of processes or "auto"'), + ] + boolean_options = ['inplace', 'force'] + + def initialize_options(self): + self.build_base = None + self.inplace = None + self.force = None + self.parallel = None + + def finalize_options(self): + self.set_undefined_options('build', + ('build_base', 'build_base'), + ('inplace', 'inplace'), + ('force', 'force'), + ('parallel', 'parallel'), + ) + if self.parallel is None: + self.parallel = 1 + elif self.parallel == 'auto': + import multiprocessing + self.parallel = multiprocessing.cpu_count() + else: + self.parallel = int(self.parallel) + + def run(self): + from tools import modeldata + modeldir = os.path.join('data' if self.inplace else self.build_base, 'models') + self.mkpath(modeldir) + if self.force and not self.dry_run: + for filename in os.listdir(modeldir): + filename = os.path.join(modeldir, filename) + os.remove(filename) + def create_modeldata(directory, testfunc): + modeldata.create_modeldata(directory, testfunc, self.parallel) + if self.force: + testfunc = None + else: + testfunc = lambda filename: newer('pybiklib/model.py', filename) + message = 'generating model data using {} processes'.format(self.parallel) + self.execute(create_modeldata, [modeldir, testfunc], msg=message) + data_files = self.distribution.data_files + for filename in os.listdir(modeldir): + sourcepath = os.path.join(modeldir, filename) + data_files.append(('share/pybik/models', (sourcepath,))) + + +class build_i18n(distutils.cmd.Command): description = "integrate the gettext framework" user_options = [ @@ -58,11 +484,16 @@ ('domain=', 'd', 'gettext domain'), ('merge-po', 'm', 'merge po files against template'), ('po-dir=', 'p', 'directory that holds the i18n files'), - ('bug-contact=', None, 'contact address for msgid bugs')] + ('bug-contact=', None, 'contact address for msgid bugs'), + ('inplace', 'i', 'ignore build-lib and put compiled UI modules into the source ' + 'directory alongside your pure Python modules'), + ('force', 'f', 'forcibly build everything (ignore file timestamps)'), + ] - boolean_options = ['merge-po'] + boolean_options = ['merge-po', 'inplace', 'force'] def initialize_options(self): + self.build_base = None self.desktop_files = [] self.xml_files = [] self.key_files = [] @@ -71,290 +502,376 @@ self.merge_po = False self.bug_contact = None self.po_dir = None + self.inplace = None + self.force = None def finalize_options(self): + self.set_undefined_options('build', ('build_base', 'build_base'), + ('inplace', 'inplace'), + ('force', 'force'), + ) + if self.inplace: + self.mo_dir = 'data/locale' + else: + self.mo_dir = os.path.join(self.build_base, 'mo') if self.domain is None: self.domain = self.distribution.metadata.name if self.po_dir is None: self.po_dir = "po" + if self.bug_contact is None: + self.bug_contact = self.distribution.bug_contact - def run(self): - """ - Update the language files, generate mo files and add them - to the to be installed files - """ - data_files = self.distribution.data_files + def do_merge_po(self): + '''Update po(t) files and print a report''' - if self.bug_contact is not None: - os.environ["XGETTEXT_ARGS"] = "--msgid-bugs-address=%s " % \ - self.bug_contact - - # Print a warning if there is a Makefile that would overwrite our - # values - if os.path.exists("%s/Makefile" % self.po_dir): - self.announce(""" -WARNING: Intltool will use the values specified from the - existing po/Makefile in favor of the vaules - from setup.cfg. - Remove the Makefile to avoid problems.""") - - # Update po(t) files and print a report + from tools.conv_plugin_for_translation import convert # We have to change the working dir to the po dir for intltool - cmd = ["intltool-update", (self.merge_po and "-r" or "-p"), "-g", self.domain] wd = os.getcwd() + temp_files = [] try: - for target, files in data_files: - for f in files: - if f.endswith('.script'): - self.spawn(['tools/conv-plugin-for-translation.py', f]) + for unused_target, files in self.distribution.data_files: + for in_file in files: + if in_file.endswith('.algorithm'): + out_file = in_file + '.py' + self.make_file(in_file, out_file, convert, [in_file, out_file]) + temp_files.append(out_file) os.chdir(self.po_dir) - self.spawn(cmd) + self.spawn(["intltool-update", "-r", "-g", self.domain]) finally: os.chdir(wd) - for target, files in data_files: - for f in files: - if f.endswith('.script') and os.path.isfile(f+'.py'): - os.remove(f+'.py') - + for temp_file in temp_files: + os.remove(temp_file) + + def run(self): + """Update the language files, generate mo files and add them to the to be installed files""" + + if self.bug_contact is not None: + os.environ["XGETTEXT_ARGS"] = "--msgid-bugs-address=%s " % self.bug_contact + + # Print a warning if there is a Makefile that would overwrite our values + if os.path.exists("%s/Makefile" % self.po_dir): + self.announce('' + 'WARNING: Intltool will use the values specified from the' + ' existing po/Makefile in favor of the vaules' + ' from setup.cfg.' + ' Remove the Makefile to avoid problems.') + + if self.merge_po: + self.do_merge_po() + + data_files = self.distribution.data_files for po_file in glob("%s/*.po" % self.po_dir): - lang = os.path.basename(po_file[:-3]) - mo_dir = os.path.join("build", "mo", lang, "LC_MESSAGES") + if po_isempty(po_file): + print('skipping empty po file', po_file) + continue + lang = os.path.splitext(os.path.basename(po_file))[0] + mo_dir = os.path.join(self.mo_dir, lang, "LC_MESSAGES") mo_file = os.path.join(mo_dir, "%s.mo" % self.domain) - if not os.path.exists(mo_dir): - os.makedirs(mo_dir) - cmd = ["msgfmt", po_file, "-o", mo_file] - self.spawn(cmd) + self.mkpath(mo_dir) + def msgfmt(po_file, mo_file): + self.spawn(["msgfmt", po_file, "-o", mo_file]) + self.make_file([po_file], mo_file, msgfmt, [po_file, mo_file]) targetpath = os.path.join("share/locale", lang, "LC_MESSAGES") data_files.append((targetpath, (mo_file,))) - # create translated manpage - man_dir = os.path.join('build','man',lang) - man_file = os.path.join(man_dir,'pybik.6') - if not os.path.exists(man_dir): - os.makedirs(man_dir) - self.spawn(['./tools/create_manpage.py', man_file, 'build/mo', lang]) - import subprocess - result = subprocess.call(['cmp', '--silent', man_file, os.path.join('build','man','pybik.6')]) - if result: - # only install translated manpages - data_files.append(('share/man/'+lang+'/man6', [man_file])) - # merge .in with translation - for (option, switch) in ((self.xml_files, "-x"), + if not self.desktop_files: + for targetpath, files in data_files: + for f in files: + if f.endswith('.desktop'): + self.desktop_files.append(f) + for (files, switch) in ((self.xml_files, "-x"), (self.desktop_files, "-d"), (self.schemas_files, "-s"), (self.key_files, "-k"),): - try: - file_set = eval(option) - except: - continue - for (target, files) in file_set: - build_target = os.path.join("build", target) - if not os.path.exists(build_target): - os.makedirs(build_target) - files_merged = [] - for f in files: - if f.endswith(".in"): - file_merged = os.path.basename(f[:-3]) - else: - file_merged = os.path.basename(f) - file_merged = os.path.join(build_target, file_merged) - cmd = ["intltool-merge", switch, self.po_dir, f, - file_merged] - self.spawn(cmd) - files_merged.append(file_merged) - data_files.append((target, files_merged)) - -##################### - -def py2pyx(infile, outfile): - info('py2pyx: %s --> %s' % (infile, outfile)) - os.system('python tools/py2pyx.py %s %s' % (infile, outfile)) -def py2pxd(infile, outfile): - info('py2pxd: %s --> %s' % (infile, outfile)) - os.system('tools/py2pxd.py %s %s' % (infile, outfile)) -def pyrex(self, infile, outfile): - info('pyrex: %s --> %s' % (infile, outfile)) - self.spawn(["pyrexc", infile]) -def cython(self, infile, outfile): - info('cython: %s --> %s' % (infile, outfile)) - self.spawn(["cython", '-o', outfile, infile]) + for f in files: + if f.endswith(".in"): + self.warn("aDon't know, what to do with this file: " + f) + continue + srcfile = f + '.in' + if not os.path.isfile(srcfile): + self.warn("sDon't know, what to do with this file: " + f) + continue + dstfile = f + def intltool_merge(switch, src, dst): + self.spawn(["intltool-merge", switch, self.po_dir, src, dst]) + self.make_file(glob('%s/*.po'%self.po_dir)+[srcfile], dstfile, + intltool_merge, [switch, srcfile, dstfile]) + +class build_man (distutils.cmd.Command): + description = "build the manpage" + user_options = [ + ('force', 'f', 'forcibly build everything (ignore file timestamps)'), + ] -class build_ext (distutils.command.build_ext.build_ext): - user_options = distutils.command.build_ext.build_ext.user_options + [ - ('cython',None,'Use Cython to compile pyx-files'), - ('pyrex',None,'Use pyrex to compile pyx-files')] - def __init__(self, *args): - self.cython = None - self.pyrex = None - distutils.command.build_ext.build_ext.__init__(self, *args) + def initialize_options(self): + self.force = None + self.build_base = None + self.build_dir = None def finalize_options(self): - distutils.command.build_ext.build_ext.finalize_options(self) - if self.cython is None: - if self.pyrex is None: - # Default Value - self.cython = True - else: - self.cython = not self.pyrex - else: - if self.pyrex is None: - self.cython = bool(self.cython) - else: - raise DistutilsOptionError('Option pyrex and cython conflicts') - del self.pyrex + self.set_undefined_options('build', ('build_base', 'build_base'), + ('force', 'force'), + ) + self.set_undefined_options('build_scripts', ('build_dir', 'build_dir')) - def swig_sources(self, sources, extension): - in_files = sources + extension.depends - pyx_files = [] - pyx_files_dep = [] - for in_file in in_files: - out_files = pyx_files if in_file in sources else pyx_files_dep - if in_file.endswith('.py'): - out_file = os.path.join(self.build_temp, in_file[:-3]+'_c.py') - out_file2 = os.path.join(self.build_temp, in_file[:-3]+'_c.pxd') - self.mkpath(os.path.dirname(out_file)) - self.make_file(in_files, out_file, py2pyx, (in_file, out_file)) - self.make_file(in_files, out_file2, py2pxd, (in_file, out_file2)) - pyx_files_dep.append(out_file2) - elif in_file.endswith(('.pxi','.pxd')): - out_file = os.path.join(self.build_temp, in_file) - self.mkpath(os.path.dirname(out_file)) - self.copy_file(in_file, out_file) - else: - out_file = in_file - out_files.append(out_file) - out_files = [] - for in_file in pyx_files: - if in_file.endswith('.py'): - out_file = in_file[:-3]+'.c' - self.make_file(pyx_files+pyx_files_dep, out_file, - cython if self.cython else pyrex, (self, in_file, out_file)) - out_files.append(out_file) - else: - out_files.append(in_file) - return distutils.command.build_ext.build_ext.swig_sources(self, out_files, extension) - - -class build_man (distutils.cmd.Command): - description = "build the manpage" - user_options = [] def run(self): + def create_manpage(script_file, section, man_file): + os.environ['PYTHONPATH'] = '.' + self.spawn(['help2man', '--name', config.SHORT_DESCRIPTION, '--section', section, + '--output', man_file, '--no-info', script_file]) + data_files = self.distribution.data_files - man_dir = os.path.join('build', 'man') - man_file = os.path.join(man_dir, 'pybik.6') - if not os.path.exists(man_dir): - os.makedirs(man_dir) - self.spawn(['./tools/create_manpage.py', man_file]) - data_files.append(('share/man/man6', [man_file])) - def initialize_options(self): pass - def finalize_options(self): pass + man_dir = os.path.join(self.build_base, 'man') + self.mkpath(man_dir) + if '.' not in sys.path: + sys.path.insert(0, '.') + section = '6' + for script in os.listdir(self.build_dir): + script_file = os.path.join(self.build_dir, script) + man_file = os.path.join(man_dir, '.'.join((script, section))) + self.make_file(['pybiklib/config.py', script_file], man_file, + create_manpage, [script_file, section, man_file]) + data_files.append(('share/man/man'+section, [man_file])) + + +class install_lib (distutils.command.install_lib.install_lib): + user_options = distutils.command.install_lib.install_lib.user_options + [ + ('arch-only', None, 'Install only architecture dependent files'), + ('indep-only', None, 'Install only architecture independent files'), + ] + boolean_options = ['arch-only', 'indep-only'] + + def initialize_options(self): + distutils.command.install_lib.install_lib.initialize_options(self) + self.data_dir = None + self.arch_only = None + self.indep_only = None -class build(distutils.command.build.build): - """Adds extra commands to the build target.""" def finalize_options(self): - distutils.command.build.build.finalize_options(self) - self.sub_commands.append(("build_man", lambda cmd: True)) - self.sub_commands.append(("build_i18n", lambda cmd: True)) + distutils.command.install_lib.install_lib.finalize_options(self) + self.set_undefined_options('install', + ('arch_only', 'arch_only'), + ('indep_only', 'indep_only'), + ) + if not self.arch_only and not self.indep_only: + self.arch_only = self.indep_only = True + + def build(self): + if not self.skip_build: + if self.distribution.has_pure_modules() and self.indep_only: + self.run_command('build_py') + if self.distribution.has_ext_modules() and self.arch_only: + self.run_command('build_ext') + + +class install (distutils.command.install.install): + user_options = distutils.command.install.install.user_options + [ + ('data-dir=', 't', 'Directory where the application will find the data'), + ('arch-only', None, 'Install only architecture dependent files'), + ('indep-only', None, 'Install only architecture independent files'), + ] + boolean_options = ['arch-only', 'indep-only'] + def initialize_options(self): + distutils.command.install.install.initialize_options(self) + self.data_dir = None + self.arch_only = False + self.indep_only = False -class install (distutils.command.install.install): + def finalize_options(self): + distutils.command.install.install.finalize_options(self) + if self.data_dir is None: + self.data_dir = os.path.join(self.install_data, 'share') + if not self.arch_only and not self.indep_only: + self.arch_only = self.indep_only = True + if not self.indep_only: + self.__class__.sub_commands = [(cmd, func) + for cmd, func in distutils.command.install.install.sub_commands + if cmd == 'install_lib'] + def run(self): - filename = os.path.join(os.path.dirname(__file__), 'pybiklib', 'config.py') - tmpfile = filename + '.orig' - if self.install_layout == 'deb': - datadir = os.path.join(self.prefix, 'share') - else: - datadir = os.path.join(self.install_data, 'share') - appdatadir = os.path.join(datadir, 'pybik') - os.rename(filename, tmpfile) - try: - try: - with open(tmpfile, 'r') as file_in, open(filename, 'w') as file_out: - for line in file_in: - line = re.sub(r'^(data_dir\s*=\s*).*$', - r'\1' + repr(datadir), - line) - line = re.sub(r'^(appdata_dir\s*=\s*).*$', - r'\1' + repr(appdatadir), - line) - file_out.write(line) - file_out.flush() - except (OSError, IOError) as e: - print e - sys.exit(1) - distutils.command.install.install.run(self) - finally: - os.rename(tmpfile, filename) + if not self.skip_build: + # distutils.command.install.install.run() will run build, but we need + # to modify a file between build and install + build_cmd = self.distribution.get_command_obj('build') + build_cmd.arch_only = self.arch_only + build_cmd.indep_only = self.indep_only + self.run_command('build') + self.skip_build = True + filename = os.path.join(self.build_lib, 'pybiklib', 'config.py') + app_data_dir = os.path.join(self.data_dir, 'pybik') + if self.indep_only: + with open(filename, 'r') as f: + text = f.read() + for pattern, repl in [ + (r'^(data_dir\s*=\s*).*$', r'\1' + repr(self.data_dir)), + (r'^(appdata_dir\s*=\s*).*$', r'\1' + repr(app_data_dir)),]: + text = re.sub(pattern, repl, text, count=1, flags=re.MULTILINE) + with open(filename, 'w') as f: + f.write(text) + distutils.command.install.install.run(self) + if self.record: + self.warn('The --record option is broken, files from the build_ui command are not recorded.') + + class clean (distutils.command.clean.clean): + user_options = distutils.command.clean.clean.user_options + [ + ('inplace', 'i', 'Remove compiled modules in the source directory'), + ('generated-code', None, 'Remove generated code included in distributed source'), + ('really-all', 'r', 'Remove really all generated code'), + ] + boolean_options = distutils.command.clean.clean.boolean_options + [ + 'inplace', 'generated-code', 'really-all' + ] + + def initialize_options(self): + distutils.command.clean.clean.initialize_options(self) + self.inplace = None + self.generated_code = False + self.really_all = False + + def finalize_options(self): + distutils.command.clean.clean.finalize_options(self) + self.set_undefined_options('build', + ('inplace', 'inplace'), + ) + if self.really_all: + self.all = True + self.inplace = True + self.generated_code = True + def run(self): if self.all: - for _dir in ['mo', 'man']: - _dir = os.path.join('build', _dir) + for _dir in ['mo', 'man', 'models']: + _dir = os.path.join(self.build_base, _dir) if os.path.exists(_dir): remove_tree(_dir, dry_run=self.dry_run, verbose=self.verbose) else: - debug("'%s' does not exist -- can't clean it", _dir) - _file = 'po/pybik.pot' - if os.path.exists(_file): - if self.verbose >= 1: - info("removing '%s'", _file) + warn("'%s' does not exist -- can't clean it", _dir) + distutils.command.clean.clean.run(self) + if self.inplace: + for dirname in ('pybiklib/', 'pybiklib/ui/', 'data/plugins/'): + for pat in ('*.pyc', '*.so'): + for filename in glob(dirname+pat): + info('removing %r', filename) + if not self.dry_run: + os.remove(filename) + if self.generated_code: + for dirname in ('pybiklib/ui', 'csrc', 'data/locale'): + if os.path.exists(dirname): + remove_tree(dirname, dry_run=self.dry_run, verbose=self.verbose) + else: + warn("'%s' does not exist -- can't clean it", dirname) + filename = 'pybik' + if os.path.exists(filename): + info('removing %r', filename) if not self.dry_run: - os.remove(_file) + os.remove(filename) else: - debug("'%s' does not exist -- can't clean it", _file) - distutils.command.clean.clean.run(self) + warn("'%s' does not exist -- can't clean it", filename) + + +class sdist(distutils.command.sdist.sdist): + user_options = distutils.command.sdist.sdist.user_options + [ + ('debian-names', None, 'Create archive files with Debian names'), + ] + boolean_options = distutils.command.sdist.sdist.boolean_options + [ + 'debian-names' + ] + + def initialize_options(self): + distutils.command.sdist.sdist.initialize_options(self) + self.debian_names = False + + def run(self): + from tools import create_docs + copyright = create_docs.read_utf8('debian/copyright') # pylint: disable=W0622 + copyright = copyright.replace( + ' The full text of the GPL is distributed in\n' + ' /usr/share/common-licenses/GPL-3 on Debian systems.', + ' The full text of the GPL is distributed in\n' + ' the original source archive in the file COPYING.') + create_docs.write_utf8('copyright', copyright) + create_docs.create_README() + + distutils.command.sdist.sdist.run(self) + for archive_file in self.archive_files: + if self.debian_names: + debian_file = archive_file.replace('-', '_', 1).replace('.tar', '.orig.tar', 1) + os.rename(archive_file, debian_file) + + def get_file_list(self): + self.filelist.append('copyright') + for f in glob('po/*.po'): + if po_isempty(f): + print('skipping empty po file', f) + else: + self.filelist.files.append(f) + distutils.command.sdist.sdist.get_file_list(self) -setup( name=config.PACKAGE, +setup( + # Metadata + name=config.PACKAGE, version=config.VERSION, - description='Pybik - the magic cube', - author=config.AUTHORS[0], - author_email=config.CONTACT, + description=config.SHORT_DESCRIPTION, + long_description=config.LONG_DESCRIPTION, + author=config.AUTHOR, + author_email=config.CONTACT_EMAIL, + bug_contact=config.CONTACT_FILEBUG, url=config.WEBSITE, license=config.LICENSE_NAME, - scripts=['pybik'], + + # Files + scripts=['pybiklib/pybik.py'], data_files=[ ('share/applications', ['data/applications/pybik.desktop']), ('share/pixmaps', ['data/pixmaps/pybik.png']), - ('share/pybik/ui', glob('data/ui/*')), - ('share/pybik/scripts', glob('data/scripts/*.py')), - ('share/pybik/scripts', glob('data/scripts/*.script')), + ('share/pybik/ui', glob('data/ui/*.png')), + ('share/pybik/ui/images', glob('data/ui/images/*')), + ('share/pybik/plugins', glob('data/plugins/*.py')), + ('share/pybik/plugins', glob('data/plugins/*.algorithm')), + ('share/pybik/', ['data/GPL-3']), ], + qt_ui_files=[('pybiklib/ui', glob('data/ui/*.ui'))], ext_modules=[ - Extension("pybiklib/drwBlock_c", - ["pybiklib/drwBlock.py"], - depends=["pybiklib/cube.py", - "pybiklib/math.pxd", - 'pybiklib/gl.pxd'], - libraries=['GL']), - Extension("pybiklib/cube_c", - ["pybiklib/cube.py"], - depends=["pybiklib/math.pxd", - 'pybiklib/gl.pxd'], - libraries=['GL']), - Extension("pybiklib/glarea_common_c", - ["pybiklib/glarea_common.py"], - depends=["pybiklib/math.pxd", - "pybiklib/glu.pxd", - 'pybiklib/gl.pxd'], + Extension('pybiklib/_gldraw', + ['pybiklib/gldraw.py'], + depends=['pybiklib/gl.pxd'], + libraries=['GL'], + define_macros=[('GL_GLEXT_PROTOTYPES', None)]), + Extension('pybiklib/_glarea', + ["pybiklib/glarea.py"], + depends=['pybiklib/gl.pxd', + 'pybiklib/glu.pxd', + 'pybiklib/gldraw.py'], libraries=['GL', 'GLU']), ], packages=['pybiklib'], package_dir={'pybiklib': 'pybiklib',}, + + # setup classes + distclass=Distribution, cmdclass={ + 'build': build, + 'build_csrc': build_csrc, 'build_ext': build_ext, + 'build_scripts': build_scripts, + 'build_ui': build_ui, + 'build_models': build_models, 'build_i18n': build_i18n, 'build_man': build_man, - 'build': build, 'install_data': distutils.command.install_data.install_data, + 'install_lib': install_lib, 'install': install, 'clean': clean, + 'sdist': sdist, }, ) diff -Nru pybik-0.5/test/test_gui.py pybik-1.0.1/test/test_gui.py --- pybik-0.5/test/test_gui.py 2011-06-28 06:20:26.000000000 +0000 +++ pybik-1.0.1/test/test_gui.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,308 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright © 2009, 2011 B. Clausius -# -# 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 . - -import sys, os - -from ldtp import * -from ldtputils import * -from ooldtp import * - -from nose.plugins.skip import SkipTest - -sys.path.insert(0, os.path.dirname(__file__)+'/..') -from pybiklib.confstore import confstore - -os.environ['GUI_TIMEOUT'] = '2' -os.environ['LANG'] = '' - -BUTTON_ANIMSPEED_RESET = 'btnClearAnimspeed' -BUTTON_COLOR_RESET = 'btnClearFaceColor' -BUTTON_IMAGE_RESET = 'btnClearImageFile' -BUTTON_LIGHTING = 'btnLighting' -BUTTON_LIGHTING_RESET = 'btnClearLighting' -BUTTON_PATTERN_RESET = 'btnClearPattern' -BUTTON_SIZE = 'sbtnSpinButtonSize' -BUTTON_SIZE_RESET = 'btnClearSize' -DIALOG_EDIT_COLORS = 'dlgColorselector' -DIALOG_PREFERENCES = 'dlgPreferences' -ENTRY_FORMULA = 'txtEntryFormula' -HSCALE_ANIMSPEED = '???AnimSpeed' -MENU_COLORS = 'mnuEdit;mnuColor' -MENU_EDIT = 'mnuEdit' -MENU_GAME = 'mnuGame' -MENU_HELP = 'mnuHelp' -MENU_INFO = 'mnuHelp;mnuAbout' -MENU_NEW_RANDOM = 'mnuGame;mnuNewrandom' -MENU_NEW_SOLVED = 'mnuGame;mnuNewsolved' -MENU_PLAY_TOOLBAR = 'mnuView;mnuPlayToolbar' -MENU_PREFERENCES = 'mnuEdit;mnuPreferences' -MENU_QUIT = 'mnuGame;mnuQuit' -MENU_STATUSBAR = 'mnuView;mnuStatusBar' -MENU_VIEW = 'mnuView' -RADIOBUTTON_MOSAIC = 'btnMosaic' -RADIOBUTTON_TILE = 'btnTiled' -STATUSBAR_MAIN = 'statStatusbarMain' -TOOLBAR_PLAY = 'tbarToolbarPlay' -TOOLBUTTON_ADD_MARK = 'btnAddmark' -TOOLBUTTON_FORWARD = 'btnForward' -TOOLBUTTON_NEXT = 'btnNext' -TOOLBUTTON_PLAY = 'btnPlay' -TOOLBUTTON_PREVIOUS = 'btnPrevious' -TOOLBUTTON_REMOVE_MARK = 'btnRemovemark' -TOOLBUTTON_REWIND = 'btnRewind' -TOOLBUTTON_STOP = 'btnStop' -TREEVIEW_SCRIPTS = 'ttblTreeviewScripts' -WINDOW_MAIN = 'Pybik' - -class AppPybik (component): - def __init__(self): - component.__init__(self, WINDOW_MAIN) - - @classmethod - def launch(cls, *args): - cmd = os.path.dirname(__file__) + '/../pybik' - if args: - launchapp(cmd, list(args)) - else: - launchapp(cmd) - pybik = cls() - assert pybik.waittillguiexist () - return pybik - - def quit(self): - self.selectmenuitem (MENU_QUIT) - return self.waittillguinotexist () - - def set_formula(self, formula, pos, status): - '''Sets formula text with cursor position and checks statusbar text''' - assert self.settextvalue (ENTRY_FORMULA, formula), formula - assert self.setcursorposition (ENTRY_FORMULA, pos), pos - assert self.activatetext (ENTRY_FORMULA) - text = self.getstatusbartext (STATUSBAR_MAIN) - assert text == status, (text, status) - return True - - def set_formula_pos(self, pos, status): - '''Sets cursor position in formula and checks statusbar text''' - assert self.setcursorposition (ENTRY_FORMULA, pos), pos - assert self.activatetext (ENTRY_FORMULA) - text = self.getstatusbartext (STATUSBAR_MAIN) - assert text == status, (text, status) - return True - -class DlgBase (component): - def __init__(self): - component.__init__(self, self.DIALOG) - - @classmethod - def open(cls): - dlg = cls() - assert dlg.waittillguiexist () - return dlg - - def close(self): - assert self.click ('btnClose') - return self.waittillguinotexist () - - def yes(self): - assert self.click ('btnYes') - return self.waittillguinotexist () - - def no(self): - assert self.click ('btnNo') - return self.waittillguinotexist () - - -class DlgQuestion (DlgBase): - DIALOG = "dlgQuestion" - - -class DlgPreferences (DlgBase): - DIALOG = DIALOG_PREFERENCES - - def close(self, confirm): - assert self.click ('btnClose') - if confirm: - dlgQuestion = DlgQuestion.open() - assert dlgQuestion.yes() - return self.waittillguinotexist () - - -class DlgEditColors (DlgBase): - DIALOG = DIALOG_EDIT_COLORS - - -def test_start_quit(): - '''Verify, that the app starts and some widgets exist''' - Pybik = AppPybik.launch() - assert Pybik.verifystatusbar (STATUSBAR_MAIN) - assert Pybik.quit() - - -def test_bars_hide_show(): - Pybik = AppPybik.launch() - - #TODO - #assert Pybik.verifystatusbarvisible(TOOLBAR_PLAY) - #assert Pybik.selectmenuitem(MENU_PLAY_TOOLBAR) - #assert not Pybik.verifystatusbarvisible(TOOLBAR_PLAY) - - assert Pybik.verifystatusbarvisible(STATUSBAR_MAIN) - assert Pybik.selectmenuitem(MENU_STATUSBAR) - assert not Pybik.verifystatusbarvisible(STATUSBAR_MAIN) - - assert Pybik.quit() - - -def test_set_pos(): - Pybik = AppPybik.launch() - - assert Pybik.set_formula('', 0, '0 / 0 moves') - assert Pybik.set_formula('ffb', 0, '0 / 3 moves') - assert Pybik.set_formula_pos(1, '1 / 3 moves') - assert Pybik.set_formula_pos(3, '3 / 3 moves') - assert Pybik.set_formula("llr'u2' b2", 0, '0 / 5 moves') - assert Pybik.set_formula_pos(1, '1 / 5 moves') - assert Pybik.set_formula_pos(2, '2 / 5 moves') - assert Pybik.set_formula_pos(3, '3 / 5 moves') - assert Pybik.set_formula_pos(4, '3 / 5 moves') - assert Pybik.set_formula_pos(5, '4 / 5 moves') - assert Pybik.set_formula_pos(6, '4 / 5 moves') - assert Pybik.set_formula_pos(7, '4 / 5 moves') - assert Pybik.set_formula_pos(8, '4 / 5 moves') - assert Pybik.set_formula_pos(9, '5 / 5 moves') - assert Pybik.set_formula_pos(10,'5 / 5 moves') - assert Pybik.set_formula_pos(5, '4 / 5 moves') - - assert Pybik.quit() - - assert confstore.saved_moves == "llr'u2' b2", repr(confstore.saved_moves) - assert confstore.saved_pos == 8, confstore.saved_pos - - -def test_set_dimension_from_config(): - raise SkipTest - confstore.dimension = 3 - confstore.saved_state = 'Cube 4 identity:' - confstore.saved_moves = '' - - Pybik = AppPybik.launch() - assert Pybik.selectmenuitem (MENU_NEW_SOLVED) - assert Pybik.quit() - - assert confstore.dimension == 3, confstore.dimension - assert confstore.saved_state == 'Cube 3 identity:', repr(confstore.saved_state) - assert confstore.saved_moves == '', repr(confstore.saved_moves) - -def test_set_dimension_cmd(): - '''Set dimension from commandline''' - confstore.dimension = 3 - confstore.saved_state = 'Cube 3 identity:' - confstore.saved_moves = '' - - Pybik = AppPybik.launch('--size=4') - assert Pybik.selectmenuitem (MENU_NEW_SOLVED) - assert Pybik.quit() - - assert confstore.dimension == 3, confstore.dimension - assert confstore.saved_state == 'Cube 3 identity:', repr(confstore.saved_state) - assert confstore.saved_moves == '', repr(confstore.saved_moves) - -def test_set_dimension_dlg(): - '''Set dimension with dialog''' - confstore.dimension = 3 - confstore.saved_state = 'Cube 3 identity:' - confstore.saved_moves = '' - - Pybik = AppPybik.launch() - assert Pybik.selectmenuitem (MENU_NEW_SOLVED) - - assert Pybik.selectmenuitem (MENU_PREFERENCES) - preferences = DlgPreferences.open() - assert preferences.verifysetvalue(BUTTON_SIZE, 3) - assert preferences.close(confirm=False) - - confstore.clear_cache() - assert confstore.dimension == 3, confstore.dimension - assert confstore.saved_state == 'Cube 3 identity:', repr(confstore.saved_state) - assert confstore.saved_moves == '', repr(confstore.saved_moves) - - assert Pybik.selectmenuitem (MENU_PREFERENCES) - preferences = DlgPreferences.open() - assert preferences.verifysetvalue(BUTTON_SIZE, 3) - assert preferences.setvalue(BUTTON_SIZE, 4) - assert preferences.verifysetvalue(BUTTON_SIZE, 4) - assert preferences.close(confirm=True) - - assert Pybik.quit() - - confstore.clear_cache() - assert confstore.dimension == 4, confstore.dimension - assert confstore.saved_state == 'Cube 4 identity:', repr(confstore.saved_state) - assert confstore.saved_moves == '', repr(confstore.saved_moves) - -def test_new_random(): - confstore.dimension = 3 - confstore.saved_state = 'Cube 3 identity:' - confstore.saved_moves = '' - - Pybik = AppPybik.launch('--debug=0') - assert Pybik.selectmenuitem (MENU_NEW_RANDOM) - assert Pybik.quit() - - confstore.clear_cache() - assert confstore.dimension == 3, confstore.dimension - assert (confstore.saved_state == "Cube 3 blocks_compact: " - "0,0,2,l 2,0,1,lu 0,2,0,uu 2,2,1,fll 1,1,0,u 2,1,2,ff 0,2,2,l 1,0,0,uu 2,0,0,f' " - "2,1,0,fuu 1,0,1,ll 0,0,1,ll 0,1,1,f' 1,1,1, 2,1,1,f 1,2,0,l' 1,2,1,ll 1,0,2,ffl' " - "2,0,2,l 0,1,2,f'u 2,2,2,u 1,2,2,u' 1,1,2,u 0,2,1,f'u 2,2,0,f'u' 0,1,0,ffu' 0,0,0,ffu'" - ), repr(confstore.saved_state) - assert confstore.saved_moves == '', repr(confstore.saved_moves) - -def test_solver_mellor(): - raise SkipTest - confstore.dimension = 3 - confstore.saved_state = 'Cube 3 identity:' - confstore.saved_moves = '' - - Pybik = AppPybik.launch('--debug=0') - assert Pybik.selectmenuitem (MENU_NEW_RANDOM) - #assert Pybik.expandtablecell(TREEVIEW_SCRIPTS, 'Solvers') - #assert Pybik.expandtablecell(TREEVIEW_SCRIPTS, 0) - #assert Pybik.doubleclickrow(TREEVIEW_SCRIPTS, 'Mellor (3x3)') - #assert Pybik.doesrowexist(TREEVIEW_SCRIPTS, 'Solvers', True) - print Pybik.getrowcount(TREEVIEW_SCRIPTS) - print Pybik.getcellvalue(TREEVIEW_SCRIPTS, 0,0) - print Pybik.expandtablecell(TREEVIEW_SCRIPTS, 0) - assert Pybik.doubleclickrow(TREEVIEW_SCRIPTS, 0) - wait(1) - assert Pybik.click(TOOLBUTTON_STOP) - wait(3) - assert Pybik.click(TOOLBUTTON_FORWARD) - wait(1) - assert Pybik.quit() - - confstore.clear_cache() - assert confstore.dimension == 3, confstore.dimension - assert confstore.saved_state == "Cube 3 identity:", repr(confstore.saved_state) - assert confstore.saved_moves == '', repr(confstore.saved_moves) - -if __name__ == '__main__': - import nose - nose.runmodule() - diff -Nru pybik-0.5/tools/cmp-setup_ui.sh pybik-1.0.1/tools/cmp-setup_ui.sh --- pybik-0.5/tools/cmp-setup_ui.sh 1970-01-01 00:00:00.000000000 +0000 +++ pybik-1.0.1/tools/cmp-setup_ui.sh 2013-02-02 21:15:48.000000000 +0000 @@ -0,0 +1,10 @@ +#!/bin/bash + +rm -rf pybiklib/ui/ +./setup.py build_ui --pyside -if >&2 +mv pybiklib/ui/ pybiklib/ui-pyside +./setup.py build_ui --pyqt4 -if >&2 +mv pybiklib/ui/ pybiklib/ui-pyqt4 +diff -u pybiklib/ui-pyside pybiklib/ui-pyqt4 +rm -rf pybiklib/ui-pyside pybiklib/ui-pyqt4 + diff -Nru pybik-0.5/tools/conv-plugin-for-translation.py pybik-1.0.1/tools/conv-plugin-for-translation.py --- pybik-0.5/tools/conv-plugin-for-translation.py 2012-01-06 16:35:34.000000000 +0000 +++ pybik-1.0.1/tools/conv-plugin-for-translation.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,48 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright © 2011-2012 B. Clausius -# -# 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 . - -import sys, os, re - -def convert(source_filename, target_filename): - with open(source_filename) as source: - lines = source.readlines() - re_field = re.compile(r'^(.*): (.+)$') - with open(target_filename, 'w') as target: - for line in lines: - match = re_field.match(line) - field, value = match.groups() if match else (None, None) - if field == 'Path': - sep = value[0] - format = '_({!r})' if sep != '@' else '{!r}' - value = '; '.join(format.format(v) for v in value.split(sep) if v) - else: - value = '' - target.write(value) - target.write('\n') - -def main(): - if len(sys.argv) != 2: - print 'usage: {} scriptfile'.format(os.path.basename(sys.argv[0])) - return 1 - filename = sys.argv[1] - convert(filename, filename+'.py') - -if __name__ == '__main__': - sys.exit(main()) - - diff -Nru pybik-0.5/tools/conv_plugin_for_translation.py pybik-1.0.1/tools/conv_plugin_for_translation.py --- pybik-0.5/tools/conv_plugin_for_translation.py 1970-01-01 00:00:00.000000000 +0000 +++ pybik-1.0.1/tools/conv_plugin_for_translation.py 2012-12-12 12:34:26.000000000 +0000 @@ -0,0 +1,76 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright © 2011-2012 B. Clausius +# +# 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 . + +from __future__ import print_function, division + +import sys, os, re + +def convert(source_filename, target_filename): + with open(source_filename) as source: + lines = source.readlines() + re_field = re.compile(r'^(.*): (.+)$') + with open(target_filename, 'w') as target: + translation_comment = None + dstlineno = 0 + for srclineno, line in enumerate(lines): + match = re_field.match(line) + field, value = match.groups() if match else (None, None) + if field == 'Path': + sep = value[0] + formatstr = '_({!r})' if sep != '@' else '{!r}' + values = [] + for v in value.split(sep): + if v: + if translation_comment and translation_key in re.split('\W+', v): + values.append(translation_comment) + v = formatstr.format(v) + values.append(v) + value = '\n'.join(values) + dstlineno += len(values) + translation_comment = None + elif line.strip().startswith('#'): + translation_comment = line.strip() + translation_key = translation_comment.strip('#').strip().split() + if translation_key: + translation_key = translation_key[0] + else: + translation_comment = None + value = None + else: + translation_comment = None + value = None + if value is None: + if dstlineno <= srclineno: + value = '' + dstlineno += 1 + else: + continue + target.write(value) + target.write('\n') + +def main(): + if len(sys.argv) != 2: + print('usage: {} scriptfile'.format(os.path.basename(sys.argv[0]))) + return 1 + filename = sys.argv[1] + convert(filename, filename+'.py') + +if __name__ == '__main__': + sys.exit(main()) + + diff -Nru pybik-0.5/tools/create-gl-pxd.py pybik-1.0.1/tools/create-gl-pxd.py --- pybik-0.5/tools/create-gl-pxd.py 1970-01-01 00:00:00.000000000 +0000 +++ pybik-1.0.1/tools/create-gl-pxd.py 2012-12-05 13:21:06.000000000 +0000 @@ -0,0 +1,79 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright © 2012 B. Clausius +# +# 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 . + +from __future__ import print_function, division + +import sys +import re + +from bcpath import path + +srcdir = path('/usr/include/GL') +dstdir = path('pybiklib') +filenames = ['gl.h', #'glext.h' +] +dstfilename = dstdir / 'gl.pxd' + +def convert_file(*psrc): + src = [(_psrc, _psrc.text()) for _psrc in psrc] + yield '\n\n# from {}:\n'.format(psrc[0]) + yield "cdef extern from '{}/{}':".format(psrc[0].dirname.basename, psrc[0].basename) + for match in re.finditer(r'^\#define[ \t]+(\w+).*?$', src[0][1], re.MULTILINE | re.DOTALL): + if match.group(1).startswith('GL_'): + yield match.expand(r' enum: \1') + + for psrc, tsrc in src: + yield '\n\n# from {}:\n'.format(psrc) + for match in re.finditer(r'^(typedef[\s\w]*);.*?$', tsrc, re.MULTILINE | re.DOTALL): + mg1 = match.group(1) + if mg1.find('_t') == -1 and not (mg1[-2:].isalpha() and mg1[-2:].isupper()): + yield match.expand(r'c\1') + + for psrc, tsrc in src: + yield '\n\n# from {} with:\n'.format(psrc) + yield "cdef extern from '{}/{}':".format(psrc.dirname.basename, psrc.basename) + for match in re.finditer(r'^GLAPI([\s\w*]*?)G?L?APIENTRY([^(]*)\(([^)]*)\);(.*?)$', tsrc, + re.MULTILINE | re.DOTALL): + mg2s2 = match.group(2).strip()[-2:] + if mg2s2.isalpha() and mg2s2.isupper(): + continue + for mgf in (match.group(1).find, match.group(3).find): + if not mgf('GLsizeiptr') == mgf('GLintptr') == mgf('64') == mgf('GLsync') == -1: + break + else: + if match.group(3).strip() == 'void': + template = r' cdef\1\2()\4' + else: + template = r' cdef\1\2(\3)\4' + yield match.expand(template).replace('const ', '').replace(' in,', ' in_,').replace('/*', '#/*') + +def main(): + pdst = dstfilename + with open(pdst, 'w') as fdst: + print('# {}'.format(pdst), file=fdst) + print('# generated with {}'.format(sys.argv[0]), file=fdst) + psrc = srcdir / 'gl.h' + psrcext = srcdir / 'glext.h' + for token in convert_file(psrc, psrcext): + print(token, file=fdst) + + +if __name__ == '__main__': + main() + + diff -Nru pybik-0.5/tools/create-gl-pxd.sh pybik-1.0.1/tools/create-gl-pxd.sh --- pybik-0.5/tools/create-gl-pxd.sh 2011-11-14 21:37:07.000000000 +0000 +++ pybik-1.0.1/tools/create-gl-pxd.sh 1970-01-01 00:00:00.000000000 +0000 @@ -1,76 +0,0 @@ -#!/bin/bash - -# Copyright © 2009-2011 B. Clausius -# -# 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 . - -gl_h="GL/gl.h" -gl_h_abs="/usr/include/$gl_h" -glext_h="GL/glext.h" -glext_h_abs="/usr/include/$glext_h" -gl_pxd='pybiklib/gl.pxd' - -echo "convert header: $gl_h_abs --> $gl_pxd" - -{ - echo "# $gl_pxd" -} > $gl_pxd - -cmd='grep "#define GL_" | awk '\''{ print "\ \ \ \ enum: " $2 }'\' -echo "$cmd" -{ - echo - echo - echo "# This section was generated with:" - echo "# $cmd" - echo - echo "cdef extern from '$gl_h':" - eval $cmd <$gl_h_abs -} >> $gl_pxd - -cmd='sed -n '\''/typedef/s/^\([^;]*\);\(.*\)$/c\1/p'\'' | grep -v APIENTRYP' -echo "$cmd" -{ - echo - echo - echo "# This section was generated from $gl_h with:" - echo "# $cmd" - echo - eval $cmd <$gl_h_abs -} >> $gl_pxd - -cmd='sed -n '\''/typedef/s/^\([^;]*\);\(.*\)$/c\1/p'\'' | grep -v APIENTRYP | grep -v "int.._t" | grep -v struct | grep -v ptrdiff_t' -echo "$cmd" -{ - echo - echo - echo "# This section was generated from $glext_h with:" - echo "# $cmd" - echo - eval $cmd <$glext_h_abs -} >> $gl_pxd - -cmd='sed -n -e :a -e '\''/([^)]*$/N; /([^)]*$/N; /([^)]*$/N; s/^GLAPI\(.*\)GLAPIENTRY\([^(]*\)\(([^)]*)\);/\ \ \ \ cdef\1\2\3/p; ta'\'' | sed "s/const //g" | sed '\''sx\(/\*.*\*/\)$x#\1xg'\'' | sed '\''s/( *void *)/()/'\' -echo "$cmd" -{ - echo - echo - echo "# This section was generated with:" - echo "# $cmd" - echo - echo "cdef extern from '$gl_h':" - eval $cmd <$gl_h_abs -} >> $gl_pxd - - diff -Nru pybik-0.5/tools/create_docs.py pybik-1.0.1/tools/create_docs.py --- pybik-0.5/tools/create_docs.py 1970-01-01 00:00:00.000000000 +0000 +++ pybik-1.0.1/tools/create_docs.py 2013-01-07 15:01:45.000000000 +0000 @@ -0,0 +1,138 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright © 2012-2013 B. Clausius +# +# 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 . + +from __future__ import print_function, division, unicode_literals + +import sys, os +sys.path.insert(0, '.') +import re + +from pybiklib import config +from pybiklib.config import wrap + +try: + _ +except NameError: + import __builtin__ + __builtin__.__dict__['_'] = lambda s: s + + +def underline(title, underline_char='='): + return '{}\n{}'.format(title, underline_char*len(title)) + +def clean_links(text): + footnotes = [] + def add_footnote(match): + if match.group(2) != '|': + return match.group(0) + elif match.group(1) != '': + footnote = match.group(1) + if footnote in footnotes: + footnotes.append(footnotes.index(footnote)+1) + else: + footnotes.append(footnote) + return '' + else: + footnote = footnotes[-1] + if type(footnote) is int: + del footnotes[-1] + return ' [{}]'.format(footnote) + else: + return ' [{}]'.format(len(footnotes)) + text = re.sub(r'<(.*?)(\|?)>', add_footnote, text) + return text, ['[{}] <{}>'.format(i+1, footnote) for i, footnote in enumerate(footnotes)] + +def read_utf8(filename): + with open(filename, 'rb') as f: + text = f.read() + return text.decode('utf-8') + +def write_utf8(filename, text): + text = text.encode('utf-8') + with open(filename, 'wb') as f: + f.write(text) + +def create_README(filename=None, skip_install=False): + if not filename: + filename = 'README' + news_template = [ + ('{appname}', '{description}\n\n' + 'Author: {AUTHOR} <{CONTACT_EMAIL}>\n' + 'License: {LICENSE_NAME}\n' + 'Project page: <{WEBSITE}>'), + ('Installation', wrap( + 'If Pybik is available for your distribution, ' + 'you should install Pybik with a package manager. ' + 'Otherwise see the file INSTALL for installation instructions.')), + ('Feedback', '{feedback}'), + ('Translation', '{translation}'), + ('License', '{license}'), + ] + readme = { + 'appname': 'About {} {}'.format(config.APPNAME, config.VERSION), + 'description': wrap(config.LONG_DESCRIPTION), + 'AUTHOR': config.AUTHOR, + 'CONTACT_EMAIL':config.CONTACT_EMAIL, + 'LICENSE_NAME': config.LICENSE_NAME, + 'WEBSITE': config.WEBSITE, + 'feedback': wrap(clean_links(config.get_filebug_text())), + 'translation': wrap(clean_links(config.TRANSLATION_TEXT)), + 'license': wrap(config.LICENSE_INFO) + '\n\n' + wrap(config.LICENSE_NOT_FOUND), + } + + text = '' + for title, body in news_template: + if skip_install and title == 'Installation': + continue + title = underline(title.format(**readme)) + body = body.format(**readme) + text += '\n{}\n\n{}\n\n'.format(title, body) + write_utf8(filename, text) + + +def main(): + skip_install = False + args = sys.argv[1:] + if not args: + print('usage: {} [--skip-install] README[=filename]'.format(os.path.basename(sys.argv[0]))) + sys.exit(1) + for arg in args: + if arg == '--skip-install': + skip_install = True + elif not arg.startswith('--'): + fileinfo = arg.split('=', 1) + if len(fileinfo) == 1: + fileinfo.append(None) + if fileinfo[0] == 'README': + create_README(fileinfo[1], skip_install=skip_install) + else: + print('Unknown Argument:', arg) + sys.exit(1) + else: + print('Unknown Option:', arg) + sys.exit(1) + + +if __name__ == '__main__': + try: + _ + except NameError: + __builtins__._ = lambda text: text + main() + + diff -Nru pybik-0.5/tools/create_manpage.py pybik-1.0.1/tools/create_manpage.py --- pybik-0.5/tools/create_manpage.py 2012-01-06 16:35:52.000000000 +0000 +++ pybik-1.0.1/tools/create_manpage.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,108 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -# Copyright © 2011-2012 B. Clausius -# -# 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 . - -import sys, os -import datetime -sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) -os.environ['COLUMNS'] = '1000' -try: - __builtins__._ = lambda x: x - __builtins__.ngettext = lambda s, p, n: (s if n == 1 else p) -except AttributeError: - __builtins__['_'] = lambda x: x - __builtins__['ngettext'] = lambda s, p, n: (s if n == 1 else p) - - -def set_domain(localedir, lang): - os.environ['LANGUAGE'] = lang - try: - from pybiklib import config - import gettext - gettext.install(config.PACKAGE, localedir, names=['ngettext']) - except ImportError: - print 'gettext not found.' - -template = ur''' -.\"This file is generated automatically. -.TH {app} 6 "{date}" "" - -.SH {NAME} -{program} - {description} - -.SH {SYNOPSIS} -.B {program} -{options} -.br - -.SH {OPTIONS}''' -template_option = ur''' -.B -.IP {option} -{help}''' - -def write_manpage(outfile): - from pybiklib import main, config - parser = main.arg_parser() - options = parser.format_usage() - options = options.lstrip('usage:') - options = options.strip() - options = options.lstrip(parser.prog) - options = options.strip() - options = options.replace('-', '\-') - outfile.write(template.format( - app=unicode(config.get_appname_short(),'utf-8'), - date=str(datetime.date.today()), - #Translators: Strings from file create_manpage.py are visible only in the man-page - NAME=unicode(_('NAME'),'utf-8'), - program=config.PACKAGE, - description=parser.description, - SYNOPSIS=unicode(_('SYNOPSIS'),'utf-8'), - options=options, - OPTIONS=unicode(_('OPTIONS'),'utf-8'), - ).encode('utf8')) - for action in parser._actions: - if action.metavar is None: - option = r',\ '.join(action.option_strings) - else: - option = r',\ '.join(r'\ '.join((o, action.metavar)) for o in action.option_strings) - option = option.replace('-', '\-') - outfile.write(template_option.format( - option=option, - help=action.help, - ).encode('utf8')) - outfile.write('\n') - -def main_(): - if len(sys.argv) > 1 and sys.argv[1]: - filename = sys.argv[1] - outfile = open(filename, 'w') - else: - filename = None - outfile = sys.stdout - if len(sys.argv) > 3 and sys.argv[2] and sys.argv[3]: - set_domain(sys.argv[2], sys.argv[3]) - try: - write_manpage(outfile) - finally: - if filename is not None: - outfile.close() - -if __name__ == '__main__': - sys.exit(main_()) - - diff -Nru pybik-0.5/tools/modeldata.py pybik-1.0.1/tools/modeldata.py --- pybik-0.5/tools/modeldata.py 1970-01-01 00:00:00.000000000 +0000 +++ pybik-1.0.1/tools/modeldata.py 2013-01-07 15:02:03.000000000 +0000 @@ -0,0 +1,148 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright © 2012-2013 B. Clausius +# +# 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 . + +from __future__ import print_function, division, unicode_literals + +import sys, os +sys.path.insert(0, '.') +import cPickle as pickle +from multiprocessing import Pool, cpu_count + +from pybiklib import model +model.use_modeldata = False + + +dedup_data = [] +cnt_dups = [] +cnt_values = [] + +def dedup_reset(): + dedup_data[:] = [[] for unused_i in range(6)] + cnt_dups[:] = [0] * 6 + cnt_values[:] = [0] * 6 + +def pool_dedup(level, value): + if isinstance(value, dict): + iterator = value.items() + elif isinstance(value, list): + iterator = enumerate(value) + elif isinstance(value, tuple): + iterator = [] + else: + return value + cnt_values[level] += 1 + try: + didx = dedup_data[level].index((type(value), value)) + except ValueError: + dedup_data[level].append((type(value), value)) + for k, v in iterator: + v = pool_dedup(level+1, v) + value[k] = v + else: + dtype, dvalue = dedup_data[level][didx] + assert value == dvalue and type(value) == type(dvalue) == dtype, (value, dvalue) + cnt_dups[level] += 1 + value = dvalue + return value + +def pool_functions(parallel): + pool = None + try: + if parallel > 1: + pool = Pool(processes=parallel) + except OSError as e: + print('process pool not available ({}):'.format(e)) + print(' maybe /dev/shm is not mounted,') + print(' deactivating multiprocessing') + sys.stdout.flush() # when Pool(…) fails this line is + if pool is not None: + return pool.imap_unordered + else: + from itertools import imap + return imap + +def enum_modelfiles(dirname, testfunc): + ignored = [] + modelfiles = [] + for Model in model.models: + for i in range(1, 11): + for j in range(1, 11): + for k in range(1, 11): + sizes = Model.norm_sizes((i, j, k)) + filename = Model.get_datafilename(sizes) + filename = os.path.join(dirname, filename) + if filename in modelfiles or filename in ignored: + continue + if testfunc(filename): + modelfiles.append(filename) + else: + ignored.append(filename) + if modelfiles: + for filename in sorted(ignored): + print('skipping', filename) + return sorted(modelfiles, reverse=True) + +def pool_enum_modelfile(filename): + sizes_list = [] + for Model in model.models: + for i in range(1, 11): + for j in range(1, 11): + for k in range(1, 11): + sizes = Model.norm_sizes((i, j, k)) + if os.path.basename(filename) != Model.get_datafilename(sizes): + continue + if (Model, sizes) in sizes_list: + continue + sizes_list.append((Model, sizes)) + return sizes_list + +def pool_create_modelfiledata(sizes_list): + savedata = {} + for Model, sizes in sizes_list: + modelobj = Model(sizes, None) + modelobj.gl_data() # here the Block.visible_glfaces lists are filled + savedata[(Model.type, sizes)] = modelobj.get_savedata() + return savedata + +def pool_create_modelfile(filename): + sizes_list = pool_enum_modelfile(filename) + savedata = pool_create_modelfiledata(sizes_list) + dedup_reset() + savedata = pool_dedup(0, savedata) + with open(filename, 'wb') as datafile: + pickle.dump(savedata, datafile, -1) + vals = ['%6s' % v for v in cnt_values] + dups = ['%6s' % d for d in cnt_dups] + return 'generated {} with {} models\n vals: {}\n dups: {}'.format( + filename, len(sizes_list), ' '.join(vals), ' '.join(dups)) + +def create_modeldata(dirname, testfunc=None, parallel=1): + if testfunc is None: + testfunc = lambda arg: True + imap_model = pool_functions(parallel) + modelfiles = enum_modelfiles(dirname, testfunc) + for lines in imap_model(pool_create_modelfile, modelfiles): + print(lines) + sys.stdout.flush() + + +if __name__ == '__main__': + create_modeldata('data/models', parallel=cpu_count()) + #create_modeldata('data/models', parallel=1) + + diff -Nru pybik-0.5/tools/profile.py pybik-1.0.1/tools/profile.py --- pybik-0.5/tools/profile.py 2011-06-28 06:20:26.000000000 +0000 +++ pybik-1.0.1/tools/profile.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,105 +0,0 @@ -#!/usr/bin/python -#-*- coding:utf-8 -*- - -# Pybik -- A 3 dimensional magic cube game. -# Copyright © 2009, 2011 B. Clausius -# -# 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 . - - -import sys -import getopt -import cProfile -import pstats - -def main(): - opt_vals = app_opts (sys.argv, file='profile.tmp') - if opt_vals['run']: - run(opt_vals) - if opt_vals['out']: - out(opt_vals) - return 0 - -def app_opts (argv, **opt_vals): - shortopts = "hn:f:" - shortoptmap = {'h':"help", 'n':"name", 'r':'run', 'o':'out', - 'y':'pure-python', 'f':'file'} - longopts = [] - - for o,opt in shortoptmap.items(): - if o not in shortopts: - shortopts += o - if o+':' in shortopts: - longopts.append(opt+'=') - else: - longopts.append(opt) - - for o in longopts: - if o.endswith('='): - if not o[:-1] in opt_vals: - opt_vals[o[:-1]] = '' - else: - if not o in opt_vals: - opt_vals[o] = False - - #print opt_vals - #print argv - try: - opts,unused_args = getopt.getopt(argv[1:], shortopts, longopts) - except getopt.GetoptError, e: - print e - exit(1) - #print opts,unused_args - for opt,optarg in opts: - if len(opt) == 2 and opt[1] in shortoptmap: - opt = '--'+shortoptmap[opt[1]] - if opt == "--help": - print 'usage:', argv[0], 'options...' - for so,lo in shortoptmap.items(): - if o == ':': - continue - elif so+':' in shortopts: - print ' -%s arg, --%s=arg' % (so,lo) - else: - print ' -%s, --%s' % (so,lo) - exit (0) - elif opt[2:] in longopts: - opt_vals[opt[2:]] = True - elif opt[2:]+'=' in longopts: - opt_vals[opt[2:]] = optarg - else: - opt_vals[opt.lstrip('-')] = optarg - - #print opt_vals - return opt_vals - -def run(opts): - global main_module - import main as main_module - if opts['pure-python']: - statement = 'main_module.main(["", "--solved", "--pure-python"])' - cProfile.run(statement, opts['file']) - else: - statement = 'main_module.main(["", "--solved"])' - cProfile.run(statement, opts['file']) - -def out(opts): - p = pstats.Stats(opts['file']) - p.strip_dirs().sort_stats(-1).print_stats(opts['name']) - - -if __name__ == '__main__': - sys.exit(main()) - - diff -Nru pybik-0.5/tools/py2pxd.py pybik-1.0.1/tools/py2pxd.py --- pybik-0.5/tools/py2pxd.py 2011-06-28 06:20:26.000000000 +0000 +++ pybik-1.0.1/tools/py2pxd.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,56 +0,0 @@ -#!/usr/bin/python -#-*- coding:utf-8 -*- - -# Pybik -- A 3 dimensional magic cube game. -# Copyright © 2009, 2011 B. Clausius -# -# 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 . - - -from __future__ import with_statement - -import sys, os, re - -def main(argv): - arg_src = argv[0] - arg_dst = argv[1] - if not os.path.exists(arg_src): - print >>sys.stderr, 'error:', arg_src, 'does not exist' - return 1 - #if os.path.exists(arg_dst): - # print >>sys.stderr, 'error:', arg_dst, 'already exists' - # return 1 - create_pxd(arg_src, arg_dst) - return 0 - -def create_pxd(src_path, dst_path): - re_pxd = re.compile(r'( *)#pxd (.*)', re.DOTALL) - with open(src_path,'r') as srcf: - with open(dst_path,'w') as dstf: - for line in srcf: - #if line.startswith('#pxd '): - m = re_pxd.match(line) - if m: - line = m.expand(r'\1\2') - dstf.write(line) - -if __name__ == '__main__': - try: - main(sys.argv[1:]) - except: - sys.exit(1) - else: - sys.exit(0) - - diff -Nru pybik-0.5/tools/py2pyx.py pybik-1.0.1/tools/py2pyx.py --- pybik-0.5/tools/py2pyx.py 2011-06-28 06:20:26.000000000 +0000 +++ pybik-1.0.1/tools/py2pyx.py 2012-12-05 13:28:27.000000000 +0000 @@ -2,7 +2,7 @@ #-*- coding:utf-8 -*- # Pybik -- A 3 dimensional magic cube game. -# Copyright © 2009, 2011 B. Clausius +# Copyright © 2009, 2011-2012 B. Clausius # # 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 @@ -18,45 +18,88 @@ # along with this program. If not, see . -from __future__ import with_statement +from __future__ import print_function, division import sys, os, re +class Py2pyxParseError (Exception): pass + + def main(argv): - arg_src = argv[0] - arg_dst = argv[1] + if not (1 < len(argv) <= 4): + print('usage:', os.path.basename(__file__), 'python-file [pyx-filename [pxd-filename]]', + file=sys.stderr) + return 1 + + arg_src = argv[1] + arg_dst = argv[2] if len(argv) > 2 else None + arg_pxd = argv[3] if len(argv) > 3 else None if not os.path.exists(arg_src): - print >>sys.stderr, 'error:', arg_src, 'does not exist' + print('error:', arg_src, 'does not exist', file=sys.stderr) return 1 - create_pyx(arg_src, arg_dst) + create_pyx(arg_src, arg_dst, arg_pxd) return 0 - -def create_pyx(src_path, dst_path): - with open(src_path,'r') as srcf: - with open(dst_path,'w') as dstf: - text = srcf.read() - ## replace a line with a cdef line - #text = re.compile(r'^( *)#(cdef .*)\n\1.*$', re.M).sub(r'\1\2\n\1', text) - # insert a line - text = re.compile(r'^( *)#px\+', re.M).sub(r'\1', text) - # remove next line - text = re.compile(r'^( *)#px-\n.*$', re.M).sub(r'\1\n\1', text) - # remove next n lines - for n in range(1,11): - text = re.compile(r'^( *)#px-%d'%n+r'\n.*'*n+'$', re.M).sub(r'\1'+r'\n\1'*n, text) - # replace next line with a line - text = re.compile(r'^( *)#px/(.*)\n.*$', re.M).sub(r'\1\2\n\1', text) - # remove comment - text = re.compile(r'^( *)#px .*$', re.M).sub(r'\1', text) - - dstf.write(text) - + +def create_pyx(src_path, dst_path, pxd_path): + errors = 0 + openw = lambda path: open(path, 'w') if path else sys.stdout + remove_lines = 0 + + copy = lambda lineno, match: (match.string, None, 0) + add = lambda lineno, match: (match.expand(r'\1\4 \2\n'), None, 0) + def remove(unused_lineno, match): + count = match.group(4) + if count == '': + count = 1 + else: + count = int(count) + return match.expand(r'\1#px \2\4\n'), None, count + replace = lambda lineno, match: (match.expand(r'\1\4 \2\n'), None, 1) + comment = lambda lineno, match: (match.expand(r'\1\2\4\n'), None, 0) + pxd = lambda lineno, match: (match.expand(r'\1#px \2\4\n'), + match.expand(r'\1\4') + ' #line {}\n'.format(lineno), + 0) + add_pxd = lambda lineno, match: (match.expand(r'\1\4 \2\n'), + match.expand(r'\1\4\n') + ' #line {}\n'.format(lineno), + 0) + def repl_pxd(lineno, match): + if match.group(6): + return (match.expand(r'\1\4 \2\n'), + match.expand(r'\1\5') + ' #line {}\n'.format(lineno), + 1) + else: + return (match.expand(r'\1#px \2\4\n'), + match.expand(r'\1\4') + ' #line {}\n'.format(lineno), + 1) + fdict = {None:copy, '+':add, '-':remove, '/':replace, ' ':comment, + 'd ':pxd, 'd+':add_pxd, 'd/':repl_pxd} + + with open(src_path,'r') as srcf, openw(dst_path) as dstf, openw(pxd_path) as pxdf: + pxdf.write('#file: {}\n\n'.format(src_path)) + for lineno, line in enumerate(srcf): + try: + match = re.match(r'^( *)(#px(d |d\+|d/|.)|)((.*?)(:?))\n$', line) + if remove_lines > 0: + pyxline = match.expand(r'\1#px \2\4\n') + pxdline = None + remove_lines -= 1 + continue + pyxline, pxdline, remove_lines = fdict[match.group(3)](lineno, match) + except Exception as e: + print('%s:%d:'%(src_path, lineno), e, file=sys.stderr) + print(' Invalid line:', line, file=sys.stderr, end='') + pyxline = line + pxdline = None + errors += 1 + finally: + dstf.write(pyxline) + if pxdline is not None: + pxdf.write(pxdline) + if errors: + raise Py2pyxParseError('create_pyx failed with %s errors' % errors) + + if __name__ == '__main__': - try: - main(sys.argv[1:]) - except: - sys.exit(1) - else: - sys.exit(0) - + sys.exit(main(sys.argv)) + diff -Nru pybik-0.5/tools/pybik-crashdb.conf pybik-1.0.1/tools/pybik-crashdb.conf --- pybik-0.5/tools/pybik-crashdb.conf 2011-06-28 06:12:04.000000000 +0000 +++ pybik-1.0.1/tools/pybik-crashdb.conf 1970-01-01 00:00:00.000000000 +0000 @@ -1,6 +0,0 @@ -pybik = { - 'impl' : 'launchpad', - 'project' : 'pybik', - 'bug_pattern_base' : None, - 'staging' : True, -} diff -Nru pybik-0.5/tools/pybik_x pybik-1.0.1/tools/pybik_x --- pybik-0.5/tools/pybik_x 2011-06-28 05:42:29.000000000 +0000 +++ pybik-1.0.1/tools/pybik_x 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -#!/bin/sh - -# Pybik -- A 3 dimensional magic cube game. -# Copyright (C) 2009 B. Clausius -# -# 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 . - -cd pybiklib - -case $1 in - py) - shift - python pybik.py --solved --pure-python --debug=2 "$@" - ;; - c) - shift - python pybik.py --solved --debug=2 "$@" - ;; - profile-py) - shift - python ../tools/profile.py -r -f ../tools/display-py.tmp - python ../tools/profile.py -o -f ../tools/display-py.tmp -n display >>../tools/display.log - ;; - profile-c) - shift - python ../tools/profile.py -r -x -f ../tools/display-c.tmp - python ../tools/profile.py -o -x -f ../tools/display-c.tmp -n display >>../tools/display.log - ;; - profile-cmp) - shift - python ../tools/profile.py -o -f ../tools/display-py.tmp -n display - python ../tools/profile.py -o -x -f ../tools/display-c.tmp -n display - ;; - profile-log) - less +G ../tools/display.log - ;; - *) - python pybik.py "$@" - ;; -esac diff -Nru pybik-0.5/tools/singmaster-to-pybik.py pybik-1.0.1/tools/singmaster-to-pybik.py --- pybik-0.5/tools/singmaster-to-pybik.py 1970-01-01 00:00:00.000000000 +0000 +++ pybik-1.0.1/tools/singmaster-to-pybik.py 2012-12-05 13:29:48.000000000 +0000 @@ -0,0 +1,55 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright © 2012 B. Clausius +# +# 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 . + +from __future__ import print_function, division, unicode_literals + + +def convert(salg): + moves = { + "": "", + "F": "f", "B": "b", "R": "r", "L": "l", "U": "u", "D": "d", + "F'": "f-", "B'": "b-", "R'": "r-", "L'": "l-", "U'": "u-", "D'": "d-", + "F2": "ff", "B2": "bb", "R2": "rr", "L2": "ll", "U2": "uu", "D2": "dd", + "F'2": "ff", "B'2": "bb", "R'2": "rr", "L'2": "ll", "U'2": "uu", "D'2": "dd", + "M": "r2-", "E": "u2-", "S": "f2", + "M'": "r2", "E'": "u2", "S'": "f2-", + "M2": "r2r2", "E2": "u2u2", "S2": "f2f2", + "M2'": "r2r2", "E2'": "u2u2", "S2'": "f2f2", + "x": "R", "y": "U", "z": "F", + "x'": "R-", "y'": "U-", "z'": "F-", + "x2": "RR", "y2": "UU", "z2": "FF", + "x2'": "RR", "y2'": "UU", "z2'": "FF", + } + palg = '' + for m in salg.split(' '): + palg += moves[m.strip('()')] + return palg + +def main(): + while True: + try: + line = raw_input('> ') + except EOFError: + return + print(':', convert(line)) + + +if __name__ == '__main__': + main() + + diff -Nru pybik-0.5/tools/source_pybik.py pybik-1.0.1/tools/source_pybik.py --- pybik-0.5/tools/source_pybik.py 2011-06-28 06:20:26.000000000 +0000 +++ pybik-1.0.1/tools/source_pybik.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -#-*- coding:utf-8 -*- - -# Pybik -- A 3 dimensional magic cube game. -# Copyright © 2009-2011 B. Clausius -# -# 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 . - -'''apport hook for pybik''' - -import apport -from apport.hookutils import command_output - -def add_info(report): - if not apport.packaging.is_distro_package(report['Package'].split()[0]): - report['ThirdParty'] = 'True' - report['CrashDB'] = 'pybik' - report['GconfPybik'] = command_output(['gconftool-2', '-R', '/apps/pybik']) - diff -Nru pybik-0.5/tools/uni2img.py pybik-1.0.1/tools/uni2img.py --- pybik-0.5/tools/uni2img.py 1970-01-01 00:00:00.000000000 +0000 +++ pybik-1.0.1/tools/uni2img.py 2012-12-05 13:30:10.000000000 +0000 @@ -0,0 +1,61 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright © 2012 B. Clausius +# +# 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 . + +from __future__ import print_function, division, unicode_literals + +import os +import unicodedata + + +symbols = [ + #('ATOM SYMBOL', 'DejaVu-Sans-Oblique', 300, '+0+3'), + ('ATOM SYMBOL', 'FreeSerif-Mittel', 256, '+0-6'), + #('BEAMED EIGHTH NOTES', 'DejaVu-Sans-Oblique', 256, '+0-6'), + ('BEAMED EIGHTH NOTES', 'FreeSerif-Mittel', 256, '+0+16'), + ('BLACK SMILING FACE', 'DejaVu-Sans-Oblique', 256, '-1+5'), + ('PEACE SYMBOL', 'DejaVu-Sans-Oblique', 300, '-2+5'), + ('SHAMROCK', 'DejaVu-Sans-Oblique', 300, '-1+5'), + ('SKULL AND CROSSBONES','DejaVu-Sans-Oblique', 300, '-1+5'), + #('SKULL AND CROSSBONES','FreeSerif-Mittel', 300, '+0+0'), + #('SNOWFLAKE', 'DejaVu-Sans-Oblique', 300, '-1+5'), + ('SNOWFLAKE', 'FreeSerif-Mittel', 320, '+0+14'), + ('WHITE SMILING FACE', 'DejaVu-Sans-Oblique', 256, '-1+5'), + #('WHITE SUN WITH RAYS', 'DejaVu-Sans-Oblique', 300, '+0+4'), + ('WHITE SUN WITH RAYS', 'FreeMono-Standard', 390, '+0+0'), + ('YIN YANG', 'DejaVu-Sans-Oblique', 300, '-2+5'), + #'FOUR LEAF CLOVER', + #'ANTICLOCKWISE GAPPED CIRCLE ARROW', + #'CLOCKWISE GAPPED CIRCLE ARROW', +] + + +path = 'data/ui/images' + +def main(): + for name, font, size, pos in symbols: + c = unicodedata.lookup(name) + os.system('convert -size 256x256 null: -alpha transparent -font {} -pointsize {} -gravity center' + ' -annotate 0x0{} {} "{}/{}.png"' + .format(font, size, pos, c, path, name) + .encode('utf-8')) + + +if __name__ == '__main__': + main() + +