diff options
author | Alexander Larsson <alexl@redhat.com> | 2012-05-15 13:53:48 +0200 |
---|---|---|
committer | Alexander Larsson <alexl@redhat.com> | 2012-05-15 13:53:48 +0200 |
commit | 4a398416711f19a0046007dfdbc299c4134d151a (patch) | |
tree | 75800168d32b2a6841f2d47f6266751a391ece4a /src | |
parent | e7424b256053c975ea1c7aaf0b7dfb30a6b4bde4 (diff) | |
parent | 744851ea2dad9a26bddb952e6d85f28cb9c451af (diff) | |
download | gnome-contacts-4a398416711f19a0046007dfdbc299c4134d151a.tar.gz |
Add 'src/listbox/' from commit '744851ea2dad9a26bddb952e6d85f28cb9c451af'
git-subtree-dir: src/listbox
git-subtree-mainline: e7424b256053c975ea1c7aaf0b7dfb30a6b4bde4
git-subtree-split: 744851ea2dad9a26bddb952e6d85f28cb9c451af
Diffstat (limited to 'src')
-rw-r--r-- | src/listbox/.gitignore | 43 | ||||
-rw-r--r-- | src/listbox/AUTHORS | 1 | ||||
-rw-r--r-- | src/listbox/COPYING | 481 | ||||
-rw-r--r-- | src/listbox/ChangeLog | 0 | ||||
-rw-r--r-- | src/listbox/INSTALL | 370 | ||||
-rw-r--r-- | src/listbox/Makefile.am | 25 | ||||
-rw-r--r-- | src/listbox/NEWS | 0 | ||||
-rw-r--r-- | src/listbox/README | 0 | ||||
-rwxr-xr-x | src/listbox/autogen.sh | 4 | ||||
-rw-r--r-- | src/listbox/configure.ac | 25 | ||||
-rw-r--r-- | src/listbox/egg-list-box.doap | 18 | ||||
-rw-r--r-- | src/listbox/egg-list-box.vala | 895 | ||||
-rw-r--r-- | src/listbox/test-list.vala | 189 |
13 files changed, 2051 insertions, 0 deletions
diff --git a/src/listbox/.gitignore b/src/listbox/.gitignore new file mode 100644 index 0000000..fa9e249 --- /dev/null +++ b/src/listbox/.gitignore @@ -0,0 +1,43 @@ +*.bak +*.lo +*.o +*.orig +*.rej +*.tab.c +*~ +.deps +.libs +Makefile +Makefile.in +/aclocal.m4 +/autom4te.cache +/autoscan.log +/compile +/config.cache +/config.guess +/config.h +/config.h.in +/config.log +/config.lt +/config.status +/config.status.lineno +/config.sub +/configure +/configure.lineno +/configure.scan +/ltmain.sh +/depcomp +/install-sh +/intltool-extract +/intltool-extract.in +/intltool-merge +/intltool-merge.in +/intltool-update +/intltool-update.in +/libtool +/missing +/m4 +/stamp-h1 +*.stamp +*.c +test-list diff --git a/src/listbox/AUTHORS b/src/listbox/AUTHORS new file mode 100644 index 0000000..96f5ee5 --- /dev/null +++ b/src/listbox/AUTHORS @@ -0,0 +1 @@ +Alexander Larsson <alexl@redhat.com> diff --git a/src/listbox/COPYING b/src/listbox/COPYING new file mode 100644 index 0000000..5bc8fb2 --- /dev/null +++ b/src/listbox/COPYING @@ -0,0 +1,481 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + 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 Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, 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 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 a program 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. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, 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 companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + 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, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +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 compile 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) 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. + + c) 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. + + d) 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 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. + + 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 to +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 Library 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 Library General Public + License as published by the Free Software Foundation; either + version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +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! diff --git a/src/listbox/ChangeLog b/src/listbox/ChangeLog new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/listbox/ChangeLog diff --git a/src/listbox/INSTALL b/src/listbox/INSTALL new file mode 100644 index 0000000..a1e89e1 --- /dev/null +++ b/src/listbox/INSTALL @@ -0,0 +1,370 @@ +Installation Instructions +************************* + +Copyright (C) 1994-1996, 1999-2002, 2004-2011 Free Software Foundation, +Inc. + + Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. This file is offered as-is, +without warranty of any kind. + +Basic Installation +================== + + Briefly, the shell commands `./configure; make; make install' should +configure, build, and install this package. The following +more-detailed instructions are generic; see the `README' file for +instructions specific to this package. Some packages provide this +`INSTALL' file but do not implement all of the features documented +below. The lack of an optional feature in a given package is not +necessarily a bug. More recommendations for GNU packages can be found +in *note Makefile Conventions: (standards)Makefile Conventions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. Caching is +disabled by default to prevent problems with accidental use of stale +cache files. + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You need `configure.ac' if +you want to change it or regenerate `configure' using a newer version +of `autoconf'. + + The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. + + Running `configure' might take a while. While running, it prints + some messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package, generally using the just-built uninstalled binaries. + + 4. Type `make install' to install the programs and any data files and + documentation. When installing into a prefix owned by root, it is + recommended that the package be configured and built as a regular + user, and only the `make install' phase executed with root + privileges. + + 5. Optionally, type `make installcheck' to repeat any self-tests, but + this time using the binaries in their final installed location. + This target does not install anything. Running this target as a + regular user, particularly if the prior `make install' required + root privileges, verifies that the installation completed + correctly. + + 6. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + + 7. Often, you can also type `make uninstall' to remove the installed + files again. In practice, not all packages have tested that + uninstallation works correctly, even though it is required by the + GNU Coding Standards. + + 8. Some packages, particularly those that use Automake, provide `make + distcheck', which can by used by developers to test that all other + targets like `make install' and `make uninstall' work correctly. + This target is generally not run by end users. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. Run `./configure --help' +for details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c99 CFLAGS=-g LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you can use GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. This +is known as a "VPATH" build. + + With a non-GNU `make', it is safer to compile the package for one +architecture at a time in the source code directory. After you have +installed the package for one architecture, use `make distclean' before +reconfiguring for another architecture. + + On MacOS X 10.5 and later systems, you can create libraries and +executables that work on multiple system types--known as "fat" or +"universal" binaries--by specifying multiple `-arch' options to the +compiler but only a single `-arch' option to the preprocessor. Like +this: + + ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CPP="gcc -E" CXXCPP="g++ -E" + + This is not guaranteed to produce working output in all cases, you +may have to build one architecture at a time and combine the results +using the `lipo' tool if you have problems. + +Installation Names +================== + + By default, `make install' installs the package's commands under +`/usr/local/bin', include files under `/usr/local/include', etc. You +can specify an installation prefix other than `/usr/local' by giving +`configure' the option `--prefix=PREFIX', where PREFIX must be an +absolute file name. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +pass the option `--exec-prefix=PREFIX' to `configure', the package uses +PREFIX as the prefix for installing programs and libraries. +Documentation and other data files still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. In general, the +default for these options is expressed in terms of `${prefix}', so that +specifying just `--prefix' will affect all of the other directory +specifications that were not explicitly provided. + + The most portable way to affect installation locations is to pass the +correct locations to `configure'; however, many packages provide one or +both of the following shortcuts of passing variable assignments to the +`make install' command line to change installation locations without +having to reconfigure or recompile. + + The first method involves providing an override variable for each +affected directory. For example, `make install +prefix=/alternate/directory' will choose an alternate location for all +directory configuration variables that were expressed in terms of +`${prefix}'. Any directories that were specified during `configure', +but not in terms of `${prefix}', must each be overridden at install +time for the entire installation to be relocated. The approach of +makefile variable overrides for each directory variable is required by +the GNU Coding Standards, and ideally causes no recompilation. +However, some platforms have known limitations with the semantics of +shared libraries that end up requiring recompilation when using this +method, particularly noticeable in packages that use GNU Libtool. + + The second method involves providing the `DESTDIR' variable. For +example, `make install DESTDIR=/alternate/directory' will prepend +`/alternate/directory' before all installation names. The approach of +`DESTDIR' overrides is not required by the GNU Coding Standards, and +does not work on platforms that have drive letters. On the other hand, +it does better at avoiding recompilation issues, and works well even +when some directory options were not specified in terms of `${prefix}' +at `configure' time. + +Optional Features +================= + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + + Some packages offer the ability to configure how verbose the +execution of `make' will be. For these packages, running `./configure +--enable-silent-rules' sets the default to minimal output, which can be +overridden with `make V=1'; while running `./configure +--disable-silent-rules' sets the default to verbose, which can be +overridden with `make V=0'. + +Particular systems +================== + + On HP-UX, the default C compiler is not ANSI C compatible. If GNU +CC is not installed, it is recommended to use the following options in +order to use an ANSI C compiler: + + ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" + +and if that doesn't work, install pre-built binaries of GCC for HP-UX. + + HP-UX `make' updates targets which have the same time stamps as +their prerequisites, which makes it generally unusable when shipped +generated files such as `configure' are involved. Use GNU `make' +instead. + + On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot +parse its `<wchar.h>' header file. The option `-nodtk' can be used as +a workaround. If GNU CC is not installed, it is therefore recommended +to try + + ./configure CC="cc" + +and if that doesn't work, try + + ./configure CC="cc -nodtk" + + On Solaris, don't put `/usr/ucb' early in your `PATH'. This +directory contains several dysfunctional programs; working variants of +these programs are available in `/usr/bin'. So, if you need `/usr/ucb' +in your `PATH', put it _after_ `/usr/bin'. + + On Haiku, software installed for all users goes in `/boot/common', +not `/usr/local'. It is recommended to use the following options: + + ./configure --prefix=/boot/common + +Specifying the System Type +========================== + + There may be some features `configure' cannot figure out +automatically, but needs to determine by the type of machine the package +will run on. Usually, assuming the package is built to be run on the +_same_ architectures, `configure' can figure that out, but if it prints +a message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS + KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the option `--target=TYPE' to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + + Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +causes the specified `gcc' to be used as the C compiler (unless it is +overridden in the site shell script). + +Unfortunately, this technique does not work for `CONFIG_SHELL' due to +an Autoconf bug. Until the bug is fixed you can use this workaround: + + CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash + +`configure' Invocation +====================== + + `configure' recognizes the following options to control how it +operates. + +`--help' +`-h' + Print a summary of all of the options to `configure', and exit. + +`--help=short' +`--help=recursive' + Print a summary of the options unique to this package's + `configure', and exit. The `short' variant lists options used + only in the top level, while the `recursive' variant lists options + also present in any nested packages. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--prefix=DIR' + Use DIR as the installation prefix. *note Installation Names:: + for more details, including other options available for fine-tuning + the installation locations. + +`--no-create' +`-n' + Run the configure checks, but stop before creating any output + files. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff --git a/src/listbox/Makefile.am b/src/listbox/Makefile.am new file mode 100644 index 0000000..d98958a --- /dev/null +++ b/src/listbox/Makefile.am @@ -0,0 +1,25 @@ +NULL = + +AM_CPPFLAGS = \ + -include config.h \ + $(LISTBOX_CFLAGS) \ + $(NULL) + +AM_VALAFLAGS = \ + @LISTBOX_PACKAGES@ \ + $(NULL) + +noinst_PROGRAMS = test-list + +test_list_SOURCES = \ + egg-list-box.vala \ + test-list.vala \ + $(NULL) +test_list_LDADD = $(LISTBOX_LIBS) + +CLEANFILES = \ + $(test_list_SOURCES:.vala=.c) \ + *.vapi *.stamp + +EXTRA_DIST = \ + $(NULL) diff --git a/src/listbox/NEWS b/src/listbox/NEWS new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/listbox/NEWS diff --git a/src/listbox/README b/src/listbox/README new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/listbox/README diff --git a/src/listbox/autogen.sh b/src/listbox/autogen.sh new file mode 100755 index 0000000..e48ee08 --- /dev/null +++ b/src/listbox/autogen.sh @@ -0,0 +1,4 @@ +#!/bin/sh +mkdir -p m4 +autoreconf -fiv -Wall || exit +./configure --enable-maintainer-mode "$@" diff --git a/src/listbox/configure.ac b/src/listbox/configure.ac new file mode 100644 index 0000000..edd2169 --- /dev/null +++ b/src/listbox/configure.ac @@ -0,0 +1,25 @@ +AC_PREREQ([2.67]) +AC_INIT([egg-list-box],[3.5.1],[http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-contacts]) +AC_CONFIG_SRCDIR([test-list.vala]) +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_MACRO_DIR([m4]) +AM_INIT_AUTOMAKE +# Enable silent rules is available +AM_SILENT_RULES([yes]) +AM_MAINTAINER_MODE([enable]) +AC_CONFIG_FILES([Makefile + ]) + +LT_INIT +AC_PROG_CC +AM_PROG_VALAC([0.16.0]) +AC_PROG_INSTALL + +pkg_modules="gtk+-3.0 >= 3.4.0 + glib-2.0 >= 2.31.10" +PKG_CHECK_MODULES(LISTBOX, [$pkg_modules]) + +LISTBOX_PACKAGES="--pkg gtk+-3.0" +AC_SUBST(LISTBOX_PACKAGES) + +AC_OUTPUT diff --git a/src/listbox/egg-list-box.doap b/src/listbox/egg-list-box.doap new file mode 100644 index 0000000..ed9e8ef --- /dev/null +++ b/src/listbox/egg-list-box.doap @@ -0,0 +1,18 @@ +<Project xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" + xmlns:foaf="http://xmlns.com/foaf/0.1/" + xmlns:gnome="http://api.gnome.org/doap-extensions#" + xmlns="http://usefulinc.com/ns/doap#"> + + <name xml:lang="en">EggListBox</name> + <shortdesc xml:lang="en">Sorting widget container</shortdesc> + <category rdf:resource="http://api.gnome.org/doap-extensions#desktop" /> + + <maintainer> + <foaf:Person> + <foaf:name>Alexander Larsson</foaf:name> + <foaf:mbox rdf:resource="mailto:alexl@redhat.com" /> + <gnome:userid>alexl</gnome:userid> + </foaf:Person> + </maintainer> +</Project> diff --git a/src/listbox/egg-list-box.vala b/src/listbox/egg-list-box.vala new file mode 100644 index 0000000..505b871 --- /dev/null +++ b/src/listbox/egg-list-box.vala @@ -0,0 +1,895 @@ +/* -*- Mode: vala; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 8 -*- */ +/* + * Copyright (C) 2011 Alexander Larsson <alexl@redhat.com> + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +using Gtk; + +public class Egg.ListBox : Container { + public delegate bool FilterFunc (Widget child); + public delegate void UpdateSeparatorFunc (ref Widget? separator, Widget child, Widget? before); + + private struct ChildInfo { + Widget widget; + Widget? separator; + SequenceIter<ChildInfo?> iter; + int y; + int height; + } + + private Sequence<ChildInfo?> children; + private HashTable<unowned Widget, unowned ChildInfo?> child_hash; + private CompareDataFunc<Widget>? sort_func; + private FilterFunc? filter_func; + private UpdateSeparatorFunc? update_separator_func; + private unowned ChildInfo? selected_child; + private unowned ChildInfo? prelight_child; + private unowned ChildInfo? cursor_child; + private SelectionMode selection_mode; + + + public ListBox () { + set_can_focus (true); + set_has_window (true); + set_redraw_on_allocate (true); + + selection_mode = SelectionMode.SINGLE; + + children = new Sequence<ChildInfo?>(); + child_hash = new HashTable<unowned Widget, unowned ChildInfo?> (GLib.direct_hash, GLib.direct_equal); + } + + public Widget? get_selected_child (){ + if (selected_child != null) + return selected_child.widget; + + return null; + } + + public virtual signal void child_selected (Widget? child) { + } + + public virtual signal void child_activated (Widget? child) { + } + + + public void set_selection_mode (SelectionMode mode) { + if (mode == SelectionMode.MULTIPLE) { + warning ("Multiple selections not supported"); + return; + } + selection_mode = mode; + if (mode == SelectionMode.NONE) + update_selected (null); + } + + public void set_filter_func (owned FilterFunc? f) { + filter_func = (owned)f; + refilter (); + } + + public void set_separator_funcs (owned UpdateSeparatorFunc? update_separator) { + update_separator_func = (owned)update_separator; + reseparate (); + } + + public void refilter () { + apply_filter_all (); + reseparate (); + queue_resize (); + } + + public void resort () { + children.sort (do_sort); + reseparate (); + queue_resize (); + } + + public void reseparate () { + for (var iter = children.get_begin_iter (); !iter.is_end (); iter = iter.next ()) { + update_separator (iter); + } + queue_resize (); + } + + public void set_sort_func (owned CompareDataFunc<Widget>? f) { + sort_func = (owned)f; + resort (); + } + + public void child_changed (Widget widget) { + unowned ChildInfo? info = lookup_info (widget); + if (info == null) + return; + + var prev_next = get_previous_visible (info.iter); + + if (sort_func != null) { + children.sort_changed (info.iter, do_sort); + this.queue_resize (); + } + apply_filter (info.widget); + update_separator (info.iter); + update_separator (get_next_visible (info.iter)); + update_separator (prev_next); + + } + + /****** Implementation ***********/ + + private int do_sort (ChildInfo? a, ChildInfo? b) { + return sort_func (a.widget, b.widget); + } + + [Signal (action=true)] + public virtual signal void activate_cursor_child () { + select_and_activate (cursor_child); + } + + [Signal (action=true)] + public virtual signal void toggle_cursor_child () { + if (cursor_child == null) + return; + + if (selection_mode == SelectionMode.SINGLE && + selected_child == cursor_child) + update_selected (null); + else + select_and_activate (cursor_child); + } + + [Signal (action=true)] + public virtual signal void move_cursor (MovementStep step, int count) { + Gdk.ModifierType state; + + bool modify_selection_pressed = false; + + if (Gtk.get_current_event_state (out state)) { + var modify_mod_mask = this.get_modifier_mask (Gdk.ModifierIntent.MODIFY_SELECTION); + if ((state & modify_mod_mask) == modify_mod_mask) + modify_selection_pressed = true; + } + + unowned ChildInfo? child = null; + switch (step) { + case MovementStep.BUFFER_ENDS: + if (count < 0) + child = get_first_visible (); + else + child = get_last_visible (); + break; + case MovementStep.DISPLAY_LINES: + if (cursor_child != null) { + SequenceIter<ChildInfo?>? iter = cursor_child.iter; + + while (count < 0 && iter != null) { + iter = get_previous_visible (iter); + count++; + } + while (count > 0 && iter != null) { + iter = get_next_visible (iter); + count--; + } + if (iter != null && !iter.is_end ()) { + child = iter.get (); + } + } + break; + case MovementStep.PAGES: + int page_size = 100; + var vadj = get_focus_vadjustment (); + if (vadj != null) + page_size = (int) vadj.get_page_increment (); + + if (cursor_child != null) { + int start_y = cursor_child.y; + int end_y = start_y; + SequenceIter<ChildInfo?>? iter = cursor_child.iter; + + child = cursor_child; + if (count < 0) { + /* Up */ + + while (iter != null && !iter.is_begin ()) { + iter = get_previous_visible (iter); + if (iter == null) + break; + unowned ChildInfo? prev = iter.get (); + if (prev.y < start_y - page_size) + break; + child = prev; + } + } else { + /* Down */ + + while (iter != null && !iter.is_end ()) { + iter = get_next_visible (iter); + if (iter.is_end ()) + break; + unowned ChildInfo? next = iter.get (); + if (next.y > start_y + page_size) + break; + child = next; + } + } + end_y = child.y; + if (end_y != start_y && vadj != null) + vadj.value += end_y - start_y; + + } + break; + default: + return; + } + + if (child == null) { + error_bell (); + return; + } + + update_cursor (child); + if (!modify_selection_pressed) + update_selected (child); + } + + private static void add_move_binding (BindingSet binding_set, uint keyval, Gdk.ModifierType modmask, + MovementStep step, int count) { + BindingEntry.add_signal (binding_set, keyval, modmask, + "move-cursor", 2, + typeof (MovementStep), step, + typeof (int), count); + + if ((modmask & Gdk.ModifierType.CONTROL_MASK) == Gdk.ModifierType.CONTROL_MASK) + return; + + BindingEntry.add_signal (binding_set, keyval, Gdk.ModifierType.CONTROL_MASK, + "move-cursor", 2, + typeof (MovementStep), step, + typeof (int), count); + } + + [CCode (cname = "klass")] + private static extern void *workaround_for_local_var_klass; + static construct { + unowned BindingSet binding_set = BindingSet.by_class (workaround_for_local_var_klass); + + add_move_binding (binding_set, Gdk.Key.Home, 0, + MovementStep.BUFFER_ENDS, -1); + add_move_binding (binding_set, Gdk.Key.KP_Home, 0, + MovementStep.BUFFER_ENDS, -1); + + add_move_binding (binding_set, Gdk.Key.End, 0, + MovementStep.BUFFER_ENDS, 1); + add_move_binding (binding_set, Gdk.Key.KP_End, 0, + MovementStep.BUFFER_ENDS, 1); + + add_move_binding (binding_set, Gdk.Key.Up, Gdk.ModifierType.CONTROL_MASK, + MovementStep.DISPLAY_LINES, -1); + add_move_binding (binding_set, Gdk.Key.KP_Up, Gdk.ModifierType.CONTROL_MASK, + MovementStep.DISPLAY_LINES, -1); + + add_move_binding (binding_set, Gdk.Key.Down, Gdk.ModifierType.CONTROL_MASK, + MovementStep.DISPLAY_LINES, 1); + add_move_binding (binding_set, Gdk.Key.KP_Down, Gdk.ModifierType.CONTROL_MASK, + MovementStep.DISPLAY_LINES, 1); + + add_move_binding (binding_set, Gdk.Key.Page_Up, 0, + MovementStep.PAGES, -1); + add_move_binding (binding_set, Gdk.Key.KP_Page_Up, 0, + MovementStep.PAGES, -1); + + add_move_binding (binding_set, Gdk.Key.Page_Down, 0, + MovementStep.PAGES, 1); + add_move_binding (binding_set, Gdk.Key.KP_Page_Down, 0, + MovementStep.PAGES, 1); + + BindingEntry.add_signal (binding_set, Gdk.Key.space, Gdk.ModifierType.CONTROL_MASK, + "toggle-cursor-child", 0); + + activate_signal = GLib.Signal.lookup ("activate-cursor-child", typeof (ListBox)); + } + + unowned ChildInfo? find_child_at_y (int y) { + unowned ChildInfo? child_info = null; + for (var iter = children.get_begin_iter (); !iter.is_end (); iter = iter.next ()) { + unowned ChildInfo? info = iter.get (); + if (y >= info.y && y < info.y + info.height) { + child_info = info; + break; + } + } + return child_info; + } + + private void update_cursor (ChildInfo? child) { + cursor_child = child; + this.grab_focus (); + this.queue_draw (); + var vadj = get_focus_vadjustment (); + if (child != null && vadj != null) + vadj.clamp_page (cursor_child.y, + cursor_child.y + cursor_child.height); + } + + private void update_selected (ChildInfo? child) { + if (child != selected_child && + (child == null || selection_mode != SelectionMode.NONE)) { + selected_child = child; + child_selected (selected_child != null ? selected_child.widget : null); + queue_draw (); + } + if (child != null) + update_cursor (child); + } + + private void select_and_activate (ChildInfo? child) { + Widget? w = null; + if (child != null) + w = child.widget; + update_selected (child); + if (w != null) + child_activated (w); + } + + private void update_prelight (ChildInfo? child) { + if (child != prelight_child) { + prelight_child = child; + queue_draw (); + } + } + + public override bool enter_notify_event (Gdk.EventCrossing event) { + if (event.window != get_window ()) + return false; + + unowned ChildInfo? child = find_child_at_y ((int)event.y); + update_prelight (child); + + return false; + } + + public override bool leave_notify_event (Gdk.EventCrossing event) { + if (event.window != get_window ()) + return false; + + if (event.detail != Gdk.NotifyType.INFERIOR) { + update_prelight (null); + } else { + unowned ChildInfo? child = find_child_at_y ((int)event.y); + update_prelight (child); + } + + return false; + } + + public override bool motion_notify_event (Gdk.EventMotion event) { + unowned ChildInfo? child = find_child_at_y ((int)event.y); + update_prelight (child); + return false; + } + + private Widget? button_down_child; + public override bool button_press_event (Gdk.EventButton event) { + if (event.button == 1) { + unowned ChildInfo? child = find_child_at_y ((int)event.y); + if (child != null) + button_down_child = child.widget; + + /* TODO: Should mark as active while down, and handle grab breaks */ + } + return false; + } + + public override bool button_release_event (Gdk.EventButton event) { + if (event.button == 1) { + unowned ChildInfo? child = find_child_at_y ((int)event.y); + if (child != null && child.widget == button_down_child) + select_and_activate (child); + button_down_child = null; + } + return false; + } + + public override bool focus (DirectionType direction) { + bool had_focus; + bool focus_into; + Widget recurse_into = null; + + focus_into = true; + had_focus = has_focus; + + unowned ChildInfo? current_focus_child = null; + unowned ChildInfo? next_focus_child = null; + + if (had_focus) { + /* If on row, going right, enter into possible container */ + if (direction == DirectionType.RIGHT || + direction == DirectionType.TAB_FORWARD) { + /* TODO: Handle null cursor child */ + recurse_into = cursor_child.widget; + } + current_focus_child = cursor_child; + /* Unless we're going up/down we're always leaving + the container */ + if (direction != DirectionType.UP && + direction != DirectionType.DOWN) + focus_into = false; + } else if (this.get_focus_child () != null) { + /* There is a focus child, always navigat inside it first */ + recurse_into = this.get_focus_child (); + current_focus_child = lookup_info (recurse_into); + + /* If exiting child container to the right, exit row */ + if (direction == DirectionType.RIGHT || + direction == DirectionType.TAB_FORWARD) + focus_into = false; + + /* If exiting child container to the left, select row or out */ + if (direction == DirectionType.LEFT || + direction == DirectionType.TAB_BACKWARD) { + next_focus_child = current_focus_child; + } + } else { + /* If coming from the left, enter into possible container */ + if (direction == DirectionType.LEFT || + direction == DirectionType.TAB_BACKWARD) { + if (selected_child != null) + recurse_into = selected_child.widget; + } + } + + if (recurse_into != null) { + if (recurse_into.child_focus (direction)) + return true; + } + + if (!focus_into) + return false; // Focus is leaving us + + /* TODO: This doesn't handle up/down going into a focusable separator */ + + if (next_focus_child == null) { + if (current_focus_child != null) { + if (direction == DirectionType.UP) { + var i = get_previous_visible (current_focus_child.iter); + if (i != null) + next_focus_child = i.get (); + } else { + var i = get_next_visible (current_focus_child.iter); + if (!i.is_end ()) + next_focus_child = i.get (); + } + } else { + switch (direction) { + case DirectionType.DOWN: + case DirectionType.TAB_FORWARD: + next_focus_child = get_first_visible (); + break; + case DirectionType.UP: + case DirectionType.TAB_BACKWARD: + next_focus_child = get_last_visible (); + break; + default: + next_focus_child = selected_child; + if (next_focus_child == null) + next_focus_child = get_first_visible (); + break; + } + } + } + + if (next_focus_child == null) { + if (direction == DirectionType.UP || direction == DirectionType.DOWN) { + error_bell (); + return true; + } + + return false; + } + + bool modify_selection_pressed = false; + Gdk.ModifierType state; + + if (Gtk.get_current_event_state (out state)) { + var modify_mod_mask = this.get_modifier_mask (Gdk.ModifierIntent.MODIFY_SELECTION); + if ((state & modify_mod_mask) == modify_mod_mask) + modify_selection_pressed = true; + } + + update_cursor (next_focus_child); + if (!modify_selection_pressed) + update_selected (next_focus_child); + + return true; + } + + public override bool draw (Cairo.Context cr) { + Allocation allocation; + this.get_allocation (out allocation); + + var context = this.get_style_context (); + + context.save (); + context.render_background (cr, + 0, 0, allocation.width, allocation.height); + + if (selected_child != null) { + context.set_state (StateFlags.SELECTED); + context.render_background (cr, + 0, selected_child.y, + allocation.width, selected_child.height); + } + + if (prelight_child != null && prelight_child != selected_child) { + context.set_state (StateFlags.PRELIGHT); + context.render_background (cr, + 0, prelight_child.y, + allocation.width, prelight_child.height); + } + + if (has_visible_focus() && cursor_child != null) { + context.render_focus (cr, 0, cursor_child.y, + allocation.width, cursor_child.height); + } + + context.restore (); + + base.draw (cr); + + return true; + } + + public override void realize () { + Allocation allocation; + get_allocation (out allocation); + set_realized (true); + + Gdk.WindowAttr attributes = { }; + attributes.x = allocation.x; + attributes.y = allocation.y; + attributes.width = allocation.width; + attributes.height = allocation.height; + attributes.window_type = Gdk.WindowType.CHILD; + attributes.event_mask = this.get_events () | + Gdk.EventMask.ENTER_NOTIFY_MASK | + Gdk.EventMask.LEAVE_NOTIFY_MASK | + Gdk.EventMask.POINTER_MOTION_MASK | + Gdk.EventMask.EXPOSURE_MASK | + Gdk.EventMask.BUTTON_PRESS_MASK | + Gdk.EventMask.BUTTON_RELEASE_MASK; + + attributes.wclass = Gdk.WindowWindowClass.INPUT_OUTPUT; + var window = new Gdk.Window (get_parent_window (), attributes, + Gdk.WindowAttributesType.X | + Gdk.WindowAttributesType.Y); + window.set_user_data (this); + this.set_window (window); + } + + private void apply_filter (Widget child) { + bool do_show = true; + if (filter_func != null) + do_show = filter_func (child); + child.set_child_visible (do_show); + } + + private void apply_filter_all () { + for (var iter = children.get_begin_iter (); !iter.is_end (); iter = iter.next ()) { + unowned ChildInfo? child_info = iter.get (); + apply_filter (child_info.widget); + } + } + + private unowned ChildInfo? get_first_visible () { + for (var iter = children.get_begin_iter (); !iter.is_end (); iter = iter.next ()) { + unowned ChildInfo? child_info = iter.get (); + unowned Widget widget = child_info.widget; + if (widget.get_visible () && widget.get_child_visible ()) + return child_info; + } + return null; + } + + private unowned ChildInfo? get_last_visible () { + var iter = children.get_end_iter (); + while (!iter.is_begin ()) { + iter = iter.prev (); + unowned ChildInfo? child_info = iter.get (); + unowned Widget widget = child_info.widget; + if (widget.get_visible () && widget.get_child_visible ()) + return child_info; + } + return null; + } + + private SequenceIter<ChildInfo?>? get_previous_visible (SequenceIter<ChildInfo?> _iter) { + if (_iter.is_begin()) + return null; + var iter = _iter; + + do { + iter = iter.prev (); + + unowned ChildInfo? child_info = iter.get (); + unowned Widget widget = child_info.widget; + if (widget.get_visible () && widget.get_child_visible ()) + return iter; + } while (!iter.is_begin ()); + + return null; + } + + private SequenceIter<ChildInfo?>? get_next_visible (SequenceIter<ChildInfo?> _iter) { + if (_iter.is_end()) + return _iter; + + var iter = _iter; + do { + iter = iter.next (); + + if (!iter.is_end ()) { + unowned ChildInfo? child_info = iter.get (); + unowned Widget widget = child_info.widget; + if (widget.get_visible () && widget.get_child_visible ()) + return iter; + } + } while (!iter.is_end ()); + + return iter; + } + + private void update_separator (SequenceIter<ChildInfo?>? iter) { + if (iter == null || iter.is_end ()) + return; + + unowned ChildInfo? info = iter.get (); + var before_iter = get_previous_visible (iter); + var widget = info.widget; + Widget? before_widget = null; + if (before_iter != null) { + unowned ChildInfo? before_info = before_iter.get (); + before_widget = before_info.widget; + } + + if (update_separator_func != null && + widget.get_visible () && + widget.get_child_visible ()) { + var old_separator = info.separator; + update_separator_func (ref info.separator, widget, before_widget); + if (old_separator != info.separator) { + if (old_separator != null) + old_separator.unparent (); + if (info.separator != null) { + info.separator.set_parent (this); + info.separator.show (); + } + this.queue_resize (); + } + } else if (info.separator != null) { + info.separator.unparent (); + info.separator = null; + this.queue_resize (); + } + } + + private unowned ChildInfo? lookup_info (Widget widget) { + return child_hash.get (widget); + } + + public override void add (Widget widget) { + ChildInfo? the_info = { widget }; + unowned ChildInfo? info = the_info; + SequenceIter<ChildInfo?> iter; + + child_hash.set (widget, info); + + if (sort_func != null) + iter = children.insert_sorted ((owned) the_info, do_sort); + else + iter = children.append ((owned) the_info); + + apply_filter (widget); + + var prev_next = get_next_visible (iter); + update_separator (iter); + update_separator (get_next_visible (iter)); + update_separator (prev_next); + + info.iter = iter; + + widget.set_parent (this); + } + + public override void remove (Widget widget) { + unowned ChildInfo? info = lookup_info (widget); + if (info == null) { + warning ("Tried to remove non-child %p\n", widget); + return; + } + + if (info == selected_child) + update_selected (null); + if (info == prelight_child) + prelight_child = null; + if (info == cursor_child) + cursor_child = null; + + var next = get_next_visible (info.iter); + + bool was_visible = widget.get_visible (); + widget.unparent (); + + child_hash.remove (widget); + children.remove (info.iter); + + update_separator (next); + + if (was_visible && this.get_visible ()) + this.queue_resize (); + } + + public override void forall_internal (bool include_internals, + Gtk.Callback callback) { + for (var iter = children.get_begin_iter (); !iter.is_end (); iter = iter.next ()) { + unowned ChildInfo? child_info = iter.get (); + if (child_info.separator != null && include_internals) + callback (child_info.separator); + callback (child_info.widget); + } + } + + public override void compute_expand_internal (out bool hexpand, out bool vexpand) { + base.compute_expand_internal (out hexpand, out vexpand); + /* We don't expand vertically beyound the minimum size */ + vexpand = false; + } + + public override Type child_type () { + return typeof (Widget); + } + + public override Gtk.SizeRequestMode get_request_mode () { + return SizeRequestMode.HEIGHT_FOR_WIDTH; + } + + public override void get_preferred_height (out int minimum_height, out int natural_height) { + int natural_width; + get_preferred_width_internal (null, out natural_width); + get_preferred_height_for_width_internal (natural_width, out minimum_height, out natural_height); + } + + public override void get_preferred_height_for_width (int width, out int minimum_height, out int natural_height) { + minimum_height = 0; + var context = this.get_style_context (); + int focus_width, focus_pad; + context.get_style ("focus-line-width", out focus_width, + "focus-padding", out focus_pad); + for (var iter = children.get_begin_iter (); !iter.is_end (); iter = iter.next ()) { + unowned ChildInfo? child_info = iter.get (); + unowned Widget widget = child_info.widget; + int child_min; + + if (!widget.get_visible () || !widget.get_child_visible ()) + continue; + + if (child_info.separator != null) { + child_info.separator.get_preferred_height_for_width (width, out child_min, null); + minimum_height += child_min; + } + + widget.get_preferred_height_for_width (width - 2 * (focus_width + focus_pad), + out child_min, null); + minimum_height += child_min + 2 * (focus_width + focus_pad); + } + + /* We always allocate the minimum height, since handling + expanding rows is way too costly, and unlikely to + be used, as lists are generally put inside a scrolling window + anyway. + */ + natural_height = minimum_height; + } + + public override void get_preferred_width (out int minimum_width, out int natural_width) { + var context = this.get_style_context (); + int focus_width, focus_pad; + context.get_style ("focus-line-width", out focus_width, + "focus-padding", out focus_pad); + minimum_width = 0; + natural_width = 0; + for (var iter = children.get_begin_iter (); !iter.is_end (); iter = iter.next ()) { + unowned ChildInfo? child_info = iter.get (); + unowned Widget widget = child_info.widget; + int child_min, child_nat; + + if (!widget.get_visible () || !widget.get_child_visible ()) + continue; + + widget.get_preferred_width (out child_min, out child_nat); + minimum_width = int.max (minimum_width, child_min + 2 * (focus_width + focus_pad)); + natural_width = int.max (natural_width, child_nat + 2 * (focus_width + focus_pad)); + + if (child_info.separator != null) { + child_info.separator.get_preferred_width (out child_min, out child_nat); + minimum_width = int.max (minimum_width, child_min); + natural_width = int.max (natural_width, child_nat); + } + } + } + + public override void get_preferred_width_for_height (int height, out int minimum_width, out int natural_width) { + get_preferred_width_internal (out minimum_width, out natural_width); + } + + public override void size_allocate (Gtk.Allocation allocation) { + Allocation child_allocation = { 0, 0, 0, 0}; + Allocation separator_allocation = { 0, 0, 0, 0}; + + set_allocation (allocation); + + var window = get_window(); + if (window != null) + window.move_resize (allocation.x, + allocation.y, + allocation.width, + allocation.height); + + var context = this.get_style_context (); + int focus_width, focus_pad; + context.get_style ("focus-line-width", out focus_width, + "focus-padding", out focus_pad); + + child_allocation.x = allocation.x + focus_width + focus_pad; + child_allocation.y = allocation.y; + child_allocation.width = allocation.width - 2 * (focus_width + focus_pad); + + separator_allocation.x = allocation.x; + separator_allocation.width = allocation.width; + + for (var iter = children.get_begin_iter (); !iter.is_end (); iter = iter.next ()) { + unowned ChildInfo? child_info = iter.get (); + unowned Widget widget = child_info.widget; + int child_min; + + if (!widget.get_visible () || !widget.get_child_visible ()) { + child_info.y = child_allocation.y; + child_info.height = 0; + continue; + } + + if (child_info.separator != null) { + child_info.separator.get_preferred_height_for_width (allocation.width, out child_min, null); + separator_allocation.height = child_min; + separator_allocation.y = child_allocation.y; + + child_info.separator.size_allocate (separator_allocation); + + child_allocation.y += child_min; + } + + child_info.y = child_allocation.y; + child_allocation.y += focus_width + focus_pad; + + widget.get_preferred_height_for_width (child_allocation.width, out child_min, null); + child_allocation.height = child_min; + + child_info.height = child_allocation.height + 2 * (focus_width + focus_pad); + widget.size_allocate (child_allocation); + + child_allocation.y += child_min + focus_width + focus_pad; + } + } +} diff --git a/src/listbox/test-list.vala b/src/listbox/test-list.vala new file mode 100644 index 0000000..0c1c06a --- /dev/null +++ b/src/listbox/test-list.vala @@ -0,0 +1,189 @@ +/* -*- Mode: vala; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 8 -*- */ +/* + * Copyright (C) 2011 Alexander Larsson <alexl@redhat.com> + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +using Gtk; +using Egg; + +public void update_separator (ref Widget? separator, + Widget widget, + Widget? before) +{ + if (before == null || + (widget is Label && (widget as Label).get_text () == "blah3")) { + if (separator == null) { + var hbox = new Box(Orientation.HORIZONTAL, 0); + var l = new Label ("Separator"); + hbox.add (l); + var b = new Button.with_label ("button"); + hbox.add (b); + l.show (); + b.show (); + separator = hbox; + } + + var hbox = separator as Box; + var id = widget.get_data<int>("sort_id"); + var l = hbox.get_children ().data as Label; + l.set_text ("Separator %d".printf (id)); + } else { + separator = null; + } + print ("update separator => %p\n", separator); +} + +public static int +compare_label (Widget a, Widget b) { + var aa = a.get_data<int>("sort_id"); + var bb = b.get_data<int>("sort_id"); + return bb - aa; +} + +public static int +compare_label_reverse (Widget a, Widget b) { + return - compare_label (a, b); +} + +public static bool +filter (Widget widget) { + var text = (widget as Label).get_text (); + return strcmp (text, "blah3") != 0; +} + +public static int +main (string[] args) { + + Gtk.init (ref args); + + var w = new Window (); + var hbox = new Box(Orientation.HORIZONTAL, 0); + w.add (hbox); + + var list = new ListBox(); + hbox.add (list); + + list.child_activated.connect ( (child) => { + print ("activated %p\n", child); + }); + + list.child_selected.connect ( (child) => { + print ("selected %p\n", child); + }); + + var l = new Label ("blah4"); + l.set_data ("sort_id", 4); + list.add (l); + var l3 = new Label ("blah3"); + l3.set_data ("sort_id", 3); + list.add (l3); + l = new Label ("blah1"); + l.set_data ("sort_id", 1); + list.add (l); + l = new Label ("blah2"); + l.set_data ("sort_id", 2); + list.add (l); + + var row_vbox = new Box (Orientation.VERTICAL, 0); + var row_hbox = new Box (Orientation.HORIZONTAL, 0); + row_vbox.set_data ("sort_id", 3); + l = new Label ("da box for da man"); + row_hbox.add (l); + var check = new CheckButton (); + row_hbox.add (check); + var button = new Button.with_label ("ya!"); + row_hbox.add (button); + row_vbox.add (row_hbox); + check = new CheckButton (); + row_vbox.add (check); + list.add (row_vbox); + + button = new Button.with_label ("focusable row"); + button.set_hexpand (false); + button.set_halign (Align.START); + list.add (button); + + var vbox = new Box(Orientation.VERTICAL, 0); + hbox.add (vbox); + + var b = new Button.with_label ("sort"); + vbox.add (b); + b.clicked.connect ( () => { + list.set_sort_func (compare_label); + }); + + b = new Button.with_label ("reverse"); + vbox.add (b); + b.clicked.connect ( () => { + list.set_sort_func (compare_label_reverse); + }); + + b = new Button.with_label ("change"); + vbox.add (b); + b.clicked.connect ( () => { + if (l3.get_text () == "blah3") { + l3.set_text ("blah5"); + l3.set_data ("sort_id", 5); + } else { + l3.set_text ("blah3"); + l3.set_data ("sort_id", 3); + } + list.child_changed (l3); + }); + + b = new Button.with_label ("filter"); + vbox.add (b); + b.clicked.connect ( () => { + list.set_filter_func (filter); + }); + + b = new Button.with_label ("unfilter"); + vbox.add (b); + b.clicked.connect ( () => { + list.set_filter_func (null); + }); + + int new_button_nr = 1; + b = new Button.with_label ("add"); + vbox.add (b); + b.clicked.connect ( () => { + var ll = new Label ("blah2 new %d".printf (new_button_nr)); + l.set_data ("sort_id", new_button_nr); + new_button_nr++; + + list.add (ll); + l.show (); + }); + + b = new Button.with_label ("separate"); + vbox.add (b); + b.clicked.connect ( () => { + list.set_separator_funcs (update_separator); + }); + + b = new Button.with_label ("unseparate"); + vbox.add (b); + b.clicked.connect ( () => { + list.set_separator_funcs (null); + }); + + + w.show_all (); + + Gtk.main (); + + return 0; +} |