--- /dev/null
+TODO: this file is grossly inadequate
+
+Charles Goodwin
+- Most of the widgets
+
+David Crawshaw
+- Workings of the key widgets
--- /dev/null
+================================================================================
+The contents of this distribution are copyrighted and licensed as follows:
+================================================================================
+
+- The XWT Standard Library (all files except org/gimp/tigert/**) is
+ Copyright by various authors; it is licensed to the public under the
+ GNU Library General Public License.
+
+- The files in the subdirectory org/gimp/tigert/** are Copyright
+ Tigert Labs, and are licensed under the GNU General Public
+ License. "The icons are released under the Gnu General Public
+ License, meaning you can use them in free software projects free of
+ charge. If you wish to use these for other things (or if you need
+ other icons for your project) contact me." [from
+ http://tigert.gimp.org/gnome/gnome-stock/]
+
+
+
+========================================================================
+The GNU General Public License
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
+
+
+
+========================================================================
+The GNU Lesser General Public License
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser 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 Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "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
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY 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
+LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
--- /dev/null
+TODO: readme file
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex>
+ <meta:doc>
+ Author: Name
+ </meta:doc>
+
+ <ui:box>
+
+ </ui:box>
+</ibex>
--- /dev/null
+<ibex xmlns:theme="ibex.theme" \r
+ xmlns="org.ibex.theme.win2k" \r
+ xmlns:games="org.ibex.games">\r
+ <theme:surface />\r
+ <ui:box fill="#d4d0c8" maxwidth="600" maxheight="600" cols="1">\r
+ \r
+ ibex.ui.frame = thisbox;\r
+\r
+ <!-- <ui:box text="menus aren't implemented" height="20" align="left"/> -->\r
+ <tabpane>\r
+ <games:reversi.main tabtext="Reversi"/> \r
+ <games:checkers.main tabtext="Checkers"/>\r
+ <games:chess.main tabtext="Chess"/> \r
+<!-- <sampler:color_picker tabtext="Color Picker"/> \r
+ <sampler:transparency tabtext="Transparency"/> \r
+ <sampler:fonts tabtext="Fonts"/> \r
+ <sampler:html tabtext="HTML"/> \r
+ <sampler:spreadsheet tabtext="Spreadsheet"/> -->\r
+ </tabpane> \r
+ </ui:box>\r
+</ibex>
\ No newline at end of file
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex>
+ <meta:doc>
+ See ibex.widget.cardpane for details
+
+ <todo>
+ Make cardpane aware of 'enabled' cards
+ </todo>
+ </meta:doc>
+
+ <ui:box>
+
+ // public interface
+
+ thisbox.nextcard;
+ thisbox.nextstep;
+ thisbox.prevcard;
+ thisbox.prevstep;
+ thisbox.show;
+
+ // private variables
+
+ var steps = [];
+ var stepmarker = 0;
+ var stepping = false;
+
+ // childadded write trap
+ childadded ++= function(v) {
+ // show v if it is the first card
+ if (numchildren > 1) v.visible = false;
+ else { cascade = v; show = v; }
+ }
+
+ // childremoved write trap
+ childremoved ++= function(v) {
+ // if v is the shown card, attempt to show another
+ if (show == v) {
+ if (next) next = true;
+ else if (prev) prev = true;
+ }
+ }
+
+ // write trap to show the next card in the cardpane
+ nextcard ++= function(v) {
+ if (nextcard) nextcard.show = true;
+ }
+
+ // read trap to fetch the next card in the cardpane
+ nextcard ++= function() {
+ if (show and numchildren - 1 > show) return thisbox[show + 1];
+ else return null;
+ }
+
+ // write trap to step forward to the next in the show-chain
+ nextstep ++= function(v) {
+ stepping = true;
+ if (nextstep) nextstep.show = true;
+ stepping = false;
+ }
+
+ // read trap to fetch the next step in the show-chain
+ nextstep ++= function() {
+ if (steps.length - 1 > stepmarker) return steps[stepmarker + 1];
+ else return false;
+ }
+
+ // write trap to show the previous card in the cardpane
+ prevcard ++= function(v) {
+ if (prevcard) prevcard.show = true;
+ }
+
+ // read trap to fetch the previous card in the cardpane
+ prevcard ++= function() {
+ if (show and show > 0) return thisbox[show - 1];
+ else return false;
+ }
+
+ // write trap to step back to the previous in the show-chain
+ prevstep ++= function(v) {
+ stepping = true;
+ if (prevstep) prevstep.show = true;
+ stepping = false;
+ }
+
+ // read trap to fetch the previous step in the show-chain
+ prevstep ++= function() {
+ if (stepmarker > 0) return steps[stepmarker - 1];
+ else return false;
+ }
+
+ // write trap to show a card by box or index
+ show ++= function(v) {
+ var card;
+
+ if (typeof(v) == "number" and numchildren > v) card = thisbox[v];
+ else if (typeof(v) == "object" and (thisbox.indexof(v) or thisbox.indexof(v) == 0)) card = v;
+
+ if (card) {
+ // hide the previously shown card and show the new one
+ //if (cascade) cascade.visible = false;
+ for (var i=0; numchildren > i; i++) { thisbox[i].visible = false; }
+ card.visible = true;
+
+ // remember where we are
+ if (!stepping) {
+ stepmarker ++;
+ if (stepmarker != steps.length) steps.splice(stepmarker, steps.length - stepsmarker);
+ if (stepmarker > 100) steps.splice(0);
+ steps[stepmarker] = card;
+ }
+
+ cascade = card;
+ }
+ else return;
+ }
+
+ </ui:box>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex>
+ <meta:doc>
+ See ibex.theme.clickable for details
+ </meta:doc>
+
+ <ibex.lib.repeatable />
+ <ui:box>
+
+ // template properties
+ thisbox.enabled; // self explanatory
+ thisbox.repeats; // if a repeating action is desired
+
+ // event triggers
+ thisbox.action; // action trigger
+
+ // state properties
+ thisbox.primed; // track activation irrespective of mouse.inside
+
+ // physical state triggers
+ thisbox.active; // active state (mouse.inside and primed)
+ thisbox.hover; // hover state (mouse.inside and !primed)
+ thisbox.normal; // normal state (!mouse.inside)
+
+ enabled ++= function(v) {
+ cascade = v;
+ // deprime us when disabled
+ if (!v) { primed = false; normal = true; }
+ }
+
+ focused ++= function(v) {
+ cascade = v;
+ // unprime if defocused
+ if (!v and primed) primed = false;
+ }
+
+ primed ++= function(v) {
+ if (enabled) {
+ // determine physical state and activate trigger
+ v ? active = true : (mouse.inside ? hover = true : normal = true);
+ // set repeat state if necessary
+ if (repeats) repeat = v;
+ }
+ // do nothing when not enabled
+ else cascade = false;
+ }
+
+ KeyPressed ++= function(v) {
+ if (v == "enter" or v == " ") primed = true;
+ else if (v == "escape") primed = false;
+ }
+
+ KeyReleased ++= function(v) {
+ if (v == "enter" or v == " ")
+ if (primed and enabled)
+ { action = true; primed = false; }
+ }
+
+ Enter ++= function(v) {
+ if (enabled) {
+ if (primed) {
+ active = true;
+ if (repeats) repeat = true;
+ }
+ else hover = true;
+ }
+ }
+
+ Leave ++= function(v) {
+ if (enabled) {
+ normal = true;
+ if (repeats) repeat = false;
+ }
+ }
+
+ Press1 ++= function(v) {
+ if (enabled) {
+ primed = true;
+
+ surface.Release1 ++= function(v) {
+ // clean up
+ if (enabled) {
+ if (primed) {
+ if (mouse.inside) repeats ? repeat = false : action = true;
+ primed = false; // important: must occur _after_ action
+ }
+ }
+
+ surface.Release1 --= callee;
+ }
+ }
+ }
+
+ // initialise as normal state
+ // FIXME: redo this using better method (?)
+ SizeChange ++= function(v) {
+ normal = true;
+ SizeChange --= callee;
+ }
+
+ </ui:box>
+</ibex>
--- /dev/null
+<!-- Copyright 2004 - see COPYING for details [LGPL] -->
+
+<ibex>
+ <meta:doc>
+ See ibex.theme.focusable for more details
+
+ <author>Charles Goodwin</author>
+ <author>David Crawshaw</author>
+ </meta:doc>
+
+ <ui:box>
+
+ thisbox.enabled; // whether a focusable is enabled
+ thisbox.focusable; // whether a focusable may be focused
+ thisbox.focused; // whether a focusable is focused
+ thisbox.nextfocus; // read for the focus after thisbox on the surface
+ thisbox.prevfocus; // read for the focus before thisbox on the surface
+
+ // private function to assign to traps
+ var checkfocus = function(v) { if (!v and focused) focused = false; }
+
+ enabled ++= checkfocus; // disabling prevents focus
+ focusable ++= checkfocus; // making unfocusable prevents focus
+
+ // read trap to return focusable state
+ focusable ++= function() { return enabled and cascade; }
+
+ // write trap to set focused state
+ focused ++= function(v) {
+ if (v and surface and focusable) {
+ if (surface.focus) {
+ surface.focus.focused = false;
+ }
+ surface.focus = thisbox;
+ }
+ else if (!v and surface and surface.focus == thisbox)
+ surface.focus = null;
+ else cascade = false;
+ }
+
+ // read trap to return the focus after thisbox on the surface
+ nextfocus ++= function() { return surface.nextFocus(thisbox); }
+
+ // read trap to return the focus before thisbox on the surface
+ prevfocus ++= function() { return surface.prevFocus(thisbox); }
+
+ // write trap to handle surface change
+ surface ++= function(v) {
+ // drop from current surface if there is one
+ if (cascade) cascade.dropFocus(thisbox);
+
+ // add to new surface
+ v.addFocus(thisbox);
+ }
+
+ // write trap to focus on Press1
+ Press1 ++= function(v) { if (!focused and focusable) focused = true; }
+
+ </ui:box>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex>
+ <meta:doc>
+ Authors: Charles Goodwin, David Crawshaw
+
+ For documentation, see ibex.theme.surface
+ </meta:doc>
+
+ <ui:box>
+
+ var focus = null; // the current focus
+
+ // the focus list for this surface
+ var fvector = ibex..ibex.util.vector..newVector();
+ //var fvector = ibex..ibex.util.vector(ibex.box);
+
+ // read trap to access the focused child
+ surface.focus ++= function() { return focus; }
+
+ surface.setFocus ++= function(v) {
+ if (v and v.focusable and fvector.contains(v)) {
+ if (focus and focus != v) focus.focused = false;
+ return true;
+ }
+ else if (!v and focus) {
+ focus.focused = false;
+ return true;
+ }
+ else return false;
+ }
+
+ // function to add a focus to the focus vector, optionally after w
+ surface.addFocus = function(v, w) {
+ // make sure we're not already in the focus list
+ surface.dropFocus(v);
+
+ if (w and fvector.contains(w))
+ return fvector.insert(v, w);
+ else return fvector.push(v);
+ }
+
+ // function to drop a focus from the focus vector for this surface
+ surface.dropFocus = function(v) {
+ if (fvector.contains(v)) {
+ if (focus == v) focus = v.nextfocus;
+ return fvector.remove(v);
+ }
+ else return false;
+ }
+
+ // function to return the next-in-line for focus after v
+ surface.nextFocus ++= function(v) {
+ var nf = fvector.after(v);
+ while (!nf.focusable and nf != v) nf = fvector.after(nf);
+ return nf;
+ }
+
+ // function to return the previous-in-line for focus after v
+ surface.prevFocus ++= function(v) {
+ var pf = fvector.after(v);
+ while (!pf.focusable and pf != v) pf = fvector.before(pf);
+ return pf;
+ }
+
+ // private function to map events from this root ui:box onto the focused child
+ var passEvent = function(v) { if (focus) focus[trapname] = v; }
+
+ _KeyPressed ++= passEvent; // pass keypress events to focused child
+ _KeyReleased ++= passEvent; // pass keyrelease events to focused child
+
+ </ui:box>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex>
+ <meta:doc>
+ Author: Charles Goodwin
+ </meta:doc>
+
+ static.flip = function(f) {
+ if (f == "width") return "height";
+ else if (f == "height") return "width";
+ else if (f == "x") return "y";
+ else if (f == "y") return "x";
+ else if (f == "maxwidth") return "maxheight";
+ else if (f == "maxheight") return "maxwidth";
+ else if (f == "minwidth") return "minheight";
+ else if (f == "minheight") return "minwidth";
+ else if (f == "horizontal") return "vertical";
+ else if (f == "vertical") return "horizontal";
+ else if (f == "hshrink") return "vshrink";
+ else if (f == "vshrink") return "hshrink";
+ else if (f == "cols") return "rows";
+ else if (f == "rows") return "cols";
+ return null;
+ }
+
+ <ui:box>
+
+ thisbox.dim = "width";
+ thisbox.globalpos = "globalx";
+ thisbox.mindim = "minwidth";
+ thisbox.maxdim = "maxwidth";
+ thisbox.pos = "x";
+ thisbox.shr = "hshrink";
+ thisbox.flip = static.flip;
+
+ thisbox.orient ++= function(v) {
+ if (v == "horizontal") {
+ if (cols) rows = cols;
+ dim = "width";
+ maxdim = "maxwidth";
+ mindim = "minwidth";
+ pos = "x";
+ shr = "hshrink";
+ }
+ else {
+ if (rows) cols = rows;
+ dim = "height";
+ maxdim = "maxheight";
+ mindim = "minheight";
+ pos = "y";
+ shr = "vshrink";
+ }
+ }
+
+ </ui:box>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex>
+ <meta:doc>
+ See xwt.theme.redirect for details
+ </meta:doc>
+
+ <ui:box>
+
+ var locks = {};
+ var redirects = {};
+
+ thisbox.redirectTo = function(v) {
+ if (v == null) {
+ ibex.log.warn("Attempted to redirect properties to a null value");
+ return false;
+ }
+
+ for (var i=1; arguments.length > i; i++) {
+ // get property from arguments
+ var p = arguments[i];
+
+ // remove the trap if it already exists
+ if (redirects[p]) dropRedirect(v, p);
+
+ // create and store redirecting functions
+ redirects[p] = [v,
+ function(w) {
+ if (!locks[p]) { locks[p] = true; cascade = w; thisbox[p] = w; locks[p] = null; }
+ },
+ function(w) {
+ if (!locks[p]) { locks[p] = true; v[p] = w; locks[p] = null; }
+ return true;
+ },
+ function() { return v[p]; }];
+
+ // assign redirecting traps
+ try { // try/catch for properties that can't have write traps
+ thisbox[p] ++= redirects[p][2];
+ v[p] ++= redirects[p][1];
+ } catch(e) {
+ redirects[p][1] = null;
+ redirects[p][2] = null;
+ }
+ // try/catch for properties that can't have read traps
+ try { thisbox[p] ++= redirects[p][3]; }
+ catch(e) { redirects[p][3] = null; }
+ }
+
+ // report success
+ return true;
+ }
+
+ thisbox.dropRedirect = function(v) {
+ for (var i=1; arguments.length > i; i++) {
+ // get property from arguments
+ var p = arguments[i];
+
+ // remove redirect traps and reference
+ if (redirects[p]) {
+ if (redirects[p][1]) redirects[p][0] --= redirects[p][1];
+ if (redirects[p][2]) thisbox[p] --= redirects[p][2];
+ if (redirects[p][3]) thisbox[p] --= redirects[p][3];
+ redirects[p] = null;
+ }
+ }
+
+ return true;
+ }
+
+ </ui:box>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex>
+ <meta:doc>
+ Author: Charles Goodwin
+
+ See ibex.theme.repeatable for details
+ </meta:doc>
+
+ <ui:box>
+
+ thisbox.counter = 0; // consecutive repetition counter
+ thisbox.interval = 100; // repetition interval (ms)
+ thisbox.initialinterval; // the initial interval of a repeating action
+ thisbox.repeat; // repeating state
+
+ interval ++= function() {
+ // return interval for counter > 0 or initialinterval otherwise
+ return counter ? cascade : initialinterval ? initialinterval : cascade;
+ }
+
+ repeat ++= function(v) {
+ if (v) {
+ // only start if previously false
+ if (!repeat) {
+ cascade = v;
+
+ ibex.thread = function() {
+ while (repeat) {
+ action = true;
+ counter ++;
+ ibex.thread.sleep(interval);
+ }
+ }
+ }
+ }
+ else counter = 0;
+ }
+
+ </ui:box>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex>
+ <meta:doc>
+ Author: Charles Goodwin
+ </meta:doc>
+
+ <ui:box>
+
+ // public variables
+ thisbox.amount;
+ thisbox.hide;
+ thisbox.page;
+ thisbox.shift;
+ thisbox.slave;
+ thisbox.smart;
+
+ // theme box variables
+ thisbox.th_back;
+ thisbox.th_next;
+ thisbox.th_thumb;
+ thisbox.th_track;
+
+ // private variables
+ var listeners = {};
+ var motion;
+ var movefun1 = function(v) { th_thumb.action = true; }
+ var movefun2 = function(v) { recall["track"] = th_track.mouse[pos]; }
+ var recall = {};
+ var percent;
+
+ // attempt to shift slave by given amount
+ shift ++= function(v) {
+ motion = true;
+ slave[0][pos] = ibex.math.min(0, ibex.math.max(slave[dim] - slave[0][dim], slave[0][pos] - v));
+ syncThumb();
+ motion = false;
+ }
+
+ // set up slave
+ slave ++= function(v) {
+ v.SizeChange ++= slaveFunc;
+ v[0].PosChange ++= slaveFunc;
+ v[0].SizeChange ++= slaveFunc;
+
+ cascade = v;
+ syncThumb();
+ }
+
+ smart ++= function(v) { cascade = v; syncThumb(); }
+
+ th_back ++= function(v) { v.action ++= function(w) { shift = -1*amount; } }
+ th_next ++= function(v) { v.action ++= function(w) { shift = amount; } }
+
+ th_track ++= function(v) {
+ v.action ++= function(w) {
+ if (th_thumb[pos] > recall["track"]) shift = -1*page;
+ else if (recall["track"] > th_thumb[pos] + th_thumb[dim]) shift = page;
+ }
+
+ v.repeat ++= function(w) {
+ if (w) { Move ++= movefun2; movefun2(); }
+ else { Move --= movefun2; recall["track"] = null; }
+ }
+
+ v.SizeChange ++= function(w) { syncThumb(); }
+ }
+
+ th_thumb ++= function(v) {
+ v.action ++= function(w) {
+ th_thumb[pos] = ibex.math.max(0,
+ ibex.math.min(th_track[dim] - th_thumb[dim],
+ recall["thumb"] + (surface.mouse[pos] - recall["start"])));
+ syncSlave();
+ }
+
+ v.Press1 ++= function(w) {
+ motion = true;
+ recall["start"] = surface.mouse[pos];
+ recall["thumb"] = th_thumb[pos];
+ surface.Move ++= movefun1;
+ surface.Release1 ++= function(w) {
+ motion = false;
+ surface.Move --= movefun1;
+ surface.Release1 --= callee;
+ }
+ }
+ }
+
+ // public functions
+
+ thisbox.addListener = function(v) {
+ listeners[v] = [v, v[0]];
+ v.SizeChange ++= listenerFunc;
+ v[0].PosChange ++= listenerFunc;
+ v[0].SizeChange ++= listenerFunc;
+ syncAllListeners();
+ }
+
+ thisbox.removeListener = function(v) {
+ if (listeners[v] != null) {
+ listeners[v][0].SizeChange --= listenerFunc;
+ listeners[v][1].PosChange --= listenerFunc;
+ listeners[v][1].SizeChange --= listenerFunc;
+ listeners[v] = null;
+ }
+ }
+
+ // sync functions
+
+ var syncAllListeners = function(v) {
+ if (motion) {
+ for (key in listeners) {
+ if (v == listeners[key][0]) continue;
+ syncListener(listeners[key][0]);
+ }
+ }
+ }
+
+ var syncListener = function(v) {
+ percent = slave[0][pos] / (slave[dim] - slave[0][dim]);
+ if (v and v[0]) v[0][pos] = percent * (v[dim] - v[0][dim]);
+ }
+
+ var syncSlave = function() {
+ if (slave) {
+ percent = th_thumb[pos] / (th_track[dim] - th_thumb[dim]);
+ slave[0][pos] = percent * (slave[dim] - slave[0][dim]);
+ }
+ }
+
+ var syncThumb = function() {
+ if (slave == null || slave[0] == null || slave[dim] >= slave[0][dim]) {
+ if (enabled) enabled = false;
+ th_thumb[dim] = th_track[dim];
+ th_thumb[pos] = 0;
+ }
+ else {
+ if (!enabled) enabled = true;
+ th_thumb[dim] = ibex.math.min(th_track[dim], (slave[dim] / slave[0][dim]) * th_track[dim]);
+ percent = slave[0][pos] / (slave[dim] - slave[0][dim]);
+ th_thumb[pos] = ibex.math.max(0, (th_track[dim] - th_thumb[dim]) * percent);
+ }
+ }
+
+ // reusable functions
+
+ var listenerFunc = function(v) {
+ if (!motion and trapee.constrain) {
+ motion = true;
+ syncAllListeners(trapee);
+ syncSlave();
+ motion = false;
+ }
+ }
+
+ var slaveFunc = function(v) {
+ if (!motion) {
+ motion = true;
+ syncThumb();
+ syncAllListeners();
+ motion = false;
+ }
+ }
+
+ </ui:box>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex>
+ <meta:doc>
+ Author: Charles Goodwin
+ </meta:doc>
+
+ <ui:box>
+
+ thisbox.th_hscroll;
+ thisbox.th_vscroll;
+ thisbox.th_viewport;
+
+ th_viewport ++= function(v) {
+ th_hscroll.slave = v;
+ th_vscroll.slave = v;
+ }
+
+ </ui:box>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex>
+ <meta:doc>
+ Author: Charles Goodwin
+
+ See ibex.theme.selectable for documentation
+
+ TODO:
+ 1..n selection model with rolling selection
+ </meta:doc>
+
+ // static content
+
+ var groups = {}; // the groups of selectables
+
+ static.toGroup = function(v, oldg, g) {
+
+ // no group given, create group
+ if (3 > arguments.length) {
+ g = { members : (ibex..ibex.util.vector..newVector(v)),
+ selected : null, selection : [] };
+ //groups[g] = g;
+ groups[g] = g;
+ }
+ // validate group
+ else if (g and groups[g] != g) {
+ ibex.log.warn("Invalid group passed to toGroup: " + g + " " + groups[g]);
+ return oldg;
+ }
+
+ // remove v from oldg
+ if (oldg and g != oldg) {
+ oldg.members.remove(v);
+
+ // clean up group info
+ if (oldg.selection[v]) v.selected = false;
+
+ // clean up groups list
+ if (!oldg.members.length) groups[oldg] = null;
+ }
+
+ // add to group
+ if (g) {
+ if (g != oldg) g.members.push(v);
+ return g;
+ }
+ else return null;
+ }
+
+ // end of static content
+
+ <ui:box>
+
+ thisbox.mixed; // mixed status
+ thisbox.nextselect; // next group member to select
+ thisbox.prevselect; // previous group member to select
+ thisbox.selected; // selection status
+
+ var groupref; // internal reference to group
+
+ // group read trap
+ thisbox.group ++= function() {
+ // if no group, get one
+ if (!groupref) groupref = static.toGroup(thisbox);
+ return groupref;
+ }
+
+ // group write trap
+ thisbox.group ++= function(v) {
+ // add us to group v
+ groupref = static.toGroup(thisbox, groupref, v);
+ }
+
+ // selected read trap
+ thisbox.selected ++= function() {
+ if (mixed) return true;
+ else return cascade;
+ }
+
+ // selected write trap
+ thisbox.selected ++= function(v) {
+ if (groupref) {
+ if (v) {
+ if (groupref.selected != thisbox) {
+ if (groupref.selected) groupref.selected.selected = false;
+ groupref.selected = thisbox;
+ }
+ }
+ else if (groupref.selected == thisbox) groupref.selected = null;
+ }
+ }
+
+ // find the next selectable member
+ thisbox.nextselect ++= function() {
+ var ns = thisbox;
+ do {
+ ns = groupref.members.after(ns);
+ if (!ns) ns = groupref.members.first;
+ } while (!ns.enabled and ns != thisbox);
+
+ return ns.enabled ? ns : null;
+ }
+
+ // find the previous selectable member
+ thisbox.prevselect ++= function() {
+ var ps = thisbox;
+ do {
+ ps = groupref.members.before(ps);
+ if (!ps) ps = groupref.members.last;
+ } while (!ps.enabled and ps != thisbox);
+
+ return ps.enabled ? ps : null;
+ }
+
+ // integration with clickable
+ action ++= function(v) { selected = true; }
+
+ // integration with clickable and focusable
+ focusable ++= function() { return cascade and (primed or selected); }
+
+ // integration with focusable
+ nextfocus ++= function() {
+ var nf = cascade;
+ while (nf.group == groupref and nf != thisbox) nf = cascade;
+ return nf;
+ }
+
+ // integration with focusable
+ prevfocus ++= function() {
+ var pf = cascade;
+ while (pf.group == groupref and pf != thisbox) pf = cascade;
+ return pf;
+ }
+
+ </ui:box>
+</ibex>
--- /dev/null
+<!-- Copyright 2004 - see COPYING for details [LGPL] -->\r
+\r
+<ibex>\r
+ <meta:doc>\r
+ Author: Charles Goodwin\r
+ </meta:doc>\r
+\r
+ <ui:box>\r
+\r
+ // public variables\r
+\r
+ thisbox.interval; // user defined interval between steps\r
+ thisbox.lowerlimit; // the lower limit of the value range\r
+ thisbox.upperlimit; // the upper limit of the value range\r
+ thisbox.step; // the current step (integer)\r
+ thisbox.value; // the current value\r
+\r
+ // theme box traps\r
+\r
+ thisbox.th_track; // the track in which the slider runs\r
+ thisbox.th_handle; // the slider handle\r
+\r
+ // private variables\r
+\r
+ var numsteps; // the number of steps\r
+\r
+ // write trap adjust the step according to the mouse position\r
+ action ++= function(v) {\r
+ step = ibex.math.round(numsteps * (track[mousepos] - handle[dim] / 2) / (track[dim] - handle[dim]));\r
+ }\r
+\r
+ var synclimits = function(v) {\r
+ cascade = v;\r
+\r
+ // we need all of the following to be set\r
+ if (interval == null || lowerlimit == null || upperlimit == null) return;\r
+\r
+ // interval should to be a factor of (upperlimit - lowerlimit)\r
+ if ((upperlimit - lowerlimit) % interval)\r
+ ibex.println("WARNING: limit difference is not divisible by interval");\r
+ \r
+ // work out the number of steps\r
+ numsteps = (upperlimit - lowerlimit) / interval;\r
+ }\r
+\r
+ interval ++= synclimits;\r
+ lowerlimit ++= synclimits;\r
+ upperlimit ++= synclimits;\r
+\r
+ orient ++= function(v) {\r
+ arguments.cascade(v);\r
+ track[mindim] = 0;\r
+ track[flip(mindim)] = handle[flip(dim)];\r
+ }\r
+\r
+ step ++= function(v) {\r
+ // make sure step has a valid value\r
+ arguments.cascade((0 > v) ? 0 : (v > numsteps) ? numsteps : v);\r
+ // adjust the handle position according to the step\r
+ handle[pos] = step * (track[dim] - handle[dim]) / numsteps;\r
+ }\r
+\r
+ // read trap to return value based on current step\r
+ value ++= function() {\r
+ return ibex.math.min(lowerlimit + step * interval, upperlimit);\r
+ }\r
+\r
+ // write trap to set the step according to the given value\r
+ value ++= function(v) {\r
+ step = ibex.math.round((v - lowerlimit) / interval);\r
+ }\r
+\r
+ // theme box traps\r
+\r
+ handle ++= function(v) {\r
+ // always absolute so we can be moved\r
+ v.packed = false;\r
+\r
+ // make sure the widget always has the correct flip(dim)\r
+ v.SizeChange ++= function(v) {\r
+ track[flip(dim)] = handle[flip(dim)];\r
+ }\r
+ }\r
+\r
+ KeyPressed ++= function(v) {\r
+ if (v == "left" or v == "down") step -= 1;\r
+ else if (v == "right" or v == "up") step += 1;\r
+ }\r
+\r
+ Press1 ++= function(v) {\r
+ // activate the slider handle\r
+ var shift = surface.addEvent("_Move", thisbox, "Move");\r
+\r
+ /* argh what to do? */\r
+ if (root.Move == null) {\r
+ action = true;\r
+ root.Move = function() { action = true; }\r
+ root.Release1 = function() { root._Move = null; root._Release1 = null; }\r
+ }\r
+ }\r
+\r
+ </ui:box>\r
+</ibex>\r
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex>
+ <meta:doc>
+ Author: Charles Goodwin
+
+ FIXME:
+ - be more restrictive of puts to value
+ - value needs to be trappable
+ </meta:doc>
+
+ <ui:box>
+
+ // public variables
+
+ thisbox.interval; // interval by which up/down in/de-crement the result
+ thisbox.maxvalue; // maximum value of the result
+ thisbox.minvalue; // minimum value of the result
+ thisbox.precision; // number of decimal places of result
+
+ var is_int; // parse integeters or floats
+
+ // theme box variables
+
+ thisbox.th_less; // the button to decrement
+ thisbox.th_more; // the button to increment
+ thisbox.th_output; // the th_output for the result
+
+ // private function to get the value from a string
+ var parse = function(v) { return is_int ? ibex.math.parseInt(v) : ibex.math.parseFloat(v); }
+
+ // write trap to establish is_int based on interval
+ interval ++= function(v) { is_int = !(v % 1); }
+
+ KeyPressed ++= function(v) {
+ if (v == "down" or v == "DOWN") th_less.action = true;
+ else if (v == "up" or v == "UP") th_more.action = true;
+ }
+
+ value ++= function() { return ibex.string.parse(th_output.text); }
+
+ value ++= function(v) { th_output.text = "" + v; }
+
+ // theme box traps
+
+ th_less ++= function(v) {
+ v.action ++= function(v) {
+ th_output.text = "" + ibex.math.max(parse(th_output.text) - interval, minvalue);
+ }
+ }
+
+ th_more ++= function(v) {
+ v.action ++= function(v) {
+ th_output.text = "" + ibex.math.min(parse(th_output.text) + interval, maxvalue);
+ }
+ }
+
+ </ui:box>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex>
+ <meta:doc>
+ Surface:
+ Applied to every new surface (frame/window)
+ </meta:doc>
+
+ <ibex.lib.redirect />
+ <ui:box>
+
+ var s = {};
+
+ // proxy to the surface object
+ thisbox.surface ++= function() { return s; };
+
+ // root.distanceTo proxy function
+ s.distanceto = function(v) { return distanceto(v); }
+
+ // access to the surface mouse object
+ s.mouse ++= function() { return thisbox.mouse; }
+
+ // redirect events to the surface object for access
+ redirectTo(surface,
+ "Click1", "Click2", "Click3",
+ "DoubleClick1", "DoubleClick2", "DoubleClick3",
+ "KeyPressed", "KeyReleased",
+ "Move", "PosChange", "SizeChange",
+ "Press1", "Press2", "Press3",
+ "Release1", "Release2", "Release3");
+
+ </ui:box>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex>
+ <meta:doc>
+ Author: Charles Goodwin
+ </meta:doc>
+
+ <ui:box>
+
+ thisbox.th_head;
+ thisbox.th_content;
+
+ var tabgroup;
+
+ th_content ++= function(v) {
+ v.childadded ++= function(c) {
+ // create the tab if needed
+ if (!c.tab) {
+ if (!c.tab) c.tab = ibex..ibex.widget.tab(ibex.box);
+
+ if (!tabgroup) tabgroup = c.tab.group;
+ else c.tab.group = tabgroup;
+
+ c.tab.selected ++= function(s) {
+ cascade = s;
+ if (c.tab.selected and !c.visible) th_content.show = c;
+ }
+
+ c.tab.text = c.tabtext;
+
+ c.tabtext ++= function(t) {
+ c.tab.text = t;
+ }
+ }
+
+ // place the tab
+ th_head[v.indexof(c)] = c.tab;
+ }
+
+ v.show ++= function(c) {
+ cascade = c;
+ if (c.visible and !c.tab.selected) c.tab.selected = true;
+ }
+
+ th_content --= callee;
+ }
+
+ </ui:box>
+</ibex>
--- /dev/null
+<ibex xmlns:lib="ibex.lib">
+ // WARNING: more HACKs than a lumberjack
+
+ <org.ibex.theme.win2k.edit />
+ <ui:box shrink="true">
+ thisbox.splitable = true; // tells flow code that this object can be split or joined with another block
+ thisbox.block = true; // tells text code that this object exists inside a subfocus
+
+ thisbox.split = function(w) {
+ ibex.log.info("split called");
+ var pos = ibex..ibex.lib.text.edit..static.getpos(text, w, width, font, fontsize);
+ //var pos = static.getpos(text, w, width, font, fontsize);
+
+ // give new box requested text range
+ var newbox = ibex.box;
+ ibex.log.info("split called, box made");
+ ibex..ibex.lib.text.block(newbox);
+ newbox.text = text.substring(0, pos);
+ ibex.log.info("split called, applied block template and text given");
+
+ // give this box the remaining text
+ text = text.substring(pos);
+ ibex.log.info("split called, updated old box");
+
+ return newbox;
+ }
+ </ui:box>
+
+
+ // TODO: share with ibex.lib.text.edit
+ static.getpos = function(t, pxpos, pxlen, tfont, tsize) {
+ // short circuit extremes
+ if (0 >= pxpos) return 0;
+ if (pxpos >= pxlen) return t.length;
+
+ // inital guess based on average character width
+ var guessch = ibex.math.min(t.length, ibex.math.floor(pxpos / (pxlen / t.length)));
+ var guesspx = ibex.ui.font.width(tfont, tsize, t.substring(0, guessch));
+
+ if (guesspx > pxpos) {
+ while (guesspx > pxpos) {
+ // textwidth of individual character must account for font kerning
+ guesspx -= ibex.ui.font.width(tfont, tsize, t.substring(guessch -1, guessch +1));
+ guesspx += ibex.ui.font.width(tfont, tsize, t.charAt(guessch));
+ guessch--;
+ }
+ } else if (pxpos > guesspx) {
+ while (pxpos > guesspx) {
+ guessch++;
+ if (guessch >= t.length) break;
+ guesspx += ibex.ui.font.width(tfont, tsize, t.substring(guessch -1, guessch+1));
+ guesspx -= ibex.ui.font.width(tfont, tsize, t.charAt(guessch));
+ }
+ guessch--; // round down
+ }
+
+ return guessch;
+ }
+
+
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex>
+
+ // Returns number of chars the pixel position pos is into text t.
+ //
+ // Always rounds down.
+ //
+ // t : string -- basis for character counting
+ // pxpos : int -- pixel position on the text from string t
+ // pxlen : int -- pixel width of text t (often box width)
+ // tfont : font -- name of font used for width of text
+ // tsize : int -- size of font used for width of text
+ static.getpos = function(t, pxpos, pxlen, tfont, tsize) {
+ // short circuit extremes
+ if (0 >= pxpos) return 0;
+ if (pxpos >= pxlen) return t.length;
+
+ // inital guess based on average character width
+ var guessch = ibex.math.min(t.length, ibex.math.floor(pxpos / (pxlen / t.length)));
+ var guesspx = ibex.ui.font.width(tfont, tsize, t.substring(0, guessch));
+
+ if (guesspx > pxpos) {
+ while (guesspx > pxpos) {
+ // textwidth of individual character must account for font kerning
+ guesspx -= ibex.ui.font.width(tfont, tsize, t.substring(guessch -1, guessch +1));
+ guesspx += ibex.ui.font.width(tfont, tsize, t.charAt(guessch));
+ guessch--;
+ }
+ } else if (pxpos > guesspx) {
+ while (pxpos > guesspx) {
+ guessch++;
+ if (guessch >= t.length) break;
+ guesspx += ibex.ui.font.width(tfont, tsize, t.substring(guessch -1, guessch+1));
+ guesspx -= ibex.ui.font.width(tfont, tsize, t.charAt(guessch));
+ }
+ guessch--; // round down
+ }
+
+ return guessch;
+ }
+
+
+ <ui:box shrink="true">
+
+ // add and remove cursor traps as the cursor box changes
+ thisbox.cur ++= function(newcur) {
+ if (cur) {
+ cur.pos --= cur_pos;
+ cur.posx --= cur_posx_read;
+ cur.posx --= cur_posx_write;
+ }
+ if (newcur) {
+ newcur.pos ++= cur_pos;
+ newcur.posx ++= cur_posx_read;
+ newcur.posx ++= cur_posx_write;
+ }
+ }
+
+ // add and remove selection traps as the selection box changes
+ thisbox.sel ++= function(newsel) {
+ if (sel) {
+ sel.pos1 --= sel_pos1;
+ sel.pos2 --= sel_pos2;
+ }
+ if (newsel) {
+ newsel.pos1 ++= sel_pos1;
+ newsel.pos2 ++= sel_pos2;
+ }
+ }
+
+ // designed to trap cur.pos -- updates position of the cursor
+ // based on the character position stored in cur.pos
+ var cur_pos = function(newpos) {
+ //ibex.log.info("cur.pos trap put "+newpos+", text.length="+text.length);
+ if (newpos > text.length) newpos = text.length;
+ else if (0 > newpos) newpos = 0;
+
+ if (newpos > 0) ibex.thread = function() {
+ ibex.ui.font.wait(font, fontsize, text);
+ cur.x = ibex.ui.font.width(font, fontsize, text.substring(0, newpos));
+ } else cur.x = 0;
+
+ if (focused) cur.visible = true;
+ }
+
+ // designed to trap cur.posx --
+ // returns the pixel based position of the cursor
+ var cur_posx_read = function() { return cur.x; }
+
+ // designed to trap cur.posx -- updates cur.pos
+ // based on the pixel value stored in cur.posx
+ //
+ // this two-step put to the x value is designed to normalise
+ // the position of the cursor to being between characters
+ var cur_posx_write = function(newx) {
+ // calculate the cursor position in terms of characters
+ ibex.thread = function() {
+ ibex.ui.font.wait(font, fontsize, text);
+
+ // short circuit limits
+ if (0 >= newx) { cur.pos = 0; return; }
+ if (newx > width) { cur.pos = text.length; return; }
+
+ var pos = static.getpos(text, newx, width, font, fontsize);
+
+ // getpos always rounds down see if we can get closer
+ // to the mark by skipping over a char
+ if (text.length > pos) {
+ var diff = newx - ibex.ui.font.width(font, fontsize, text.substring(0, pos));
+ if (diff > ibex.ui.font.width(font, fontsize, text.charAt(pos)) / 2) pos++;
+ }
+
+ cur.pos = pos;
+ }
+ }
+
+ // designed to trap sel.pos1 -- resets the selection and
+ // prepares it to start again from the given character position
+ var sel_pos1 = function(v) {
+ sel.text = null;
+ }
+
+ // designed to trap sel.pos2 -- obtains the second selection
+ // position and
+ var sel_pos2 = function(v) {
+ ibex.log.info("pos2 trapped, new value="+v+", (pos1="+sel.pos1+")");
+ var p1, p2;
+ if (v > sel.pos1) { p1 = sel.pos1; p2 = v; }
+ else { p2 = sel.pos1; p1 = v; }
+
+ // update selected text
+ sel.text = text.substring(p1, p2);
+ sel.x = ibex.ui.font.width(font, fontsize, text.substring(0, p1));
+ }
+
+ // designed to be applied to thisbox.Move
+ var move = function(v) {
+ cur.posx = mouse.x;
+ ibex.thread = function() { sel.pos2 = cur.pos; }
+ }
+
+ focused ++= function(v) {
+ cur.visible = v;
+ }
+
+ Press1 ++= function(v) {
+ ibex.log.info("Press1 in ibex.lib.text");
+ cur.posx = mouse.x;
+ // TODO: enable selection
+ ibex.thread = function() {
+ sel.pos1 = cur.pos;
+ Move ++= move;
+ }
+ }
+
+ // TODO: use surface.Release1
+ Release1 ++= function(v) {
+ ibex.log.info("Release1 in ibex.lib.text");
+ Move --= move;
+ }
+
+ KeyPressed ++= function(v) {
+ ibex.log.info("KeyPressed called with value: "+v);
+
+ // TODO: check for casing and for prefix modifers (eg. C-Y, a-g)
+ if (v.length > 1) switch (v) {
+ // TODO
+ case "left": cur.pos--; return;
+ case "C-LEFT":
+ case "c-left": return;
+
+ case "right": cur.pos++; return;
+ case "C-RIGHT":
+ case "c-right": return;
+
+ case "home": cur.pos = 0; return;
+ case "end": cur.pos = text.length; return;
+ case "DELETE":
+ case "back_space":
+ text = text.substring(0, cur.pos - 1) + text.substring(cur.pos);
+ cur.pos--;
+ return;
+ case "BACK_SPACE":
+ case "delete":
+ text = text.substring(0, cur.pos) + text.substring(cur.pos + 1);
+ return;
+ case "shift": ibex.log.warn("not-yet-implemented"); return;
+ case "alt": ibex.log.warn("not-yet-implemented"); return;
+ case "ctrl": ibex.log.warn("not-yet-implemented"); return;
+ case "insert": ibex.log.warn("not-yet-implemented"); return;
+ case "tab": ibex.log.warn("not-yet-implemented"); return;
+ }
+
+ if (v.length == 1) {
+ ibex.log.info("KeyPressed resulting in text insertion of "+v);
+ text = text.substring(0, cur.pos) + v + text.substring(cur.pos);
+ cur.pos += v.length;
+ }
+ }
+ </ui:box>
+</ibex>
--- /dev/null
+<ibex>
+ <org.ibex.theme.win2k.focusable /> // HACK: should be in a better place
+ <ui:box align="topleft" fill="green" packed="false">
+ <ui:box id="content" rows="0" cols="1" shrink="true" align="topleft" fill="yellow" />
+
+ var packing = -1;
+
+ SizeChange ++= function(v) {
+ ibex.thread = function() { $content.maxwidth = thisbox.width; }
+ pack(0);
+ }
+ // TODO: align ++= function(a) { for (var i=0; $content.numchildren > i; i++) $content[i].align = a; }
+
+
+ var currentfocus = null; // HACK: for subfocus model
+ thisbox._KeyPressed ++= function(v) {
+ if (currentfocus) currentfocus.KeyPressed = v;
+ return true;
+ }
+
+ // creates an empty row, ready for insertion into $content
+ thisbox.row = function() {
+ var b = ibex.box;
+ b.shrink = true;
+ //b.align = thisbox.align;
+ b.align = "topleft";
+
+ var packtrap = function(v) { pack($content.indexof(b)); }
+ b.SizeChange ++= packtrap;
+
+ // ------------------------------------------------------
+ // HACK: quick and dirty subfocusing for text
+
+ var block_prevfocus = function() {
+ // find prev focusable in current row
+ var index = b.indexof(trapee);
+ if (index > 0) return b[index - 1];
+
+ // look in prev row
+ var r = $content.indexof(b);
+ if (r > 0 and $content[r - 1].numchildren > 0) return $content[r - 1][($content[r - 1].numchildren)];
+ }
+ var block_nextfocus = function() {
+ ibex.log.info("block_nextfocus: finding next focus");
+ // find next focusable in current row
+ var index = b.indexof(trapee);
+ if (b.numchildren - 1 > index) return b[index + 1];
+
+ // look in next row
+ var r = $content.indexof(b);
+ if ($content.numchildren - 1 > r and $content[r + 1].numchildren > 0) return $content[r + 1][0];
+ }
+ var block_curpos = function(v) {
+ if (0 > v) {
+ var movefocus = trapee.parent.prevfocus; // usage of HACK mentioned below
+ if (movefocus) {
+ trapee.parent.focused = false; movefocus.cur.pos = movefocus.text.length;
+ movefocus.focused = true; currentfocus = movefocus;
+ }
+ } else if (v > trapee.parent.text.length) {
+ ibex.log.info("stepped over right-hand block boundry");
+ var movefocus = trapee.parent.nextfocus;
+ if (movefocus) {
+ ibex.log.info("changing focus");
+ trapee.parent.focused = false; movefocus.cur.pos = 0;
+ movefocus.focused = true; currentfocus = movefocus;
+ }
+ }
+ }
+ var block_press1 = function(c) {
+ if (currentfocus != trapee) {
+ if (currentfocus) currentfocus.focused = false;
+ trapee.focused = true;
+ currentfocus = trapee;
+ }
+ }
+ b.childadded ++= function(c) {
+ c.prevfocus ++= block_prevfocus;
+ c.nextfocus ++= block_nextfocus;
+ c.cur.pos ++= block_curpos;
+ c.Press1 ++= block_press1;
+ c.cur.parent = c; // HACK: need for block_curpos above
+ }
+ b.childremoved ++= function(c) {
+ c.prevfocus --= block_prevfocus;
+ c.nextfocus --= block_nextfocus;
+ c.cur.pos --= block_curpos;
+ c.Press1 --= block_press1;
+ }
+ // ------------------------------------------------------
+
+ return b;
+ }
+
+ // HACK: clean this up conceptually
+ childadded ++= function(newc) { if (thisbox.indexof(newc) >= 0) add(newc); }
+
+ // add a block of text to the flow element
+ thisbox.add = function(b) {
+ if (1 > $content.numchildren) $content[0] = row();
+ var r = $content[$content.numchildren -1];
+
+ // HACK: for subfocus model
+ if (currentfocus) b.focused = false;
+ else { b.focused = true; currentfocus = b; }
+
+ r[r.numchildren] = b;
+ }
+
+ // launch the packNow function in a background thread
+ var pack = function(ind) {
+ if (packing == -1) {
+ packing = ind;
+ ibex.thread = packNow;
+ } else if (packing > ind) {
+ // background thread already queued, so just
+ // update location from which to start
+ packing = ind;
+ }
+ }
+
+ // pack the contents of this flow starting at row matching value of packing
+ var packNow = function() {
+ var ind = packing;
+ if (0 > ind) return;
+
+ // work through each row, packing them
+ ROW: for (; $content.numchildren > ind; ind++) {
+ ibex.log.debug("tag 2, ind="+ind);
+ var r = $content[ind];
+
+ // calculate excess width of row contents (negative to represent free space)
+ var w = 0;
+ for (var i=0; r.numchildren > i; i++) w += r[i].width;
+ w -= $content.maxwidth;
+
+ var nextr = ind+1;
+ ibex.log.debug("tag 3, w="+w+", nextr="+nextr+", $content.numchildren="+$content.numchildren);
+
+ if (0 > w and $content.numchildren > nextr) {
+ // attempt to pack contents from next row into current row
+ w = -1 * w;
+
+ // find first non-empty following row
+ var n = $content[nextr];
+ ibex.log.debug("tag 4, n==null?"+(n==null));
+ while (n != null and 1 > n.numchildren and $content.numchildren > nextr) {
+ n.thisbox = null; n = $content[nextr];
+ }
+ ibex.log.debug("tag 5 n.numchildren="+(n==null?-1:n.numchildren));
+ if (n == null || 1 > n.numchildren) break ROW;
+
+ // move up excess blocks
+ while (w > n[0].width) {
+ ibex.log.debug("r["+r.numchildren+"] = n[0] (n.numchildren="+n.numchildren+")");
+ w -= n[0].width; r[r.numchildren] = n[0];
+ debugState();
+ while (n.numchildren == 0) {
+ $content[nextr] = null;
+ debugState();
+ if (nextr >= $content.numchildren) break ROW;
+ n = $content[nextr];
+ }
+ }
+
+ ibex.log.debug("tag 6");
+
+ // attempt to split up final block
+ if (n.numchildren > 0 and n[0].splitable) {
+ var splitb = n[0].split(w);
+ if (splitb) r[r.numchildren] = splitb;
+ }
+
+ } else if (w > 0) {
+ // push row contents to next row
+ if (nextr == $content.numchildren) $content[$content.numchildren] = row();
+
+ // move off excess blocks
+ var b;
+ for (b = r[r.numchildren -1]; b != null and w > b.width; b = r[r.numchildren -1]) {
+ $content[nextr][0] = b;
+ w -= b.width;
+ }
+
+ if (b == null) continue ROW;
+
+ if (b.splitable) {
+ // attempt to split up final block
+ var newb = b.split(b.width - w);
+ if (newb != null) {
+ b.thisbox = null;
+ r[r.numchildren] = newb;
+ $content[nextr][0] = b;
+ continue;
+ }
+ }
+
+ // split failed
+ if (r.numchildren > 1) $content[nextr][0] = b;
+ else ibex.log.warn("box exceeds window limit"); // FIXME: how do we handle this?
+
+ ibex.log.debug("tag 10");
+ }
+
+ }
+
+ //ibex.log.debug(debugState());
+ packing = -1;
+ }
+
+ var debugState = function() {
+ var str = "---- DEBUG $content child="+$content.numchildren
+ + "maxwidth="+$content.width+", width="+$content.width+", height="+$content.height+"\n";
+ for (var i=0; $content.numchildren > i; i++) {
+ str += "$content["+i+"].numchildren="+$content[i].numchildren + "\n";
+ for (var j=0; $content[i].numchildren > j; j++) {
+ str += "$content["+i+"]["+j+"] text="+$content[i][j].text
+ + " width="+$content[i][j].width+", height="+$content[i][j].height+"\n";
+ }
+ }
+ str += "----";
+ return str;
+ }
+
+ </ui:box>
+</ibex>
--- /dev/null
+<ibex xmlns:win2k="org.ibex.theme.win2k" xmlns:lib="ibex.lib">
+ <lib:clickable enabled="true" />
+ <win2k:button enabled="true" repeats="false" />
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns:lib="ibex.lib" xmlns:theme="ibex.theme">
+ <meta:doc>
+ Clickable:
+ A template for a clickable widget that also integrates
+ well with focusable widgets
+
+ Usage:
+ - Trap action to implement the action of your widget
+ - Trap active, hover, and normal to set the visible state
+
+ Properties:
+ action ---- : the widgets action
+ active ---- : the active state
+ activated - : when activated but not necessarily active
+ enabled --- : enables/disables widget
+ hover ----- : when the mouse hovers over the widget
+ normal ---- : the normal state of the widget
+ repeats --- : whether this is a repeating action on mousedown
+
+ See also:
+ ibex.theme.focusable
+ ibex.theme.repeatable
+ </meta:doc>
+
+ <theme:repeatable />
+ <lib:clickable enabled="true" repeats="false" />
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex>
+ <meta:doc>
+ Simple text widget. Provides standard cursor and selection tools
+ for editing the text contents of this template.
+
+ Single line, single font, single size.
+
+ Designed to have focusable applied.
+
+ Properties:
+ text : string : Text to edit.
+ font : font : Font to use displaying the text.
+ fontsize : integer : Size of the font to use displaying the text.
+ textcolor : color : Color to use displaying the text.
+ </meta:doc>
+
+ <ui:box />
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns="ibex.lib">
+ <meta:doc>
+ Registers a ui:box as focusable with its surface.
+
+ When a ui:box is focused, it holds the event focus for the surface
+ (capable of receiving key and mouse events).
+
+ A ui:box may have its focused state changed at any time by the
+ surface manging the focus, unless the property focusable is set to
+ false.
+
+ Properties:
+ focused : boolean : True if thisbox has the event focus.
+ focusable : boolean : True if thisbox may accept the event focus.
+
+ See also:
+ ibex.theme.surface
+ </meta:doc>
+
+ <focusable />
+</ibex>
--- /dev/null
+<ibex>
+ <ui:box>
+ ibex.log.warn("this shouldn't happen either");
+ </ui:box>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns="ibex.lib">
+ <meta:doc>
+ Repeater:
+ Invokes an action repeatedly
+
+ Usage:
+ - Implement action += with the desired behaviour
+ - Put [true|false] to repeat to [start|stop]
+
+ Properties:
+ initialinterval - : if you want an initial pause
+ interval -------- : repeat after this many ms
+ repeat ---------- : repeating state
+ </meta:doc>
+
+ <repeatable />
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns="ibex.lib">
+ <meta:doc>
+ Selectable:
+ Enables a widget as part of a group of selectable widgets
+ which may be mutually selectable either exclusively or as
+ as an (optionally limited) exclusive group
+
+ Usage:
+ Group selectable widgets together by putting a group to
+ $widget.group (order is important):
+
+ $sel3.group = $sel2.group = $sel1.group;
+
+ Properties:
+ group ---- : the selection group a widget belongs to
+ selected - : if a widget is selected
+ </meta:doc>
+
+ <selectable />
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns="ibex.lib">
+ <redirect />
+ <surface />
+ <focusmanager />
+</ibex>
--- /dev/null
+<!-- Copyright 2003 Charles Goodwin
+ LGPL - see COPYING for details -->
+
+<ibex>
+ <meta:doc>
+ ibex.util.group
+ A utility for grouping together widgets that wish to be affiliated
+ with each other in an arbitrary fashion
+
+ Usage
+ Call ibex.util.group..newGroup((str)name) to create a new 'super
+ group' and use to ibex.util.group..syncGroup() to create and group
+ widgets together
+ </meta:doc>
+
+ // reference for super groups
+ var groups = {};
+
+ // v - widget to group
+ // s - super group
+ // g - sub group
+ memberInsert = function(v, s, g) {
+
+ // if necessary, create the supergroup
+ if (!groups[s]) groups[s] = [];
+
+ // if no subgroup specified, create one
+ if (3 > arguments.length)
+ groups[s][groups[s].length] = g = { members : ibex.util.vector..newVector([m]) };
+ }
+
+ memberPosition = function(v, s, g) {
+ /* TODO */
+ }
+
+ // v - widget to group
+ // s - super group
+ // g - sub group
+ memberRemove = function(v, s, g) {
+ /* TODO */
+ }
+
+ <ui:box>
+
+ /* TODO */
+
+ </ui:box>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex>
+ <meta:doc>
+ ibex.util.list
+ An ordered array for quick removal and retreival of elements. It uses
+ binary insertion to keep the array ordered, and a binary retrieval to
+ quickly find an elements position in the ordered array.
+
+ Usage
+ Call ibex.util.list..newList() to create and return a new list, optionally
+ passing it an array of elements to initialise the list with.
+ </meta:doc>
+
+ // inserts an element at the correct position in the list
+ elementInsert = function(v, list) {
+ // initial checks to see whether position lies within the list
+ if (list[0] > v) list.unshift(v);
+ else if (v >= list[list.length - 1]) list.push(v);
+ // find insertion position in the list
+ else {
+ var low, mid = 0;
+ var end = list.length - 1;
+
+ while (true) {
+ mid = ibex.math.floor(low + (end - low) / 2);
+
+ if (list[mid] > v)
+ if (v > list[low]) end = mid;
+ else list.splice(low + 1, 0, [v]);
+ else if (v > list[mid]) low = mid;
+ else list.splice(mid + 1, 0, [v]);
+ }
+ }
+ }
+
+ // returns an elements position in the list
+ elementPosition = function(v, list) {
+ // initial check to see whether v is in the list
+ if (list[0] > v || v > list[list.length - 1]) return null;
+ // find our position within the list
+ else {
+ var low, mid = 0;
+ var end = list.length - 1;
+
+ while (true) {
+ mid = ibex.math.floor(low + (end - low) / 2);
+
+ if(list[mid] > v)
+ if (v > list[low]) end = mid;
+ else return low;
+ else if (v > list[mid])
+ if (lost[end] > v) low = mid;
+ else return end;
+ else return mid;
+ }
+ }
+ }
+
+
+ // removes an element from the list
+ elementRemove = function(v, list) {
+ var pos = elementPosition(v, list);
+ if (pos) list.splice(pos, 1);
+ }
+
+ // creates and returns a new list, with optional initial elements
+ newList += function(v) {
+ // create and store list
+ var nl = ibex..ibex.util.list(ibex.box);
+
+ // insert elements if given
+ if (arguments.length)
+ for (var i = 0; v.length > i; i++)
+ nl.elementInsert(v[i]);
+
+ // return newly created list
+ return nl;
+ }
+
+ <ui:box>
+
+ // store elements in this array
+ var elements = [];
+
+ // returns the length of the list
+ thisbox.length ++= function() { return elements.length; }
+
+ // inserts argument v into the list
+ thisbox.insert ++= function(v) { static.elementInsert(v, elements); cascade = null; }
+
+ // removes argument v from the list
+ thisbox.remove ++= function(v) { static.elementRemove(v, elements); cascade = null; }
+
+ // returns the position of v in the list
+ thisbox.position ++= function() { return static.elementPosition(thisbox, elements); }
+
+ </ui:box>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex>
+ <meta:doc>
+ Maintainer:
+ Contributer:
+ </meta:doc>
+
+ <ui:box>
+
+ </ui:box>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex>
+ <meta:doc>
+ Author: Charles Goodwin
+
+ TODO:
+ Add move(v) function
+ </meta:doc>
+
+ // start of static content
+
+ newVector = function(v) {
+ var new_vec = ibex.box;
+ ibex..ibex.util.vector(new_vec);
+ if (v) new_vec.push(v);
+ return new_vec;
+ }
+
+ // end of static content
+
+ <ui:box>
+
+ var elements = {}; // hash containing all our elements
+ var obj1; // the first (#1) object in elements
+ var objn; // the nth (last) object in elements
+ var count = 0; // counts the number of elements
+
+ // private function to add to an empty elements
+ var addtoempty = function(v) {
+ elements[v] = { self: v };
+ obj1 = objn = v;
+ ++count;
+ return true;
+ }
+
+ // private function to leave elements empty
+ var makesempty = function(v) {
+ elements[v] = null;
+ obj1 = objn = null;
+ --count;
+ return true;
+ }
+
+ // read trap to return the first object in elements
+ thisbox.first ++= function() { return obj1; }
+
+ // read trap to return the last object in elements
+ thisbox.last ++= function() { return objn; }
+
+ // read trap to return the length of elements
+ thisbox.length ++= function() { return count; }
+
+ // function to return the object after v in elements
+ thisbox.after = function(v) { return elements[v].next ? elements[v].next.self : null; }
+
+ // function to return the object before v in elements
+ thisbox.before = function(v) { return elements[v].prev ? elements[v].prev.self : null; }
+
+ // function to check where elements contains v
+ thisbox.contains = function(v) { return elements[v] ? true : false; }
+
+ // function to insert v optionally after w
+ thisbox.insert = function(v, w) {
+ if (arguments.length == 1) return push(v);
+ else if (!elements[v] and elements[w]) {
+ elements[v] = { next: elements[w].next, prev: w, self: v };
+ elements[elements[w].next].prev = v;
+ elements[w].next = v;
+ ++count;
+ return true;
+ }
+ else return false;
+ }
+
+ // function to remove v
+ thisbox.remove = function(v) {
+ if (elements[v]) {
+ if (count == 1) return makesempty(v);
+ else {
+ elements[elements[v].prev].next = elements[v].next;
+ elements[elements[v].next].prev = elements[v].prev;
+ elements[v] = null;
+ --count;
+ return true;
+ }
+ }
+ else return false;
+ }
+
+ // function to pop last object from elements
+ thisbox.pop = function() {
+ if (count == 1) return makesempty(objn);
+ else if (count) {
+ var drop = objn;
+ elements[elements[objn].prev].next = null;
+ elements[drop] = null;
+ objn = elements[elements[drop].prev].self;
+ --count;
+ return drop;
+ }
+ else return null;
+ }
+
+ // function to push v onto the end of elements
+ thisbox.push = function(v) {
+ if (!count) return addtoempty(v);
+ else if (!elements[v]) {
+ elements[v] = { prev: elements[objn], self: v };
+ elements[objn].next = elements[v];
+ objn = v;
+ ++count;
+ return true;
+ }
+ return false;
+ }
+
+ // function to shift first object from elements
+ thisbox.shift = function() {
+ if (count == 1) return makesempty(obj1);
+ else if (count) {
+ var drop = obj1;
+ elements[elements[drop].next].prev = null;
+ elements[drop] = null;
+ obj1 = elements[elements[drop].next].self;
+ --count;
+ return drop;
+ }
+ else return null;
+ }
+
+ // function to unshfit v onto the front of elements
+ thisbox.unshift = function(v) {
+ if (!count) return addtoempty(v);
+ else if (!elements[v]) {
+ elements[v] = { next: elements[obj1], self: v };
+ elements[obj1].prev = elements[v];
+ obj1 = v;
+ ++count;
+ return true;
+ }
+ else return false;
+ }
+
+ </ui:box>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns="org.ibex.theme.win2k">
+ <meta:doc>
+ <name>Basic Button</name>
+ <desc>Creates a button widget</desc>
+ <usage>
+ Put to the text property of a button for a basic label,
+ or simply wrap the button around more complex content
+ </usage>
+ </meta:doc>
+
+ <redirect />
+ <margin redirect="$content">
+ <bevel form="up" id="widget">
+ <pad id="pad">
+ <ui:box id="content" />
+ </pad>
+ </bevel>
+
+ // glue code
+
+ redirectTo($content, "fill", "text", "textcolor");
+ redirectTo($pad, "padding", "padding-left", "padding-right", "padding-top", "padding-bottom");
+ redirectTo($widget, "form");
+
+ if ($widget.margin) thisbox.margin = $widget.margin;
+ if ($widget.padding) $content.padding = $widget.padding;
+
+ </margin>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns:theme="org.ibex.theme.win2k">
+ <meta:doc>
+ <name>Border Widget</name>
+ <desc>Adds a border to your boxes</desc>
+ <usage>
+ For Images:
+ Putting to image will create a border from the contents of
+ a directory of the same name; the directory is expected
+ to contain 8 images - nw, nn, ne, ww, ee, sw, ss, se -
+ which combine to form the border
+
+ Fill and depth:
+ putting to fill and depth will create a border the colour
+ of fill and the size of depth
+ </usage>
+ </meta:doc>
+
+ <theme:border />
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns="org.ibex.theme.win2k">
+ <meta:doc>
+ <name>Basic Button</name>
+ <desc>Creates a button widget</desc>
+ <usage>
+ Put to the text property of a button for a basic label,
+ or simply wrap the button around more complex content
+ </usage>
+ </meta:doc>
+
+ <redirect />
+ <margin redirect="$content" shrink="true">
+ <button id="widget">
+ .clickable(thisbox);
+ .focusable(thisbox);
+ <pad id="pad">
+ <ui:box id="content" />
+ </pad>
+ </button>
+
+ // glue code
+
+ redirectTo($content, "text", "textcolor");
+ redirectTo($pad, "padding", "padding-left", "padding-right", "padding-top", "padding-bottom");
+ redirectTo($widget, "action", "enabled", "fill");
+
+ if ($widget.margin) thisbox.margin = $widget.margin;
+ if ($widget.padding) $pad.padding = $widget.padding;
+
+ $widget.textcolor ++= function(v) { $content.textcolor = v; }
+
+ </margin>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex>
+ <meta:doc>
+ Author: Charles Goodwin
+ </meta:doc>
+
+ <org.ibex.theme.win2k.cardpane />
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns="org.ibex.theme.win2k">
+ <meta:doc>
+ <name>Check Box</name>
+ <desc>Creates a check box widget</desc>
+ <usage>
+ Put to the text property of a check for a basic label,
+ or simply wrap the check around more complex content
+ </usage>
+ </meta:doc>
+
+ <redirect />
+ <margin redirect="$content" shrink="true">
+ <check id="widget">
+ .clickable(thisbox);
+ .focusable(thisbox);
+ <pad id="pad">
+ <ui:box id="content" />
+ </pad>
+ </check>
+
+ // glue code
+
+ redirectTo($content, "text", "textcolor");
+ redirectTo($pad, "padding", "padding-left", "padding-right", "padding-top", "padding-bottom");
+ redirectTo($widget, "enabled", "fill", "group", "selected");
+
+ if ($widget.margin) thisbox.margin = $widget.margin;
+ if ($widget.padding) $pad.padding = $widget.padding;
+
+ $widget.textcolor ++= function(v) { $content.textcolor = v; }
+
+ </margin>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns:theme="org.ibex.theme.win2k">
+ <meta:doc>
+ <name>Label Widget</name>
+ <desc>A label with text flow and inline images</desc>
+ <author>David Crawshaw</author>
+ </meta:doc>
+
+ <theme:redirect />
+ <theme:focusable />
+ <theme:margin focusable="true" focused="false" vshrink="true">
+ <theme:pad id="pad">
+ <theme:edit id="widget" />
+ </theme:pad>
+
+ // glue code
+ redirectTo($pad, "padding", "padding-left", "padding-right", "padding-top", "padding-bottom");
+ redirectTo($widget, "focusable", "focused", "text", "textcolor", "font", "fontsize", "editable");
+
+ </theme:margin>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex>
+ <meta:doc>
+ Author: Charles Goodwin
+ </meta:doc>
+
+ <ibex.theme.margin />
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex>
+ <meta:doc>
+ Author: Charles Goodwin
+ </meta:doc>
+
+ <ibex.theme.pad />
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns="org.ibex.theme.win2k">
+ <meta:doc>
+ <name>Radio Button</name>
+ <desc>Creates a radio button widget</desc>
+ <usage>
+ Put to the text property of a radio for a basic label,
+ or simply wrap the radio around more complex content
+ </usage>
+ </meta:doc>
+
+ <redirect />
+ <margin redirect="$content" shrink="true">
+ <radio id="widget">
+ .clickable(thisbox);
+ .focusable(thisbox);
+ .selectable(thisbox);
+ <pad id="pad">
+ <ui:box id="content" />
+ </pad>
+ </radio>
+
+ // glue code
+
+ redirectTo($content, "text", "textcolor");
+ redirectTo($pad, "padding", "padding-left", "padding-right", "padding-top", "padding-bottom");
+ redirectTo($widget, "enabled", "fill", "group", "selected");
+
+ if ($widget.margin) thisbox.margin = $widget.margin;
+ if ($widget.padding) $pad.padding = $widget.padding;
+
+ $widget.textcolor ++= function(v) { $content.textcolor = v; }
+
+ </margin>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns:theme="org.ibex.theme.win2k">
+ <meta:doc>
+ <name>Property Redirect</name>
+ <desc>A widget used to redirect properties to another box</desc>
+ <usage>
+ Pass the a {property:target} list to addredirect:
+ $redirect.addredirect = {p1:$t1, p2:$t2, p3:$t3};
+
+ Similarly use delredirect to remove redirections.
+ </usage>
+ </meta:doc>
+
+ <theme:redirect />
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns:theme="org.ibex.theme.win2k">
+ <meta:doc>
+ <name>Scrollbar</name>
+ <desc>A scrollbar widget, commonly found in scrollpanes</desc>
+ <usage>
+ Put to the text property of a button for a basic label,
+ or simply wrap the button around more complex content
+ </usage>
+ </meta:doc>
+
+ <theme:redirect />
+ <theme:margin redirect="null" orient="horizontal">
+ <theme:scrollbar id="widget">
+ ibex..org.ibex.theme.win2k.polarizable(thisbox);
+ </theme:scrollbar>
+
+ // glue code
+
+ redirectTo($widget, "orient", "slave");
+
+ if ($widget.margin) thisbox.margin = $widget.margin;
+ if ($widget.padding) $content.padding = $widget.padding;
+
+ //var shrfun = function(v) { ibex.log.info(trapname); }
+ //$widget.shrink ++= shrfun;
+ //$widget.hshrink ++= shrfun;
+ //$widget.vshrink ++= shrfun;
+
+ $widget.SizeChange ++= function(v) { thisbox.hshrink = $widget.hshrink; thisbox.vshrink = $widget.vshrink; }
+
+ </theme:margin>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns:theme="org.ibex.theme.win2k">
+ <meta:doc>
+ <name>Scrollbar</name>
+ <desc>A scrollbar widget, commonly found in scrollpanes</desc>
+ <usage>
+ Put to the text property of a button for a basic label,
+ or simply wrap the button around more complex content
+ </usage>
+ </meta:doc>
+
+ <theme:redirect />
+ <theme:margin redirect="$content">
+ <theme:scrollpane id="widget">
+ <theme:pad id="pad">
+ <ui:box id="content" />
+ </theme:pad>
+ </theme:scrollpane>
+
+ // glue code
+
+ addredirect = { fill: $content };
+ addredirect = { padding: $pad };
+
+ if ($widget.margin) thisbox.margin = $widget.margin;
+ if ($widget.padding) $pad.padding = $widget.padding;
+
+ </theme:margin>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns="org.ibex.theme.win2k">
+ <meta:doc>
+ <name>Slider Widget</name>
+ <desc>Creates a sliding value selector</desc>
+ <usage>
+ </usage>
+ </meta:doc>
+
+ <redirect />
+ <margin redirect="null" shrink="true">
+ <pad id="pad">
+ <slider id="widget">
+ .clickable(thisbox);
+ .focusable(thisbox);
+ </slider>
+ </pad>
+
+ // glue code
+
+ redirectTo($pad, "fill", "padding", "padding-left", "padding-right", "padding-top", "padding-bottom");
+ redirectTo($widget, "enabled", "maxvalue", "minvalue", "value");
+
+ if ($widget.margin) thisbox.margin = $widget.margin;
+ if ($widget.padding) $pad.padding = $widget.padding;
+
+ $widget.textcolor ++= function(v) { $content.textcolor = v; }
+
+ </margin>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns="org.ibex.theme.win2k">
+ <meta:doc>
+ <name>Spin Widget</name>
+ <desc>Creates a spin value selector</desc>
+ <usage>
+ </usage>
+ </meta:doc>
+
+ <redirect />
+ <margin redirect="null" shrink="true">
+ <spin id="widget">
+ .clickable(thisbox);
+ .focusable(thisbox);
+ th_output = $content;
+ <pad id="pad">
+ <ui:box id="content" />
+ </pad>
+ </spin>
+
+ // glue code
+
+ redirectTo($content, "textcolor");
+ redirectTo($pad, "fill", "padding", "padding-left", "padding-right", "padding-top", "padding-bottom");
+ redirectTo($widget, "enabled", "interval", "maxvalue", "minvalue", "value");
+
+ if ($widget.margin) thisbox.margin = $widget.margin;
+ if ($widget.padding) $pad.padding = $widget.padding;
+
+ </margin>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns="org.ibex.theme.win2k">
+ <meta:doc>
+ <name>Tab</name>
+ <desc>A tab for use in a tabpane</desc>
+ <usage>
+ Tabpane automatically manages tabs, so for most circumstances
+ you will not be wanting to use this widget manually
+ </usage>
+ </meta:doc>
+
+ <redirect />
+ <margin redirect="$content" selected="false">
+ <tab id="widget">
+ .clickable(thisbox);
+ .focusable(thisbox);
+ .selectable(thisbox);
+ <pad id="pad">
+ <ui:box id="content" />
+ </pad>
+ </tab>
+
+ // glue code
+
+ redirectTo($content, "text", "textcolor");
+ redirectTo($pad, "fill", "padding", "padding-left", "padding-right", "padding-top", "padding-bottom");
+ redirectTo($widget, "group", "selected");
+
+ if ($widget.margin) thisbox.margin = $widget.margin;
+ if ($widget.padding) $pad.padding = $widget.padding;
+
+ </margin>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns="org.ibex.theme.win2k">
+ <meta:doc>
+ <name>Tabpane</name>
+ <desc>Creates a tabpane wigdet for tabbing between views</desc>
+ <usage>
+ Each child box of a tabpane is used as a card with a tab,
+ with the tabtext property of each card defining tab text
+ </usage>
+ </meta:doc>
+
+ <redirect />
+ <margin redirect="$content">
+ <tabpane id="widget">
+ th_content = $content;
+ <pad id="pad">
+ <cardpane id="content" />
+ </pad>
+ </tabpane>
+
+ // glue code
+
+ redirectTo($content, "show");
+ redirectTo($pad, "padding", "padding-left", "padding-right", "padding-top", "padding-bottom");
+ redirectTo($widget, "fill");
+
+ if ($widget.margin) thisbox.margin = $widget.margin;
+ if ($widget.padding) $pad.padding = $widget.padding;
+
+ </margin>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex>
+ <box>
+ ibex..ibex.theme.textarea(.focusable(thisbox));
+ </box>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns:theme="org.ibex.theme.win2k">
+ <theme:redirect />
+ <theme:focusable />
+ <theme:margin fill="white" vshrink="true">
+ <theme:bevel id="pad" form="down">
+ <theme:edit id="widget" />
+ </theme:bevel>
+
+ redirectTo($pad, "padding", "padding-left", "padding-right", "padding-top", "padding-bottom");
+ redirectTo($widget, "focusable", "focused", "text", "textcolor", "font", "fontsize");
+ </theme:margin>
+</ibex>
--- /dev/null
+<ibex>
+ <org.ibex.test.alpha1 />
+/*
+ ibex.log.info("Starting widget test suite...");
+
+ // clone the ibex resource to create our environment
+ var ibex_world = ibex.clone(ibex);
+ ibex.log.info("Successfully cloned environment");
+
+ // clone the ibex namespace within our environent
+ var ibex_res = ibex.clone(ibex..ibex);
+ ibex.log.info("Succesfully did resource clone");
+
+ // trap the theme namespace to return the desired theme
+ ibex_res.theme ++= function() { return ibex..org.ibex.theme.win2k; }
+ ibex.log.info("Successfully themed environment");
+
+ // trap the ibex namespace to return our themed namespace
+ ibex_world..ibex ++= function() { return ibex_res; }
+ ibex.log.info("Successfully themed resource environment");
+
+ // instantiate our application in the themed environment
+ ibex_world..org.ibex.test.alpha(ibex.box);
+ ibex.log.info("Successfully initiated test suite");
+*/
+</ibex>
--- /dev/null
+<ibex>\r
+ <ui:box text="Checkers">\r
+ \r
+ </ui:box>\r
+</ibex>
\ No newline at end of file
--- /dev/null
+<ibex>\r
+ <ui:box text="Chess">\r
+ \r
+ </ui:box>\r
+</ibex>
\ No newline at end of file
--- /dev/null
+<ibex xmlns:theme="ibex.theme"
+ xmlns="org.ibex.theme.win2k"
+ xmlns:games="org.ibex.games"
+ xmlns:reversi="org.ibex.games.reversi">
+<ui:box cols="8" >
+for (var i = 1; i lt 9; i++) {
+ for (var j= 1; j lt 9;j++) {
+
+ thisbox[thisbox.numchildren] = ibex.box;
+ var child = ibex..org.ibex.games.reversi.square(thisbox[thisbox.numchildren - 1]);
+ child.boardx=i;
+ child.boardy=j;
+ child.pos=j + (i -1) * 8;
+ }
+}
+
+
+</ui:box>
+</ibex>
\ No newline at end of file
--- /dev/null
+<ibex xmlns:theme="ibex.theme" \r
+ xmlns="ibex.widget"\r
+ xmlns:games="org.ibex.games"\r
+ xmlns:reversi="org.ibex.games.reversi">\r
+\r
+ <ui:box cols="3" shrink="false">\r
+ <ui:box fill="white" shrink="false"/>\r
+ <ui:box fill="white" shrink="false"/>\r
+ <ui:box fill="white" shrink="false"/>\r
+ <ui:box fill="white" shrink="false" cols="1">\r
+ <button text="New Game" >\r
+ Press1 ++= function(f) {\r
+ ibex.log.info("starting new game");\r
+// $reversiboard[31].fill=".org.ibex.games.reversi.dark_stone";\r
+ }\r
+ </button>\r
+\r
+ </ui:box>\r
+ <reversi:board fill="white"/>\r
+ <ui:box fill="white" shrink="false"/>\r
+ <ui:box fill="white" shrink="false"/>\r
+ <ui:box fill="white" shrink="false"/>\r
+ <ui:box fill="white" shrink="false"/>\r
+ <ui:box/>\r
+ </ui:box>\r
+</ibex>
\ No newline at end of file
--- /dev/null
+<ibex xmlns:theme="ibex.theme" \r
+ xmlns="org.ibex.theme.win2k" \r
+ xmlns:games="org.ibex.games"\r
+ xmlns:reversi="org.ibex.games.reversi">\r
+\r
+<ui:box shrink="true" fill="black">\r
+Press1 ++= function (f) {\r
+ibex.log.info("caught click: " + f + " on box");\r
+ibex.log.info("color is: " + thisbox.color);\r
+}\r
+\r
+pos ++= function(p)\r
+{\r
+//if both are even or both are odd, be lighter color\r
+if ( (thisbox.boardx/2 == ibex.math.round(thisbox.boardx/2) and\r
+ thisbox.boardy/2 == ibex.math.round(thisbox.boardy/2)) or\r
+ (thisbox.boardx/2 != ibex.math.round(thisbox.boardx/2) and\r
+ thisbox.boardy/2 != ibex.math.round(thisbox.boardy/2))\r
+ ) {\r
+ thisbox.fill="#1E9393";\r
+ } \r
+else {\r
+ thisbox.fill="#0D8080";\r
+ }\r
+}\r
+\r
+<bevel form="up">\r
+<ui:box width="50" height="50" />\r
+\r
+\r
+</bevel>\r
+</ui:box>\r
+</ibex>
\ No newline at end of file
--- /dev/null
+<ibex xmlns:widget="org.ibex.theme.win2k" xmlns="org.ibex.test">
+ <ui:box cols="1">
+
+ <ui:box cols="1" text="no text widget, no copy"/>
+ <ui:box cols="1" text="no text widget, no paste"/>
+ </ui:box>
+</ibex>
+
--- /dev/null
+<ibex xmlns:widget="org.ibex.theme.win2k" xmlns="org.ibex.test">
+ <ui:box cols="1">
+ <ui:box cols="1" text="no color picker"/>
+ </ui:box>
+</ibex>
+
--- /dev/null
+<ibex xmlns:widget="org.ibex.theme.win2k" xmlns="org.ibex.test">
+ <ui:box cols="3">
+
+ <ui:box cols="1">
+ <ui:box text="no tree widget">
+ </ui:box>
+ <ui:box height="4" fill="black"/>
+ <ui:box>
+ <ui:box cols="3">
+ <ui:box text="Group"/>
+ <ui:box shrink="true" cols="1">
+ $r2.group = $r1.group;
+ $r3.group = $r1.group;
+ $r4.group = $r1.group;
+ // r1.group = $r2.group = $r3.group = $r4;
+ <radio text="radio button 1" id="r1"/>
+ <radio text="radio button 2" id="r2"/>
+ <radio text="radio button 3" id="r3"/>
+ <radio text="radio button 4" id="r4"/>
+ </ui:box>
+ <ui:box cols="1">
+ <check text="checkbox 1"/>
+ <check text="checkbox 2"/>
+ <check text="checkbox 3"/>
+ <check text="checkbox 4"/>
+ </ui:box>
+ </ui:box>
+ </ui:box>
+ </ui:box>
+
+ <ui:box width="4" fill="black"/>
+ <ui:box>
+ <ui:box text="none of these widgets work yet">
+ </ui:box>
+ </ui:box>
+ </ui:box>
+</ibex>
+
--- /dev/null
+<ibex xmlns:widget="org.ibex.theme.win2k" xmlns="org.ibex.test">
+ <ui:box cols="1">
+ <ui:box cols="1" text="how do you get a list of available fonts?"/>
+ </ui:box>
+</ibex>
\ No newline at end of file
--- /dev/null
+<ibex xmlns:widget="org.ibex.theme.win2k" xmlns="org.ibex.test">
+ <ui:box cols="1">
+ <ui:box cols="1" text="no text widget"/>
+ <ui:box cols="1">
+ <button text="Update HTML"/>
+ </ui:box>
+ <ui:box cols="1" text="no html widget"/>
+ </ui:box>
+</ibex>
\ No newline at end of file
--- /dev/null
+<ibex xmlns:widget="org.ibex.theme.win2k" xmlns="org.ibex.test">
+ <ui:box cols="1">
+ <ui:box cols="1" text="lack of a text widget makes a spreadsheet difficult"/>
+ </ui:box>
+</ibex>
\ No newline at end of file
--- /dev/null
+<ibex xmlns:widget="org.ibex.theme.win2k" xmlns="org.ibex.test">
+ <ui:box cols="1">
+ <ui:box cols="1" text="not a clue how to implement draggable, transparent images"/>
+ </ui:box>
+</ibex>
--- /dev/null
+<ibex xmlns:widget="org.ibex.theme.win2k" xmlns="org.ibex.test">
+ <ui:box cols="3">
+
+ <ui:box cols="1">
+ <button text="Minimize"/>
+ Press1 ++= function (f) {
+ ibex.log.info("minimizing window");
+ root.Minimized=true;
+ }
+ <button text="Maximize"/>
+ <button text="Unminimize"/>
+ <button text="UnMaximize"/>
+ </ui:box>
+ <ui:box cols="1" width="5" fill="black"/>
+ <ui:box cols="1" fill="white" text="no widget = no status">
+ </ui:box>
+ </ui:box>
+</ibex>
+
--- /dev/null
+<ibex xmlns:theme="ibex.theme" xmlns="ibex.widget">
+ <theme:surface />
+ <ui:box cols="1" fill="#d4d0c8" maxwidth="400" maxheight="300">
+
+ ibex.ui.frame = thisbox;
+
+ // $r4.group = $r3.group = $r2.group = $r1.group;
+ $r2.group = $r1.group;
+ $r3.group = $r1.group;
+ $r4.group = $r1.group;
+
+ $bg.fill ++= function(v) {
+ cascade = v;
+ if (v == "white") $r1.selected = true;
+ else if (v == "red") $r2.selected = true;
+ else if (v == "green") $r3.selected = true;
+ else if (v == "blue") $r4.selected = true;
+ else if (v == null and $r1.group.selected) $r1.group.selected.selected = false;
+ }
+
+ $b1.action ++= function(v) {
+ if ($r1.group.selected and $r1.group.selected.nextselect)
+ $r1.group.selected.nextselect.selected = true;
+ else for (var i=0; $radios.numchildren > i; i++)
+ if ($radios[i].enabled) { $radios[i].selected = true; break; }
+ }
+
+ $b2.action ++= function(v) {
+ var targets = [];
+ for (var i=0; 4 > i; i++) if ($radios[i].enabled) targets[targets.length] = $radios[i];
+
+ if (targets.length > 0) {
+ var n = ibex.math.floor(targets.length * ibex.math.random());
+ targets[n].selected = true;
+ }
+ else ibex.log.info("No enabled colors to choose from!");
+ }
+
+ $b3.action ++= function(v) { $bg.fill = null; }
+
+ $c1.selected ++= function(v) { $r1.enabled = !v; }
+ $c2.selected ++= function(v) { $r2.enabled = !v; }
+ $c3.selected ++= function(v) { $r3.enabled = !v; }
+ $c4.selected ++= function(v) { $r4.enabled = !v; }
+
+ $r1.selected ++= function(v) { if (v and $bg.fill != "#ffffff") $bg.fill = "white"; }
+ $r2.selected ++= function(v) { if (v and $bg.fill != "#ff0000") $bg.fill = "red"; }
+ $r3.selected ++= function(v) { if (v and $bg.fill != "#008000") $bg.fill = "green"; }
+ $r4.selected ++= function(v) { if (v and $bg.fill != "#0000ff") $bg.fill = "blue"; }
+
+ <ui:box>
+ <ui:box id="buttons" cols="1">
+ <button id="b1" margin="10 5 0 5" text="cycle" />
+ <button id="b2" margin="10 5 0 5" text="random" />
+ <button id="b3" margin="10 5 0 5" text="reset" />
+ </ui:box>
+
+ <ui:box id="checks" cols="1">
+ <check id="c1" margin="10 5 0 5" text="disable white button" />
+ <check id="c2" margin="10 5 0 5" text="disable red button" />
+ <check id="c3" margin="10 5 0 5" text="disable green button" />
+ <check id="c4" margin="10 5 0 5" text="disable blue button" />
+ </ui:box>
+
+ <ui:box id="radios" cols="1">
+ <radio id="r1" margin="10 5 0 5" text="white bg" />
+ <radio id="r2" margin="10 5 0 5" text="red bg" />
+ <radio id="r3" margin="10 5 0 5" text="green bg" />
+ <radio id="r4" margin="10 5 0 5" text="blue bg" />
+ </ui:box>
+ </ui:box>
+ <bevel id="bg" form="down" margin="10" />
+ </ui:box>
+</ibex>
--- /dev/null
+<ibex xmlns:widget="ibex.widget" xmlns:theme="ibex.theme">
+ <theme:surface />
+ <ui:box fill="#d4d0c8" maxwidth="200" maxheight="200">
+ ibex.ui.frame = thisbox;
+ ibex.log.info($c.clip);
+ <widget:scrollpane fill="white" margin="10" padding="10">
+ <ui:box id="c" cols="4" width="800" height="800">
+ <ui:box fill="black" />
+ <ui:box fill="red" />
+ <ui:box fill="green" />
+ <ui:box fill="blue" />
+ <ui:box fill="blue" />
+ <ui:box fill="black" />
+ <ui:box fill="red" />
+ <ui:box fill="green" />
+ <ui:box fill="green" />
+ <ui:box fill="blue" />
+ <ui:box fill="black" />
+ <ui:box fill="red" />
+ <ui:box fill="red" />
+ <ui:box fill="green" />
+ <ui:box fill="blue" />
+ <ui:box fill="black" />
+ </ui:box>
+ </widget:scrollpane>
+ </ui:box>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns:theme="org.ibex.theme.win2k">
+ <theme:clickable />
+ <theme:button />
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns:lib="xml.lib" xmlns="org.ibex.theme.win2k">
+ <clickable />
+ <focusable />
+ <check />
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns="ibex.theme">
+ <repeatable />
+ <clickable />
+ <ui:box>
+ ibex.log.info("Applying clickable test widget");
+ normal ++= function(v) { fill="white"; }
+ hover ++= function(v) { fill="blue"; }
+ active ++= function(v) { fill="red"; }
+ action ++= function(v) { ibex.log.info("Action fired"); }
+ </ui:box/>
+</ibex>
--- /dev/null
+<ibex xmlns:theme="org.ibex.theme.win2k" xmlns:lib="ibex.lib" xmlns:libtext="ibex.lib.text">
+ <ui:box maxwidth="300" maxheight="300">
+ ibex.ui.frame = thisbox;
+
+ <libtext:flow>
+ <lib:text.block text="Hello " />
+ <lib:text.block text="World," />
+ <lib:text.block text="this is a test " />
+ <lib:text.block text="of the " />
+ <lib:text.block text="Emergency Broadcast "/>
+ <lib:text.block text="System."/>
+ </libtext:flow>
+ </ui:box>
+</ibex>
--- /dev/null
+<ibex xmlns:widget="ibex.widget" xmlns:theme="ibex.theme">
+ <theme:surface />
+ <ui:box cols="1" fill="#d4d0c8" maxwidth="400" maxheight="200">
+ ibex.ui.frame = thisbox;
+
+ <ui:box rows="1">
+ <ui:box />
+ <widget:label fontsize="20" text="Hello World, this is a test." />
+ <ui:box />
+ </ui:box>
+ </ui:box>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns:lib="ibex.lib" xmlns:test="org.ibex.test">
+ <lib:surface />
+ <lib:eventmanager />
+ <lib:focusmanager />
+ <ui:box minwidth="200" minheight="200" cols="3" fill="black">
+ ibex.log.info("Loading widget test");
+ ibex.ui.frame = thisbox;
+
+ <ui:box/>
+ <ui:box/>
+ <ui:box/>
+ <ui:box/>
+ <test:clickable />
+ <ui:box/>
+ <ui:box/>
+ <ui:box/>
+ <ui:box/>
+ </ui:box>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns:lib="xml.lib" xmlns="org.ibex.theme.win2k">
+ <clickable />
+ <selectable />
+ <radio />
+</ibex>
--- /dev/null
+<ibex xmlns="org.ibex.theme.win2k">
+ <clickable />
+ <selectable />
+ <tab />
+</ibex>
--- /dev/null
+<ibex xmlns="org.ibex.theme.win2k" xmlns:theme="ibex.theme">
+ <theme:surface />
+ <ui:box fill="#d4d0c8" maxwidth="200" maxheight="200">
+
+ ibex.ui.frame = thisbox;
+
+ <tabpane>
+ <ui:box tabtext="testfoo">
+ <ui:box text="left">
+ <spin value="0" step="1" />
+ </ui:box>
+ <ui:box text="right">
+ <spin value="0" step="5" />
+ </ui:box>
+ </ui:box>
+ <ui:box tabtext="test1">
+ <ui:box text="test1 content" />
+ </ui:box>
+ <ui:box tabtext="test2">
+ <ui:box text="test2 content" />
+ </ui:box>
+ <ui:box tabtext="test3">
+ <ui:box text="test3 content" />
+ </ui:box>
+ </tabpane>
+ </ui:box>
+</ibex>
--- /dev/null
+<ibex xmlns:widget="ibex.widget">
+ <ui:box rows="1" fill="#d4d0c8" minwidth="400" minheight="300">
+ ibex.ui.frame = thisbox;
+
+ <ui:box />
+ <widget:textfield fontsize="20" text="Hello" />
+ <ui:box />
+ </ui:box>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex>
+ <ui:box>
+
+ </ui:box>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex>
+ <meta:doc>
+ Author: Charles Goodwin
+
+ TODO:
+ - make border accept values other than resources
+ - border-left/right/top/bottom
+ - take more than one argument to border like CSS
+ </meta:doc>
+
+ <ui:box rows="3" redirect="$content">
+
+ border ++= function(v) {
+ if (typeof(v) == "object") {
+ $nw.fill = v["nw"];
+ $nn.fill = v["nn"];
+ $ne.fill = v["ne"];
+ $ww.fill = v["ww"];
+ $ee.fill = v["ee"];
+ $sw.fill = v["sw"];
+ $ss.fill = v["ss"];
+ $se.fill = v["se"];
+ }
+ // border string
+ else {
+ }
+ }
+
+ // top row
+ <ui:box id="nw" shrink="true" />
+ <ui:box id="ww" hshrink="true" />
+ <ui:box id="sw" shrink="true" />
+
+ // middle row
+ <ui:box id="nn" vshrink="true" />
+ <ui:box id="content" />
+ <ui:box id="ss" vshrink="true" />
+
+ // bottom row
+ <ui:box id="ne" shrink="true" />
+ <ui:box id="ee" hshrink="true" />
+ <ui:box id="se" shrink="true" />
+
+ </ui:box>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns="ibex.lib">
+ <clickable enabled="true" interval="100" repeats="false" />
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns="ibex.lib">
+ <focusable enabled="true" focusable="true" />
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 see COPYING for details [LGPL] -->
+
+<ibex>
+ <meta:doc>
+ Author: Charles Goodwin
+
+ TODO:
+ - ? differentiate between pt and px
+ - ? proper child and property redirection
+ </meta:doc>
+
+ <ui:box redirect="$content">
+
+ thisbox.margin = 0;
+ thisbox["margin-top"] = 0;
+ thisbox["margin-right"] = 0;
+ thisbox["margin-bottom"] = 0;
+ thisbox["margin-left"] = 0;
+
+ margin ++= function(v) {
+ var p = v.split(' ');
+
+ if (p.length == 1) {
+ thisbox["margin-top"] = v;
+ thisbox["margin-right"] = v;
+ thisbox["margin-bottom"] = v;
+ thisbox["margin-left"] = v;
+ }
+ else if (p.length == 2) {
+ thisbox["margin-top"] = p[0];
+ thisbox["margin-right"] = p[1];
+ thisbox["margin-bottom"] = p[0];
+ thisbox["margin-left"] = p[1];
+ }
+ else if (p.length == 4) {
+ thisbox["margin-top"] = p[0];
+ thisbox["margin-right"] = p[1];
+ thisbox["margin-bottom"] = p[2];
+ thisbox["margin-left"] = p[3];
+ }
+ else ibex.log.warn("Invalid number of values for margin: " + p.length);
+ }
+
+ thisbox["margin-top"] ++= function(v) { $top.height = v; }
+ thisbox["margin-right"] ++= function(v) { $right.width = v; }
+ thisbox["margin-bottom"] ++= function(v) { $bottom.height = v; }
+ thisbox["margin-left"] ++= function(v) { $left.width = v; }
+
+ <ui:box id="left" width="0" />
+ <ui:box cols="1">
+ <ui:box id="top" height="0" />
+ <ui:box id="content" />
+ <ui:box id="bottom" height="0" />
+ </ui:box>
+ <ui:box id="right" width="0" />
+ </ui:box>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 see COPYING for details [LGPL] -->
+
+<ibex>
+ <meta:doc>
+ Author: Charles Goodwin
+
+ TODO:
+ - ? differentiate between pt and px
+ - ? proper child and property redirection
+ </meta:doc>
+
+ <ui:box redirect="$content">
+
+ thisbox.padding = 0;
+ thisbox["padding-top"] = 0;
+ thisbox["padding-right"] = 0;
+ thisbox["padding-bottom"] = 0;
+ thisbox["padding-left"] = 0;
+
+ padding ++= function(v) {
+ var p = v.split(' ');
+
+ if (p.length == 1) {
+ thisbox["padding-top"] = v;
+ thisbox["padding-right"] = v;
+ thisbox["padding-bottom"] = v;
+ thisbox["padding-left"] = v;
+ }
+ else if (p.length == 2) {
+ thisbox["padding-top"] = p[0];
+ thisbox["padding-right"] = p[1];
+ thisbox["padding-bottom"] = p[0];
+ thisbox["padding-left"] = p[1];
+ }
+ else if (p.length == 4) {
+ thisbox["padding-top"] = p[0];
+ thisbox["padding-right"] = p[1];
+ thisbox["padding-bottom"] = p[2];
+ thisbox["padding-left"] = p[3];
+ }
+ else ibex.log.warn("Invalid number of values for padding: " + p.length);
+ }
+
+ thisbox["padding-top"] ++= function(v) { $top.height = v; }
+ thisbox["padding-right"] ++= function(v) { $right.width = v; }
+ thisbox["padding-bottom"] ++= function(v) { $bottom.height = v; }
+ thisbox["padding-left"] ++= function(v) { $left.width = v; }
+
+ <ui:box id="left" width="0" />
+ <ui:box cols="1">
+ <ui:box id="top" height="0" />
+ <ui:box id="content" />
+ <ui:box id="bottom" height="0" />
+ </ui:box>
+ <ui:box id="right" width="0" />
+ </ui:box>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns="ibex.lib">
+ <selectable />
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns="org.ibex.theme.win2k" xmlns:base="org.ibex.theme.base">
+ <meta:doc>
+ <author>Charles Goodwin</author>
+ </meta:doc>
+
+ <base:border-img>
+ thisbox.form ++= function(v) { if (v != cascade) border = .image["bevel" + v]; }
+ </base:border-img>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns="org.ibex.theme.base">
+ <border-img />
+ <ui:box />
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns="org.ibex.theme.win2k">
+ <bevel redirect="$content" padding="5 10">
+
+ active ++= function(v) { form = "down"; }
+
+ enabled ++= function(v) { textcolor = v ? "#000000" : "#888888"; }
+
+ focused ++= function(v) { cascade = v; normal = true; }
+
+ var normal_fun = function(v) { form = "up"; }
+
+ hover ++= normal_fun;
+ normal ++= normal_fun;
+
+ <ui:box id="content" />
+ </bevel>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns="ibex.lib">
+ <meta:doc>
+ Author: Charles Goodwin
+ </meta:doc>
+
+ <cardpane />
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns="org.ibex.theme.win2k">
+ <ui:box redirect="$content" align="center" padding="0 5">
+
+ action ++= function(v) { selected = !selected; }
+
+ active ++= function(v) { $bg.fill = "#d4d0c8"; }
+
+ enabled ++= function(v) {
+ $bg.fill = v ? "#ffffff" : "#d4d0c8";
+ textcolor = v ? "#000000" : "#888888";
+ }
+
+ focused ++= function(v) { cascade = v; fill = focused ? "#aaa" : null; }
+
+ var setbg = function(v) { $bg.fill = "#ffffff"; }
+ hover ++= setbg;
+ normal ++= setbg;
+
+ mixed ++= function(v) {
+ if (v) {
+ $check.fill = .image.check_mixed;
+ $check.visible = true;
+ }
+ }
+
+ selected ++= function(v) { cascade = v; $check.visible = selected; }
+
+ <bevel form="down" width="14" height="14">
+ <ui:box id="bg" fill="white">
+ <ui:box id="check" fill=".image.check" shrink="true" visible="false" />
+ </ui:box>
+ </bevel>
+ <ui:box id="content" />
+ </ui:box>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns="ibex.lib">
+ <clickable enabled="true" interval="100" repeats="false" />
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex>
+ <ui:box>
+ ibex..ibex.lib.draggable(thisbox);
+ </ui:box>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns:lib="ibex.lib">
+ <lib:text.edit />
+ <ui:box>
+ // TODO: move these boxes into static so they're shared amongst text
+ // widgets. as the gains from this are minimal and the static
+ // selection stuff will require quite a bit of fancy footwork,
+ // this is put off until Nitrogen core is *at least* as fast as
+ // Lithium was.
+ <ui:box id="cur" packed="false" width="1" x="0" y="0" pos="0" fill="black" align="topleft" />
+ <ui:box id="sel" packed="false" shrink="true" pos1="0" pos2="0" fill="blue" textcolor="white" align="topleft" />
+
+ thisbox.cur = $cur;
+ thisbox.sel = $sel;
+
+ font ++= function(v) { $sel.font = v; }
+ fontsize ++= function(v) { $sel.fontsize = v; }
+
+ // TODO: move to static (later); see above note
+ ibex.thread = function() {while (true) { if (focused) cur.visible = !cur.visible; ibex.thread.sleep(800); } }
+ </ui:box>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns="ibex.lib">
+ <focusable focusable="true" />
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns="org.ibex.theme.base">
+ <margin />
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns="org.ibex.theme.base">
+ <pad />
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns="ibex.lib">
+ <meta:doc>Author: Charles Goodwin</meta:doc>
+ <polarizable />
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns="org.ibex.theme.win2k">
+ <ui:box redirect="$content" align="center" padding="0 5">
+
+ var fill1 = .image.radiobg;
+ var fill2 = .image.radiobg_active;
+
+ active ++= function(v) { if ($bg.fill != fill2) $bg.fill = fill2; }
+
+ enabled ++= function(v) {
+ $bg.fill = v ? fill1 : fill2;
+ textcolor = v ? "#000000" : "#888888";
+ }
+
+ focused ++= function(v) { cascade = v; fill = focused ? "#aaa" : null; }
+
+ var normal_fun = function(v) { if ($bg.fill != fill1) $bg.fill = fill1; }
+ hover ++= normal_fun;
+ normal ++= normal_fun;
+
+ mixed ++= function(v) { $radio.fill = v ? .image.radio_mixed : .image.radio; }
+
+ selected ++= function(v) { cascade = v; $radio.visible = selected; }
+
+ <ui:box id="bg" shrink="true">
+ <ui:box id="radio" fill=".image.radio" shrink="true" visible="false" />
+ </ui:box>
+ <ui:box id="content" />
+
+ </ui:box>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns="ibex.lib">
+ <redirect />
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns="ibex.lib">
+ <repeatable interval="100" />
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns:lib="ibex.lib" xmlns="org.ibex.theme.win2k">
+ <meta:doc>
+ Author: Charles Goodwin
+ </meta:doc>
+
+ <lib:scrollbar amount="20">
+
+ var mousepos;
+ var movefunc = function(v) { mousepos = $track.mouse[pos]; }
+
+ th_back = $back;
+ th_next = $next;
+ th_thumb = $thumb;
+ th_track = $track;
+
+ orient ++= function(v) {
+ cascade = v;
+ thisbox[shr] = false;
+ thisbox[flip(shr)] = true;
+
+ if (rows) {
+ $backimg.fill = .image.arrowleft;
+ $nextimg.fill = .image.arrowright;
+ }
+ else {
+ $backimg.fill = .image.arrowup;
+ $nextimg.fill = .image.arrowdown;
+ }
+ }
+
+ page ++= function() {
+ if (slave) return 0.9 * (slave[dim]);
+ else return 0;
+ }
+
+/* FIXME: fix erratic showing of $shadow
+ $track.action ++= function(v) {
+ if ($thumb[pos] > mousepos) {
+ $shadow[dim] = $thumb[pos];
+ $shadow[pos] = 0;
+ }
+ else {
+ $shadow[dim] = $track[dim] - $thumb[dim] - $thumb[pos];
+ $shadow[pos] = $thumb[dim] + $thumb[pos];
+ }
+ }
+
+ $track.repeat ++= function(v) {
+ if (v) Move ++= movefunc;
+ else Move --= movefunc;
+ cascade = v;
+ $shadow.visible = v;
+ }
+*/
+ $track.Press1 ++= function(v) { if ($thumb.mouse.inside) return true; }
+
+ <button id="back" fill="#d0d4c8" width="16" height="16" repeats="true" shrink="true">
+ .clickable(thisbox);
+ <ui:box id="backimg" shrink="true" />
+ </button>
+ <clickable id="track" enabled="true" fill=".image.scrollbg" repeats="true">
+ <ui:box id="shadow" align="topleft" fill="#888888" packed="false" visible="false" />
+ <bevel id="thumb" align="topleft" fill="#d0d4c8" form="up" packed="false" />
+ </clickable>
+ <button id="next" fill="#d0d4c8" width="16" height="16" repeats="true" shrink="true">
+ .clickable(thisbox);
+ <ui:box id="nextimg" shrink="true" />
+ </button>
+ </lib:scrollbar>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns:lib="ibex.lib" xmlns="ibex.widget">
+ <meta:doc>
+ Author: Charles Goodwin
+ </meta:doc>
+
+ <lib:scrollpane redirect="$content">
+
+ th_hscroll = $hscroll;
+ th_vscroll = $vscroll;
+ th_viewport = $view;
+
+ $hscroll.SizeChange ++= function(v) { $inset.height = $hscroll.height; }
+ $vscroll.SizeChange ++= function(v) { $inset.width = $vscroll.width; }
+
+ orient ++= function(v) {
+ if (v == "horizontal") { hshrink = false; vshrink = true; }
+ else if (v == "vertical") { hshrink = true; vshrink = false; }
+ }
+
+ <bevel form="down">
+ <ui:box rows="2">
+ <ui:box id="view">
+ <ui:box id="content" align="topleft" packed="false" shrink="true" />
+ </ui:box>
+ <scrollbar id="hscroll" orient="horizontal" />
+ <scrollbar id="vscroll" orient="vertical" />
+ <ui:box id="inset" />
+ </ui:box>
+ </bevel>
+ </lib:scrollpane>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns="ibex.lib">
+ <selectable />
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns="org.ibex.theme.win2k">
+ <meta:doc>
+ Author: Charles Goodwin
+ </meta:doc>
+
+ <ui:box cols="1">
+
+ th_track = $track;
+ th_handle = $handle;
+ th_ruler = $ruler;
+
+ <ui:box id="track" />
+ <ui:box id="handle" />
+ <ui:box id="ruler" />
+ </ui:box>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns="org.ibex.theme.win2k" xmlns:lib="ibex.lib">
+ <meta:doc>
+ Author: Charles Goodwin
+ </meta:doc>
+
+ <lib:spin redirect="$content" padding="3">
+
+ th_more = $more;
+ th_less = $less;
+
+ <bevel form="down">
+ <ui:box id="content" fill="white" />
+ <ui:box cols="1" width="15">
+ <button id="more">
+ .clickable(thisbox);
+ <ui:box align="center" fill=".image.arrowup_small" shrink="true" />
+ </button>
+ <button id="less">
+ .clickable(thisbox);
+ <ui:box align="center" fill=".image.arrowdown_small" shrink="true" />
+ </button>
+ </ui:box>
+ </bevel>
+ </lib:spin>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns="ibex.lib">
+ <surface />
+ <eventmanager />
+ <focusmanager />
+ <ui:box>
+
+ _KeyPressed += function(v) {
+ if (v == "tab") {
+ surface.nextFocus();
+ } else if (v == "TAB") {
+ surface.prevFocus();
+ }
+ }
+
+ </ui:box>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns="org.ibex.theme.win2k">
+ <meta:doc>
+ Author: Charles Goodwin
+ </meta:doc>
+
+ <ui:box redirect="$content" cols="1" padding="4 10">
+
+ selected ++= function(v) {
+ cascade = v;
+ $content.fill = selected ? "#d4d0c8" : "#c4c0b8";
+ $gap.height = selected ? 0 : 2;
+ }
+
+ <ui:box id="gap" vshrink="true" />
+ <bevel form="tabtop">
+ <ui:box id="content" />
+ </bevel>
+
+ </ui:box>
+</ibex>
--- /dev/null
+<!-- Copyleft 2004 - see COPYING for details [LGPL] -->
+
+<ibex xmlns="org.ibex.theme.win2k" xmlns:lib="ibex.lib">
+ <meta:doc>
+ Author: Charles Goodwin
+ </meta:doc>
+
+ <lib:tabpane />
+ <ui:box redirect="$content" margin="10" padding="10">
+
+ th_head = $header;
+
+ var syncshadow = function(v) {
+ if (typeof(v) != "object" and th_content.show) v = th_content.show.tab;
+ $shadow.width = v.width - 3;
+ $shadow.x = v.x + 1;
+ $shadow.y = $header.height;
+ }
+
+ th_content ++= function(v) {
+ v.show ++= function(c) {
+ if (c and c.tab) {
+ //if (v.show) v.show.tab.SizeChange --= syncshadow;
+ if (cascade) cascade.tab.SizeChange --= syncshadow;
+ c.tab.SizeChange ++= syncshadow;
+ syncshadow(c.tab);
+ }
+ }
+ }
+
+ <ui:box id="body" cols="1">
+ <ui:box align="topleft" id="header" height="27" shrink="true" />
+ <bevel form="up" thickness="2">
+ <ui:box id="content" />
+ </bevel>
+ <ui:box id="shadow" align="topleft" height="2" packed="false" fill="#d4d0c8" />
+ </ui:box>
+ </ui:box>
+</ibex>
--- /dev/null
+<ibex xmlns:theme="ibex.theme" xmlns="org.ibex.theme.win2k" xmlns:sampler="org.ibex.sampler">
+ <theme:surface />
+ <ui:box fill="#d4d0c8" maxwidth="600" maxheight="200" cols="1">
+
+ ibex.ui.frame = thisbox;
+
+ <ui:box text="menus aren't implemented" height="20" align="left"/>
+ <tabpane>
+ <sampler:dialog tabtext="Widgets"/>
+ <sampler:window_manager_interaction tabtext="Windowing"/>
+ <sampler:clipboard tabtext="Clipboard"/>
+ <sampler:color_picker tabtext="Color Picker"/>
+ <sampler:transparency tabtext="Transparency"/>
+ <sampler:fonts tabtext="Fonts"/>
+ <sampler:html tabtext="HTML"/>
+ <sampler:spreadsheet tabtext="Spreadsheet"/>
+ </tabpane>
+ </ui:box>
+</ibex>