summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mininewt/CHANGES57
-rw-r--r--mininewt/COPYING481
-rw-r--r--mininewt/Makefile96
-rw-r--r--mininewt/button.c190
-rw-r--r--mininewt/buttonbar.c46
-rw-r--r--mininewt/checkbox.c290
-rw-r--r--mininewt/checkboxtree.c792
-rw-r--r--mininewt/config.h12
-rw-r--r--mininewt/dialogboxes.c422
-rw-r--r--mininewt/dialogboxes.h30
-rw-r--r--mininewt/eawidth.c463
-rw-r--r--mininewt/entry.c382
-rw-r--r--mininewt/form.c1137
-rw-r--r--mininewt/grid.c393
-rw-r--r--mininewt/label.c81
-rw-r--r--mininewt/listbox.c764
-rw-r--r--mininewt/newt.c710
-rw-r--r--mininewt/newt.h373
-rw-r--r--mininewt/newt_pr.h83
-rw-r--r--mininewt/scale.c85
-rw-r--r--mininewt/scrollbar.c124
-rw-r--r--mininewt/showchars.c44
-rw-r--r--mininewt/showkey.c41
-rw-r--r--mininewt/snackmodule.c1245
-rw-r--r--mininewt/textbox.c410
-rw-r--r--mininewt/whiptail.c232
-rw-r--r--mininewt/whiptcl.c296
-rw-r--r--mininewt/windows.c275
28 files changed, 9554 insertions, 0 deletions
diff --git a/mininewt/CHANGES b/mininewt/CHANGES
new file mode 100644
index 000000000..1b581a908
--- /dev/null
+++ b/mininewt/CHANGES
@@ -0,0 +1,57 @@
+***************
+THIS FILE IS OBSOLETE -- UPDATE THE SPEC FILE INSTEAD
+***************
+
+0.59 -> 0.50.10
+ - added support for help
+ - added cusor on/off stuff
+
+0.57 -> 0.59
+ - minor fixes
+
+0.55 -> 0.56
+ - added newtCheckboxTreeSetEntry(), newtCheckboxTreeGetEntryValue()
+ and newtCheckboxTreeSetEntryValue()
+ - checkboxtree callbacks
+ - if collapsing branches at the end of the list and list length
+ is larger then height, move first visible entry accordingly
+ - allow selection of all checkboxes on current branch
+ - snack bindings for the above
+
+0.54 -> 0.55
+ - added newtCheckboxTreeGetCurrent() and snack bindings
+ - updated snack stuff to allow manual placement of grid
+ wrapped windows
+
+0.53 -> 0.54
+ - fix segfault in newtRadioGetCurrent
+
+0.52 -> 0.53
+ - place cursor in checkboxtree's more carefully
+
+0.51 -> 0.52
+ - listbox bug fixes
+
+0.50 -> 0.51
+ - added newtFormSetTimer() (and test case, and python)
+ - checkboxtree's could improperly leave info from closed trees
+ at the end of the display
+
+0.40 -> 0.50
+ - added CheckboxTree widget
+ - vastly improved python bindings
+
+0.30 -> 0.40
+ - GPM mouse support added
+
+0.30 -> 0.31:
+ - pgdn could core dump on short textboxes
+
+0.25 -> 0.30:
+ - newtDrawRootText() didn't use the specified position properly
+ - removed relics of original listbox code still handing around
+ checkbox.c
+ - renamed DOBORDER flag to simply BORDER
+ - listboxes no longer scroll by default
+ - newtListboxSetEntry() uses a key, not an index
+ - listbox scrollbars should work properly in borders
diff --git a/mininewt/COPYING b/mininewt/COPYING
new file mode 100644
index 000000000..eb685a5ec
--- /dev/null
+++ b/mininewt/COPYING
@@ -0,0 +1,481 @@
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, 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
+
+ Appendix: 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., 675 Mass Ave, Cambridge, MA 02139, 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/mininewt/Makefile b/mininewt/Makefile
new file mode 100644
index 000000000..fa0c1eafe
--- /dev/null
+++ b/mininewt/Makefile
@@ -0,0 +1,96 @@
+
+include ../Makefile.inc
+
+LIBS = -lslang -lm #-lefence
+SHLIBS = -lslang -lm -lc
+
+GPM_SUPPORT=
+
+CFLAGS = -Os -I/usr/include/slang
+
+VERSION = 0.51.0
+CVSTAG = r$(subst .,-,$(VERSION))
+SONAME = 0.51
+
+PYTHONVERS = $(shell ls -d /usr/include/python* | sed "s|/usr/include/||g")
+
+OBJS = newt.o button.o form.o checkbox.o entry.o label.o listbox.o \
+ scrollbar.o textbox.o scale.o grid.o windows.o buttonbar.o \
+ checkboxtree.o
+SOBJS = $(patsubst %.o,%.lo,$(OBJS))
+DOBJS = $(patsubst %.o,%.do,$(OBJS))
+PROGS =
+LIBNEWT = libnewt.a($(OBJS))
+ifeq (i386, $(ARCH))
+LIBNEWT=libnewt-diet.a($(DOBJS))
+endif
+LIBNEWTSH = libnewt.so.$(VERSION)
+LIBNEWTSONAME = libnewt.so.$(SONAME)
+
+SHCFLAGS = -fPIC
+
+
+#--------------------------------------
+
+SOURCES = $(subst .o,.c,$(TESTOBJS) $(OBJS))
+
+ifeq (.depend,$(wildcard .depend))
+TARGET=$(PROGS)
+else
+TARGET=depend $(PROGS)
+endif
+
+all: $(LIBNEWTSH) $(LIBNEWT) _snackmodule.so
+
+_snackmodule.so: snackmodule.c $(LIBNEWTSH)
+ for ver in $(PYTHONVERS) ; do \
+ if [ ! -f "$$ver/_snackmodule.so" -o $(LIBNEWTSH) -nt "$$ver/_snackmodule.so" ]; then \
+ mkdir -p $$ver ;\
+ gcc $(CFLAGS) -I/usr/include/$$ver -fPIC -c -o $$ver/snackmodule.o snackmodule.c ;\
+ gcc --shared $(SHCFLAGS) -o $$ver/_snackmodule.so $$ver/snackmodule.o -L . $(LIBNEWTSH) ;\
+ fi ; \
+ done
+
+veryclean: clean
+ rm -f .depend
+
+clean:
+ rm -f $(PROGS) *.o *.lo *.do *.so* *.a
+
+depend:
+ $(CPP) $(CFLAGS) -M $(SOURCES) > .depend
+
+$(SHAREDDIR):
+ mkdir -p $(SHAREDDIR)
+
+sharedlib: $(LIBNEWTSH)
+
+$(LIBNEWTSH): $(SOBJS)
+ gcc -shared -o $(LIBNEWTSH) -Wl,-soname,$(LIBNEWTSONAME) $(SOBJS) $(SHLIBS)
+
+%.do: %.c
+ diet $(CC) -c $(CFLAGS) -o $@ $<
+
+%.lo: %.c
+ $(CC) $(SHCFLAGS) -c $(CFLAGS) -o $@ $<
+
+newt.o: newt.c Makefile
+ $(CC) $(CFLAGS) -DVERSION=\"$(VERSION)\" -c -o $@ $<
+
+newt.do: newt.c Makefile
+ diet $(CC) $(SHCFLAGS) $(CFLAGS) -DVERSION=\"$(VERSION)\" -c -o $@ $<
+
+newt.lo: newt.c Makefile
+ $(CC) $(SHCFLAGS) $(CFLAGS) -DVERSION=\"$(VERSION)\" -c -o $@ $<
+
+
+install: $(LIBNEWT) $(LIBNEWTSH) _snackmodule.so
+ install -m 644 $(LIBNEWT) $(DESTDIR)/$(RUNTIMEDIR)
+ install -s -m 755 $(LIBNEWTSH) $(DESTDIR)/$(RUNTIMEDIR)/$(LIBNEWTSONAME)
+ for ver in $(PYTHONVERS) ; do \
+ install -s -m 755 $$ver/_snackmodule.so $(DESTDIR)/$(RUNTIMEDIR)
+ done
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/mininewt/button.c b/mininewt/button.c
new file mode 100644
index 000000000..1ff360dc5
--- /dev/null
+++ b/mininewt/button.c
@@ -0,0 +1,190 @@
+#include <slang.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+struct button {
+ char * text;
+ int compact;
+};
+
+static void buttonDrawIt(newtComponent co, int active, int pushed);
+static void buttonDrawText(newtComponent co, int active, int pushed);
+
+static void buttonDraw(newtComponent c);
+static void buttonDestroy(newtComponent co);
+static struct eventResult buttonEvent(newtComponent c,
+ struct event ev);
+static void buttonPlace(newtComponent co, int newLeft, int newTop);
+
+static struct componentOps buttonOps = {
+ buttonDraw,
+ buttonEvent,
+ buttonDestroy,
+ buttonPlace,
+ newtDefaultMappedHandler,
+} ;
+
+static newtComponent createButton(int left, int row, const char * text, int compact) {
+ newtComponent co;
+ struct button * bu;
+
+ co = malloc(sizeof(*co));
+ bu = malloc(sizeof(struct button));
+ co->data = bu;
+
+ bu->text = strdup(text);
+ bu->compact = compact;
+ co->ops = &buttonOps;
+
+ if (bu->compact) {
+ co->height = 1;
+ co->width = strlen(text) + 3;
+ } else {
+ co->height = 4;
+ co->width = strlen(text) + 5;
+ }
+
+ co->top = row;
+ co->left = left;
+ co->takesFocus = 1;
+ co->isMapped = 0;
+
+ newtGotorc(co->top, co->left);
+
+ return co;
+}
+
+newtComponent newtCompactButton(int left, int row, const char * text) {
+ return createButton(left, row, text, 1);
+}
+
+newtComponent newtButton(int left, int row, const char * text) {
+ return createButton(left, row, text, 0);
+}
+
+static void buttonDestroy(newtComponent co) {
+ struct button * bu = co->data;
+
+ free(bu->text);
+ free(bu);
+ free(co);
+}
+
+static void buttonPlace(newtComponent co, int newLeft, int newTop) {
+ co->top = newTop;
+ co->left = newLeft;
+
+ newtGotorc(co->top, co->left);
+}
+
+static void buttonDraw(newtComponent co) {
+ buttonDrawIt(co, 0, 0);
+}
+
+static void buttonDrawIt(newtComponent co, int active, int pushed) {
+ struct button * bu = co->data;
+
+ if (!co->isMapped) return;
+
+ SLsmg_set_color(NEWT_COLORSET_BUTTON);
+
+ if (bu->compact) {
+ if (active)
+ SLsmg_set_color(NEWT_COLORSET_COMPACTBUTTON);
+ else
+ SLsmg_set_color(NEWT_COLORSET_BUTTON);
+ newtGotorc(co->top+ pushed, co->left + 1 + pushed);
+ SLsmg_write_char('<');
+ SLsmg_write_string(bu->text);
+ SLsmg_write_char('>');
+ } else {
+ if (pushed) {
+ SLsmg_set_color(NEWT_COLORSET_BUTTON);
+ newtDrawBox(co->left + 1, co->top + 1, co->width - 1, 3, 0);
+
+ SLsmg_set_color(NEWT_COLORSET_WINDOW);
+ newtClearBox(co->left, co->top, co->width, 1);
+ newtClearBox(co->left, co->top, 1, co->height);
+ } else {
+ newtDrawBox(co->left, co->top, co->width - 1, 3, 1);
+ }
+
+ buttonDrawText(co, active, pushed);
+ }
+}
+
+static void buttonDrawText(newtComponent co, int active, int pushed) {
+ struct button * bu = co->data;
+
+ if (pushed) pushed = 1;
+
+ if (active)
+ SLsmg_set_color(NEWT_COLORSET_ACTBUTTON);
+ else
+ SLsmg_set_color(NEWT_COLORSET_BUTTON);
+
+ newtGotorc(co->top + 1 + pushed, co->left + 1 + pushed);
+ SLsmg_write_char(' ');
+ SLsmg_write_string(bu->text);
+ SLsmg_write_char(' ');
+}
+
+static struct eventResult buttonEvent(newtComponent co,
+ struct event ev) {
+ struct eventResult er;
+ struct button * bu = co->data;
+
+ if (ev.when == EV_NORMAL) {
+ switch (ev.event) {
+ case EV_FOCUS:
+ buttonDrawIt(co, 1, 0);
+ er.result = ER_SWALLOWED;
+ break;
+
+ case EV_UNFOCUS:
+ buttonDrawIt(co, 0, 0);
+ er.result = ER_SWALLOWED;
+ break;
+
+ case EV_KEYPRESS:
+ if (ev.u.key == ' ' || ev.u.key == '\r') {
+ if (!bu->compact) {
+ /* look pushed */
+ buttonDrawIt(co, 1, 1);
+ newtRefresh();
+ newtDelay(150000);
+ buttonDrawIt(co, 1, 0);
+ newtRefresh();
+ newtDelay(150000);
+ }
+
+ er.result = ER_EXITFORM;
+ } else
+ er.result = ER_IGNORED;
+ break;
+ case EV_MOUSE:
+ if (ev.u.mouse.type == MOUSE_BUTTON_DOWN &&
+ co->top <= ev.u.mouse.y &&
+ co->top + co->height - !bu->compact > ev.u.mouse.y &&
+ co->left <= ev.u.mouse.x &&
+ co->left + co->width - !bu->compact > ev.u.mouse.x) {
+ if (!bu->compact) {
+ buttonDrawIt(co, 1, 1);
+ newtRefresh();
+ newtDelay(150000);
+ buttonDrawIt(co, 1, 0);
+ newtRefresh();
+ newtDelay(150000);
+ }
+ er.result = ER_EXITFORM;
+ }
+ break;
+ }
+ } else
+ er.result = ER_IGNORED;
+
+ return er;
+}
diff --git a/mininewt/buttonbar.c b/mininewt/buttonbar.c
new file mode 100644
index 000000000..45473c9d2
--- /dev/null
+++ b/mininewt/buttonbar.c
@@ -0,0 +1,46 @@
+#include <stdarg.h>
+
+#include "newt.h"
+
+/* if they try and pack more then 50 buttons, screw 'em */
+newtGrid newtButtonBarv(char * button1, newtComponent * b1comp, va_list args) {
+ newtGrid grid;
+ struct buttonInfo {
+ char * name;
+ newtComponent * compPtr;
+ } buttons[50];
+ int num;
+ int i;
+
+ buttons[0].name = button1, buttons[0].compPtr = b1comp, num = 1;
+ while (1) {
+ buttons[num].name = va_arg(args, char *);
+ if (!buttons[num].name) break;
+ buttons[num].compPtr = va_arg(args, newtComponent *);
+ num++;
+ }
+
+ grid = newtCreateGrid(num, 1);
+
+ for (i = 0; i < num; i++) {
+ *buttons[i].compPtr = newtButton(-1, -1, buttons[i].name);
+ newtGridSetField(grid, i, 0, NEWT_GRID_COMPONENT,
+ *buttons[i].compPtr,
+ num ? 1 : 0, 0, 0, 0, 0, 0);
+ }
+
+ return grid;
+}
+
+newtGrid newtButtonBar(char * button1, newtComponent * b1comp, ...) {
+ va_list args;
+ newtGrid grid;
+
+ va_start(args, b1comp);
+
+ grid = newtButtonBarv(button1, b1comp, args);
+
+ va_end(args);
+
+ return grid;
+}
diff --git a/mininewt/checkbox.c b/mininewt/checkbox.c
new file mode 100644
index 000000000..eee514c98
--- /dev/null
+++ b/mininewt/checkbox.c
@@ -0,0 +1,290 @@
+#include <slang.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+enum type { CHECK, RADIO };
+
+struct checkbox {
+ char * text;
+ char * seq;
+ char * result;
+ newtComponent prevButton, lastButton;
+ enum type type;
+ char value;
+ int active, inactive;
+ const void * data;
+ int flags;
+ int hasFocus;
+};
+
+static void makeActive(newtComponent co);
+
+static void cbDraw(newtComponent c);
+static void cbDestroy(newtComponent co);
+struct eventResult cbEvent(newtComponent co, struct event ev);
+
+static struct componentOps cbOps = {
+ cbDraw,
+ cbEvent,
+ cbDestroy,
+ newtDefaultPlaceHandler,
+ newtDefaultMappedHandler,
+} ;
+
+newtComponent newtRadiobutton(int left, int top, const char * text, int isDefault,
+ newtComponent prevButton) {
+ newtComponent co;
+ newtComponent curr;
+ struct checkbox * rb;
+ char initialValue;
+
+ if (isDefault)
+ initialValue = '*';
+ else
+ initialValue = ' ';
+
+ co = newtCheckbox(left, top, text, initialValue, " *", NULL);
+ rb = co->data;
+ rb->type = RADIO;
+
+ rb->prevButton = prevButton;
+
+ for (curr = co; curr; curr = rb->prevButton) {
+ rb = curr->data;
+ rb->lastButton = co;
+ }
+
+ return co;
+}
+
+newtComponent newtRadioGetCurrent(newtComponent setMember) {
+ struct checkbox * rb = setMember->data;
+
+ setMember = rb->lastButton;
+ rb = setMember->data;
+
+ while (rb && rb->value != '*') {
+ setMember = rb->prevButton;
+ if (!setMember)
+ return NULL;
+ rb = setMember->data;
+ }
+
+ return setMember;
+}
+
+char newtCheckboxGetValue(newtComponent co) {
+ struct checkbox * cb = co->data;
+
+ return cb->value;
+}
+
+void newtCheckboxSetValue(newtComponent co, char value) {
+ struct checkbox * cb = co->data;
+
+ *cb->result = value;
+ cbDraw(co);
+}
+
+newtComponent newtCheckbox(int left, int top, const char * text, char defValue,
+ const char * seq, char * result) {
+ newtComponent co;
+ struct checkbox * cb;
+
+ if (!seq) seq = " *";
+
+ co = malloc(sizeof(*co));
+ cb = malloc(sizeof(struct checkbox));
+ co->data = cb;
+ cb->flags = 0;
+ if (result)
+ cb->result = result;
+ else
+ cb->result = &cb->value;
+
+ cb->text = strdup(text);
+ cb->seq = strdup(seq);
+ cb->type = CHECK;
+ cb->hasFocus = 0;
+ cb->inactive = COLORSET_CHECKBOX;
+ cb->active = COLORSET_ACTCHECKBOX;
+ defValue ? (*cb->result = defValue) : (*cb->result = cb->seq[0]);
+
+ co->ops = &cbOps;
+
+ co->callback = NULL;
+ co->height = 1;
+ co->width = strlen(text) + 4;
+ co->top = top;
+ co->left = left;
+ co->takesFocus = 1;
+
+ return co;
+}
+
+void newtCheckboxSetFlags(newtComponent co, int flags, enum newtFlagsSense sense) {
+ struct checkbox * cb = co->data;
+ int row, col;
+
+ cb->flags = newtSetFlags(cb->flags, flags, sense);
+
+ if (!(cb->flags & NEWT_FLAG_DISABLED))
+ co->takesFocus = 1;
+ else
+ co->takesFocus = 0;
+
+ newtGetrc(&row, &col);
+ cbDraw(co);
+ newtGotorc(row, col);
+}
+
+static void cbDraw(newtComponent c) {
+ struct checkbox * cb = c->data;
+
+ if (c->top == -1 || !c->isMapped) return;
+
+ if (cb->flags & NEWT_FLAG_DISABLED) {
+ cb->inactive = NEWT_COLORSET_DISENTRY;
+ cb->active = NEWT_COLORSET_DISENTRY;
+ } else {
+ cb->inactive = COLORSET_CHECKBOX;
+ cb->active = COLORSET_ACTCHECKBOX;
+ }
+
+ SLsmg_set_color(cb->inactive);
+
+ newtGotorc(c->top, c->left);
+
+ switch (cb->type) {
+ case RADIO:
+ SLsmg_write_string("( ) ");
+ break;
+
+ case CHECK:
+ SLsmg_write_string("[ ] ");
+ break;
+
+ default:
+ break;
+ }
+
+ SLsmg_write_string(cb->text);
+
+ if (cb->hasFocus)
+ SLsmg_set_color(cb->active);
+
+ newtGotorc(c->top, c->left + 1);
+ SLsmg_write_char(*cb->result);
+}
+
+static void cbDestroy(newtComponent co) {
+ struct checkbox * cb = co->data;
+
+ free(cb->text);
+ free(cb->seq);
+ free(cb);
+ free(co);
+}
+
+struct eventResult cbEvent(newtComponent co, struct event ev) {
+ struct checkbox * cb = co->data;
+ struct eventResult er;
+ const char * cur;
+
+ if (ev.when == EV_NORMAL) {
+ switch (ev.event) {
+ case EV_FOCUS:
+ cb->hasFocus = 1;
+ cbDraw(co);
+ er.result = ER_SWALLOWED;
+ break;
+
+ case EV_UNFOCUS:
+ cb->hasFocus = 0;
+ cbDraw(co);
+ er.result = ER_SWALLOWED;
+ break;
+
+ case EV_KEYPRESS:
+ if (ev.u.key == ' ') {
+ if (cb->type == RADIO) {
+ makeActive(co);
+ } else if (cb->type == CHECK) {
+ cur = strchr(cb->seq, *cb->result);
+ if (!cur)
+ *cb->result = *cb->seq;
+ else {
+ cur++;
+ if (! *cur)
+ *cb->result = *cb->seq;
+ else
+ *cb->result = *cur;
+ }
+ cbDraw(co);
+ er.result = ER_SWALLOWED;
+
+ if (co->callback)
+ co->callback(co, co->callbackData);
+ } else {
+ er.result = ER_IGNORED;
+ }
+ } else if(ev.u.key == NEWT_KEY_ENTER) {
+ er.result = ER_IGNORED;
+ } else {
+ er.result = ER_IGNORED;
+ }
+ break;
+ case EV_MOUSE:
+ if (ev.u.mouse.type == MOUSE_BUTTON_DOWN) {
+ if (cb->type == RADIO) {
+ makeActive(co);
+ } else if (cb->type == CHECK) {
+ cur = strchr(cb->seq, *cb->result);
+ if (!cur)
+ *cb->result = *cb->seq;
+ else {
+ cur++;
+ if (! *cur)
+ *cb->result = *cb->seq;
+ else
+ *cb->result = *cur;
+ }
+ cbDraw(co);
+ er.result = ER_SWALLOWED;
+
+ if (co->callback)
+ co->callback(co, co->callbackData);
+ }
+ }
+ }
+ } else
+ er.result = ER_IGNORED;
+
+ return er;
+}
+
+static void makeActive(newtComponent co) {
+ struct checkbox * cb = co->data;
+ struct checkbox * rb;
+ newtComponent curr;
+
+ /* find the one that's turned off */
+ curr = cb->lastButton;
+ rb = curr->data;
+ while (curr && rb->value == rb->seq[0]) {
+ curr = rb->prevButton;
+ if (curr) rb = curr->data;
+ }
+ if (curr) {
+ rb->value = rb->seq[0];
+ cbDraw(curr);
+ }
+ cb->value = cb->seq[1];
+ cbDraw(co);
+
+ if (co->callback)
+ co->callback(co, co->callbackData);
+}
diff --git a/mininewt/checkboxtree.c b/mininewt/checkboxtree.c
new file mode 100644
index 000000000..2c8df85cc
--- /dev/null
+++ b/mininewt/checkboxtree.c
@@ -0,0 +1,792 @@
+#include <slang.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+struct items {
+ char * text;
+ const void *data;
+ unsigned char selected;
+ struct items *next;
+ struct items *prev;
+ struct items *branch;
+ int flags;
+ int depth;
+};
+
+struct CheckboxTree {
+ newtComponent sb;
+ struct items * itemlist;
+ struct items ** flatList, ** currItem, ** firstItem;
+ int flatCount;
+ int flags;
+ int sbAdjust;
+ int curWidth;
+ int userHasSetWidth;
+ char * seq;
+ char * result;
+};
+
+static void ctDraw(newtComponent c);
+static void ctDestroy(newtComponent co);
+static void ctPlace(newtComponent co, int newLeft, int newTop);
+struct eventResult ctEvent(newtComponent co, struct event ev);
+static void ctMapped(newtComponent co, int isMapped);
+static struct items * findItem(struct items * items, const void * data);
+static void buildFlatList(newtComponent co);
+static void doBuildFlatList(struct CheckboxTree * ct, struct items * item);
+enum countWhat { COUNT_EXPOSED=0, COUNT_SELECTED=1 };
+static int countItems(struct items * item, enum countWhat justExposed);
+static inline void updateWidth(newtComponent co, struct CheckboxTree * ct,
+ int maxField);
+
+static struct componentOps ctOps = {
+ ctDraw,
+ ctEvent,
+ ctDestroy,
+ ctPlace,
+ ctMapped,
+} ;
+
+static inline void updateWidth(newtComponent co, struct CheckboxTree * ct,
+ int maxField) {
+ ct->curWidth = maxField;
+ co->width = ct->curWidth + ct->sbAdjust;
+
+ if (ct->sb)
+ ct->sb->left = co->left + co->width - 1;
+}
+
+static int countItems(struct items * item, enum countWhat what) {
+ int count = 0;
+
+ while (item) {
+ if ((!item->branch && item->selected == what) || (what == COUNT_EXPOSED))
+ count++;
+ if (item->branch || (what == COUNT_EXPOSED && item->selected))
+ count += countItems(item->branch, what);
+ item = item->next;
+ }
+
+ return count;
+}
+
+static void doBuildFlatList(struct CheckboxTree * ct, struct items * item) {
+ while (item) {
+ ct->flatList[ct->flatCount++] = item;
+ if (item->branch && item->selected) doBuildFlatList(ct, item->branch);
+ item = item->next;
+ }
+}
+
+static void buildFlatList(newtComponent co) {
+ struct CheckboxTree * ct = co->data;
+
+ if (ct->flatList) free(ct->flatList);
+ ct->flatCount = countItems(ct->itemlist, COUNT_EXPOSED);
+
+ ct->flatList = malloc(sizeof(*ct->flatList) * (ct->flatCount+1));
+ ct->flatCount = 0;
+ doBuildFlatList(ct, ct->itemlist);
+ ct->flatList[ct->flatCount] = NULL;
+}
+
+int newtCheckboxTreeAddItem(newtComponent co,
+ const char * text, const void * data,
+ int flags, int index, ...) {
+ va_list argList;
+ int numIndexes;
+ int * indexes;
+ int i;
+
+ va_start(argList, index);
+ numIndexes = 0;
+ i = index;
+ while (i != NEWT_ARG_LAST) {
+ numIndexes++;
+ i = va_arg(argList, int);
+ }
+
+ va_end(argList);
+
+ indexes = alloca(sizeof(*indexes) * (numIndexes + 1));
+ va_start(argList, index);
+ numIndexes = 0;
+ i = index;
+ va_start(argList, index);
+ while (i != NEWT_ARG_LAST) {
+ indexes[numIndexes++] = i;
+ i = va_arg(argList, int);
+ }
+ va_end(argList);
+
+ indexes[numIndexes++] = NEWT_ARG_LAST;
+
+ return newtCheckboxTreeAddArray(co, text, data, flags, indexes);
+}
+
+static int doFindItemPath(struct items * items, void * data, int * path,
+ int * len) {
+ int where = 0;
+
+ while (items) {
+ if (items->data == data) {
+ if (path) path[items->depth] = where;
+ if (len) *len = items->depth + 1;
+ return 1;
+ }
+
+ if (items->branch && doFindItemPath(items->branch, data, path, len)) {
+ if (path) path[items->depth] = where;
+ return 1;
+ }
+
+ items = items->next;
+ where++;
+ }
+
+ return 0;
+}
+
+int * newtCheckboxTreeFindItem(newtComponent co, void * data) {
+ int len;
+ int * path;
+ struct CheckboxTree * ct = co->data;
+
+ if (!doFindItemPath(ct->itemlist, data, NULL, &len)) return NULL;
+
+ path = malloc(sizeof(*path) * (len + 1));
+ doFindItemPath(ct->itemlist, data, path, NULL);
+ path[len] = NEWT_ARG_LAST;
+
+ return path;
+}
+
+int newtCheckboxTreeAddArray(newtComponent co,
+ const char * text, const void * data,
+ int flags, int * indexes) {
+ struct items * curList, * newNode, * item;
+ struct items ** listPtr = NULL;
+ int i, index, numIndexes;
+ struct CheckboxTree * ct = co->data;
+
+ numIndexes = 0;
+ while (indexes[numIndexes] != NEWT_ARG_LAST) numIndexes++;
+
+ if (!ct->itemlist) {
+ if (numIndexes > 1) return -1;
+
+ ct->itemlist = malloc(sizeof(*ct->itemlist));
+ item = ct->itemlist;
+ item->prev = NULL;
+ item->next = NULL;
+ } else {
+ curList = ct->itemlist;
+ listPtr = &ct->itemlist;
+
+ i = 0;
+ index = indexes[i];
+ while (i < numIndexes) {
+ item = curList;
+
+ if (index == NEWT_ARG_APPEND) {
+ item = NULL;
+ } else {
+ while (index && item)
+ item = item->next, index--;
+ }
+
+ i++;
+ if (i < numIndexes) {
+ curList = item->branch;
+ listPtr = &item->branch;
+ if (!curList && (i + 1 != numIndexes)) return -1;
+
+ index = indexes[i];
+ }
+ }
+
+ if (!curList) { /* create a new branch */
+ item = malloc(sizeof(*curList->prev));
+ item->next = item->prev = NULL;
+ *listPtr = item;
+ } else if (!item) { /* append to end */
+ item = curList;
+ while (item->next) item = item->next;
+ item->next = malloc(sizeof(*curList->prev));
+ item->next->prev = item;
+ item = item->next;
+ item->next = NULL;
+ } else {
+ newNode = malloc(sizeof(*newNode));
+ newNode->prev = item->prev;
+ newNode->next = item;
+
+ if (item->prev) item->prev->next = newNode;
+ item->prev = newNode;
+ item = newNode;
+ if (!item->prev) *listPtr = item;
+ }
+ }
+
+ item->text = strdup(text);
+ item->data = data;
+ if (flags & NEWT_FLAG_SELECTED) {
+ item->selected = 1;
+ } else {
+ item->selected = 0;
+ }
+ item->flags = flags;
+ item->branch = NULL;
+ item->depth = numIndexes - 1;
+
+ i = 4 + (3 * item->depth);
+
+ if ((ct->userHasSetWidth == 0) && ((strlen(text) + i + ct->sbAdjust) > co->width)) {
+ updateWidth(co, ct, strlen(text) + i);
+ }
+
+ return 0;
+}
+
+static struct items * findItem(struct items * items, const void * data) {
+ struct items * i;
+
+ while (items) {
+ if (items->data == data) return items;
+ if (items->branch) {
+ i = findItem(items->branch, data);
+ if (i) return i;
+ }
+
+ items = items->next;
+ }
+
+ return NULL;
+}
+
+static void listSelected(struct items * items, int * num, const void ** list, int seqindex) {
+ while (items) {
+ if ((seqindex ? items->selected==seqindex : items->selected) && !items->branch)
+ list[(*num)++] = (void *) items->data;
+ if (items->branch)
+ listSelected(items->branch, num, list, seqindex);
+ items = items->next;
+ }
+}
+
+void newtCheckboxTreeSetWidth(newtComponent co, int width) {
+ struct CheckboxTree * ct = co->data;
+
+ co->width = width;
+ ct->curWidth = co->width - ct->sbAdjust;
+ ct->userHasSetWidth = 1;
+ if (ct->sb) ct->sb->left = co->width + co->left - 1;
+ ctDraw(co);
+}
+
+const void ** newtCheckboxTreeGetSelection(newtComponent co, int *numitems)
+{
+ return newtCheckboxTreeGetMultiSelection(co, numitems, 0);
+}
+
+const void ** newtCheckboxTreeGetMultiSelection(newtComponent co, int *numitems, char seqnum)
+{
+ struct CheckboxTree * ct;
+ const void **retval;
+ int seqindex=0;
+
+ if(!co || !numitems) return NULL;
+
+ ct = co->data;
+
+ if (seqnum) {
+ while( ct->seq[seqindex] && ( ct->seq[seqindex] != seqnum )) seqindex++;
+ } else {
+ seqindex = 0;
+ }
+
+ *numitems = countItems(ct->itemlist, (seqindex ? seqindex : COUNT_SELECTED));
+ if (!*numitems) return NULL;
+
+ retval = malloc(*numitems * sizeof(void *));
+ *numitems = 0;
+ listSelected(ct->itemlist, numitems, retval, seqindex);
+
+ return retval;
+}
+
+newtComponent newtCheckboxTree(int left, int top, int height, int flags) {
+ return newtCheckboxTreeMulti(left, top, height, NULL, flags);
+}
+
+newtComponent newtCheckboxTreeMulti(int left, int top, int height, char *seq, int flags) {
+ newtComponent co;
+ struct CheckboxTree * ct;
+
+ co = malloc(sizeof(*co));
+ ct = malloc(sizeof(struct CheckboxTree));
+ co->callback = NULL;
+ co->data = ct;
+ co->ops = &ctOps;
+ co->takesFocus = 1;
+ co->height = height;
+ co->width = 0;
+ co->isMapped = 0;
+ ct->curWidth = 0;
+ ct->userHasSetWidth = 0;
+ ct->itemlist = NULL;
+ ct->firstItem = NULL;
+ ct->currItem = NULL;
+ ct->flatList = NULL;
+
+ ct->flags = flags;
+
+ if (seq)
+ ct->seq = strdup(seq);
+ else
+ ct->seq = strdup(" *");
+ if (flags & NEWT_FLAG_SCROLL) {
+ ct->sb = newtVerticalScrollbar(left, top, height,
+ COLORSET_LISTBOX, COLORSET_ACTLISTBOX);
+ ct->sbAdjust = 2;
+ } else {
+ ct->sb = NULL;
+ ct->sbAdjust = 0;
+ }
+
+ return co;
+}
+
+static void ctMapped(newtComponent co, int isMapped) {
+ struct CheckboxTree * ct = co->data;
+
+ co->isMapped = isMapped;
+ if (ct->sb)
+ ct->sb->ops->mapped(ct->sb, isMapped);
+}
+
+static void ctPlace(newtComponent co, int newLeft, int newTop) {
+ struct CheckboxTree * ct = co->data;
+
+ co->top = newTop;
+ co->left = newLeft;
+
+ if (ct->sb)
+ ct->sb->ops->place(ct->sb, co->left + co->width - 1, co->top);
+}
+
+int ctSetItem(newtComponent co, struct items *item, enum newtFlagsSense sense)
+{
+ struct CheckboxTree * ct = co->data;
+ struct items * currItem;
+ struct items * firstItem;
+
+ if (!item)
+ return 1;
+
+ switch(sense) {
+ case NEWT_FLAGS_RESET:
+ item->selected = 0;
+ break;
+ case NEWT_FLAGS_SET:
+ item->selected = 1;
+ break;
+ case NEWT_FLAGS_TOGGLE:
+ if (item->branch)
+ item->selected = !item->selected;
+ else if (!(ct->flags & NEWT_CHECKBOXTREE_UNSELECTABLE)) {
+ item->selected++;
+ if (item->selected==strlen(ct->seq))
+ item->selected = 0;
+ }
+ break;
+ }
+
+ if (item->branch) {
+ currItem = *ct->currItem;
+ firstItem = *ct->firstItem;
+
+ buildFlatList(co);
+
+ ct->currItem = ct->flatList;
+ while (*ct->currItem != currItem) ct->currItem++;
+
+ ct->firstItem = ct->flatList;
+ if (ct->flatCount > co->height) {
+ struct items ** last = ct->flatList + ct->flatCount - co->height;
+ while (*ct->firstItem != firstItem && ct->firstItem != last)
+ ct->firstItem++;
+ }
+ }
+
+ return 0;
+}
+
+static void ctSetItems(struct items *item, int selected)
+{
+ for (; item; item = item->next) {
+ if (!item->branch)
+ item->selected = selected;
+ else
+ ctSetItems(item->branch, selected);
+ }
+}
+
+static void ctDraw(newtComponent co) {
+ struct CheckboxTree * ct = co->data;
+ struct items ** item;
+ int i, j;
+ char * spaces;
+ int currRow;
+
+ if (!co->isMapped) return ;
+
+ if (!ct->firstItem) {
+ buildFlatList(co);
+ ct->firstItem = ct->currItem = ct->flatList;
+ }
+
+ item = ct->firstItem;
+
+ i = 0;
+
+ newtTrashScreen();
+
+ while (*item && i < co->height) {
+ newtGotorc(co->top + i, co->left);
+ if (*item == *ct->currItem) {
+ SLsmg_set_color(NEWT_COLORSET_ACTLISTBOX);
+ currRow = co->top + i;
+ } else
+ SLsmg_set_color(NEWT_COLORSET_LISTBOX);
+
+ for (j = 0; j < (*item)->depth; j++)
+ SLsmg_write_string(" ");
+
+ if ((*item)->branch) {
+ if ((*item)->selected)
+ SLsmg_write_string("<-> ");
+ else
+ SLsmg_write_string("<+> ");
+ } else {
+ if (ct->flags & NEWT_CHECKBOXTREE_HIDE_BOX) {
+ if ((*item)->selected)
+ SLsmg_set_color(NEWT_COLORSET_ACTLISTBOX);
+ SLsmg_write_string(" ");
+ } else {
+ char tmp[5];
+ snprintf(tmp,5,"[%c] ",ct->seq[(*item)->selected]);
+ SLsmg_write_string(tmp);
+ }
+ }
+
+ SLsmg_write_nstring((*item)->text, co->width - 4 -
+ (3 * (*item)->depth));
+
+ SLsmg_set_color(NEWT_COLORSET_LISTBOX);
+
+ item++;
+ i++;
+ }
+
+ /* There could be empty lines left (i.e. if the user closes an expanded
+ list which is the last thing in the tree, and whose elements are
+ displayed at the bottom of the screen */
+ if (i < co->height) {
+ spaces = alloca(co->width);
+ memset(spaces, ' ', co->width);
+ SLsmg_set_color(NEWT_COLORSET_LISTBOX);
+ }
+ while (i < co->height) {
+ newtGotorc(co->top + i, co->left);
+ SLsmg_write_nstring(spaces, co->width);
+ i++;
+ }
+
+ if(ct->sb) {
+ newtScrollbarSet(ct->sb, ct->currItem - ct->flatList,
+ ct->flatCount - 1);
+ ct->sb->ops->draw(ct->sb);
+ }
+
+ newtGotorc(currRow, co->left + 1);
+}
+
+static void ctDestroy(newtComponent co) {
+ struct CheckboxTree * ct = co->data;
+ struct items * item, * nextitem;
+
+ nextitem = item = ct->itemlist;
+
+ while (item != NULL) {
+ nextitem = item->next;
+ free(item->text);
+ free(item);
+ item = nextitem;
+ }
+
+ free(ct->seq);
+ free(ct);
+ free(co);
+}
+
+struct eventResult ctEvent(newtComponent co, struct event ev) {
+ struct CheckboxTree * ct = co->data;
+ struct eventResult er;
+ struct items ** listEnd, ** lastItem;
+ int key, selnum = 1;
+
+ er.result = ER_IGNORED;
+
+ if(ev.when == EV_EARLY || ev.when == EV_LATE) {
+ return er;
+ }
+
+ switch(ev.event) {
+ case EV_KEYPRESS:
+ key = ev.u.key;
+ if (key == (char) key && key != ' ') {
+ for (selnum = 0; ct->seq[selnum]; selnum++)
+ if (key == ct->seq[selnum])
+ break;
+ if (!ct->seq[selnum])
+ switch (key) {
+ case '-': selnum = 0; break;
+ case '+':
+ case '*': selnum = 1; break;
+ }
+ if (ct->seq[selnum])
+ key = '*';
+ }
+ switch(key) {
+ case ' ':
+ case NEWT_KEY_ENTER:
+ ctSetItem(co, *ct->currItem, NEWT_FLAGS_TOGGLE);
+ er.result = ER_SWALLOWED;
+ if (!(*ct->currItem)->branch || (*ct->currItem)->selected)
+ key = NEWT_KEY_DOWN;
+ else
+ key = '*';
+ break;
+ case '*':
+ if ((*ct->currItem)->branch) {
+ ctSetItems((*ct->currItem)->branch, selnum);
+ if (!(*ct->currItem)->selected)
+ key = NEWT_KEY_DOWN;
+ } else {
+ (*ct->currItem)->selected = selnum;
+ key = NEWT_KEY_DOWN;
+ }
+ er.result = ER_SWALLOWED;
+ break;
+ }
+ switch (key) {
+ case '*':
+ ctDraw(co);
+ if(co->callback) co->callback(co, co->callbackData);
+ return er;
+ case NEWT_KEY_HOME:
+ ct->currItem = ct->flatList;
+ ct->firstItem = ct->flatList;
+ ctDraw(co);
+ if(co->callback) co->callback(co, co->callbackData);
+ er.result = ER_SWALLOWED;
+ return er;
+ case NEWT_KEY_END:
+ ct->currItem = ct->flatList + ct->flatCount - 1;
+ if (ct->flatCount <= co->height)
+ ct->firstItem = ct->flatList;
+ else
+ ct->firstItem = ct->flatList + ct->flatCount - co->height;
+ ctDraw(co);
+ if(co->callback) co->callback(co, co->callbackData);
+ er.result = ER_SWALLOWED;
+ return er;
+ case NEWT_KEY_DOWN:
+ if (ev.u.key != NEWT_KEY_DOWN) {
+ if(co->callback) co->callback(co, co->callbackData);
+ if (strlen(ct->seq) != 2) {
+ ctDraw(co);
+ return er;
+ }
+ }
+ if ((ct->currItem - ct->flatList + 1) < ct->flatCount) {
+ ct->currItem++;
+
+ if (ct->currItem - ct->firstItem >= co->height)
+ ct->firstItem++;
+
+ ctDraw(co);
+ } else if (ev.u.key != NEWT_KEY_DOWN)
+ ctDraw(co);
+ if(co->callback) co->callback(co, co->callbackData);
+ er.result = ER_SWALLOWED;
+ return er;
+ case NEWT_KEY_UP:
+ if (ct->currItem != ct->flatList) {
+ ct->currItem--;
+
+ if (ct->currItem < ct->firstItem)
+ ct->firstItem = ct->currItem;
+
+ ctDraw(co);
+ }
+ er.result = ER_SWALLOWED;
+ if(co->callback) co->callback(co, co->callbackData);
+ return er;
+ case NEWT_KEY_PGUP:
+ if (ct->firstItem - co->height < ct->flatList) {
+ ct->firstItem = ct->currItem = ct->flatList;
+ } else {
+ ct->currItem -= co->height;
+ ct->firstItem -= co->height;
+ }
+
+ ctDraw(co);
+ if(co->callback) co->callback(co, co->callbackData);
+ er.result = ER_SWALLOWED;
+ return er;
+ case NEWT_KEY_PGDN:
+ listEnd = ct->flatList + ct->flatCount - 1;
+ lastItem = ct->firstItem + co->height - 1;
+
+ if (lastItem + co->height > listEnd) {
+ ct->firstItem = listEnd - co->height + 1;
+ ct->currItem = listEnd;
+ } else {
+ ct->currItem += co->height;
+ ct->firstItem += co->height;
+ }
+
+ ctDraw(co);
+ if(co->callback) co->callback(co, co->callbackData);
+ er.result = ER_SWALLOWED;
+ return er;
+ }
+ break;
+
+ case EV_FOCUS:
+ ctDraw(co);
+ er.result = ER_SWALLOWED;
+ break;
+
+ case EV_UNFOCUS:
+ ctDraw(co);
+ er.result = ER_SWALLOWED;
+ break;
+ default:
+ break;
+ }
+
+ return er;
+}
+
+const void * newtCheckboxTreeGetCurrent(newtComponent co) {
+ struct CheckboxTree * ct = co->data;
+
+ if (!ct->currItem) return NULL;
+ return (*ct->currItem)->data;
+}
+
+void newtCheckboxTreeSetEntry(newtComponent co, const void * data, const char * text)
+{
+ struct CheckboxTree * ct;
+ struct items * item;
+ int i;
+
+ if (!co) return;
+ ct = co->data;
+ item = findItem(ct->itemlist, data);
+ if (!item) return;
+
+ free(item->text);
+ item->text = strdup(text);
+
+ i = 4 + (3 * item->depth);
+
+ if ((ct->userHasSetWidth == 0) && ((strlen(text) + i + ct->sbAdjust) > co->width)) {
+ updateWidth(co, ct, strlen(text) + i);
+ }
+
+ ctDraw(co);
+}
+
+char newtCheckboxTreeGetEntryValue(newtComponent co, const void * data)
+{
+ struct CheckboxTree * ct;
+ struct items * item;
+
+ if (!co) return -1;
+ ct = co->data;
+ item = findItem(ct->itemlist, data);
+ if (!item) return -1;
+ if (item->branch)
+ return item->selected ? NEWT_CHECKBOXTREE_EXPANDED : NEWT_CHECKBOXTREE_COLLAPSED;
+ else
+ return ct->seq[item->selected];
+}
+
+void newtCheckboxTreeSetEntryValue(newtComponent co, const void * data, char value)
+{
+ struct CheckboxTree * ct;
+ struct items * item;
+ int i;
+
+ if (!co) return;
+ ct = co->data;
+ item = findItem(ct->itemlist, data);
+ if (!item || item->branch) return;
+
+ for(i = 0; ct->seq[i]; i++)
+ if (value == ct->seq[i])
+ break;
+
+ if (!ct->seq[i]) return;
+ item->selected = i;
+
+ ctDraw(co);
+}
+
+
+void newtCheckboxTreeSetCurrent(newtComponent co, void * data) {
+ struct CheckboxTree * ct = co->data;
+ int * path;
+ int i, j, itemsAfter;
+ struct items * treeTop, * item;
+
+ path = newtCheckboxTreeFindItem(co, data);
+ if (!path) return;
+
+ /* traverse the path and turn on all of the branches to this point */
+ for (i = 0, treeTop = ct->itemlist; path[i + 1] != NEWT_ARG_LAST; i++) {
+ for (j = 0, item = treeTop; j < path[i]; j++)
+ item = item->next;
+
+ item->selected = 1;
+ treeTop = item->branch;
+ }
+
+ buildFlatList(co);
+
+ item = findItem(ct->itemlist, data);
+
+ i = 0;
+ while (ct->flatList[i] != item) i++;
+
+ /* choose the top item */
+ j = i - (co->height / 2);
+
+ if ((j + co->height) > ct->flatCount)
+ j = ct->flatCount - co->height;
+
+ if (j < 0)
+ j = 0;
+
+ ct->firstItem = ct->flatList + j;
+ ct->currItem = ct->flatList + i;
+
+ ctDraw(co);
+}
diff --git a/mininewt/config.h b/mininewt/config.h
new file mode 100644
index 000000000..8a1438c96
--- /dev/null
+++ b/mininewt/config.h
@@ -0,0 +1,12 @@
+/* config.h. Generated by configure. */
+/* config.h.in. Generated automatically from configure.in by autoheader. */
+
+/* Define if you have the <alloca.h> header file. */
+#define HAVE_ALLOCA_H 1
+
+/* Define if you have the <sys/select.h> header file. */
+#define HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if GPM support is enabled */
+/* #undef USE_GPM */
+
diff --git a/mininewt/dialogboxes.c b/mininewt/dialogboxes.c
new file mode 100644
index 000000000..41440094a
--- /dev/null
+++ b/mininewt/dialogboxes.c
@@ -0,0 +1,422 @@
+/* simple dialog boxes, used by both whiptail and tcl dialog bindings */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "dialogboxes.h"
+#include "newt.h"
+#include "popt.h"
+
+/* globals -- ick */
+static int buttonHeight = 1;
+static newtComponent (*makeButton)(int left, int right, const char * text) =
+ newtCompactButton;
+
+static void addButtons(int height, int width, newtComponent form,
+ newtComponent * okay, newtComponent * cancel,
+ int flags) {
+ if (flags & FLAG_NOCANCEL) {
+ *okay = makeButton((width - 8) / 2, height - buttonHeight - 1, "Ok");
+ *cancel = NULL;
+ newtFormAddComponent(form, *okay);
+ } else {
+ *okay = makeButton((width - 18) / 3, height - buttonHeight - 1, "Ok");
+ *cancel = makeButton(((width - 18) / 3) * 2 + 9,
+ height - buttonHeight - 1, "Cancel");
+ newtFormAddComponents(form, *okay, *cancel, NULL);
+ }
+}
+
+static newtComponent textbox(int maxHeight, int width, const char * text,
+ int flags, int * height) {
+ newtComponent tb;
+ int sFlag = (flags & FLAG_SCROLL_TEXT) ? NEWT_FLAG_SCROLL : 0;
+ int i;
+ char * buf, * dst;
+ const char * src;
+
+ dst = buf = alloca(strlen(text) + 1);
+ src = text;
+ while (*src) {
+ if (*src == '\\' && *(src + 1) == 'n') {
+ src += 2;
+ *dst++ = '\n';
+ } else
+ *dst++ = *src++;
+ }
+ *dst++ = '\0';
+
+ tb = newtTextbox(1, 0, width, maxHeight, NEWT_FLAG_WRAP | sFlag);
+ newtTextboxSetText(tb, buf);
+
+ i = newtTextboxGetNumLines(tb);
+ if (i < maxHeight) {
+ newtTextboxSetHeight(tb, i);
+ maxHeight = i;
+ }
+
+ *height = maxHeight;
+
+ return tb;
+}
+
+int gauge(const char * text, int height, int width, poptContext optCon, int fd,
+ int flags) {
+ newtComponent form, scale, tb;
+ int top;
+ const char * arg;
+ char * end;
+ int val;
+ FILE * f = fdopen(fd, "r");
+ char buf[3000];
+ char buf3[50];
+ int i;
+
+ setlinebuf(f);
+
+ if (!(arg = poptGetArg(optCon))) return DLG_ERROR;
+ val = strtoul(arg, &end, 10);
+ if (*end) return DLG_ERROR;
+
+ tb = textbox(height - 3, width - 2, text, flags, &top);
+
+ form = newtForm(NULL, NULL, 0);
+
+ scale = newtScale(2, height - 2, width - 4, 100);
+ newtScaleSet(scale, val);
+
+ newtFormAddComponents(form, tb, scale, NULL);
+
+ newtDrawForm(form);
+ newtRefresh();
+
+ while (fgets(buf, sizeof(buf) - 1, f)) {
+ buf[strlen(buf) - 1] = '\0';
+
+ if (!strcmp(buf, "XXX")) {
+ fgets(buf3, sizeof(buf3) - 1, f);
+ buf3[strlen(buf3) - 1] = '\0';
+ arg = buf3;
+
+ i = 0;
+ while (fgets(buf + i, sizeof(buf) - 1 - i, f)) {
+ buf[strlen(buf) - 1] = '\0';
+ if (!strcmp(buf + i, "XXX")) {
+ *(buf + i) = '\0';
+ break;
+ }
+ i = strlen(buf);
+ }
+
+ newtTextboxSetText(tb, buf);
+ } else {
+ arg = buf;
+ }
+
+ val = strtoul(buf, &end, 10);
+ if (!*end) {
+ newtScaleSet(scale, val);
+ newtDrawForm(form);
+ newtRefresh();
+ }
+ }
+
+ return DLG_OKAY;
+}
+
+int inputBox(const char * text, int height, int width, poptContext optCon,
+ int flags, char ** result) {
+ newtComponent form, entry, okay, cancel, answer, tb;
+ char * val;
+ int rc = DLG_OKAY;
+ int top;
+
+ val = poptGetArg(optCon);
+ tb = textbox(height - 3 - buttonHeight, width - 2,
+ text, flags, &top);
+
+ form = newtForm(NULL, NULL, 0);
+ entry = newtEntry(1, top + 1, val, width - 2, &val,
+ NEWT_FLAG_SCROLL | NEWT_FLAG_RETURNEXIT);
+
+ newtFormAddComponents(form, tb, entry, NULL);
+
+ addButtons(height, width, form, &okay, &cancel, flags);
+
+ answer = newtRunForm(form);
+ if (answer == cancel)
+ rc = DLG_CANCEL;
+
+ *result = val;
+
+ return rc;
+}
+
+int listBox(const char * text, int height, int width, poptContext optCon,
+ int flags, char ** result) {
+ newtComponent form, okay, tb, answer, listBox;
+ newtComponent cancel = NULL;
+ const char * arg;
+ char * end;
+ int listHeight;
+ int numItems = 0;
+ int allocedItems = 5;
+ int i, top;
+ int rc = DLG_OKAY;
+ char buf[80], format[20];
+ int maxTagWidth = 0;
+ int maxTextWidth = 0;
+ int scrollFlag;
+ struct {
+ const char * text;
+ const char * tag;
+ } * itemInfo = malloc(allocedItems * sizeof(*itemInfo));
+
+ if (!(arg = poptGetArg(optCon))) return DLG_ERROR;
+ listHeight = strtoul(arg, &end, 10);
+ if (*end) return DLG_ERROR;
+
+ while ((arg = poptGetArg(optCon))) {
+ if (allocedItems == numItems) {
+ allocedItems += 5;
+ itemInfo = realloc(itemInfo, sizeof(*itemInfo) * allocedItems);
+ }
+
+ itemInfo[numItems].tag = arg;
+ if (!(arg = poptGetArg(optCon))) return DLG_ERROR;
+
+ if (!(flags & FLAG_NOITEM)) {
+ itemInfo[numItems].text = arg;
+ } else
+ itemInfo[numItems].text = "";
+
+ if (strlen(itemInfo[numItems].text) > (unsigned int)maxTextWidth)
+ maxTextWidth = strlen(itemInfo[numItems].text);
+ if (strlen(itemInfo[numItems].tag) > (unsigned int)maxTagWidth)
+ maxTagWidth = strlen(itemInfo[numItems].tag);
+
+ numItems++;
+ }
+
+ form = newtForm(NULL, NULL, 0);
+
+ tb = textbox(height - 4 - buttonHeight - listHeight, width - 2,
+ text, flags, &top);
+
+ if (listHeight >= numItems) {
+ scrollFlag = 0;
+ i = 0;
+ } else {
+ scrollFlag = NEWT_FLAG_SCROLL;
+ i = 2;
+ }
+
+ listBox = newtListbox(3 + ((width - 10 - maxTagWidth - maxTextWidth - i)
+ / 2),
+ top + 1, listHeight,
+ NEWT_FLAG_RETURNEXIT | scrollFlag);
+
+ sprintf(format, "%%-%ds %%s", maxTagWidth);
+ for (i = 0; i < numItems; i++) {
+ sprintf(buf, format, itemInfo[i].tag, itemInfo[i].text);
+ newtListboxAddEntry(listBox, buf, (void *) i);
+ }
+
+ newtFormAddComponents(form, tb, listBox, NULL);
+
+ addButtons(height, width, form, &okay, &cancel, flags);
+
+ answer = newtRunForm(form);
+ if (answer == cancel)
+ rc = DLG_CANCEL;
+
+ i = (int) newtListboxGetCurrent(listBox);
+ *result = itemInfo[i].tag;
+
+ return rc;
+}
+
+int checkList(const char * text, int height, int width, poptContext optCon,
+ int useRadio, int flags, char *** selections) {
+ newtComponent form, okay, tb, subform, answer;
+ newtComponent sb = NULL, cancel = NULL;
+ const char * arg;
+ char * end;
+ int listHeight;
+ int numBoxes = 0;
+ int allocedBoxes = 5;
+ int i;
+ int numSelected;
+ int rc = DLG_OKAY;
+ char buf[80], format[20];
+ int maxWidth = 0;
+ int top;
+ struct {
+ const char * text;
+ const char * tag;
+ newtComponent comp;
+ } * cbInfo = malloc(allocedBoxes * sizeof(*cbInfo));
+ char * cbStates = malloc(allocedBoxes * sizeof(cbStates));
+
+ if (!(arg = poptGetArg(optCon))) return DLG_ERROR;
+ listHeight = strtoul(arg, &end, 10);
+ if (*end) return DLG_ERROR;
+
+ while ((arg = poptGetArg(optCon))) {
+ if (allocedBoxes == numBoxes) {
+ allocedBoxes += 5;
+ cbInfo = realloc(cbInfo, sizeof(*cbInfo) * allocedBoxes);
+ cbStates = realloc(cbStates, sizeof(*cbStates) * allocedBoxes);
+ }
+
+ cbInfo[numBoxes].tag = arg;
+ if (!(arg = poptGetArg(optCon))) return DLG_ERROR;
+
+ if (!(flags & FLAG_NOITEM)) {
+ cbInfo[numBoxes].text = arg;
+ if (!(arg = poptGetArg(optCon))) return DLG_ERROR;
+ } else
+ cbInfo[numBoxes].text = "";
+
+ if (!strcmp(arg, "1") || !strcasecmp(arg, "on") ||
+ !strcasecmp(arg, "yes"))
+ cbStates[numBoxes] = '*';
+ else
+ cbStates[numBoxes] = ' ';
+
+ if (strlen(cbInfo[numBoxes].tag) > (unsigned int)maxWidth)
+ maxWidth = strlen(cbInfo[numBoxes].tag);
+
+ numBoxes++;
+ }
+
+ form = newtForm(NULL, NULL, 0);
+
+ tb = textbox(height - 3 - buttonHeight - listHeight, width - 2,
+ text, flags, &top);
+
+ if (listHeight < numBoxes) {
+ sb = newtVerticalScrollbar(width - 4,
+ top + 1,
+ listHeight, NEWT_COLORSET_CHECKBOX,
+ NEWT_COLORSET_ACTCHECKBOX);
+ newtFormAddComponent(form, sb);
+ }
+ subform = newtForm(sb, NULL, 0);
+ newtFormSetBackground(subform, NEWT_COLORSET_CHECKBOX);
+
+ sprintf(format, "%%-%ds %%s", maxWidth);
+ for (i = 0; i < numBoxes; i++) {
+ sprintf(buf, format, cbInfo[i].tag, cbInfo[i].text);
+
+ if (useRadio)
+ cbInfo[i].comp = newtRadiobutton(4, top + 1 + i, buf,
+ cbStates[i] != ' ',
+ i ? cbInfo[i - 1].comp : NULL);
+ else
+ cbInfo[i].comp = newtCheckbox(4, top + 1 + i, buf,
+ cbStates[i], NULL, cbStates + i);
+
+ newtFormAddComponent(subform, cbInfo[i].comp);
+ }
+
+ newtFormSetHeight(subform, listHeight);
+ newtFormSetWidth(subform, width - 10);
+
+ newtFormAddComponents(form, tb, subform, NULL);
+
+ addButtons(height, width, form, &okay, &cancel, flags);
+
+ answer = newtRunForm(form);
+ if (answer == cancel)
+ rc = DLG_CANCEL;
+
+ if (useRadio) {
+ answer = newtRadioGetCurrent(cbInfo[0].comp);
+ for (i = 0; i < numBoxes; i++)
+ if (cbInfo[i].comp == answer) {
+ *selections = malloc(sizeof(char *) * 2);
+ (*selections)[0] = cbInfo[i].tag;
+ (*selections)[1] = NULL;
+ break;
+ }
+ } else {
+ numSelected = 0;
+ for (i = 0; i < numBoxes; i++) {
+ if (cbStates[i] != ' ') numSelected++;
+ }
+
+ *selections = malloc(sizeof(char *) * (numSelected + 1));
+
+ numSelected = 0;
+ for (i = 0; i < numBoxes; i++) {
+ if (cbStates[i] != ' ')
+ (*selections)[numSelected++] = cbInfo[i].tag;
+ }
+
+ (*selections)[numSelected] = NULL;
+ }
+
+ return rc;
+}
+
+int messageBox(const char * text, int height, int width, int type, int flags) {
+ newtComponent form, yes, tb, answer;
+ newtComponent no = NULL;
+ int tFlag = (flags & FLAG_SCROLL_TEXT) ? NEWT_FLAG_SCROLL : 0;
+
+ form = newtForm(NULL, NULL, 0);
+
+ tb = newtTextbox(1, 1, width - 2, height - 3 - buttonHeight,
+ NEWT_FLAG_WRAP | tFlag);
+ newtTextboxSetText(tb, text);
+
+ newtFormAddComponent(form, tb);
+
+ switch ( type ) {
+ case MSGBOX_INFO:
+ break;
+ case MSGBOX_MSG:
+ yes = makeButton((width - 8) / 2, height - 1 - buttonHeight, "Ok");
+ newtFormAddComponent(form, yes);
+ break;
+ default:
+ yes = makeButton((width - 16) / 3, height - 1 - buttonHeight, "Yes");
+ no = makeButton(((width - 16) / 3) * 2 + 9, height - 1 - buttonHeight,
+ "No");
+ newtFormAddComponents(form, yes, no, NULL);
+
+ if (flags & FLAG_DEFAULT_NO)
+ newtFormSetCurrent(form, no);
+ }
+
+ if ( type != MSGBOX_INFO ) {
+ newtRunForm(form);
+
+ answer = newtFormGetCurrent(form);
+
+ if (answer == no)
+ return DLG_CANCEL;
+ }
+ else {
+ newtDrawForm(form);
+ newtRefresh();
+ }
+
+
+
+ return DLG_OKAY;
+}
+
+void useFullButtons(int state) {
+ if (state) {
+ buttonHeight = 3;
+ makeButton = newtButton;
+ } else {
+ buttonHeight = 1;
+ makeButton = newtCompactButton;
+ }
+}
diff --git a/mininewt/dialogboxes.h b/mininewt/dialogboxes.h
new file mode 100644
index 000000000..29dab12c7
--- /dev/null
+++ b/mininewt/dialogboxes.h
@@ -0,0 +1,30 @@
+#ifndef H_DIALOGBOXES
+#define H_DIALOGBOXES
+
+#include "popt.h"
+
+#define MSGBOX_MSG 0
+#define MSGBOX_YESNO 1
+#define MSGBOX_INFO 2
+
+#define FLAG_NOITEM (1 << 0)
+#define FLAG_NOCANCEL (1 << 1)
+#define FLAG_SCROLL_TEXT (1 << 2)
+#define FLAG_DEFAULT_NO (1 << 3)
+
+#define DLG_ERROR -1
+#define DLG_OKAY 0
+#define DLG_CANCEL 1
+
+int messageBox(const char * text, int height, int width, int type, int flags);
+int checkList(const char * text, int height, int width, poptContext optCon,
+ int useRadio, int flags, char *** selections);
+int listBox(const char * text, int height, int width, poptContext optCon,
+ int flags, char ** result);
+int inputBox(const char * text, int height, int width, poptContext optCon,
+ int flags, char ** result);
+int gauge(const char * text, int height, int width, poptContext optCon, int fd,
+ int flags);
+void useFullButtons(int state);
+
+#endif
diff --git a/mininewt/eawidth.c b/mininewt/eawidth.c
new file mode 100644
index 000000000..7001e96c8
--- /dev/null
+++ b/mininewt/eawidth.c
@@ -0,0 +1,463 @@
+/* #define TEST_GET_EAST_ASIA_STR_WIDTH 1 */
+
+#include <assert.h>
+#include <locale.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "eawidth.h"
+
+/*
+ * If the amount of columns the cursor advances on a TAB character depends
+ * on the current position, set this to a negative number (i.e. -8 for tab
+ * stops every eight columns. If static, set to a positive number. Zero if
+ * tabs are ignored.
+ */
+static const int tab_width = -8;
+
+typedef struct {
+ unsigned short start, end;
+ east_asia_type type;
+} eaw_db_type;
+
+static const eaw_db_type eaw_db[] = {
+ { 0x0020,0x007E,narrow },
+ { 0x00A1,0x00A1,ambiguous }, /*INVERTED EXCLAMATION MARK*/
+ { 0x00A2,0x00A3,narrow },
+ { 0x00A4,0x00A4,ambiguous }, /*CURRENCY SIGN*/
+ { 0x00A5,0x00A6,narrow },
+ { 0x00A7,0x00A8,ambiguous },
+ { 0x00AA,0x00AA,ambiguous }, /*FEMININE ORDINAL INDICATOR*/
+ { 0x00AC,0x00AC,narrow }, /*NOT SIGN*/
+ { 0x00AD,0x00AD,ambiguous }, /*SOFT HYPHEN*/
+ { 0x00AF,0x00AF,narrow }, /*MACRON*/
+ { 0x00B0,0x00B4,ambiguous },
+ { 0x00B6,0x00BA,ambiguous },
+ { 0x00BC,0x00BF,ambiguous },
+ { 0x00C6,0x00C6,ambiguous }, /*LATIN CAPITAL LETTER AE*/
+ { 0x00D0,0x00D0,ambiguous }, /*LATIN CAPITAL LETTER ETH*/
+ { 0x00D7,0x00D8,ambiguous },
+ { 0x00DE,0x00E1,ambiguous },
+ { 0x00E6,0x00E6,ambiguous }, /*LATIN SMALL LETTER AE*/
+ { 0x00E8,0x00EA,ambiguous },
+ { 0x00EC,0x00ED,ambiguous },
+ { 0x00F0,0x00F0,ambiguous }, /*LATIN SMALL LETTER ETH*/
+ { 0x00F2,0x00F3,ambiguous },
+ { 0x00F7,0x00FA,ambiguous },
+ { 0x00FC,0x00FC,ambiguous }, /*LATIN SMALL LETTER U WITH DIAERESIS*/
+ { 0x00FE,0x00FE,ambiguous }, /*LATIN SMALL LETTER THORN*/
+ { 0x0101,0x0101,ambiguous }, /*LATIN SMALL LETTER A WITH MACRON*/
+ { 0x0111,0x0111,ambiguous }, /*LATIN SMALL LETTER D WITH STROKE*/
+ { 0x0113,0x0113,ambiguous }, /*LATIN SMALL LETTER E WITH MACRON*/
+ { 0x011B,0x011B,ambiguous }, /*LATIN SMALL LETTER E WITH CARON*/
+ { 0x0126,0x0127,ambiguous },
+ { 0x012B,0x012B,ambiguous }, /*LATIN SMALL LETTER I WITH MACRON*/
+ { 0x0131,0x0133,ambiguous },
+ { 0x0138,0x0138,ambiguous }, /*LATIN SMALL LETTER KRA*/
+ { 0x013F,0x0142,ambiguous },
+ { 0x0144,0x0144,ambiguous }, /*LATIN SMALL LETTER N WITH ACUTE*/
+ { 0x0148,0x014A,ambiguous },
+ { 0x014D,0x014D,ambiguous }, /*LATIN SMALL LETTER O WITH MACRON*/
+ { 0x0152,0x0153,ambiguous },
+ { 0x0166,0x0167,ambiguous },
+ { 0x016B,0x016B,ambiguous }, /*LATIN SMALL LETTER U WITH MACRON*/
+ { 0x01CE,0x01CE,ambiguous }, /*LATIN SMALL LETTER A WITH CARON*/
+ { 0x01D0,0x01D0,ambiguous }, /*LATIN SMALL LETTER I WITH CARON*/
+ { 0x01D2,0x01D2,ambiguous }, /*LATIN SMALL LETTER O WITH CARON*/
+ { 0x01D4,0x01D4,ambiguous }, /*LATIN SMALL LETTER U WITH CARON*/
+ { 0x01D6,0x01D6,ambiguous }, /*LATIN SMALL LETTER U W/DIAERESIS+MACRON*/
+ { 0x01D8,0x01D8,ambiguous }, /*LATIN SMALL LETTER U W/DIAERESIS+ACUTE*/
+ { 0x01DA,0x01DA,ambiguous }, /*LATIN SMALL LETTER U W/DIAERESIS+CARON*/
+ { 0x01DC,0x01DC,ambiguous }, /*LATIN SMALL LETTER U W/DIAERESIS+GRAVE*/
+ { 0x0251,0x0251,ambiguous }, /*LATIN SMALL LETTER ALPHA*/
+ { 0x0261,0x0261,ambiguous }, /*LATIN SMALL LETTER SCRIPT G*/
+ { 0x02C7,0x02C7,ambiguous }, /*CARON*/
+ { 0x02C9,0x02CB,ambiguous },
+ { 0x02CD,0x02CD,ambiguous }, /*MODIFIER LETTER LOW MACRON*/
+ { 0x02D0,0x02D0,ambiguous }, /*MODIFIER LETTER TRIANGULAR COLON*/
+ { 0x02D8,0x02DB,ambiguous },
+ { 0x02DD,0x02DD,ambiguous }, /*DOUBLE ACUTE ACCENT*/
+ { 0x0300,0x0362,ambiguous },
+ { 0x0391,0x03A9,ambiguous },
+ { 0x03B1,0x03C1,ambiguous },
+ { 0x03C3,0x03C9,ambiguous },
+ { 0x0401,0x0401,ambiguous }, /*CYRILLIC CAPITAL LETTER IO*/
+ { 0x0410,0x044F,ambiguous },
+ { 0x0451,0x0451,ambiguous }, /*CYRILLIC SMALL LETTER IO*/
+ { 0x1100,0x115F,wide },
+ { 0x2010,0x2010,ambiguous }, /*HYPHEN*/
+ { 0x2013,0x2016,ambiguous },
+ { 0x2018,0x2019,ambiguous },
+ { 0x201C,0x201D,ambiguous },
+ { 0x2020,0x2021,ambiguous },
+ { 0x2025,0x2027,ambiguous },
+ { 0x2030,0x2030,ambiguous }, /*PER MILLE SIGN*/
+ { 0x2032,0x2033,ambiguous },
+ { 0x2035,0x2035,ambiguous }, /*REVERSED PRIME*/
+ { 0x203B,0x203B,ambiguous }, /*REFERENCE MARK*/
+ { 0x2074,0x2074,ambiguous }, /*SUPERSCRIPT FOUR*/
+ { 0x207F,0x207F,ambiguous }, /*SUPERSCRIPT LATIN SMALL LETTER N*/
+ { 0x2081,0x2084,ambiguous },
+ { 0x20A9,0x20A9,half_width }, /*WON SIGN*/
+ { 0x20AC,0x20AC,ambiguous }, /*EURO SIGN*/
+ { 0x2103,0x2103,ambiguous }, /*DEGREE CELSIUS*/
+ { 0x2105,0x2105,ambiguous }, /*CARE OF*/
+ { 0x2109,0x2109,ambiguous }, /*DEGREE FAHRENHEIT*/
+ { 0x2113,0x2113,ambiguous }, /*SCRIPT SMALL L*/
+ { 0x2121,0x2122,ambiguous },
+ { 0x2126,0x2126,ambiguous }, /*OHM SIGN*/
+ { 0x212B,0x212B,ambiguous }, /*ANGSTROM SIGN*/
+ { 0x2154,0x2155,ambiguous },
+ { 0x215B,0x215B,ambiguous }, /*VULGAR FRACTION ONE EIGHTH*/
+ { 0x215E,0x215E,ambiguous }, /*VULGAR FRACTION SEVEN EIGHTHS*/
+ { 0x2160,0x216B,ambiguous },
+ { 0x2170,0x2179,ambiguous },
+ { 0x2190,0x2199,ambiguous },
+ { 0x21D2,0x21D2,ambiguous }, /*RIGHTWARDS DOUBLE ARROW*/
+ { 0x21D4,0x21D4,ambiguous }, /*LEFT RIGHT DOUBLE ARROW*/
+ { 0x2200,0x2200,ambiguous }, /*FOR ALL*/
+ { 0x2202,0x2203,ambiguous },
+ { 0x2207,0x2208,ambiguous },
+ { 0x220B,0x220B,ambiguous }, /*CONTAINS AS MEMBER*/
+ { 0x220F,0x220F,ambiguous }, /*N-ARY PRODUCT*/
+ { 0x2211,0x2211,ambiguous }, /*N-ARY SUMMATION*/
+ { 0x2215,0x2215,ambiguous }, /*DIVISION SLASH*/
+ { 0x221A,0x221A,ambiguous }, /*SQUARE ROOT*/
+ { 0x221D,0x2220,ambiguous },
+ { 0x2223,0x2223,ambiguous }, /*DIVIDES*/
+ { 0x2225,0x2225,ambiguous }, /*PARALLEL TO*/
+ { 0x2227,0x222C,ambiguous },
+ { 0x222E,0x222E,ambiguous }, /*CONTOUR INTEGRAL*/
+ { 0x2234,0x2237,ambiguous },
+ { 0x223C,0x223D,ambiguous },
+ { 0x2248,0x2248,ambiguous }, /*ALMOST EQUAL TO*/
+ { 0x224C,0x224C,ambiguous }, /*ALL EQUAL TO*/
+ { 0x2252,0x2252,ambiguous }, /*APPROXIMATELY EQUAL TO OR THE IMAGE OF*/
+ { 0x2260,0x2261,ambiguous },
+ { 0x2264,0x2267,ambiguous },
+ { 0x226A,0x226B,ambiguous },
+ { 0x226E,0x226F,ambiguous },
+ { 0x2282,0x2283,ambiguous },
+ { 0x2286,0x2287,ambiguous },
+ { 0x2295,0x2295,ambiguous }, /*CIRCLED PLUS*/
+ { 0x2299,0x2299,ambiguous }, /*CIRCLED DOT OPERATOR*/
+ { 0x22A5,0x22A5,ambiguous }, /*UP TACK*/
+ { 0x22BF,0x22BF,ambiguous }, /*RIGHT TRIANGLE*/
+ { 0x2312,0x2312,ambiguous }, /*ARC*/
+ { 0x2460,0x24BF,ambiguous },
+ { 0x24D0,0x24E9,ambiguous },
+ { 0x2500,0x254B,ambiguous },
+ { 0x2550,0x2574,ambiguous },
+ { 0x2580,0x258F,ambiguous },
+ { 0x2592,0x25A1,ambiguous },
+ { 0x25A3,0x25A9,ambiguous },
+ { 0x25B2,0x25B3,ambiguous },
+ { 0x25B6,0x25B7,ambiguous },
+ { 0x25BC,0x25BD,ambiguous },
+ { 0x25C0,0x25C1,ambiguous },
+ { 0x25C6,0x25C8,ambiguous },
+ { 0x25CB,0x25CB,ambiguous }, /*WHITE CIRCLE*/
+ { 0x25CE,0x25D1,ambiguous },
+ { 0x25E2,0x25E5,ambiguous },
+ { 0x25EF,0x25EF,ambiguous }, /*LARGE CIRCLE*/
+ { 0x2605,0x2606,ambiguous },
+ { 0x2609,0x2609,ambiguous }, /*SUN*/
+ { 0x260E,0x260F,ambiguous },
+ { 0x261C,0x261C,ambiguous }, /*WHITE LEFT POINTING INDEX*/
+ { 0x261E,0x261E,ambiguous }, /*WHITE RIGHT POINTING INDEX*/
+ { 0x2640,0x2640,ambiguous }, /*FEMALE SIGN*/
+ { 0x2642,0x2642,ambiguous }, /*MALE SIGN*/
+ { 0x2660,0x2661,ambiguous },
+ { 0x2663,0x2665,ambiguous },
+ { 0x2667,0x266A,ambiguous },
+ { 0x266C,0x266D,ambiguous },
+ { 0x266F,0x266F,ambiguous }, /*MUSIC SHARP SIGN*/
+ { 0x2E80,0x3009,wide },
+ { 0x300A,0x300B,ambiguous },
+ { 0x300C,0x3019,wide },
+ { 0x301A,0x301B,ambiguous },
+ { 0x301C,0x303E,wide },
+ { 0x3041,0xD7A3,wide },
+ { 0xE000,0xF8FF,ambiguous },
+ { 0xF900,0xFA2D,wide },
+ { 0xFE30,0xFE6B,wide },
+ { 0xFF01,0xFF5E,full_width },
+ { 0xFF61,0xFFDC,half_width },
+ { 0xFFE0,0xFFE6,full_width },
+ { 0xFFE8,0xFFEE,half_width },
+};
+
+static int
+eaw_db_cmp (const void *ck, const void *ce) {
+ const eaw_db_type *key = ck, *element = ce;
+
+ assert(key != NULL);
+ assert(element != NULL);
+ if (key->start < element->start) return -1;
+ else if (key->end > element->end) return 1;
+ return 0;
+}
+
+static int
+is_cjk_locale (const char *locale_name) {
+ static const char c[] = "zh"; /* Chinese */
+ static const char j[] = "ja"; /* Japanese */
+ static const char k[] = "ko"; /* Korean */
+
+ if (NULL == locale_name) return 0;
+ if (strncmp(locale_name, c, sizeof(c)) == 0) return 1;
+ if (strncmp(locale_name, j, sizeof(j)) == 0) return 1;
+ if (strncmp(locale_name, k, sizeof(k)) == 0) return 1;
+ return 0;
+}
+
+east_asia_type
+get_east_asia_type (wchar_t unicode) {
+ assert(0xFFFF != unicode && 0xFFFE != unicode);
+
+ if (unicode > 0xFFFF) {
+
+ /*
+ * Plane 2 is intended for CJK ideographs
+ */
+ if (unicode >= 0x20000 && unicode <= 0x2FFFD) return wide;
+ return ambiguous;
+ }
+ else {
+ eaw_db_type *pos, key;
+ size_t n;
+
+ n = sizeof(eaw_db) / sizeof(eaw_db_type);
+ key.start = key.end = (unsigned short) unicode;
+ pos = bsearch(&key, eaw_db, n, sizeof(eaw_db_type), eaw_db_cmp);
+ if (NULL != pos) return pos->type;
+ }
+ return neutral;
+}
+
+int
+east_asia_mblen (const char *locale_name, const char *s, size_t n, int x)
+{
+ wchar_t *wcs, *p;
+ int width = 0;
+
+ if (NULL == s) s = "";
+
+ /*
+ * Getting the locale name via setlocale() is expensive, so we prefer
+ * to have it passed to us.
+ */
+ if (NULL == locale_name) {
+ locale_name = setlocale(LC_CTYPE, NULL);
+ if (NULL == locale_name) return INT_MAX;
+ }
+
+ wcs = (wchar_t *) calloc(n, sizeof(wchar_t));
+ if (NULL == wcs) return INT_MAX;
+
+#if defined __GLIBC__ && !__GLIBC_PREREQ(2,2)
+#warning wide character support is broken. Glibc 2.2 or better needed.
+#endif
+
+ if ((size_t) -1 == mbstowcs(wcs, s, n)) return INT_MAX;
+
+ switch (get_east_asia_type(*wcs)) {
+ case neutral:
+
+ /*
+ * Put characters that print nothing here.
+ *
+ * XXX: Yes, I know there are a lot more than this in ISO-10646, but
+ * this function is intended to calculate the width of strings for
+ * fixed width terminals displaying legacy CJK character sets.
+ * State-of-the-art Unicode handling terminals probably won't need
+ * this function anyway.
+ */
+ if (0x0000 == *wcs) break; /* NULL */
+ if (0x0007 == *wcs) break; /* BELL */
+
+ /* FIXME: there will probably be ASCII chars after the escape
+ * code, which will be counted as part of the width even though they
+ * aren't displayed.
+ */
+ if (0x001B == *wcs) break; /* ESC */
+ if (0xFEFF == *wcs) break; /* ZWNBSP aka BOM (magic, signature) */
+
+ /*
+ * Special characters go here
+ */
+ if (0x0008 == *wcs) { /* BACKSPACE */
+ width = -1;
+ break;
+ }
+ if (0x0009 == *wcs) { /* TAB */
+ if (tab_width < 0) width = x % abs(tab_width);
+ else width = tab_width;
+ break;
+ }
+
+ /*FALLTHRU*/
+ case narrow:
+ case half_width:
+ width = 1;
+ break;
+ case wide:
+ case full_width:
+ width = 2;
+ break;
+ case ambiguous:
+ width = is_cjk_locale(locale_name) ? 2 : 1;
+ break;
+ default:
+ width = INT_MAX;
+ }
+ free(wcs);
+ return width;
+}
+
+int
+get_east_asia_str_n_width (const char *locale_name, const char *s, size_t n, int x)
+{
+ int total_width = 0;
+ wchar_t *wcs, *p;
+
+ if (NULL == s) s = "";
+
+ /*
+ * Getting the locale name via setlocale() is expensive, so we prefer
+ * to have it passed to us.
+ */
+ if (NULL == locale_name) {
+ locale_name = setlocale(LC_CTYPE, NULL);
+ if (NULL == locale_name) return INT_MAX;
+ }
+
+ wcs = (wchar_t *) calloc(n, sizeof(wchar_t));
+ if (NULL == wcs) return INT_MAX;
+
+#if defined __GLIBC__ && !__GLIBC_PREREQ(2,2)
+#warning wide character support is broken. Glibc 2.2 or better needed.
+#endif
+
+ if ((size_t) -1 == mbstowcs(wcs, s, n)) return INT_MAX;
+
+ for (p = wcs; L'\0' != *p; p++) {
+ int width = 0;
+
+ switch (get_east_asia_type(*p)) {
+ case neutral:
+
+ /*
+ * Put characters that print nothing here.
+ *
+ * XXX: Yes, I know there are a lot more than this in ISO-10646, but
+ * this function is intended to calculate the width of strings for
+ * fixed width terminals displaying legacy CJK character sets.
+ * State-of-the-art Unicode handling terminals probably won't need
+ * this function anyway.
+ */
+ if (0x0000 == *p) break; /* NULL */
+ if (0x0007 == *p) break; /* BELL */
+
+ /* FIXME: there will probably be ASCII chars after the escape
+ * code, which will be counted as part of the width even though they
+ * aren't displayed.
+ */
+ if (0x001B == *p) break; /* ESC */
+ if (0xFEFF == *p) break; /* ZWNBSP aka BOM (magic, signature) */
+
+ /*
+ * Special characters go here
+ */
+ if (0x0008 == *p) { /* BACKSPACE */
+ width = -1;
+ break;
+ }
+ if (0x0009 == *p) { /* TAB */
+ if (tab_width < 0) width = x % abs(tab_width);
+ else width = tab_width;
+ break;
+ }
+
+ /*FALLTHRU*/
+ case narrow:
+ case half_width:
+ width = 1;
+ break;
+ case wide:
+ case full_width:
+ width = 2;
+ break;
+ case ambiguous:
+ width = is_cjk_locale(locale_name) ? 2 : 1;
+ break;
+ default: abort(); /* Doh! */
+ }
+ x += width;
+ total_width += width;
+ }
+ free(wcs);
+ return total_width;
+}
+
+int
+get_east_asia_str_width (const char *locale_name, const char *s, int x) {
+ size_t n;
+ int rc;
+
+ n = strlen(s) + 1;
+ rc = get_east_asia_str_n_width (locale_name, s, n, x);
+ if (rc == INT_MAX)
+ return strlen (s);
+ return rc;
+}
+
+#if TEST_GET_EAST_ASIA_STR_WIDTH
+
+#include <stdio.h>
+
+int
+main (int argc, char *argv[]) {
+ int i;
+ char *lc;
+ const char *fmt = "word #%d ('%s') length is %zu, width is %u\n";
+
+ lc = setlocale(LC_CTYPE, "");
+ if (NULL == lc) {
+ fputs("couldn't set the default locale for LC_CTYPE\n", stderr);
+ exit(EXIT_FAILURE);
+ }
+ if (printf("character type locale is '%s'\n", lc) < 0) {
+ perror(NULL);
+ exit(EXIT_FAILURE);
+ }
+ for (i = 1; argc < 2 || i < argc; i++) {
+ char *s;
+ size_t length;
+ unsigned width;
+
+ if (argc < 2) {
+ if (scanf("%as", &s) < 1 && ferror(stdin)) {
+ perror(NULL);
+ exit(EXIT_FAILURE);
+ }
+ else if (feof(stdin)) break;
+ }
+ else s = strdup(argv[(size_t) i]);
+ if (NULL == s) {
+ perror(NULL);
+ exit(EXIT_FAILURE);
+ }
+ length = strlen(s);
+ width = get_east_asia_str_width(lc, s, 0);
+ if (printf(fmt, i, s, length, width) < 0) {
+ perror(NULL);
+ exit(EXIT_FAILURE);
+ }
+ free(s);
+ }
+ return 0;
+}
+
+#endif
diff --git a/mininewt/entry.c b/mininewt/entry.c
new file mode 100644
index 000000000..94c77ef5e
--- /dev/null
+++ b/mininewt/entry.c
@@ -0,0 +1,382 @@
+#include "config.h"
+
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#endif
+
+#include <ctype.h>
+#include <slang.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+struct entry {
+ int flags;
+ char * buf;
+ char ** resultPtr;
+ int bufAlloced;
+ int bufUsed; /* amount of the buffer that's been used */
+ int cursorPosition; /* cursor *in the string* on on screen */
+ int firstChar; /* first character position being shown */
+ newtEntryFilter filter;
+ void * filterData;
+};
+
+static void entryDraw(newtComponent co);
+static void entryDestroy(newtComponent co);
+static struct eventResult entryEvent(newtComponent co,
+ struct event ev);
+
+static struct eventResult entryHandleKey(newtComponent co, int key);
+
+static struct componentOps entryOps = {
+ entryDraw,
+ entryEvent,
+ entryDestroy,
+ newtDefaultPlaceHandler,
+ newtDefaultMappedHandler,
+} ;
+
+void newtEntrySet(newtComponent co, const char * value, int cursorAtEnd) {
+ struct entry * en = co->data;
+
+ if ((strlen(value) + 1) > (unsigned int)en->bufAlloced) {
+ free(en->buf);
+ en->bufAlloced = strlen(value) + 1;
+ en->buf = malloc(en->bufAlloced);
+ if (en->resultPtr) *en->resultPtr = en->buf;
+ }
+ memset(en->buf, 0, en->bufAlloced); /* clear the buffer */
+ strcpy(en->buf, value);
+ en->bufUsed = strlen(value);
+ en->firstChar = 0;
+ if (cursorAtEnd)
+ en->cursorPosition = en->bufUsed;
+ else
+ en->cursorPosition = 0;
+
+ entryDraw(co);
+} ;
+
+newtComponent newtEntry(int left, int top, const char * initialValue, int width,
+ char ** resultPtr, int flags) {
+ newtComponent co;
+ struct entry * en;
+
+ co = malloc(sizeof(*co));
+ en = malloc(sizeof(struct entry));
+ co->data = en;
+
+ co->top = top;
+ co->left = left;
+ co->height = 1;
+ co->width = width;
+ co->isMapped = 0;
+ co->callback = NULL;
+
+ co->ops = &entryOps;
+
+ en->flags = flags;
+ en->cursorPosition = 0;
+ en->firstChar = 0;
+ en->bufUsed = 0;
+ en->bufAlloced = width + 1;
+ en->filter = NULL;
+
+ if (!(en->flags & NEWT_FLAG_DISABLED))
+ co->takesFocus = 1;
+ else
+ co->takesFocus = 0;
+
+ if (initialValue && strlen(initialValue) > (unsigned int)width) {
+ en->bufAlloced = strlen(initialValue) + 1;
+ }
+ en->buf = malloc(en->bufAlloced);
+ en->resultPtr = resultPtr;
+ if (en->resultPtr) *en->resultPtr = en->buf;
+
+ memset(en->buf, 0, en->bufAlloced);
+ if (initialValue) {
+ strcpy(en->buf, initialValue);
+ en->bufUsed = strlen(initialValue);
+ en->cursorPosition = en->bufUsed;
+ } else {
+ *en->buf = '\0';
+ en->bufUsed = 0;
+ en->cursorPosition = 0;
+ }
+
+ return co;
+}
+
+static void entryDraw(newtComponent co) {
+ struct entry * en = co->data;
+ int i;
+ char * chptr;
+ int len;
+
+ if (!co->isMapped) return;
+
+ if (en->flags & NEWT_FLAG_DISABLED)
+ SLsmg_set_color(NEWT_COLORSET_DISENTRY);
+ else
+ SLsmg_set_color(NEWT_COLORSET_ENTRY);
+
+ if (en->flags & NEWT_FLAG_HIDDEN) {
+ newtGotorc(co->top, co->left);
+ for (i = 0; i < co->width; i++)
+ SLsmg_write_char('_');
+ newtGotorc(co->top, co->left);
+
+ return;
+ }
+
+ newtGotorc(co->top, co->left);
+
+ if (en->cursorPosition < en->firstChar) {
+ /* scroll to the left */
+ en->firstChar = en->cursorPosition;
+ } else if ((en->firstChar + co->width) <= en->cursorPosition) {
+ /* scroll to the right */
+ en->firstChar = en->cursorPosition - co->width + 1;
+ }
+
+ chptr = en->buf + en->firstChar;
+
+ if (en->flags & NEWT_FLAG_PASSWORD) {
+ char *tmpptr, *p;
+
+ tmpptr = alloca(strlen(chptr)+2);
+ strcpy(tmpptr, chptr);
+ for (p = tmpptr; *p; p++)
+ *p = '*';
+ chptr = tmpptr;
+ }
+
+ len = strlen(chptr);
+
+ if (len <= co->width) {
+ i = len;
+ SLsmg_write_string(chptr);
+ while (i < co->width) {
+ SLsmg_write_char('_');
+ i++;
+ }
+ } else {
+ SLsmg_write_nstring(chptr, co->width);
+ }
+
+ if (en->flags & NEWT_FLAG_HIDDEN)
+ newtGotorc(co->top, co->left);
+ else
+ newtGotorc(co->top, co->left + (en->cursorPosition - en->firstChar));
+}
+
+void newtEntrySetFlags(newtComponent co, int flags, enum newtFlagsSense sense) {
+ struct entry * en = co->data;
+ int row, col;
+
+ en->flags = newtSetFlags(en->flags, flags, sense);
+
+ if (!(en->flags & NEWT_FLAG_DISABLED))
+ co->takesFocus = 1;
+ else
+ co->takesFocus = 0;
+
+ newtGetrc(&row, &col);
+ entryDraw(co);
+ newtGotorc(row, col);
+}
+
+static void entryDestroy(newtComponent co) {
+ struct entry * en = co->data;
+
+ free(en->buf);
+ free(en);
+ free(co);
+}
+
+static struct eventResult entryEvent(newtComponent co,
+ struct event ev) {
+ struct entry * en = co->data;
+ struct eventResult er;
+ int ch;
+
+ if (ev.when == EV_NORMAL) {
+ switch (ev.event) {
+ case EV_FOCUS:
+ newtCursorOn();
+ if (en->flags & NEWT_FLAG_HIDDEN)
+ newtGotorc(co->top, co->left);
+ else
+ newtGotorc(co->top, co->left +
+ (en->cursorPosition - en->firstChar));
+ er.result = ER_SWALLOWED;
+ break;
+
+ case EV_UNFOCUS:
+ newtCursorOff();
+ newtGotorc(0, 0);
+ er.result = ER_SWALLOWED;
+ if (co->callback)
+ co->callback(co, co->callbackData);
+ break;
+
+ case EV_KEYPRESS:
+ ch = ev.u.key;
+ if (en->filter)
+ ch = en->filter(co, en->filterData, ch, en->cursorPosition);
+ if (ch) er = entryHandleKey(co, ch);
+ break;
+
+ case EV_MOUSE:
+ if ((ev.u.mouse.type == MOUSE_BUTTON_DOWN) &&
+ (en->flags ^ NEWT_FLAG_HIDDEN)) {
+ if (strlen(en->buf) >= ev.u.mouse.x - co->left) {
+ en->cursorPosition = ev.u.mouse.x - co->left;
+ newtGotorc(co->top,
+ co->left +(en->cursorPosition - en->firstChar));
+ } else {
+ en->cursorPosition = strlen(en->buf);
+ newtGotorc(co->top,
+ co->left +(en->cursorPosition - en->firstChar));
+ }
+ }
+ break;
+ }
+ } else
+ er.result = ER_IGNORED;
+
+ return er;
+}
+
+static struct eventResult entryHandleKey(newtComponent co, int key) {
+ struct entry * en = co->data;
+ struct eventResult er;
+ char * chptr, * insPoint;
+
+ er.result = ER_SWALLOWED;
+ switch (key) {
+ case '\r': /* Return */
+ if (en->flags & NEWT_FLAG_RETURNEXIT) {
+ er.result = ER_EXITFORM;
+ } else {
+ er.result = ER_NEXTCOMP;
+ }
+ break;
+
+ case '\001': /* ^A */
+ case NEWT_KEY_HOME:
+ en->cursorPosition = 0;
+ break;
+
+ case '\005': /* ^E */
+ case NEWT_KEY_END:
+ en->cursorPosition = en->bufUsed;
+ break;
+
+ case '\013': /* ^K */
+ en->bufUsed = en->cursorPosition;
+ memset(en->buf + en->bufUsed, 0, en->bufAlloced - en->bufUsed);
+ break;
+
+ case '\002': /* ^B */
+ case NEWT_KEY_LEFT:
+ if (en->cursorPosition)
+ en->cursorPosition--;
+ break;
+
+ case '\004':
+ case NEWT_KEY_DELETE:
+ chptr = en->buf + en->cursorPosition;
+ if (*chptr) {
+ chptr++;
+ while (*chptr) {
+ *(chptr - 1) = *chptr;
+ chptr++;
+ }
+ *(chptr - 1) = '\0';
+ en->bufUsed--;
+ }
+ break;
+
+ case NEWT_KEY_BKSPC:
+ if (en->cursorPosition) {
+ /* if this isn't true, there's nothing to erase */
+ chptr = en->buf + en->cursorPosition;
+ en->bufUsed--;
+ en->cursorPosition--;
+ while (*chptr) {
+ *(chptr - 1) = *chptr;
+ chptr++;
+ }
+ *(chptr - 1) = '\0';
+ }
+ break;
+
+ case '\006': /* ^B */
+ case NEWT_KEY_RIGHT:
+ if (en->cursorPosition < en->bufUsed)
+ en->cursorPosition++;
+ break;
+
+ default:
+ if ((key >= 0x20 && key <= 0x7e) || (key >= 0xa0 && key <= 0xff)) {
+ if (!(en->flags & NEWT_FLAG_SCROLL) && en->bufUsed >= co->width) {
+ SLtt_beep();
+ break;
+ }
+
+ if ((en->bufUsed + 1) == en->bufAlloced) {
+ en->bufAlloced += 20;
+ en->buf = realloc(en->buf, en->bufAlloced);
+ if (en->resultPtr) *en->resultPtr = en->buf;
+ memset(en->buf + en->bufUsed + 1, 0, 20);
+ }
+
+ if (en->cursorPosition == en->bufUsed) {
+ en->bufUsed++;
+ } else {
+ /* insert the new character */
+
+ /* chptr is the last character in the string */
+ chptr = (en->buf + en->bufUsed) - 1;
+ if ((en->bufUsed + 1) == en->bufAlloced) {
+ /* this string fills the buffer, so clip it */
+ chptr--;
+ } else
+ en->bufUsed++;
+
+ insPoint = en->buf + en->cursorPosition;
+
+ while (chptr >= insPoint) {
+ *(chptr + 1) = *chptr;
+ chptr--;
+ }
+
+ }
+
+ en->buf[en->cursorPosition++] = key;
+ } else {
+ er.result = ER_IGNORED;
+ }
+ }
+
+ entryDraw(co);
+
+ return er;
+}
+
+char * newtEntryGetValue(newtComponent co) {
+ struct entry * en = co->data;
+
+ return en->buf;
+}
+
+void newtEntrySetFilter(newtComponent co, newtEntryFilter filter, void * data) {
+ struct entry * en = co->data;
+ en->filter = filter;
+ en->filterData = data;
+}
diff --git a/mininewt/form.c b/mininewt/form.c
new file mode 100644
index 000000000..5564a7480
--- /dev/null
+++ b/mininewt/form.c
@@ -0,0 +1,1137 @@
+#include "config.h"
+
+#include <sys/types.h>
+
+#include <slang.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#include <sys/time.h>
+
+#ifdef USE_GPM
+#include <ctype.h>
+#include <sys/time.h> /* timeval */
+#include <sys/socket.h> /* socket() */
+#include <sys/un.h> /* struct sockaddr_un */
+#include <sys/fcntl.h> /* O_RDONLY */
+#include <sys/stat.h> /* stat() */
+#include <termios.h> /* winsize */
+#include <unistd.h>
+#include <sys/kd.h> /* KDGETMODE */
+#include <signal.h>
+#include <stdio.h>
+#endif
+
+#include "newt.h"
+#include "newt_pr.h"
+
+#ifdef USE_GPM
+/*....................................... The connection data structure */
+
+typedef struct Gpm_Connect {
+ unsigned short eventMask, defaultMask;
+ unsigned short minMod, maxMod;
+ int pid;
+ int vc;
+} Gpm_Connect;
+
+/*....................................... Stack struct */
+typedef struct Gpm_Stst {
+ Gpm_Connect info;
+ struct Gpm_Stst *next;
+} Gpm_Stst;
+
+enum Gpm_Etype {
+ GPM_MOVE=1,
+ GPM_DRAG=2, /* exactly one of the bare ones is active at a time */
+ GPM_DOWN=4,
+ GPM_UP= 8,
+
+#define GPM_BARE_EVENTS(type) ((type)&(0x0f|GPM_ENTER|GPM_LEAVE))
+
+ GPM_SINGLE=16, /* at most one in three is set */
+ GPM_DOUBLE=32,
+ GPM_TRIPLE=64, /* WARNING: I depend on the values */
+
+ GPM_MFLAG=128, /* motion during click? */
+ GPM_HARD=256, /* if set in the defaultMask, force an already
+ used event to pass over to another handler */
+
+ GPM_ENTER=512, /* enter event, user in Roi's */
+ GPM_LEAVE=1024 /* leave event, used in Roi's */
+};
+
+/*....................................... The reported event */
+
+enum Gpm_Margin {GPM_TOP=1, GPM_BOT=2, GPM_LFT=4, GPM_RGT=8};
+
+typedef struct Gpm_Event {
+ unsigned char buttons, modifiers; /* try to be a multiple of 4 */
+ unsigned short vc;
+ short dx, dy, x, y;
+ enum Gpm_Etype type;
+ int clicks;
+ enum Gpm_Margin margin;
+} Gpm_Event;
+
+static int Gpm_Open(Gpm_Connect *conn, int flag);
+static int Gpm_Close(void);
+
+static int gpm_fd=-1;
+static int gpm_flag=0;
+static int gpm_tried=0;
+Gpm_Stst *gpm_stack=NULL;
+static struct sigaction gpm_saved_suspend_hook;
+static struct sigaction gpm_saved_winch_hook;
+
+#define GPM_XTERM_ON
+#define GPM_XTERM_OFF
+#define GPM_NODE_DEV "/dev/gpmctl"
+#define GPM_NODE_CTL GPM_NODE_DEV
+
+static inline int putdata(int where, Gpm_Connect *what)
+{
+ if (write(where,what,sizeof(Gpm_Connect))!=sizeof(Gpm_Connect))
+ {
+ return -1;
+ }
+ return 0;
+}
+
+static void gpm_winch_hook (int signum)
+{
+ if (SIG_IGN != gpm_saved_winch_hook.sa_handler &&
+ SIG_DFL != gpm_saved_winch_hook.sa_handler) {
+ gpm_saved_winch_hook.sa_handler(signum);
+ } /*if*/
+}
+
+static void gpm_suspend_hook (int signum)
+{
+ Gpm_Connect gpm_connect;
+ sigset_t old_sigset;
+ sigset_t new_sigset;
+ struct sigaction sa;
+ int success;
+
+ sigemptyset (&new_sigset);
+ sigaddset (&new_sigset, SIGTSTP);
+ sigprocmask (SIG_BLOCK, &new_sigset, &old_sigset);
+
+ /* Open a completely transparent gpm connection */
+ gpm_connect.eventMask = 0;
+ gpm_connect.defaultMask = ~0;
+ gpm_connect.minMod = ~0;
+ gpm_connect.maxMod = 0;
+ /* cannot do this under xterm, tough */
+ success = (Gpm_Open (&gpm_connect, 0) >= 0);
+
+ /* take the default action, whatever it is (probably a stop :) */
+ sigprocmask (SIG_SETMASK, &old_sigset, 0);
+ sigaction (SIGTSTP, &gpm_saved_suspend_hook, 0);
+ kill (getpid (), SIGTSTP);
+
+ /* in bardo here */
+
+ /* Reincarnation. Prepare for another death early. */
+ sigemptyset(&sa.sa_mask);
+ sa.sa_handler = gpm_suspend_hook;
+ sa.sa_flags = SA_NOMASK;
+ sigaction (SIGTSTP, &sa, 0);
+
+ /* Pop the gpm stack by closing the useless connection */
+ /* but do it only when we know we opened one.. */
+ if (success) {
+ Gpm_Close ();
+ } /*if*/
+}
+
+static int Gpm_Open(Gpm_Connect *conn, int flag)
+{
+ char tty[32];
+ char *term;
+ int i;
+ struct sockaddr_un addr;
+ Gpm_Stst *new;
+ char* sock_name = 0;
+
+ /*....................................... First of all, check xterm */
+
+ if ((term=(char *)getenv("TERM")) && !strncmp(term,"xterm",5))
+ {
+ if (gpm_tried) return gpm_fd; /* no stack */
+ gpm_fd=-2;
+ GPM_XTERM_ON;
+ gpm_flag=1;
+ return gpm_fd;
+ }
+ /*....................................... No xterm, go on */
+
+
+ /*
+ * So I chose to use the current tty, instead of /dev/console, which
+ * has permission problems. (I am fool, and my console is
+ * readable/writeable by everybody.
+ *
+ * However, making this piece of code work has been a real hassle.
+ */
+
+ if (!gpm_flag && gpm_tried) return -1;
+ gpm_tried=1; /* do or die */
+
+ new=malloc(sizeof(Gpm_Stst));
+ if (!new) return -1;
+
+ new->next=gpm_stack;
+ gpm_stack=new;
+
+ conn->pid=getpid(); /* fill obvious values */
+
+ if (new->next)
+ conn->vc=new->next->info.vc; /* inherit */
+ else
+ {
+ conn->vc=0; /* default handler */
+ if (flag>0)
+ { /* forced vc number */
+ conn->vc=flag;
+ sprintf(tty,"/dev/tty%i",flag);
+ }
+ else if (flag==0) /* use your current vc */
+ {
+ char *t = ttyname(0); /* stdin */
+ if (!t) t = ttyname(1); /* stdout */
+ if (!t) goto err;
+ strcpy(tty,t);
+ if (strncmp(tty,"/dev/tty",8) || !isdigit(tty[8]))
+ goto err;
+ conn->vc=atoi(tty+8);
+ }
+ else /* a default handler -- use console */
+ sprintf(tty,"/dev/tty0");
+
+ }
+
+ new->info=*conn;
+
+ /*....................................... Connect to the control socket */
+
+ if (!(gpm_flag++))
+ {
+
+ if ( (gpm_fd=socket(AF_UNIX,SOCK_STREAM,0))<0 )
+ {
+ goto err;
+ }
+
+ bzero((char *)&addr,sizeof(addr));
+ addr.sun_family=AF_UNIX;
+ if (!(sock_name = tempnam (0, "gpm"))) {
+ goto err;
+ } /*if*/
+ strncpy (addr.sun_path, sock_name, sizeof (addr.sun_path));
+ if (bind (gpm_fd, (struct sockaddr*)&addr,
+ sizeof (addr.sun_family) + strlen (addr.sun_path))==-1) {
+ goto err;
+ } /*if*/
+
+ bzero((char *)&addr,sizeof(addr));
+ addr.sun_family=AF_UNIX;
+ strcpy(addr.sun_path, GPM_NODE_CTL);
+ i=sizeof(addr.sun_family)+strlen(GPM_NODE_CTL);
+
+ if ( connect(gpm_fd,(struct sockaddr *)(&addr),i)<0 )
+ {
+ struct stat stbuf;
+
+ /*
+ * Well, try to open a chr device called /dev/gpmctl. This should
+ * be forward-compatible with a kernel server
+ */
+ close(gpm_fd); /* the socket */
+ if ((gpm_fd=open(GPM_NODE_DEV,O_RDWR))==-1) {
+ goto err;
+ } /*if*/
+ if (fstat(gpm_fd,&stbuf)==-1 || (stbuf.st_mode&S_IFMT)!=S_IFCHR)
+ goto err;
+ }
+ }
+ /*....................................... Put your data */
+
+ if (putdata(gpm_fd,conn)!=-1)
+ {
+ /* itz Wed Dec 16 23:22:16 PST 1998 use sigaction, the old
+ code caused a signal loop under XEmacs */
+ struct sigaction sa;
+ sigemptyset(&sa.sa_mask);
+
+#if (defined(SIGWINCH))
+ /* And the winch hook .. */
+ sa.sa_handler = gpm_winch_hook;
+ sa.sa_flags = 0;
+ sigaction(SIGWINCH, &sa, &gpm_saved_winch_hook);
+#endif
+
+#if (defined(SIGTSTP))
+ if (gpm_flag == 1) {
+ /* Install suspend hook */
+ sa.sa_handler = SIG_IGN;
+ sigaction(SIGTSTP, &sa, &gpm_saved_suspend_hook);
+
+ /* if signal was originally ignored, job control is not supported */
+ if (gpm_saved_suspend_hook.sa_handler != SIG_IGN) {
+ sa.sa_flags = SA_NOMASK;
+ sa.sa_handler = gpm_suspend_hook;
+ sigaction(SIGTSTP, &sa, 0);
+ } /*if*/
+ } /*if*/
+#endif
+
+ } /*if*/
+ return gpm_fd;
+
+ /*....................................... Error: free all memory */
+ err:
+ do
+ {
+ new=gpm_stack->next;
+ free(gpm_stack);
+ gpm_stack=new;
+ }
+ while(gpm_stack);
+ if (gpm_fd>=0) close(gpm_fd);
+ if (sock_name) {
+ unlink(sock_name);
+ free(sock_name);
+ sock_name = 0;
+ } /*if*/
+ gpm_flag=0;
+ return -1;
+}
+
+/*-------------------------------------------------------------------*/
+static int Gpm_Close(void)
+{
+ Gpm_Stst *next;
+
+ gpm_tried=0; /* reset the error flag for next time */
+ if (gpm_fd==-2) /* xterm */
+ GPM_XTERM_OFF;
+ else /* linux */
+ {
+ if (!gpm_flag) return 0;
+ next=gpm_stack->next;
+ free(gpm_stack);
+ gpm_stack=next;
+ if (next)
+ putdata(gpm_fd,&(next->info));
+
+ if (--gpm_flag) return -1;
+ }
+
+ if (gpm_fd>=0) close(gpm_fd);
+ gpm_fd=-1;
+#ifdef SIGTSTP
+ sigaction(SIGTSTP, &gpm_saved_suspend_hook, 0);
+#endif
+#ifdef SIGWINCH
+ sigaction(SIGWINCH, &gpm_saved_winch_hook, 0);
+#endif
+ return 0;
+}
+
+/*-------------------------------------------------------------------*/
+static int Gpm_GetEvent(Gpm_Event *event)
+{
+ int count;
+
+ if (!gpm_flag) return 0;
+
+ if ((count=read(gpm_fd,event,sizeof(Gpm_Event)))!=sizeof(Gpm_Event))
+ {
+ if (count==0)
+ {
+ Gpm_Close();
+ return 0;
+ }
+ return -1;
+ }
+ return 1;
+}
+#endif
+
+/****************************************************************************
+ These forms handle vertical scrolling of components with a height of 1
+
+ Horizontal scrolling won't work, and scrolling large widgets will fail
+ miserably. It shouldn't be too hard to fix either of those if anyone
+ cares to. I only use scrolling for listboxes and text boxes though so
+ I didn't bother.
+*****************************************************************************/
+
+struct element {
+ int top, left; /* Actual, not virtual. These are translated */
+ newtComponent co; /* into actual through vertOffset */
+};
+
+struct fdInfo {
+ int fd;
+ int flags;
+};
+
+struct form {
+ int numCompsAlloced;
+ struct element * elements;
+ int numComps;
+ int currComp;
+ int fixedHeight;
+ int flags;
+ int vertOffset;
+ newtComponent vertBar, exitComp;
+ const char * help;
+ int numRows;
+ int * hotKeys;
+ int numHotKeys;
+ int background;
+ int beenSet;
+ int numFds;
+ struct fdInfo * fds;
+ int maxFd;
+ int timer; /* in milliseconds */
+ struct timeval lastTimeout;
+ void * helpTag;
+ newtCallback helpCb;
+};
+
+static void gotoComponent(struct form * form, int newComp);
+static struct eventResult formEvent(newtComponent co, struct event ev);
+static struct eventResult sendEvent(newtComponent comp, struct event ev);
+static void formPlace(newtComponent co, int left, int top);
+
+/* Global, ick */
+static newtCallback helpCallback;
+
+/* this isn't static as grid.c tests against it to find forms */
+struct componentOps formOps = {
+ newtDrawForm,
+ formEvent,
+ newtFormDestroy,
+ formPlace,
+ newtDefaultMappedHandler,
+} ;
+
+static inline int componentFits(newtComponent co, int compNum) {
+ struct form * form = co->data;
+ struct element * el = form->elements + compNum;
+
+ if ((co->top + form->vertOffset) > el->top) return 0;
+ if ((co->top + form->vertOffset + co->height) <
+ (el->top + el->co->height)) return 0;
+
+ return 1;
+}
+
+newtComponent newtForm(newtComponent vertBar, void * help, int flags) {
+ newtComponent co;
+ struct form * form;
+
+ co = malloc(sizeof(*co));
+ form = malloc(sizeof(*form));
+ co->data = form;
+ co->width = 0;
+ co->height = 0;
+ co->top = -1;
+ co->left = -1;
+ co->isMapped = 0;
+
+ co->takesFocus = 0; /* we may have 0 components */
+ co->ops = &formOps;
+
+ form->help = help;
+ form->flags = flags;
+ form->numCompsAlloced = 5;
+ form->numComps = 0;
+ form->currComp = -1;
+ form->vertOffset = 0;
+ form->fixedHeight = 0;
+ form->numRows = 0;
+ form->numFds = 0;
+ form->maxFd = 0;
+ form->fds = NULL;
+ form->beenSet = 0;
+ form->elements = malloc(sizeof(*(form->elements)) * form->numCompsAlloced);
+
+ form->background = COLORSET_WINDOW;
+ form->hotKeys = malloc(sizeof(int));
+ form->numHotKeys = 0;
+ form->timer = 0;
+ form->lastTimeout.tv_sec = form->lastTimeout.tv_usec = 0;
+ if (!(form->flags & NEWT_FLAG_NOF12)) {
+ newtFormAddHotKey(co, NEWT_KEY_F12);
+ }
+
+ if (vertBar)
+ form->vertBar = vertBar;
+ else
+ form->vertBar = NULL;
+
+ form->helpTag = help;
+ form->helpCb = helpCallback;
+
+ return co;
+}
+
+newtComponent newtFormGetCurrent(newtComponent co) {
+ struct form * form = co->data;
+
+ return form->elements[form->currComp].co;
+}
+
+void newtFormSetCurrent(newtComponent co, newtComponent subco) {
+ struct form * form = co->data;
+ int i, new;
+
+ for (i = 0; i < form->numComps; i++) {
+ if (form->elements[i].co == subco) break;
+ }
+
+ if (form->elements[i].co != subco) return;
+ new = i;
+
+ if (co->isMapped && !componentFits(co, new)) {
+ gotoComponent(form, -1);
+ form->vertOffset = form->elements[new].top - co->top - 1;
+ if (form->vertOffset > (form->numRows - co->height))
+ form->vertOffset = form->numRows - co->height;
+ }
+
+ gotoComponent(form, new);
+}
+
+void newtFormSetTimer(newtComponent co, int millisecs) {
+ struct form * form = co->data;
+
+ form->timer = millisecs;
+ form->lastTimeout.tv_usec = 0;
+ form->lastTimeout.tv_sec = 0;
+}
+
+void newtFormSetHeight(newtComponent co, int height) {
+ struct form * form = co->data;
+
+ form->fixedHeight = 1;
+ co->height = height;
+}
+
+void newtFormSetWidth(newtComponent co, int width) {
+ co->width = width;
+}
+
+void newtFormAddComponent(newtComponent co, newtComponent newco) {
+ struct form * form = co->data;
+
+ co->takesFocus = 1;
+
+ if (form->numCompsAlloced == form->numComps) {
+ form->numCompsAlloced += 5;
+ form->elements = realloc(form->elements,
+ sizeof(*(form->elements)) * form->numCompsAlloced);
+ }
+
+ /* we grab real values for these a bit later */
+ form->elements[form->numComps].left = -2;
+ form->elements[form->numComps].top = -2;
+ form->elements[form->numComps].co = newco;
+
+ if (newco->takesFocus && form->currComp == -1)
+ form->currComp = form->numComps;
+
+ form->numComps++;
+}
+
+void newtFormAddComponents(newtComponent co, ...) {
+ va_list ap;
+ newtComponent subco;
+
+ va_start(ap, co);
+
+ while ((subco = va_arg(ap, newtComponent)))
+ newtFormAddComponent(co, subco);
+
+ va_end(ap);
+}
+
+static void formPlace(newtComponent co, int left, int top) {
+ struct form * form = co->data;
+ int vertDelta, horizDelta;
+ struct element * el;
+ int i;
+
+ newtFormSetSize(co);
+
+ vertDelta = top - co->top;
+ horizDelta = left - co->left;
+ co->top = top;
+ co->left = left;
+
+ for (i = 0, el = form->elements; i < form->numComps; i++, el++) {
+ el->co->top += vertDelta;
+ el->top += vertDelta;
+ el->co->left += horizDelta;
+ el->left += horizDelta;
+ }
+}
+
+void newtDrawForm(newtComponent co) {
+ struct form * form = co->data;
+ struct element * el;
+ int i;
+
+ newtFormSetSize(co);
+
+ SLsmg_set_color(form->background);
+ newtClearBox(co->left, co->top, co->width, co->height);
+
+ for (i = 0, el = form->elements; i < form->numComps; i++, el++) {
+ /* the scrollbar *always* fits somewhere */
+ if (el->co == form->vertBar) {
+ el->co->ops->mapped(el->co, 1);
+ el->co->ops->draw(el->co);
+ } else {
+ /* only draw it if it'll fit on the screen vertically */
+ if (componentFits(co, i)) {
+ el->co->top = el->top - form->vertOffset;
+ el->co->ops->mapped(el->co, 1);
+ el->co->ops->draw(el->co);
+ } else {
+ el->co->ops->mapped(el->co, 0);
+ }
+ }
+ }
+
+ if (form->vertBar)
+ newtScrollbarSet(form->vertBar, form->vertOffset,
+ form->numRows - co->height);
+}
+
+static struct eventResult formEvent(newtComponent co, struct event ev) {
+ struct form * form = co->data;
+ newtComponent subco = form->elements[form->currComp].co;
+ int new, wrap = 0;
+ struct eventResult er;
+ int dir = 0, page = 0;
+ int i, num, found;
+ struct element * el;
+
+ er.result = ER_IGNORED;
+ if (!form->numComps) return er;
+
+ subco = form->elements[form->currComp].co;
+
+ switch (ev.when) {
+ case EV_EARLY:
+ if (ev.event == EV_KEYPRESS) {
+ if (ev.u.key == NEWT_KEY_TAB) {
+ er.result = ER_SWALLOWED;
+ dir = 1;
+ wrap = 1;
+ } else if (ev.u.key == NEWT_KEY_UNTAB) {
+ er.result = ER_SWALLOWED;
+ dir = -1;
+ wrap = 1;
+ }
+ }
+
+ if (form->numComps) {
+ i = form->currComp;
+ num = 0;
+ while (er.result == ER_IGNORED && num != form->numComps ) {
+ er = form->elements[i].co->ops->event(form->elements[i].co, ev);
+
+ num++;
+ i++;
+ if (i == form->numComps) i = 0;
+ }
+ }
+
+ break;
+
+ case EV_NORMAL:
+ if (ev.event == EV_MOUSE) {
+ found = 0;
+ for (i = 0, el = form->elements; i < form->numComps; i++, el++) {
+ if ((el->co->top <= ev.u.mouse.y) &&
+ (el->co->top + el->co->height > ev.u.mouse.y) &&
+ (el->co->left <= ev.u.mouse.x) &&
+ (el->co->left + el->co->width > ev.u.mouse.x)) {
+ found = 1;
+ if (el->co->takesFocus) {
+ gotoComponent(form, i);
+ subco = form->elements[form->currComp].co;
+ }
+ }
+ /* If we did not find a co to send this event to, we
+ should just swallow the event here. */
+ }
+ if (!found) {
+ er.result = ER_SWALLOWED;
+
+ return er;
+ }
+ }
+ er = subco->ops->event(subco, ev);
+ switch (er.result) {
+ case ER_NEXTCOMP:
+ er.result = ER_SWALLOWED;
+ dir = 1;
+ break;
+
+ case ER_EXITFORM:
+ form->exitComp = subco;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case EV_LATE:
+ er = subco->ops->event(subco, ev);
+
+ if (er.result == ER_IGNORED) {
+ switch (ev.u.key) {
+ case NEWT_KEY_UP:
+ case NEWT_KEY_LEFT:
+ case NEWT_KEY_BKSPC:
+ er.result = ER_SWALLOWED;
+ dir = -1;
+ break;
+
+ case NEWT_KEY_DOWN:
+ case NEWT_KEY_RIGHT:
+ er.result = ER_SWALLOWED;
+ dir = 1;
+ break;
+
+ case NEWT_KEY_PGUP:
+ er.result = ER_SWALLOWED;
+ dir = -1;
+ page = 1;
+ break;
+
+ case NEWT_KEY_PGDN:
+ er.result = ER_SWALLOWED;
+ dir = 1;
+ page = 1;
+ break;
+ }
+ }
+ }
+
+ if (dir) {
+ new = form->currComp;
+
+ if (page) {
+ new += dir * co->height;
+ if (new < 0)
+ new = 0;
+ else if (new >= form->numComps)
+ new = (form->numComps - 1);
+
+ while (!form->elements[new].co->takesFocus)
+ new = new - dir;
+ } else {
+ do {
+ new += dir;
+
+ if (wrap) {
+ if (new < 0)
+ new = form->numComps - 1;
+ else if (new >= form->numComps)
+ new = 0;
+ } else if (new < 0 || new >= form->numComps)
+ return er;
+ } while (!form->elements[new].co->takesFocus);
+ }
+
+ /* make sure this component is visible */
+ if (!componentFits(co, new)) {
+ gotoComponent(form, -1);
+
+ if (dir < 0) {
+ /* make the new component the first one */
+ form->vertOffset = form->elements[new].top - co->top;
+ } else {
+ /* make the new component the last one */
+ form->vertOffset = (form->elements[new].top +
+ form->elements[new].co->height) -
+ (co->top + co->height);
+ }
+
+ if (form->vertOffset < 0) form->vertOffset = 0;
+ if (form->vertOffset > (form->numRows - co->height))
+ form->vertOffset = form->numRows - co->height;
+
+ newtDrawForm(co);
+ }
+
+ gotoComponent(form, new);
+ er.result = ER_SWALLOWED;
+ }
+
+ return er;
+}
+
+/* this also destroys all of the components on the form */
+void newtFormDestroy(newtComponent co) {
+ newtComponent subco;
+ struct form * form = co->data;
+ int i;
+
+ /* first, destroy all of the components */
+ for (i = 0; i < form->numComps; i++) {
+ subco = form->elements[i].co;
+ if (subco->ops->destroy) {
+ subco->ops->destroy(subco);
+ } else {
+ if (subco->data) free(subco->data);
+ free(subco);
+ }
+ }
+
+ if (form->hotKeys) free(form->hotKeys);
+
+ free(form->elements);
+ free(form);
+ free(co);
+}
+
+newtComponent newtRunForm(newtComponent co) {
+ struct newtExitStruct es;
+
+ newtFormRun(co, &es);
+ if (es.reason == NEWT_EXIT_HOTKEY) {
+ if (es.u.key == NEWT_KEY_F12) {
+ es.reason = NEWT_EXIT_COMPONENT;
+ es.u.co = co;
+ } else {
+ return NULL;
+ }
+ }
+
+ return es.u.co;
+}
+
+void newtFormAddHotKey(newtComponent co, int key) {
+ struct form * form = co->data;
+
+ form->numHotKeys++;
+ form->hotKeys = realloc(form->hotKeys, sizeof(int) * form->numHotKeys);
+ form->hotKeys[form->numHotKeys - 1] = key;
+}
+
+void newtFormSetSize(newtComponent co) {
+ struct form * form = co->data;
+ int delta, i;
+ struct element * el;
+
+ if (form->beenSet) return;
+
+ form->beenSet = 1;
+
+ if (!form->numComps) return;
+
+ co->width = 0;
+ if (!form->fixedHeight) co->height = 0;
+
+ co->top = form->elements[0].co->top;
+ co->left = form->elements[0].co->left;
+ for (i = 0, el = form->elements; i < form->numComps; i++, el++) {
+ if (el->co->ops == &formOps)
+ newtFormSetSize(el->co);
+
+ el->left = el->co->left;
+ el->top = el->co->top;
+
+ if (co->left > el->co->left) {
+ delta = co->left - el->co->left;
+ co->left -= delta;
+ co->width += delta;
+ }
+
+ if (co->top > el->co->top) {
+ delta = co->top - el->co->top;
+ co->top -= delta;
+ if (!form->fixedHeight)
+ co->height += delta;
+ }
+
+ if ((co->left + co->width) < (el->co->left + el->co->width))
+ co->width = (el->co->left + el->co->width) - co->left;
+
+ if (!form->fixedHeight) {
+ if ((co->top + co->height) < (el->co->top + el->co->height))
+ co->height = (el->co->top + el->co->height) - co->top;
+ }
+
+ if ((el->co->top + el->co->height - co->top) > form->numRows) {
+ form->numRows = el->co->top + el->co->height - co->top;
+ }
+ }
+}
+
+void newtFormRun(newtComponent co, struct newtExitStruct * es) {
+ struct form * form = co->data;
+ struct event ev;
+ struct eventResult er;
+ int key, i, max;
+ int done = 0;
+ fd_set readSet, writeSet, exceptSet;
+ struct timeval nextTimeout, now, timeout;
+#ifdef USE_GPM
+ int x, y;
+ Gpm_Connect conn;
+ Gpm_Event event;
+
+ /* Set up GPM interface */
+ conn.eventMask = ~GPM_MOVE;
+ conn.defaultMask = GPM_MOVE;
+ conn.minMod = 0;
+ conn.maxMod = 0;
+
+ Gpm_Open(&conn, 0);
+#endif
+
+ newtFormSetSize(co);
+ /* draw all of the components */
+ newtDrawForm(co);
+
+ if (form->currComp == -1) {
+ gotoComponent(form, 0);
+ } else
+ gotoComponent(form, form->currComp);
+
+ while (!done) {
+ newtRefresh();
+
+ FD_ZERO(&readSet);
+ FD_ZERO(&writeSet);
+ FD_ZERO(&exceptSet);
+ FD_SET(0, &readSet);
+#ifdef USE_GPM
+ if (gpm_fd > 0) {
+ FD_SET(gpm_fd, &readSet);
+ }
+ max = form->maxFd > gpm_fd ? form->maxFd : gpm_fd;
+#else
+ max = form->maxFd;
+#endif
+
+ for (i = 0; i < form->numFds; i++) {
+ if (form->fds[i].flags & NEWT_FD_READ)
+ FD_SET(form->fds[i].fd, &readSet);
+ if (form->fds[i].flags & NEWT_FD_WRITE)
+ FD_SET(form->fds[i].fd, &writeSet);
+ if (form->fds[i].flags & NEWT_FD_EXCEPT)
+ FD_SET(form->fds[i].fd, &exceptSet);
+ }
+
+ if (form->timer) {
+ /* Calculate when we next need to return with a timeout. Do
+ this inside the loop in case a callback resets the timer. */
+ if (!form->lastTimeout.tv_sec && !form->lastTimeout.tv_usec)
+ gettimeofday(&form->lastTimeout, NULL);
+
+ nextTimeout.tv_sec = form->lastTimeout.tv_sec +
+ (form->timer / 1000);
+ nextTimeout.tv_usec = form->lastTimeout.tv_usec +
+ (form->timer % 1000) * 1000;
+
+ gettimeofday(&now, 0);
+
+ if (now.tv_sec > nextTimeout.tv_sec) {
+ timeout.tv_sec = timeout.tv_usec = 0;
+ } else if (now.tv_sec == nextTimeout.tv_sec) {
+ timeout.tv_sec = 0;
+ if (now.tv_usec > nextTimeout.tv_usec)
+ timeout.tv_usec = 0;
+ else
+ timeout.tv_usec = nextTimeout.tv_usec - now.tv_usec;
+ } else if (now.tv_sec < nextTimeout.tv_sec) {
+ timeout.tv_sec = nextTimeout.tv_sec - now.tv_sec;
+ if (now.tv_usec > nextTimeout.tv_usec)
+ timeout.tv_sec--,
+ timeout.tv_usec = nextTimeout.tv_usec + 1000000 -
+ now.tv_usec;
+ else
+ timeout.tv_usec = nextTimeout.tv_usec - now.tv_usec;
+ }
+ } else {
+ timeout.tv_sec = timeout.tv_usec = 0;
+ }
+
+ i = select(max + 1, &readSet, &writeSet, &exceptSet,
+ form->timer ? &timeout : NULL);
+ if (i < 0) continue; /* ?? What should we do here? */
+
+ if (i == 0) {
+ done = 1;
+ es->reason = NEWT_EXIT_TIMER;
+ gettimeofday(&form->lastTimeout, NULL);
+ } else
+#ifdef USE_GPM
+ if (gpm_fd > 0 && FD_ISSET(gpm_fd, &readSet)) {
+ Gpm_GetEvent(&event);
+
+ if (event.type & GPM_DOWN) {
+ /* Transform coordinates to current window */
+ newtGetWindowPos(&x, &y);
+
+ ev.event = EV_MOUSE;
+ ev.u.mouse.type = MOUSE_BUTTON_DOWN;
+ ev.u.mouse.x = event.x - x - 1;
+ ev.u.mouse.y = event.y - y - 1;
+
+ /* Send the form the event */
+ er = sendEvent(co, ev);
+
+ if (er.result == ER_EXITFORM) {
+ done = 1;
+ es->reason = NEWT_EXIT_COMPONENT;
+ es->u.co = form->exitComp;
+ }
+
+ }
+ } else
+#endif
+ {
+ if (FD_ISSET(0, &readSet)) {
+
+ key = newtGetKey();
+
+ if (key == NEWT_KEY_RESIZE) {
+ /* newtResizeScreen(1); */
+ continue;
+ }
+
+ for (i = 0; i < form->numHotKeys; i++) {
+ if (form->hotKeys[i] == key) {
+ es->reason = NEWT_EXIT_HOTKEY;
+ es->u.key = key;
+ done = 1;
+ break;
+ }
+ }
+
+ if (key == NEWT_KEY_F1 && form->helpTag && form->helpCb)
+ form->helpCb(co, form->helpTag);
+
+ if (!done) {
+ ev.event = EV_KEYPRESS;
+ ev.u.key = key;
+
+ er = sendEvent(co, ev);
+
+ if (er.result == ER_EXITFORM) {
+ done = 1;
+ es->reason = NEWT_EXIT_COMPONENT;
+ es->u.co = form->exitComp;
+ }
+ }
+ } else {
+ for (i = 0; i < form->numFds; i++) {
+ if (((form->fds[i].flags & NEWT_FD_READ)
+ && FD_ISSET(form->fds[i].fd, &readSet))
+ || ((form->fds[i].flags & NEWT_FD_WRITE)
+ && FD_ISSET(form->fds[i].fd, &writeSet))
+ || ((form->fds[i].flags & NEWT_FD_EXCEPT)
+ && FD_ISSET(form->fds[i].fd, &exceptSet))) break;
+ }
+ if(i < form->numFds)
+ es->u.watch = form->fds[i].fd;
+ else
+ es->u.watch = -1;
+
+ es->reason = NEWT_EXIT_FDREADY;
+ done = 1;
+ }
+ }
+ }
+ newtRefresh();
+#ifdef USE_GPM
+ Gpm_Close();
+#endif
+}
+
+static struct eventResult sendEvent(newtComponent co, struct event ev) {
+ struct eventResult er;
+
+ ev.when = EV_EARLY;
+ er = co->ops->event(co, ev);
+
+ if (er.result == ER_IGNORED) {
+ ev.when = EV_NORMAL;
+ er = co->ops->event(co, ev);
+ }
+
+ if (er.result == ER_IGNORED) {
+ ev.when = EV_LATE;
+ er = co->ops->event(co, ev);
+ }
+
+ return er;
+}
+
+static void gotoComponent(struct form * form, int newComp) {
+ struct event ev;
+
+ if (form->currComp != -1) {
+ ev.event = EV_UNFOCUS;
+ sendEvent(form->elements[form->currComp].co, ev);
+ }
+
+ form->currComp = newComp;
+
+ if (form->currComp != -1) {
+ ev.event = EV_FOCUS;
+ ev.when = EV_NORMAL;
+ sendEvent(form->elements[form->currComp].co, ev);
+ }
+}
+
+void newtComponentAddCallback(newtComponent co, newtCallback f, void * data) {
+ co->callback = f;
+ co->callbackData = data;
+}
+
+void newtComponentTakesFocus(newtComponent co, int val) {
+ co->takesFocus = val;
+}
+
+void newtFormSetBackground(newtComponent co, int color) {
+ struct form * form = co->data;
+
+ form->background = color;
+}
+
+void newtFormWatchFd(newtComponent co, int fd, int fdFlags) {
+ struct form * form = co->data;
+ int i;
+
+ for (i = 0; i < form->numFds; i++)
+ if (form->fds[i].fd == fd)
+ break;
+
+ if(i >= form->numFds)
+ form->fds = realloc(form->fds, (++form->numFds) * sizeof(*form->fds));
+
+ form->fds[i].fd = fd;
+ form->fds[i].flags = fdFlags;
+ if (form->maxFd < fd) form->maxFd = fd;
+}
+
+void newtSetHelpCallback(newtCallback cb) {
+ helpCallback = cb;
+}
diff --git a/mininewt/grid.c b/mininewt/grid.c
new file mode 100644
index 000000000..038b7c172
--- /dev/null
+++ b/mininewt/grid.c
@@ -0,0 +1,393 @@
+#include "config.h"
+
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+struct gridField {
+ enum newtGridElement type;
+ union {
+ newtGrid grid;
+ newtComponent co;
+ } u;
+ int padLeft, padTop, padRight, padBottom;
+ int anchor;
+ int flags;
+};
+
+struct grid_s {
+ int rows, cols;
+ int width, height; /* totals, -1 means unknown */
+ struct gridField ** fields;
+};
+
+/* this is a bit of a hack */
+extern struct componentOps formOps[];
+
+newtGrid newtCreateGrid(int cols, int rows) {
+ newtGrid grid;
+
+ grid = malloc(sizeof(*grid));
+ grid->rows = rows;
+ grid->cols = cols;
+
+ grid->fields = malloc(sizeof(*grid->fields) * cols);
+ while (cols--) {
+ grid->fields[cols] = malloc(sizeof(**(grid->fields)) * rows);
+ memset(grid->fields[cols], 0, sizeof(**(grid->fields)) * rows);
+ }
+
+ grid->width = grid->height = -1;
+
+ return grid;
+}
+
+void newtGridSetField(newtGrid grid, int col, int row,
+ enum newtGridElement type, void * val, int padLeft,
+ int padTop, int padRight, int padBottom, int anchor,
+ int flags) {
+ struct gridField * field = &grid->fields[col][row];
+
+ if (field->type == NEWT_GRID_SUBGRID)
+ newtGridFree(field->u.grid, 1);
+
+ field->type = type;
+ field->u.co = (void *) val;
+
+ field->padLeft = padLeft;
+ field->padRight = padRight;
+ field->padTop = padTop;
+ field->padBottom = padBottom;
+ field->anchor = anchor;
+ field->flags = flags;
+
+ grid->width = grid->height = -1;
+}
+
+static void distSpace(int extra, int items, int * list) {
+ int all, some, i;
+
+ all = extra / items;
+ some = extra % items;
+ for (i = 0; i < items; i++) {
+ list[i] += all;
+ if (some) {
+ list[i]++;
+ some--;
+ }
+ }
+}
+
+static void shuffleGrid(newtGrid grid, int left, int top, int set) {
+ struct gridField * field;
+ int row, col;
+ int i, j;
+ int minWidth, minHeight;
+ int * widths, * heights;
+ int thisLeft, thisTop;
+ int x, y, remx, remy;
+
+ widths = alloca(sizeof(*widths) * grid->cols);
+ memset(widths, 0, sizeof(*widths) * grid->cols);
+ heights = alloca(sizeof(*heights) * grid->rows);
+ memset(heights, 0, sizeof(*heights) * grid->rows);
+
+ minWidth = 0;
+ for (row = 0; row < grid->rows; row++) {
+ i = 0;
+ for (col = 0; col < grid->cols; col++) {
+ field = &grid->fields[col][row];
+ if (field->type == NEWT_GRID_SUBGRID) {
+ /* we'll have to redo this later */
+ if (field->u.grid->width == -1)
+ shuffleGrid(field->u.grid, left, top, 0);
+ j = field->u.grid->width;
+ } else if (field->type == NEWT_GRID_COMPONENT) {
+ if (field->u.co->ops == formOps)
+ newtFormSetSize(field->u.co);
+ j = field->u.co->width;
+ } else
+ j = 0;
+
+ j += field->padLeft + field->padRight;
+
+ if (j > widths[col]) widths[col] = j;
+ i += widths[col];
+ }
+
+ if (i > minWidth) minWidth = i;
+ }
+
+ minHeight = 0;
+ for (col = 0; col < grid->cols; col++) {
+ i = 0;
+ for (row = 0; row < grid->rows; row++) {
+ field = &grid->fields[col][row];
+ if (field->type == NEWT_GRID_SUBGRID) {
+ /* we'll have to redo this later */
+ if (field->u.grid->height == -1)
+ shuffleGrid(field->u.grid, 0, 0, 0);
+ j = field->u.grid->height;
+ } else if (field->type == NEWT_GRID_COMPONENT){
+ j = field->u.co->height;
+ } else
+ j = 0;
+
+ j += field->padTop + field->padBottom;
+
+ if (j > heights[row]) heights[row] = j;
+ i += heights[row];
+ }
+
+ if (i > minHeight) minHeight = i;
+ }
+
+ /* this catches the -1 case */
+ if (grid->width < minWidth) grid->width = minWidth; /* ack! */
+ if (grid->height < minHeight) grid->height = minHeight; /* ditto! */
+
+ if (!set) return;
+
+ distSpace(grid->width - minWidth, grid->cols, widths);
+ distSpace(grid->height - minHeight, grid->rows, heights);
+
+ thisTop = top;
+ for (row = 0; row < grid->rows; row++) {
+ i = 0;
+ thisLeft = left;
+ for (col = 0; col < grid->cols; col++) {
+ field = &grid->fields[col][row];
+
+ if (field->type == NEWT_GRID_EMPTY) continue;
+
+ x = thisLeft + field->padLeft;
+ remx = widths[col] - field->padLeft - field->padRight;
+ y = thisTop + field->padTop;
+ remy = heights[row] - field->padTop - field->padBottom;
+
+ if (field->type == NEWT_GRID_SUBGRID) {
+ remx -= field->u.grid->width;
+ remy -= field->u.grid->height;
+ } else if (field->type == NEWT_GRID_COMPONENT) {
+ remx -= field->u.co->width;
+ remy -= field->u.co->height;
+ }
+
+ if (!(field->flags & NEWT_GRID_FLAG_GROWX)) {
+ if (field->anchor & NEWT_ANCHOR_RIGHT)
+ x += remx;
+ else if (!(field->anchor & NEWT_ANCHOR_LEFT))
+ x += (remx / 2);
+ }
+
+ if (!(field->flags & NEWT_GRID_FLAG_GROWY)) {
+ if (field->anchor & NEWT_ANCHOR_BOTTOM)
+ y += remx;
+ else if (!(field->anchor & NEWT_ANCHOR_TOP))
+ y += (remy / 2);
+ }
+
+ if (field->type == NEWT_GRID_SUBGRID) {
+ if (field->flags & NEWT_GRID_FLAG_GROWX)
+ field->u.grid->width = widths[col] - field->padLeft
+ - field->padRight;
+ if (field->flags & NEWT_GRID_FLAG_GROWY)
+ field->u.grid->height = heights[col] - field->padTop
+ - field->padBottom;
+
+ shuffleGrid(field->u.grid, x, y, 1);
+ } else if (field->type == NEWT_GRID_COMPONENT) {
+ field->u.co->ops->place(field->u.co, x, y);
+ }
+
+ thisLeft += widths[col];
+ }
+
+ thisTop += heights[row];
+ }
+}
+
+void newtGridPlace(newtGrid grid, int left, int top) {
+ shuffleGrid(grid, left, top, 1);
+}
+
+void newtGridFree(newtGrid grid, int recurse) {
+ int row, col;
+
+ for (col = 0; col < grid->cols; col++) {
+ if (recurse) {
+ for (row = 0; row < grid->rows; row++) {
+ if (grid->fields[col][row].type == NEWT_GRID_SUBGRID)
+ newtGridFree(grid->fields[col][row].u.grid, 1);
+ }
+ }
+
+ free(grid->fields[col]);
+ }
+
+ free(grid->fields);
+ free(grid);
+}
+
+void newtGridGetSize(newtGrid grid, int * width, int * height) {
+ if (grid->width == -1 || grid->height == -1) {
+ grid->width = grid->height = -1;
+ shuffleGrid(grid, 0, 0, 1);
+ }
+
+ *width = grid->width;
+ *height = grid->height;
+}
+
+void newtGridWrappedWindow(newtGrid grid, char * title) {
+ int width, height, offset = 0;
+
+ newtGridGetSize(grid, &width, &height);
+ if (width < strlen(title) + 2) {
+ offset = ((strlen(title) + 2) - width) / 2;
+ width = strlen(title) + 2;
+ }
+ newtCenteredWindow(width + 2, height + 2, title);
+ newtGridPlace(grid, 1 + offset, 1);
+}
+
+void newtGridWrappedWindowAt(newtGrid grid, char * title, int left, int top) {
+ int width, height;
+
+ newtGridGetSize(grid, &width, &height);
+ newtOpenWindow(left, top, width + 2, height + 2, title);
+ newtGridPlace(grid, 1, 1);
+}
+
+void newtGridAddComponentsToForm(newtGrid grid, newtComponent form,
+ int recurse) {
+ int row, col;
+
+ for (col = 0; col < grid->cols; col++) {
+ for (row = 0; row < grid->rows; row++) {
+ if (grid->fields[col][row].type == NEWT_GRID_SUBGRID && recurse)
+ newtGridAddComponentsToForm(grid->fields[col][row].u.grid,
+ form, 1);
+ else if (grid->fields[col][row].type == NEWT_GRID_COMPONENT)
+ newtFormAddComponent(form, grid->fields[col][row].u.co);
+ }
+ }
+}
+
+/* this handles up to 50 items */
+static newtGrid stackem(int isVert, enum newtGridElement type1, void * what1,
+ va_list args, int close) {
+ struct item {
+ enum newtGridElement type;
+ void * what;
+ } items[50];
+ int i, num;
+ newtGrid grid;
+
+ items[0].type = type1, items[0].what = what1, num = 1;
+ while (1) {
+ items[num].type = va_arg(args, enum newtGridElement);
+ if (items[num].type == NEWT_GRID_EMPTY) break;
+
+ items[num].what = va_arg(args, void *);
+ num++;
+ }
+
+ grid = newtCreateGrid(isVert ? 1 : num, isVert ? num : 1);
+
+ for (i = 0; i < num; i++) {
+ newtGridSetField(grid, isVert ? 0 : i, isVert ? i : 0,
+ items[i].type, items[i].what,
+ close ? 0 : (i ? (isVert ? 0 : 1) : 0),
+ close ? 0 : (i ? (isVert ? 1 : 0) : 0), 0, 0, 0, 0);
+ }
+
+ return grid;
+}
+
+newtGrid newtGridHCloseStacked(enum newtGridElement type1, void * what1, ...) {
+ va_list args;
+ newtGrid grid;
+
+ va_start(args, what1);
+
+ grid = stackem(0, type1, what1, args, 1);
+
+ va_start(args, what1);
+
+ return grid;
+}
+
+newtGrid newtGridVCloseStacked(enum newtGridElement type1, void * what1, ...) {
+ va_list args;
+ newtGrid grid;
+
+ va_start(args, what1);
+
+ grid = stackem(1, type1, what1, args, 1);
+
+ va_start(args, what1);
+
+ return grid;
+}
+
+newtGrid newtGridVStacked(enum newtGridElement type1, void * what1, ...) {
+ va_list args;
+ newtGrid grid;
+
+ va_start(args, what1);
+
+ grid = stackem(1, type1, what1, args, 0);
+
+ va_start(args, what1);
+
+ return grid;
+}
+
+newtGrid newtGridHStacked(enum newtGridElement type1, void * what1, ...) {
+ va_list args;
+ newtGrid grid;
+
+ va_start(args, what1);
+
+ grid = stackem(0, type1, what1, args, 0);
+
+ va_start(args, what1);
+
+ return grid;
+}
+
+newtGrid newtGridBasicWindow(newtComponent text, newtGrid middle,
+ newtGrid buttons) {
+ newtGrid grid;
+
+ grid = newtCreateGrid(1, 3);
+ newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, text,
+ 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
+ newtGridSetField(grid, 0, 1, NEWT_GRID_SUBGRID, middle,
+ 0, 1, 0, 0, 0, 0);
+ newtGridSetField(grid, 0, 2, NEWT_GRID_SUBGRID, buttons,
+ 0, 1, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
+
+ return grid;
+}
+
+newtGrid newtGridSimpleWindow(newtComponent text, newtComponent middle,
+ newtGrid buttons) {
+ newtGrid grid;
+
+ grid = newtCreateGrid(1, 3);
+ newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, text,
+ 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
+ newtGridSetField(grid, 0, 1, NEWT_GRID_COMPONENT, middle,
+ 0, 1, 0, 0, 0, 0);
+ newtGridSetField(grid, 0, 2, NEWT_GRID_SUBGRID, buttons,
+ 0, 1, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
+
+ return grid;
+}
diff --git a/mininewt/label.c b/mininewt/label.c
new file mode 100644
index 000000000..f1a9cebbf
--- /dev/null
+++ b/mininewt/label.c
@@ -0,0 +1,81 @@
+#include <slang.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+struct label {
+ char * text;
+ int length;
+};
+
+static void labelDraw(newtComponent co);
+static void labelDestroy(newtComponent co);
+
+static struct componentOps labelOps = {
+ labelDraw,
+ newtDefaultEventHandler,
+ labelDestroy,
+ newtDefaultPlaceHandler,
+ newtDefaultMappedHandler,
+} ;
+
+newtComponent newtLabel(int left, int top, const char * text) {
+ newtComponent co;
+ struct label * la;
+
+ co = malloc(sizeof(*co));
+ la = malloc(sizeof(struct label));
+ co->data = la;
+
+ co->ops = &labelOps;
+
+ co->height = 1;
+ co->width = strlen(text);
+ co->top = top;
+ co->left = left;
+ co->takesFocus = 0;
+
+ la->length = strlen(text);
+ la->text = strdup(text);
+
+ return co;
+}
+
+void newtLabelSetText(newtComponent co, const char * text) {
+ int newLength;
+ struct label * la = co->data;
+
+ newLength = strlen(text);
+ if (newLength <= la->length) {
+ memset(la->text, ' ', la->length);
+ memcpy(la->text, text, newLength);
+ } else {
+ free(la->text);
+ la->text = strdup(text);
+ la->length = newLength;
+ co->width = newLength;
+ }
+
+ labelDraw(co);
+}
+
+static void labelDraw(newtComponent co) {
+ struct label * la = co->data;
+
+ if (co->isMapped == -1) return;
+
+ SLsmg_set_color(COLORSET_LABEL);
+
+ newtGotorc(co->top, co->left);
+ SLsmg_write_string(la->text);
+}
+
+static void labelDestroy(newtComponent co) {
+ struct label * la = co->data;
+
+ free(la->text);
+ free(la);
+ free(co);
+}
diff --git a/mininewt/listbox.c b/mininewt/listbox.c
new file mode 100644
index 000000000..259c5ccfb
--- /dev/null
+++ b/mininewt/listbox.c
@@ -0,0 +1,764 @@
+/* This goofed-up box whacked into shape by Elliot Lee <sopwith@cuc.edu>
+ (from the original listbox by Erik Troan <ewt@redhat.com>)
+ and contributed to newt for use under the LGPL license.
+ Copyright (C) 1996, 1997 Elliot Lee */
+
+#include <slang.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+
+/* Linked list of items in the listbox */
+struct items {
+ char * text;
+ const void *data;
+ unsigned char isSelected;
+ struct items *next;
+};
+
+/* Holds all the relevant information for this listbox */
+struct listbox {
+ newtComponent sb; /* Scrollbar on right side of listbox */
+ int curWidth; /* size of text w/o scrollbar or border*/
+ int curHeight; /* size of text w/o border */
+ int sbAdjust;
+ int bdxAdjust, bdyAdjust;
+ int numItems, numSelected;
+ int userHasSetWidth;
+ int currItem, startShowItem; /* startShowItem is the first item displayed
+ on the screen */
+ int isActive; /* If we handle key events all the time, it seems
+ to do things even when they are supposed to be for
+ another button/whatever */
+ struct items *boxItems;
+ int grow;
+ int flags; /* flags for this listbox, right now just
+ NEWT_FLAG_RETURNEXIT */
+};
+
+static void listboxDraw(newtComponent co);
+static void listboxDestroy(newtComponent co);
+static struct eventResult listboxEvent(newtComponent co, struct event ev);
+static void newtListboxRealSetCurrent(newtComponent co);
+static void listboxPlace(newtComponent co, int newLeft, int newTop);
+static inline void updateWidth(newtComponent co, struct listbox * li,
+ int maxField);
+static void listboxMapped(newtComponent co, int isMapped);
+
+static struct componentOps listboxOps = {
+ listboxDraw,
+ listboxEvent,
+ listboxDestroy,
+ listboxPlace,
+ listboxMapped,
+};
+
+static void listboxMapped(newtComponent co, int isMapped) {
+ struct listbox * li = co->data;
+
+ co->isMapped = isMapped;
+ if (li->sb)
+ li->sb->ops->mapped(li->sb, isMapped);
+}
+
+static void listboxPlace(newtComponent co, int newLeft, int newTop) {
+ struct listbox * li = co->data;
+
+ co->top = newTop;
+ co->left = newLeft;
+
+ if (li->sb)
+ li->sb->ops->place(li->sb, co->left + co->width - li->bdxAdjust - 1,
+ co->top);
+}
+
+newtComponent newtListbox(int left, int top, int height, int flags) {
+ newtComponent co, sb;
+ struct listbox * li;
+
+ if (!(co = malloc(sizeof(*co))))
+ return NULL;
+
+ if (!(li = malloc(sizeof(struct listbox)))) {
+ free(co);
+ return NULL;
+ }
+
+ li->boxItems = NULL;
+ li->numItems = 0;
+ li->currItem = 0;
+ li->numSelected = 0;
+ li->isActive = 0;
+ li->userHasSetWidth = 0;
+ li->startShowItem = 0;
+ li->sbAdjust = 0;
+ li->bdxAdjust = 0;
+ li->bdyAdjust = 0;
+ li->flags = flags & (NEWT_FLAG_RETURNEXIT | NEWT_FLAG_BORDER |
+ NEWT_FLAG_MULTIPLE | NEWT_FLAG_SHOWCURSOR);
+
+ if (li->flags & NEWT_FLAG_BORDER) {
+ li->bdxAdjust = 2;
+ li->bdyAdjust = 1;
+ }
+
+ co->height = height;
+ li->curHeight = co->height - (2 * li->bdyAdjust);
+
+ if (height) {
+ li->grow = 0;
+ if (flags & NEWT_FLAG_SCROLL) {
+ sb = newtVerticalScrollbar(left, top + li->bdyAdjust,
+ li->curHeight,
+ COLORSET_LISTBOX, COLORSET_ACTLISTBOX);
+ li->sbAdjust = 3;
+ } else {
+ sb = NULL;
+ }
+ } else {
+ li->grow = 1;
+ sb = NULL;
+ }
+
+ li->sb = sb;
+ co->data = li;
+ co->isMapped = 0;
+ co->left = left;
+ co->top = top;
+ co->ops = &listboxOps;
+ co->takesFocus = 1;
+ co->callback = NULL;
+
+ updateWidth(co, li, 5);
+
+ return co;
+}
+
+static inline void updateWidth(newtComponent co, struct listbox * li,
+ int maxField) {
+ li->curWidth = maxField;
+ co->width = li->curWidth + li->sbAdjust + 2 * li->bdxAdjust;
+
+ if (li->sb)
+ li->sb->left = co->left + co->width - li->bdxAdjust - 1;
+}
+
+void newtListboxSetCurrentByKey(newtComponent co, void * key) {
+ struct listbox * li = co->data;
+ struct items * item;
+ int i;
+
+ item = li->boxItems, i = 0;
+ while (item && item->data != key)
+ item = item->next, i++;
+
+ if (item)
+ newtListboxSetCurrent(co, i);
+}
+
+void newtListboxSetCurrent(newtComponent co, int num)
+{
+ struct listbox * li = co->data;
+
+ if (num >= li->numItems)
+ li->currItem = li->numItems - 1;
+ else if (num < 0)
+ li->currItem = 0;
+ else
+ li->currItem = num;
+
+ if (li->currItem < li->startShowItem)
+ li->startShowItem = li->currItem;
+ else if (li->currItem - li->startShowItem > li->curHeight - 1)
+ li->startShowItem = li->currItem - li->curHeight + 1;
+ if (li->startShowItem + li->curHeight > li->numItems)
+ li->startShowItem = li->numItems - li->curHeight;
+ if(li->startShowItem < 0)
+ li->startShowItem = 0;
+
+ newtListboxRealSetCurrent(co);
+}
+
+static void newtListboxRealSetCurrent(newtComponent co)
+{
+ struct listbox * li = co->data;
+
+ if(li->sb)
+ newtScrollbarSet(li->sb, li->currItem + 1, li->numItems);
+ listboxDraw(co);
+ if(co->callback) co->callback(co, co->callbackData);
+}
+
+void newtListboxSetWidth(newtComponent co, int width) {
+ struct listbox * li = co->data;
+
+ co->width = width;
+ li->curWidth = co->width - li->sbAdjust - 2 * li->bdxAdjust;
+ li->userHasSetWidth = 1;
+ if (li->sb) li->sb->left = co->width + co->left - 1;
+ listboxDraw(co);
+}
+
+void * newtListboxGetCurrent(newtComponent co) {
+ struct listbox * li = co->data;
+ int i;
+ struct items *item;
+
+ for(i = 0, item = li->boxItems; item != NULL && i < li->currItem;
+ i++, item = item->next);
+
+ if (item)
+ return (void *)item->data;
+ else
+ return NULL;
+}
+
+void newtListboxSelectItem(newtComponent co, const void * key,
+ enum newtFlagsSense sense)
+{
+ struct listbox * li = co->data;
+ int i;
+ struct items * item;
+
+ item = li->boxItems, i = 0;
+ while (item && item->data != key)
+ item = item->next, i++;
+
+ if (!item) return;
+
+ if (item->isSelected)
+ li->numSelected--;
+
+ switch(sense) {
+ case NEWT_FLAGS_RESET:
+ item->isSelected = 0; break;
+ case NEWT_FLAGS_SET:
+ item->isSelected = 1; break;
+ case NEWT_FLAGS_TOGGLE:
+ item->isSelected = !item->isSelected;
+ }
+
+ if (item->isSelected)
+ li->numSelected++;
+
+ listboxDraw(co);
+}
+
+void newtListboxClearSelection(newtComponent co)
+{
+ struct items *item;
+ struct listbox * li = co->data;
+
+ for(item = li->boxItems; item != NULL;
+ item = item->next)
+ item->isSelected = 0;
+ li->numSelected = 0;
+ listboxDraw(co);
+}
+
+/* Free the returned array after use, but NOT the values in the array */
+void ** newtListboxGetSelection(newtComponent co, int *numitems)
+{
+ struct listbox * li;
+ int i;
+ void **retval;
+ struct items *item;
+
+ if(!co || !numitems) return NULL;
+
+ li = co->data;
+ if(!li || !li->numSelected) return NULL;
+
+ retval = malloc(li->numSelected * sizeof(void *));
+ for(i = 0, item = li->boxItems; item != NULL;
+ item = item->next)
+ if(item->isSelected)
+ retval[i++] = (void *)item->data;
+ *numitems = li->numSelected;
+ return retval;
+}
+
+void newtListboxSetEntry(newtComponent co, int num, const char * text) {
+ struct listbox * li = co->data;
+ int i;
+ struct items *item;
+
+ for(i = 0, item = li->boxItems; item != NULL && i < num;
+ i++, item = item->next);
+
+ if(!item)
+ return;
+ else {
+ free(item->text);
+ item->text = strdup(text);
+ }
+ if (li->userHasSetWidth == 0 && strlen(text) > li->curWidth) {
+ updateWidth(co, li, strlen(text));
+ }
+
+ if (num >= li->startShowItem && num <= li->startShowItem + co->height)
+ listboxDraw(co);
+}
+
+void newtListboxSetData(newtComponent co, int num, void * data) {
+ struct listbox * li = co->data;
+ int i;
+ struct items *item;
+
+ for(i = 0, item = li->boxItems; item != NULL && i < num;
+ i++, item = item->next);
+
+ item->data = data;
+}
+
+int newtListboxAppendEntry(newtComponent co, const char * text,
+ const void * data) {
+ struct listbox * li = co->data;
+ struct items *item;
+
+ if(li->boxItems) {
+ for (item = li->boxItems; item->next != NULL; item = item->next);
+
+ item = item->next = malloc(sizeof(struct items));
+ } else {
+ item = li->boxItems = malloc(sizeof(struct items));
+ }
+
+ if (!li->userHasSetWidth && text && (strlen(text) > li->curWidth))
+ updateWidth(co, li, strlen(text));
+
+ item->text = strdup(text); item->data = data; item->next = NULL;
+ item->isSelected = 0;
+
+ if (li->grow)
+ co->height++, li->curHeight++;
+ li->numItems++;
+
+ return 0;
+}
+
+int newtListboxInsertEntry(newtComponent co, const char * text,
+ const void * data, void * key) {
+ struct listbox * li = co->data;
+ struct items *item, *t;
+
+ if (li->boxItems) {
+ if (key) {
+ item = li->boxItems;
+ while (item && item->data != key) item = item->next;
+
+ if (!item) return 1;
+
+ t = item->next;
+ item = item->next = malloc(sizeof(struct items));
+ item->next = t;
+ } else {
+ t = li->boxItems;
+ item = li->boxItems = malloc(sizeof(struct items));
+ item->next = t;
+ }
+ } else if (key) {
+ return 1;
+ } else {
+ item = li->boxItems = malloc(sizeof(struct items));
+ item->next = NULL;
+ }
+
+ if (!li->userHasSetWidth && text && (strlen(text) > li->curWidth))
+ updateWidth(co, li, strlen(text));
+
+ item->text = strdup(text?text:"(null)"); item->data = data;
+ item->isSelected = 0;
+
+ if (li->sb)
+ li->sb->left = co->left + co->width - li->bdxAdjust - 1;
+ li->numItems++;
+
+ listboxDraw(co);
+
+ return 0;
+}
+
+int newtListboxDeleteEntry(newtComponent co, void * key) {
+ struct listbox * li = co->data;
+ int widest = 0, t;
+ struct items *item, *item2 = NULL;
+ int num;
+
+ if (li->boxItems == NULL || li->numItems <= 0)
+ return 0;
+
+ num = 0;
+
+ item2 = NULL, item = li->boxItems;
+ while (item && item->data != key) {
+ item2 = item;
+ item = item->next;
+ num++;
+ }
+
+ if (!item)
+ return -1;
+
+ if (item2)
+ item2->next = item->next;
+ else
+ li->boxItems = item->next;
+
+ free(item->text);
+ free(item);
+ li->numItems--;
+
+ if (!li->userHasSetWidth) {
+ widest = 0;
+ for (item = li->boxItems; item != NULL; item = item->next)
+ if ((t = strlen(item->text)) > widest) widest = t;
+ }
+
+ if (li->currItem >= num)
+ li->currItem--;
+
+ if (!li->userHasSetWidth) {
+ updateWidth(co, li, widest);
+ }
+
+ listboxDraw(co);
+
+ return 0;
+}
+
+void newtListboxClear(newtComponent co)
+{
+ struct listbox * li;
+ struct items *anitem, *nextitem;
+ if(co == NULL || (li = co->data) == NULL)
+ return;
+ for(anitem = li->boxItems; anitem != NULL; anitem = nextitem) {
+ nextitem = anitem->next;
+ free(anitem->text);
+ free(anitem);
+ }
+ li->numItems = li->numSelected = li->currItem = li->startShowItem = 0;
+ li->boxItems = NULL;
+ if (!li->userHasSetWidth)
+ updateWidth(co, li, 5);
+}
+
+int newtListboxItemCount(newtComponent co)
+{
+ struct listbox *li = co->data;
+ return li->numItems;
+}
+
+/* If you don't want to get back the text, pass in NULL for the ptr-ptr. Same
+ goes for the data. */
+void newtListboxGetEntry(newtComponent co, int num, char **text, void **data) {
+ struct listbox * li = co->data;
+ int i;
+ struct items *item;
+
+ if (!li->boxItems || num >= li->numItems) {
+ if(text)
+ *text = NULL;
+ if(data)
+ *data = NULL;
+ return;
+ }
+
+ i = 0;
+ item = li->boxItems;
+ while (item && i < num) {
+ i++, item = item->next;
+ }
+
+ if (item) {
+ if (text)
+ *text = item->text;
+ if (data)
+ *data = (void *)item->data;
+ }
+}
+
+static void listboxDraw(newtComponent co)
+{
+ struct listbox * li = co->data;
+ struct items *item;
+ int i, j;
+
+ if (!co->isMapped) return ;
+
+ newtTrashScreen();
+
+ if(li->flags & NEWT_FLAG_BORDER) {
+ if(li->isActive)
+ SLsmg_set_color(NEWT_COLORSET_ACTLISTBOX);
+ else
+ SLsmg_set_color(NEWT_COLORSET_LISTBOX);
+
+ newtDrawBox(co->left, co->top, co->width, co->height, 0);
+ }
+
+ if(li->sb)
+ li->sb->ops->draw(li->sb);
+
+ SLsmg_set_color(NEWT_COLORSET_LISTBOX);
+
+ for(i = 0, item = li->boxItems; item != NULL && i < li->startShowItem;
+ i++, item = item->next);
+
+ j = i;
+
+ for (i = 0; item != NULL && i < li->curHeight; i++, item = item->next) {
+ if (!item->text) continue;
+
+ newtGotorc(co->top + i + li->bdyAdjust, co->left + li->bdxAdjust);
+ if(j + i == li->currItem) {
+ if(item->isSelected)
+ SLsmg_set_color(NEWT_COLORSET_ACTSELLISTBOX);
+ else
+ SLsmg_set_color(NEWT_COLORSET_ACTLISTBOX);
+ } else if(item->isSelected)
+ SLsmg_set_color(NEWT_COLORSET_SELLISTBOX);
+ else
+ SLsmg_set_color(NEWT_COLORSET_LISTBOX);
+
+ SLsmg_write_nstring(item->text, li->curWidth);
+
+ }
+ newtGotorc(co->top + (li->currItem - li->startShowItem) + 1, co->left + 1);
+}
+
+static struct eventResult listboxEvent(newtComponent co, struct event ev) {
+ struct eventResult er;
+ struct listbox * li = co->data;
+ struct items *item;
+ int i;
+
+ er.result = ER_IGNORED;
+
+ if(ev.when == EV_EARLY || ev.when == EV_LATE) {
+ return er;
+ }
+
+ switch(ev.event) {
+ case EV_KEYPRESS:
+ if (!li->isActive) break;
+
+ switch(ev.u.key) {
+ case ' ':
+ if(!(li->flags & NEWT_FLAG_MULTIPLE)) break;
+ newtListboxSelectItem(co, newtListboxGetCurrent(co),
+ NEWT_FLAGS_TOGGLE);
+ er.result = ER_SWALLOWED;
+ /* We don't break here, because it is cool to be able to
+ hold space to select a bunch of items in a list at once */
+
+ case NEWT_KEY_DOWN:
+ if(li->numItems <= 0) break;
+ if(li->currItem < li->numItems - 1) {
+ li->currItem++;
+ if(li->currItem > (li->startShowItem + li->curHeight - 1)) {
+ li->startShowItem = li->currItem - li->curHeight + 1;
+ if(li->startShowItem + li->curHeight > li->numItems)
+ li->startShowItem = li->numItems - li->curHeight;
+ }
+ if(li->sb)
+ newtScrollbarSet(li->sb, li->currItem + 1, li->numItems);
+ listboxDraw(co);
+ }
+ if(co->callback) co->callback(co, co->callbackData);
+ er.result = ER_SWALLOWED;
+ break;
+
+ case NEWT_KEY_ENTER:
+ if(li->numItems <= 0) break;
+ if(li->flags & NEWT_FLAG_RETURNEXIT)
+ er.result = ER_EXITFORM;
+ break;
+
+ case NEWT_KEY_UP:
+ if(li->numItems <= 0) break;
+ if(li->currItem > 0) {
+ li->currItem--;
+ if(li->currItem < li->startShowItem)
+ li->startShowItem = li->currItem;
+ if(li->sb)
+ newtScrollbarSet(li->sb, li->currItem + 1, li->numItems);
+ listboxDraw(co);
+ }
+ if(co->callback) co->callback(co, co->callbackData);
+ er.result = ER_SWALLOWED;
+ break;
+
+ case NEWT_KEY_PGUP:
+ if(li->numItems <= 0) break;
+ li->startShowItem -= li->curHeight - 1;
+ if(li->startShowItem < 0)
+ li->startShowItem = 0;
+ li->currItem -= li->curHeight - 1;
+ if(li->currItem < 0)
+ li->currItem = 0;
+ newtListboxRealSetCurrent(co);
+ er.result = ER_SWALLOWED;
+ break;
+
+ case NEWT_KEY_PGDN:
+ if(li->numItems <= 0) break;
+ li->startShowItem += li->curHeight;
+ if(li->startShowItem > (li->numItems - li->curHeight)) {
+ li->startShowItem = li->numItems - li->curHeight;
+ }
+ li->currItem += li->curHeight;
+ if(li->currItem >= li->numItems) {
+ li->currItem = li->numItems - 1;
+ }
+ newtListboxRealSetCurrent(co);
+ er.result = ER_SWALLOWED;
+ break;
+
+ case NEWT_KEY_HOME:
+ if(li->numItems <= 0) break;
+ newtListboxSetCurrent(co, 0);
+ er.result = ER_SWALLOWED;
+ break;
+
+ case NEWT_KEY_END:
+ if(li->numItems <= 0) break;
+ li->startShowItem = li->numItems - li->curHeight;
+ if(li->startShowItem < 0)
+ li->startShowItem = 0;
+ li->currItem = li->numItems - 1;
+ newtListboxRealSetCurrent(co);
+ er.result = ER_SWALLOWED;
+ break;
+ default:
+ if (li->numItems <= 0) break;
+ if (ev.u.key < NEWT_KEY_EXTRA_BASE && isalpha(ev.u.key)) {
+ for(i = 0, item = li->boxItems; item != NULL &&
+ i < li->currItem; i++, item = item->next);
+
+ if (item && item->text && (toupper(*item->text) == toupper(ev.u.key))) {
+ item = item->next;
+ i++;
+ } else {
+ item = li->boxItems;
+ i = 0;
+ }
+ while (item && item->text &&
+ toupper(*item->text) != toupper(ev.u.key)) {
+ item = item->next;
+ i++;
+ }
+ if (item) {
+ li->currItem = i;
+ if(li->currItem < li->startShowItem ||
+ li->currItem > li->startShowItem)
+ li->startShowItem =
+ li->currItem > li->numItems - li->curHeight ?
+ li->startShowItem = li->numItems - li->curHeight :
+ li->currItem;
+ if(li->sb)
+ newtScrollbarSet(li->sb, li->currItem + 1, li->numItems);
+ newtListboxRealSetCurrent(co);
+ er.result = ER_SWALLOWED;
+ }
+ }
+ }
+ break;
+
+ case EV_FOCUS:
+ li->isActive = 1;
+ listboxDraw(co);
+ if(li->flags & NEWT_FLAG_SHOWCURSOR)
+ newtCursorOn();
+ er.result = ER_SWALLOWED;
+ break;
+
+ case EV_UNFOCUS:
+ li->isActive = 0;
+ listboxDraw(co);
+ if(li->flags & NEWT_FLAG_SHOWCURSOR)
+ newtCursorOff();
+ er.result = ER_SWALLOWED;
+ break;
+
+ case EV_MOUSE:
+ /* if this mouse click was within the listbox, make the current
+ item the item clicked on. */
+ /* Up scroll arrow */
+ if (li->sb &&
+ ev.u.mouse.x == co->left + co->width - li->bdxAdjust - 1 &&
+ ev.u.mouse.y == co->top + li->bdyAdjust) {
+ if(li->numItems <= 0) break;
+ if(li->currItem > 0) {
+ li->currItem--;
+ if(li->currItem < li->startShowItem)
+ li->startShowItem = li->currItem;
+ if(li->sb)
+ newtScrollbarSet(li->sb, li->currItem + 1, li->numItems);
+ listboxDraw(co);
+ }
+ if(co->callback) co->callback(co, co->callbackData);
+ er.result = ER_SWALLOWED;
+ break;
+ }
+ /* Down scroll arrow */
+ if (li->sb &&
+ ev.u.mouse.x == co->left + co->width - li->bdxAdjust - 1 &&
+ ev.u.mouse.y == co->top + co->height - li->bdyAdjust - 1) {
+ if(li->numItems <= 0) break;
+ if(li->currItem < li->numItems - 1) {
+ li->currItem++;
+ if(li->currItem > (li->startShowItem + li->curHeight - 1)) {
+ li->startShowItem = li->currItem - li->curHeight + 1;
+ if(li->startShowItem + li->curHeight > li->numItems)
+ li->startShowItem = li->numItems - li->curHeight;
+ }
+ if(li->sb)
+ newtScrollbarSet(li->sb, li->currItem + 1, li->numItems);
+ listboxDraw(co);
+ }
+ if(co->callback) co->callback(co, co->callbackData);
+ er.result = ER_SWALLOWED;
+ break;
+ }
+ if ((ev.u.mouse.y >= co->top + li->bdyAdjust) &&
+ (ev.u.mouse.y <= co->top + co->height - (li->bdyAdjust * 2)) &&
+ (ev.u.mouse.x >= co->left + li->bdxAdjust) &&
+ (ev.u.mouse.x <= co->left + co->width + (li->bdxAdjust * 2))) {
+ li->currItem = li->startShowItem +
+ (ev.u.mouse.y - li->bdyAdjust - co->top);
+ newtListboxRealSetCurrent(co);
+ listboxDraw(co);
+ if(co->callback) co->callback(co, co->callbackData);
+ er.result = ER_SWALLOWED;
+ break;
+ }
+ }
+
+ return er;
+}
+
+static void listboxDestroy(newtComponent co) {
+ struct listbox * li = co->data;
+ struct items * item, * nextitem;
+
+ nextitem = item = li->boxItems;
+
+ while (item != NULL) {
+ nextitem = item->next;
+ free(item->text);
+ free(item);
+ item = nextitem;
+ }
+
+ if (li->sb) li->sb->ops->destroy(li->sb);
+
+ free(li);
+ free(co);
+}
diff --git a/mininewt/newt.c b/mininewt/newt.c
new file mode 100644
index 000000000..56b4e1aba
--- /dev/null
+++ b/mininewt/newt.c
@@ -0,0 +1,710 @@
+#include "config.h"
+
+#include <slang.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/signal.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <termios.h>
+#include <unistd.h>
+
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#endif
+
+#include "newt.h"
+#include "newt_pr.h"
+
+struct Window {
+ int height, width, top, left;
+ SLsmg_Char_Type * buffer;
+ char * title;
+};
+
+struct keymap {
+ char * str;
+ int code;
+ char * tc;
+};
+
+static struct Window windowStack[20];
+static struct Window * currentWindow = NULL;
+
+static char * helplineStack[20];
+static char ** currentHelpline = NULL;
+
+static int cursorRow, cursorCol;
+static int needResize;
+static int cursorOn = 1;
+static int trashScreen = 0;
+
+static const char * defaultHelpLine =
+" <Tab>/<Alt-Tab> between elements | <Space> selects | <F12> next screen"
+;
+
+const struct newtColors newtDefaultColorPalette = {
+ "white", "blue", /* root fg, bg */
+ "black", "lightgray", /* border fg, bg */
+ "black", "lightgray", /* window fg, bg */
+ "white", "black", /* shadow fg, bg */
+ "red", "lightgray", /* title fg, bg */
+ "lightgray", "red", /* button fg, bg */
+ "red", "lightgray", /* active button fg, bg */
+ "yellow", "blue", /* checkbox fg, bg */
+ "blue", "brown", /* active checkbox fg, bg */
+ "yellow", "blue", /* entry box fg, bg */
+ "blue", "lightgray", /* label fg, bg */
+ "black", "lightgray", /* listbox fg, bg */
+ "yellow", "blue", /* active listbox fg, bg */
+ "black", "lightgray", /* textbox fg, bg */
+ "lightgray", "black", /* active textbox fg, bg */
+ "white", "blue", /* help line */
+ "yellow", "blue", /* root text */
+ "blue", /* scale full */
+ "red", /* scale empty */
+ "blue", "lightgray", /* disabled entry fg, bg */
+ "white", "blue", /* compact button fg, bg */
+ "yellow", "red", /* active & sel listbox */
+ "black", "brown" /* selected listbox */
+};
+
+static const struct keymap keymap[] = {
+ { "\033OA", NEWT_KEY_UP, "kh" },
+ { "\033[A", NEWT_KEY_UP, "ku" },
+ { "\033OB", NEWT_KEY_DOWN, "kd" },
+ { "\033[B", NEWT_KEY_DOWN, "kd" },
+ { "\033[C", NEWT_KEY_RIGHT, "kr" },
+ { "\033OC", NEWT_KEY_RIGHT, "kr" },
+ { "\033[D", NEWT_KEY_LEFT, "kl" },
+ { "\033OD", NEWT_KEY_LEFT, "kl" },
+ { "\033[H", NEWT_KEY_HOME, "kh" },
+ { "\033[1~", NEWT_KEY_HOME, "kh" },
+ { "\033Ow", NEWT_KEY_END, "kH" },
+ { "\033[4~", NEWT_KEY_END, "kH" },
+
+ { "\033[3~", NEWT_KEY_DELETE, "kl" },
+ { "\033[2~", NEWT_KEY_INSERT, NULL },
+
+ { "\033\t", NEWT_KEY_UNTAB, NULL },
+
+ { "\033[5~", NEWT_KEY_PGUP, NULL },
+ { "\033[6~", NEWT_KEY_PGDN, NULL },
+ { "\033V", NEWT_KEY_PGUP, "kH" },
+ { "\033v", NEWT_KEY_PGUP, "kH" },
+
+ { "\033[[A", NEWT_KEY_F1, NULL },
+ { "\033[[B", NEWT_KEY_F2, NULL },
+ { "\033[[C", NEWT_KEY_F3, NULL },
+ { "\033[[D", NEWT_KEY_F4, NULL },
+ { "\033[[E", NEWT_KEY_F5, NULL },
+
+ { "\033OP", NEWT_KEY_F1, NULL },
+ { "\033OQ", NEWT_KEY_F2, NULL },
+ { "\033OR", NEWT_KEY_F3, NULL },
+ { "\033OS", NEWT_KEY_F4, NULL },
+
+ { "\033[11~", NEWT_KEY_F1, NULL },
+ { "\033[12~", NEWT_KEY_F2, NULL },
+ { "\033[13~", NEWT_KEY_F3, NULL },
+ { "\033[14~", NEWT_KEY_F4, NULL },
+ { "\033[15~", NEWT_KEY_F5, NULL },
+ { "\033[17~", NEWT_KEY_F6, NULL },
+ { "\033[18~", NEWT_KEY_F7, NULL },
+ { "\033[19~", NEWT_KEY_F8, NULL },
+ { "\033[20~", NEWT_KEY_F9, NULL },
+ { "\033[21~", NEWT_KEY_F10, NULL },
+ { "\033[23~", NEWT_KEY_F11, NULL },
+ { "\033[24~", NEWT_KEY_F12, NULL },
+ { "\033", NEWT_KEY_ESCAPE, NULL },
+
+ { NULL, 0, NULL }, /* LEAVE this one */
+};
+static char keyPrefix = '\033';
+
+static const char * version = "Newt windowing library version " VERSION
+ " - (C) 1996-2000 Red Hat Software. "
+ "Redistributable under the term of the Library "
+ "GNU Public License. "
+ "Written by Erik Troan\n";
+
+static newtSuspendCallback suspendCallback = NULL;
+static void * suspendCallbackData = NULL;
+
+void newtSetSuspendCallback(newtSuspendCallback cb, void * data) {
+ suspendCallback = cb;
+ suspendCallbackData = data;
+}
+
+static void handleSigwinch(int signum) {
+ needResize = 1;
+}
+
+static int getkeyInterruptHook(void) {
+ return -1;
+}
+
+void newtFlushInput(void) {
+ while (SLang_input_pending(0)) {
+ SLang_getkey();
+ }
+}
+
+void newtRefresh(void) {
+ SLsmg_refresh();
+}
+
+void newtSuspend(void) {
+ SLtt_set_cursor_visibility (1);
+ SLsmg_suspend_smg();
+ SLang_reset_tty();
+ SLtt_set_cursor_visibility (cursorOn);
+}
+
+void newtResume(void) {
+ SLsmg_resume_smg ();
+ SLsmg_refresh();
+ SLang_init_tty(0, 0, 0);
+}
+
+void newtCls(void) {
+ SLsmg_set_color(NEWT_COLORSET_ROOT);
+ SLsmg_gotorc(0, 0);
+ SLsmg_erase_eos();
+
+ newtRefresh();
+}
+
+#if defined(THIS_DOESNT_WORK)
+void newtResizeScreen(int redraw) {
+ newtPushHelpLine("");
+
+ SLtt_get_screen_size();
+ SLang_init_tty(0, 0, 0);
+
+ SLsmg_touch_lines (0, SLtt_Screen_Rows - 1);
+
+ /* I don't know why I need this */
+ SLsmg_refresh();
+
+ newtPopHelpLine();
+
+ if (redraw)
+ SLsmg_refresh();
+}
+#endif
+
+int newtInit(void) {
+ char * MonoValue, * MonoEnv = "NEWT_MONO", * lang;
+
+ lang = getenv ("LANG");
+ if (lang && !strcasecmp (lang, "ja_JP.eucJP"))
+ trashScreen = 1;
+
+ /* use the version variable just to be sure it gets included */
+ strlen(version);
+
+ SLtt_get_terminfo();
+ SLtt_get_screen_size();
+
+ MonoValue = getenv(MonoEnv);
+ if ( MonoValue == NULL ) {
+ SLtt_Use_Ansi_Colors = 1;
+ } else {
+ SLtt_Use_Ansi_Colors = 0;
+ }
+
+ SLsmg_init_smg();
+ SLang_init_tty(0, 0, 0);
+
+ newtSetColors(newtDefaultColorPalette);
+ newtCursorOff();
+ /*initKeymap();*/
+
+ /*memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = handleSigwinch;
+ sigaction(SIGWINCH, &sa, NULL);*/
+
+ SLsignal_intr(SIGWINCH, handleSigwinch);
+ SLang_getkey_intr_hook = getkeyInterruptHook;
+
+
+
+ return 0;
+}
+
+int newtFinished(void) {
+ SLsmg_gotorc(SLtt_Screen_Rows - 1, 0);
+ newtCursorOn();
+ SLsmg_refresh();
+ SLsmg_reset_smg();
+ SLang_reset_tty();
+
+ return 0;
+}
+
+void newtSetColors(struct newtColors colors) {
+ SLtt_set_color(NEWT_COLORSET_ROOT, "", colors.rootFg, colors.rootBg);
+ SLtt_set_color(NEWT_COLORSET_BORDER, "", colors.borderFg, colors.borderBg);
+ SLtt_set_color(NEWT_COLORSET_WINDOW, "", colors.windowFg, colors.windowBg);
+ SLtt_set_color(NEWT_COLORSET_SHADOW, "", colors.shadowFg, colors.shadowBg);
+ SLtt_set_color(NEWT_COLORSET_TITLE, "", colors.titleFg, colors.titleBg);
+ SLtt_set_color(NEWT_COLORSET_BUTTON, "", colors.buttonFg, colors.buttonBg);
+ SLtt_set_color(NEWT_COLORSET_ACTBUTTON, "", colors.actButtonFg,
+ colors.actButtonBg);
+ SLtt_set_color(NEWT_COLORSET_CHECKBOX, "", colors.checkboxFg,
+ colors.checkboxBg);
+ SLtt_set_color(NEWT_COLORSET_ACTCHECKBOX, "", colors.actCheckboxFg,
+ colors.actCheckboxBg);
+ SLtt_set_color(NEWT_COLORSET_ENTRY, "", colors.entryFg, colors.entryBg);
+ SLtt_set_color(NEWT_COLORSET_LABEL, "", colors.labelFg, colors.labelBg);
+ SLtt_set_color(NEWT_COLORSET_LISTBOX, "", colors.listboxFg,
+ colors.listboxBg);
+ SLtt_set_color(NEWT_COLORSET_ACTLISTBOX, "", colors.actListboxFg,
+ colors.actListboxBg);
+ SLtt_set_color(NEWT_COLORSET_TEXTBOX, "", colors.textboxFg,
+ colors.textboxBg);
+ SLtt_set_color(NEWT_COLORSET_ACTTEXTBOX, "", colors.actTextboxFg,
+ colors.actTextboxBg);
+ SLtt_set_color(NEWT_COLORSET_HELPLINE, "", colors.helpLineFg,
+ colors.helpLineBg);
+ SLtt_set_color(NEWT_COLORSET_ROOTTEXT, "", colors.rootTextFg,
+ colors.rootTextBg);
+
+ SLtt_set_color(NEWT_COLORSET_EMPTYSCALE, "", "white",
+ colors.emptyScale);
+ SLtt_set_color(NEWT_COLORSET_FULLSCALE, "", "white",
+ colors.fullScale);
+ SLtt_set_color(NEWT_COLORSET_DISENTRY, "", colors.disabledEntryFg,
+ colors.disabledEntryBg);
+
+ SLtt_set_color(NEWT_COLORSET_COMPACTBUTTON, "", colors.compactButtonFg,
+ colors.compactButtonBg);
+
+ SLtt_set_color(NEWT_COLORSET_ACTSELLISTBOX, "", colors.actSelListboxFg,
+ colors.actSelListboxBg);
+ SLtt_set_color(NEWT_COLORSET_SELLISTBOX, "", colors.selListboxFg,
+ colors.selListboxBg);
+}
+
+int newtGetKey(void) {
+ int key;
+ char buf[10], * chptr = buf;
+ const struct keymap * curr;
+
+ do {
+ key = SLang_getkey();
+ if (key == 0xFFFF) {
+ if (needResize)
+ return NEWT_KEY_RESIZE;
+
+ /* ignore other signals */
+ continue;
+ }
+
+ if (key == NEWT_KEY_SUSPEND && suspendCallback)
+ suspendCallback(suspendCallbackData);
+ } while (key == NEWT_KEY_SUSPEND);
+
+ switch (key) {
+ case 'v' | 0x80:
+ case 'V' | 0x80:
+ return NEWT_KEY_PGUP;
+
+ case 22:
+ return NEWT_KEY_PGDN;
+
+ return NEWT_KEY_BKSPC;
+ case 0x7f:
+ return NEWT_KEY_BKSPC;
+
+ case 0x08:
+ return NEWT_KEY_BKSPC;
+
+ default:
+ if (key != keyPrefix) return key;
+ }
+
+ memset(buf, 0, sizeof(buf));
+
+ *chptr++ = key;
+ while (SLang_input_pending(5)) {
+ key = SLang_getkey();
+ if (key == keyPrefix) {
+ /* he hit unknown keys too many times -- start over */
+ memset(buf, 0, sizeof(buf));
+ chptr = buf;
+ }
+
+ *chptr++ = key;
+
+ /* this search should use bsearch(), but when we only look through
+ a list of 20 (or so) keymappings, it's probably faster just to
+ do a inline linear search */
+
+ for (curr = keymap; curr->code; curr++) {
+ if (curr->str) {
+ if (!strcmp(curr->str, buf))
+ return curr->code;
+ }
+ }
+ }
+
+ for (curr = keymap; curr->code; curr++) {
+ if (curr->str) {
+ if (!strcmp(curr->str, buf))
+ return curr->code;
+ }
+ }
+
+ /* Looks like we were a bit overzealous in reading characters. Return
+ just the first character, and put everything else back in the buffer
+ for later */
+
+ chptr--;
+ while (chptr > buf)
+ SLang_ungetkey(*chptr--);
+
+ return *chptr;
+}
+
+void newtWaitForKey(void) {
+ newtRefresh();
+
+ SLang_getkey();
+ newtClearKeyBuffer();
+}
+
+void newtClearKeyBuffer(void) {
+ while (SLang_input_pending(1)) {
+ SLang_getkey();
+ }
+}
+
+int newtOpenWindow(int left, int top, int width, int height,
+ const char * title) {
+ int j, row, col;
+ int n;
+ int i;
+
+ newtFlushInput();
+
+ if (!currentWindow) {
+ currentWindow = windowStack;
+ } else {
+ currentWindow++;
+ }
+
+ currentWindow->left = left;
+ currentWindow->top = top;
+ currentWindow->width = width;
+ currentWindow->height = height;
+ currentWindow->title = title ? strdup(title) : NULL;
+
+ currentWindow->buffer = malloc(sizeof(SLsmg_Char_Type) * (width + 3) * (height + 3));
+
+ row = top - 1;
+ col = left - 1;
+ /* clip to the current screen bounds - msw */
+ if (row < 0)
+ row = 0;
+ if (col < 0)
+ col = 0;
+ if (left + width > SLtt_Screen_Cols)
+ width = SLtt_Screen_Cols - left;
+ if (top + height > SLtt_Screen_Rows)
+ height = SLtt_Screen_Rows - top;
+ n = 0;
+ for (j = 0; j < height + 3; j++, row++) {
+ SLsmg_gotorc(row, col);
+ SLsmg_read_raw(currentWindow->buffer + n,
+ currentWindow->width + 3);
+ n += currentWindow->width + 3;
+ }
+
+ newtTrashScreen();
+
+ SLsmg_set_color(NEWT_COLORSET_BORDER);
+ SLsmg_draw_box(top - 1, left - 1, height + 2, width + 2);
+
+ if (currentWindow->title) {
+ i = strlen(currentWindow->title) + 4;
+ i = ((width - i) / 2) + left;
+ SLsmg_gotorc(top - 1, i);
+ SLsmg_set_char_set(1);
+ SLsmg_write_char(SLSMG_RTEE_CHAR);
+ SLsmg_set_char_set(0);
+ SLsmg_write_char(' ');
+ SLsmg_set_color(NEWT_COLORSET_TITLE);
+ SLsmg_write_string((char *)currentWindow->title);
+ SLsmg_set_color(NEWT_COLORSET_BORDER);
+ SLsmg_write_char(' ');
+ SLsmg_set_char_set(1);
+ SLsmg_write_char(SLSMG_LTEE_CHAR);
+ SLsmg_set_char_set(0);
+ }
+
+ SLsmg_set_color(NEWT_COLORSET_WINDOW);
+ SLsmg_fill_region(top, left, height, width, ' ');
+
+ SLsmg_set_color(NEWT_COLORSET_SHADOW);
+ SLsmg_fill_region(top + height + 1, left, 1, width + 2, ' ');
+ SLsmg_fill_region(top, left + width + 1, height + 1, 1, ' ');
+
+ for (i = top; i < (top + height + 1); i++) {
+ SLsmg_gotorc(i, left + width + 1);
+ SLsmg_write_string(" ");
+ }
+
+ return 0;
+}
+
+int newtCenteredWindow(int width, int height, const char * title) {
+ int top, left;
+
+ top = (SLtt_Screen_Rows - height) / 2;
+
+ /* I don't know why, but this seems to look better */
+ if ((SLtt_Screen_Rows % 2) && (top % 2)) top--;
+
+ left = (SLtt_Screen_Cols - width) / 2;
+
+ newtOpenWindow(left, top, width, height, title);
+
+ return 0;
+}
+
+void newtPopWindow(void) {
+ int j, row, col;
+ int n = 0;
+
+ row = col = 0;
+
+ row = currentWindow->top - 1;
+ col = currentWindow->left - 1;
+ if (row < 0)
+ row = 0;
+ if (col < 0)
+ col = 0;
+ for (j = 0; j < currentWindow->height + 3; j++, row++) {
+ SLsmg_gotorc(row, col);
+ SLsmg_write_raw(currentWindow->buffer + n,
+ currentWindow->width + 3);
+ n += currentWindow->width + 3;
+ }
+
+ free(currentWindow->buffer);
+ free(currentWindow->title);
+
+ if (currentWindow == windowStack)
+ currentWindow = NULL;
+ else
+ currentWindow--;
+
+ SLsmg_set_char_set(0);
+
+ newtTrashScreen();
+
+ newtRefresh();
+}
+
+void newtGetWindowPos(int * x, int * y) {
+ if (currentWindow) {
+ *x = currentWindow->left;
+ *y = currentWindow->top;
+ } else
+ *x = *y = 0;
+}
+
+void newtGetrc(int * row, int * col) {
+ *row = cursorRow;
+ *col = cursorCol;
+}
+
+void newtGotorc(int newRow, int newCol) {
+ if (currentWindow) {
+ newRow += currentWindow->top;
+ newCol += currentWindow->left;
+ }
+
+ cursorRow = newRow;
+ cursorCol = newCol;
+ SLsmg_gotorc(cursorRow, cursorCol);
+}
+
+void newtDrawBox(int left, int top, int width, int height, int shadow) {
+ if (currentWindow) {
+ top += currentWindow->top;
+ left += currentWindow->left;
+ }
+
+ SLsmg_draw_box(top, left, height, width);
+
+ if (shadow) {
+ SLsmg_set_color(NEWT_COLORSET_SHADOW);
+ SLsmg_fill_region(top + height, left + 1, 1, width - 1, ' ');
+ SLsmg_fill_region(top + 1, left + width, height, 1, ' ');
+ }
+}
+
+void newtClearBox(int left, int top, int width, int height) {
+ if (currentWindow) {
+ top += currentWindow->top;
+ left += currentWindow->left;
+ }
+
+ SLsmg_fill_region(top, left, height, width, ' ');
+}
+
+#if 0
+/* This doesn't seem to work quite right. I don't know why not, but when
+ I rsh from an rxvt into a box and run this code, the machine returns
+ console key's (\033[B) rather then xterm ones (\033OB). */
+static void initKeymap(void) {
+ struct keymap * curr;
+
+ for (curr = keymap; curr->code; curr++) {
+ if (!curr->str)
+ curr->str = SLtt_tgetstr(curr->tc);
+ }
+
+ /* Newt's keymap handling is a bit broken. It assumes that any extended
+ keystrokes begin with ESC. If you're using a homebrek terminal you
+ will probably need to fix this, or just yell at me and I'll be so
+ ashamed of myself for doing it this way I'll fix it */
+
+ keyPrefix = 0x1b; /* ESC */
+}
+#endif
+
+void newtDelay(int usecs) {
+ fd_set set;
+ struct timeval tv;
+
+ FD_ZERO(&set);
+
+ tv.tv_sec = usecs / 1000000;
+ tv.tv_usec = usecs % 1000000;
+
+ select(0, &set, &set, &set, &tv);
+}
+
+struct eventResult newtDefaultEventHandler(newtComponent c,
+ struct event ev) {
+ struct eventResult er;
+
+ er.result = ER_IGNORED;
+ return er;
+}
+
+void newtRedrawHelpLine(void) {
+ char * buf;
+
+ SLsmg_set_color(NEWT_COLORSET_HELPLINE);
+
+ buf = alloca(SLtt_Screen_Cols + 1);
+ memset(buf, ' ', SLtt_Screen_Cols);
+ buf[SLtt_Screen_Cols] = '\0';
+
+ if (currentHelpline) {
+ int len = strlen(*currentHelpline);
+ if (SLtt_Screen_Cols < len)
+ len = SLtt_Screen_Cols;
+ memcpy(buf, *currentHelpline, len);
+ }
+ SLsmg_gotorc(SLtt_Screen_Rows - 1, 0);
+ SLsmg_write_string(buf);
+}
+
+void newtPushHelpLine(const char * text) {
+ if (!text)
+ text = defaultHelpLine;
+
+ if (currentHelpline)
+ (*(++currentHelpline)) = strdup(text);
+ else {
+ currentHelpline = helplineStack;
+ *currentHelpline = strdup(text);
+ }
+
+ newtRedrawHelpLine();
+}
+
+void newtPopHelpLine(void) {
+ if (!currentHelpline) return;
+
+ free(*currentHelpline);
+ if (currentHelpline == helplineStack)
+ currentHelpline = NULL;
+ else
+ currentHelpline--;
+
+ newtRedrawHelpLine();
+}
+
+void newtDrawRootText(int col, int row, const char * text) {
+ SLsmg_set_color(NEWT_COLORSET_ROOTTEXT);
+
+ if (col < 0) {
+ col = SLtt_Screen_Cols + col;
+ }
+
+ if (row < 0) {
+ row = SLtt_Screen_Rows + row;
+ }
+
+ SLsmg_gotorc(row, col);
+ SLsmg_write_string((char *)text);
+}
+
+int newtSetFlags(int oldFlags, int newFlags, enum newtFlagsSense sense) {
+ switch (sense) {
+ case NEWT_FLAGS_SET:
+ return oldFlags | newFlags;
+
+ case NEWT_FLAGS_RESET:
+ return oldFlags & (~newFlags);
+
+ case NEWT_FLAGS_TOGGLE:
+ return oldFlags ^ newFlags;
+
+ default:
+ return oldFlags;
+ }
+}
+
+void newtBell(void)
+{
+ SLtt_beep();
+}
+
+void newtGetScreenSize(int * cols, int * rows) {
+ if (rows) *rows = SLtt_Screen_Rows;
+ if (cols) *cols = SLtt_Screen_Cols;
+}
+
+void newtDefaultPlaceHandler(newtComponent c, int newLeft, int newTop) {
+ c->left = newLeft;
+ c->top = newTop;
+}
+
+void newtDefaultMappedHandler(newtComponent c, int isMapped) {
+ c->isMapped = isMapped;
+}
+
+void newtCursorOff(void) {
+ cursorOn = 0;
+ SLtt_set_cursor_visibility (cursorOn);
+}
+
+void newtCursorOn(void) {
+ cursorOn = 1;
+ SLtt_set_cursor_visibility (cursorOn);
+}
+
+void newtTrashScreen(void) {
+ if (trashScreen)
+ SLsmg_touch_lines (0, SLtt_Screen_Rows - 1);
+}
+
diff --git a/mininewt/newt.h b/mininewt/newt.h
new file mode 100644
index 000000000..6ffb25939
--- /dev/null
+++ b/mininewt/newt.h
@@ -0,0 +1,373 @@
+#ifndef H_NEWT
+#define H_NEWT
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdarg.h>
+
+#define NEWT_COLORSET_ROOT 2
+#define NEWT_COLORSET_BORDER 3
+#define NEWT_COLORSET_WINDOW 4
+#define NEWT_COLORSET_SHADOW 5
+#define NEWT_COLORSET_TITLE 6
+#define NEWT_COLORSET_BUTTON 7
+#define NEWT_COLORSET_ACTBUTTON 8
+#define NEWT_COLORSET_CHECKBOX 9
+#define NEWT_COLORSET_ACTCHECKBOX 10
+#define NEWT_COLORSET_ENTRY 11
+#define NEWT_COLORSET_LABEL 12
+#define NEWT_COLORSET_LISTBOX 13
+#define NEWT_COLORSET_ACTLISTBOX 14
+#define NEWT_COLORSET_TEXTBOX 15
+#define NEWT_COLORSET_ACTTEXTBOX 16
+#define NEWT_COLORSET_HELPLINE 17
+#define NEWT_COLORSET_ROOTTEXT 18
+#define NEWT_COLORSET_EMPTYSCALE 19
+#define NEWT_COLORSET_FULLSCALE 20
+#define NEWT_COLORSET_DISENTRY 21
+#define NEWT_COLORSET_COMPACTBUTTON 22
+#define NEWT_COLORSET_ACTSELLISTBOX 23
+#define NEWT_COLORSET_SELLISTBOX 24
+
+#define NEWT_ARG_LAST -100000
+#define NEWT_ARG_APPEND -1
+
+struct newtColors {
+ char * rootFg, * rootBg;
+ char * borderFg, * borderBg;
+ char * windowFg, * windowBg;
+ char * shadowFg, * shadowBg;
+ char * titleFg, * titleBg;
+ char * buttonFg, * buttonBg;
+ char * actButtonFg, * actButtonBg;
+ char * checkboxFg, * checkboxBg;
+ char * actCheckboxFg, * actCheckboxBg;
+ char * entryFg, * entryBg;
+ char * labelFg, * labelBg;
+ char * listboxFg, * listboxBg;
+ char * actListboxFg, * actListboxBg;
+ char * textboxFg, * textboxBg;
+ char * actTextboxFg, * actTextboxBg;
+ char * helpLineFg, * helpLineBg;
+ char * rootTextFg, * rootTextBg;
+ char * emptyScale, * fullScale;
+ char * disabledEntryFg, * disabledEntryBg;
+ char * compactButtonFg, * compactButtonBg;
+ char * actSelListboxFg, * actSelListboxBg;
+ char * selListboxFg, * selListboxBg;
+};
+
+enum newtFlagsSense { NEWT_FLAGS_SET, NEWT_FLAGS_RESET, NEWT_FLAGS_TOGGLE };
+
+#define NEWT_FLAG_RETURNEXIT (1 << 0)
+#define NEWT_FLAG_HIDDEN (1 << 1)
+#define NEWT_FLAG_SCROLL (1 << 2)
+#define NEWT_FLAG_DISABLED (1 << 3)
+/* OBSOLETE #define NEWT_FLAG_NOSCROLL (1 << 4) for listboxes */
+#define NEWT_FLAG_BORDER (1 << 5)
+#define NEWT_FLAG_WRAP (1 << 6)
+#define NEWT_FLAG_NOF12 (1 << 7)
+#define NEWT_FLAG_MULTIPLE (1 << 8)
+#define NEWT_FLAG_SELECTED (1 << 9)
+#define NEWT_FLAG_CHECKBOX (1 << 10)
+#define NEWT_FLAG_PASSWORD (1 << 11) /* draw '*' of chars in entrybox */
+#define NEWT_FLAG_SHOWCURSOR (1 << 12) /* Only applies to listbox for now */
+#define NEWT_FD_READ (1 << 0)
+#define NEWT_FD_WRITE (1 << 1)
+#define NEWT_FD_EXCEPT (1 << 2)
+
+#define NEWT_CHECKBOXTREE_UNSELECTABLE (1 << 12)
+#define NEWT_CHECKBOXTREE_HIDE_BOX (1 << 13)
+
+#define NEWT_CHECKBOXTREE_COLLAPSED '\0'
+#define NEWT_CHECKBOXTREE_EXPANDED '\1'
+#define NEWT_CHECKBOXTREE_UNSELECTED ' '
+#define NEWT_CHECKBOXTREE_SELECTED '*'
+
+/* Backwards compatibility */
+#define NEWT_LISTBOX_RETURNEXIT NEWT_FLAG_RETURNEXIT
+#define NEWT_ENTRY_SCROLL NEWT_FLAG_SCROLL
+#define NEWT_ENTRY_HIDDEN NEWT_FLAG_HIDDEN
+#define NEWT_ENTRY_RETURNEXIT NEWT_FLAG_RETURNEXIT
+#define NEWT_ENTRY_DISABLED NEWT_FLAG_DISABLED
+
+#define NEWT_TEXTBOX_WRAP NEWT_FLAG_WRAP
+#define NEWT_TEXTBOX_SCROLL NEWT_FLAG_SCROLL
+#define NEWT_FORM_NOF12 NEWT_FLAG_NOF12
+
+#define newtListboxAddEntry newtListboxAppendEntry
+
+
+typedef struct newtComponent_struct * newtComponent;
+
+extern const struct newtColors newtDefaultColorPalette;
+
+typedef void (*newtCallback)(newtComponent, void *);
+typedef void (*newtSuspendCallback)(void * data);
+
+int newtInit(void);
+int newtFinished(void);
+void newtCls(void);
+void newtResizeScreen(int redraw);
+void newtWaitForKey(void);
+void newtClearKeyBuffer(void);
+void newtDelay(int usecs);
+/* top, left are *not* counting the border */
+int newtOpenWindow(int left, int top, int width, int height,
+ const char * title);
+int newtCenteredWindow(int width, int height, const char * title);
+void newtPopWindow(void);
+void newtSetColors(struct newtColors colors);
+void newtRefresh(void);
+void newtSuspend(void);
+void newtSetSuspendCallback(newtSuspendCallback cb, void * data);
+void newtSetHelpCallback(newtCallback cb);
+void newtResume(void);
+void newtPushHelpLine(const char * text);
+void newtRedrawHelpLine(void);
+void newtPopHelpLine(void);
+void newtDrawRootText(int col, int row, const char * text);
+void newtBell(void);
+void newtCursorOff(void);
+void newtCursorOn(void);
+
+/* Components */
+
+newtComponent newtCompactButton(int left, int top, const char * text);
+newtComponent newtButton(int left, int top, const char * text);
+newtComponent newtCheckbox(int left, int top, const char * text, char defValue,
+ const char * seq, char * result);
+char newtCheckboxGetValue(newtComponent co);
+void newtCheckboxSetValue(newtComponent co, char value);
+void newtCheckboxSetFlags(newtComponent co, int flags, enum newtFlagsSense sense);
+
+
+newtComponent newtRadiobutton(int left, int top, const char * text, int isDefault,
+ newtComponent prevButton);
+newtComponent newtRadioGetCurrent(newtComponent setMember);
+newtComponent newtListitem(int left, int top, const char * text, int isDefault,
+ newtComponent prevItem, const void * data, int flags);
+void newtListitemSet(newtComponent co, const char * text);
+void * newtListitemGetData(newtComponent co);
+void newtGetScreenSize(int * cols, int * rows);
+
+newtComponent newtLabel(int left, int top, const char * text);
+void newtLabelSetText(newtComponent co, const char * text);
+newtComponent newtVerticalScrollbar(int left, int top, int height,
+ int normalColorset, int thumbColorset);
+void newtScrollbarSet(newtComponent co, int where, int total);
+
+newtComponent newtListbox(int left, int top, int height, int flags);
+void * newtListboxGetCurrent(newtComponent co);
+void newtListboxSetCurrent(newtComponent co, int num);
+void newtListboxSetCurrentByKey(newtComponent co, void * key);
+void newtListboxSetEntry(newtComponent co, int num, const char * text);
+void newtListboxSetWidth(newtComponent co, int width);
+void newtListboxSetData(newtComponent co, int num, void * data);
+int newtListboxAppendEntry(newtComponent co, const char * text,
+ const void * data);
+/* Send the key to insert after, or NULL to insert at the top */
+int newtListboxInsertEntry(newtComponent co, const char * text, const void * data, void * key);
+int newtListboxDeleteEntry(newtComponent co, void * data);
+void newtListboxClear(newtComponent co); /* removes all entries from listbox */
+void newtListboxGetEntry(newtComponent co, int num, char **text, void **data);
+/* Returns an array of data pointers from items, last element is NULL */
+void **newtListboxGetSelection(newtComponent co, int *numitems);
+void newtListboxClearSelection(newtComponent co);
+void newtListboxSelectItem(newtComponent co, const void * key,
+ enum newtFlagsSense sense);
+/* Returns number of items currently in listbox. */
+int newtListboxItemCount(newtComponent co);
+
+newtComponent newtCheckboxTree(int left, int top, int height, int flags);
+newtComponent newtCheckboxTreeMulti(int left, int top, int height, char *seq, int flags);
+const void ** newtCheckboxTreeGetSelection(newtComponent co, int *numitems);
+const void * newtCheckboxTreeGetCurrent(newtComponent co);
+void newtCheckboxTreeSetCurrent(newtComponent co, void * item);
+const void ** newtCheckboxTreeGetMultiSelection(newtComponent co, int *numitems, char seqnum);
+/* last item is NEWT_ARG_LAST for all of these */
+int newtCheckboxTreeAddItem(newtComponent co,
+ const char * text, const void * data,
+ int flags, int index, ...);
+int newtCheckboxTreeAddArray(newtComponent co,
+ const char * text, const void * data,
+ int flags, int * indexes);
+int * newtCheckboxTreeFindItem(newtComponent co, void * data);
+void newtCheckboxTreeSetEntry(newtComponent co, const void * data,
+ const char * text);
+void newtCheckboxTreeSetWidth(newtComponent co, int width);
+char newtCheckboxTreeGetEntryValue(newtComponent co, const void * data);
+void newtCheckboxTreeSetEntryValue(newtComponent co, const void * data,
+ char value);
+
+newtComponent newtTextboxReflowed(int left, int top, char * text, int width,
+ int flexDown, int flexUp, int flags);
+newtComponent newtTextbox(int left, int top, int width, int height, int flags);
+void newtTextboxSetText(newtComponent co, const char * text);
+void newtTextboxSetHeight(newtComponent co, int height);
+int newtTextboxGetNumLines(newtComponent co);
+char * newtReflowText(char * text, int width, int flexDown, int flexUp,
+ int * actualWidth, int * actualHeight);
+
+struct newtExitStruct {
+ enum { NEWT_EXIT_HOTKEY, NEWT_EXIT_COMPONENT, NEWT_EXIT_FDREADY,
+ NEWT_EXIT_TIMER } reason;
+ union {
+ int watch;
+ int key;
+ newtComponent co;
+ } u;
+} ;
+
+newtComponent newtForm(newtComponent vertBar, void * helpTag, int flags);
+void newtFormSetTimer(newtComponent form, int millisecs);
+void newtFormWatchFd(newtComponent form, int fd, int fdFlags);
+void newtFormSetSize(newtComponent co);
+newtComponent newtFormGetCurrent(newtComponent co);
+void newtFormSetBackground(newtComponent co, int color);
+void newtFormSetCurrent(newtComponent co, newtComponent subco);
+void newtFormAddComponent(newtComponent form, newtComponent co);
+void newtFormAddComponents(newtComponent form, ...);
+void newtFormSetHeight(newtComponent co, int height);
+void newtFormSetWidth(newtComponent co, int width);
+newtComponent newtRunForm(newtComponent form); /* obsolete */
+void newtFormRun(newtComponent co, struct newtExitStruct * es);
+void newtDrawForm(newtComponent form);
+void newtFormAddHotKey(newtComponent co, int key);
+
+typedef int (*newtEntryFilter)(newtComponent entry, void * data, int ch,
+ int cursor);
+newtComponent newtEntry(int left, int top, const char * initialValue, int width,
+ char ** resultPtr, int flags);
+void newtEntrySet(newtComponent co, const char * value, int cursorAtEnd);
+void newtEntrySetFilter(newtComponent co, newtEntryFilter filter, void * data);
+char * newtEntryGetValue(newtComponent co);
+void newtEntrySetFlags(newtComponent co, int flags, enum newtFlagsSense sense);
+
+newtComponent newtScale(int left, int top, int width, long long fullValue);
+void newtScaleSet(newtComponent co, unsigned long long amount);
+
+void newtComponentAddCallback(newtComponent co, newtCallback f, void * data);
+void newtComponentTakesFocus(newtComponent co, int val);
+
+/* this also destroys all of the components (including other forms) on the
+ form */
+void newtFormDestroy(newtComponent form);
+
+/* Key codes */
+
+#define NEWT_KEY_TAB '\t'
+#define NEWT_KEY_ENTER '\r'
+#define NEWT_KEY_SUSPEND '\032' /* ctrl - z*/
+#define NEWT_KEY_ESCAPE ''
+#define NEWT_KEY_RETURN NEWT_KEY_ENTER
+
+#define NEWT_KEY_EXTRA_BASE 0x8000
+#define NEWT_KEY_UP NEWT_KEY_EXTRA_BASE + 1
+#define NEWT_KEY_DOWN NEWT_KEY_EXTRA_BASE + 2
+#define NEWT_KEY_LEFT NEWT_KEY_EXTRA_BASE + 4
+#define NEWT_KEY_RIGHT NEWT_KEY_EXTRA_BASE + 5
+#define NEWT_KEY_BKSPC NEWT_KEY_EXTRA_BASE + 6
+#define NEWT_KEY_DELETE NEWT_KEY_EXTRA_BASE + 7
+#define NEWT_KEY_HOME NEWT_KEY_EXTRA_BASE + 8
+#define NEWT_KEY_END NEWT_KEY_EXTRA_BASE + 9
+#define NEWT_KEY_UNTAB NEWT_KEY_EXTRA_BASE + 10
+#define NEWT_KEY_PGUP NEWT_KEY_EXTRA_BASE + 11
+#define NEWT_KEY_PGDN NEWT_KEY_EXTRA_BASE + 12
+#define NEWT_KEY_INSERT NEWT_KEY_EXTRA_BASE + 13
+
+#define NEWT_KEY_F1 NEWT_KEY_EXTRA_BASE + 101
+#define NEWT_KEY_F2 NEWT_KEY_EXTRA_BASE + 102
+#define NEWT_KEY_F3 NEWT_KEY_EXTRA_BASE + 103
+#define NEWT_KEY_F4 NEWT_KEY_EXTRA_BASE + 104
+#define NEWT_KEY_F5 NEWT_KEY_EXTRA_BASE + 105
+#define NEWT_KEY_F6 NEWT_KEY_EXTRA_BASE + 106
+#define NEWT_KEY_F7 NEWT_KEY_EXTRA_BASE + 107
+#define NEWT_KEY_F8 NEWT_KEY_EXTRA_BASE + 108
+#define NEWT_KEY_F9 NEWT_KEY_EXTRA_BASE + 109
+#define NEWT_KEY_F10 NEWT_KEY_EXTRA_BASE + 110
+#define NEWT_KEY_F11 NEWT_KEY_EXTRA_BASE + 111
+#define NEWT_KEY_F12 NEWT_KEY_EXTRA_BASE + 112
+
+/* not really a key, but newtGetKey returns it */
+#define NEWT_KEY_RESIZE NEWT_KEY_EXTRA_BASE + 113
+
+#define NEWT_ANCHOR_LEFT (1 << 0)
+#define NEWT_ANCHOR_RIGHT (1 << 1)
+#define NEWT_ANCHOR_TOP (1 << 2)
+#define NEWT_ANCHOR_BOTTOM (1 << 3)
+
+#define NEWT_GRID_FLAG_GROWX (1 << 0)
+#define NEWT_GRID_FLAG_GROWY (1 << 1)
+
+typedef struct grid_s * newtGrid;
+enum newtGridElement { NEWT_GRID_EMPTY = 0,
+ NEWT_GRID_COMPONENT, NEWT_GRID_SUBGRID };
+
+newtGrid newtCreateGrid(int cols, int rows);
+/* TYPE, what, TYPE, what, ..., NULL */
+newtGrid newtGridVStacked(enum newtGridElement type, void * what, ...);
+newtGrid newtGridVCloseStacked(enum newtGridElement type, void * what, ...);
+newtGrid newtGridHStacked(enum newtGridElement type1, void * what1, ...);
+newtGrid newtGridHCloseStacked(enum newtGridElement type1, void * what1, ...);
+newtGrid newtGridBasicWindow(newtComponent text, newtGrid middle,
+ newtGrid buttons);
+newtGrid newtGridSimpleWindow(newtComponent text, newtComponent middle,
+ newtGrid buttons);
+void newtGridSetField(newtGrid grid, int col, int row,
+ enum newtGridElement type, void * val, int padLeft,
+ int padTop, int padRight, int padBottom, int anchor,
+ int flags);
+void newtGridPlace(newtGrid grid, int left, int top);
+#define newtGridDestroy newtGridFree
+void newtGridFree(newtGrid grid, int recurse);
+void newtGridGetSize(newtGrid grid, int * width, int * height);
+void newtGridWrappedWindow(newtGrid grid, char * title);
+void newtGridWrappedWindowAt(newtGrid grid, char * title, int left, int top);
+void newtGridAddComponentsToForm(newtGrid grid, newtComponent form,
+ int recurse);
+
+/* convienve */
+newtGrid newtButtonBarv(char * button1, newtComponent * b1comp, va_list args);
+newtGrid newtButtonBar(char * button1, newtComponent * b1comp, ...);
+
+/* automatically centered and shrink wrapped */
+void newtWinMessage(char * title, char * buttonText, char * text, ...);
+void newtWinMessagev(char * title, char * buttonText, char * text,
+ va_list argv);
+
+/* having separate calls for these two seems silly, but having two separate
+ variable length-arg lists seems like a bad idea as well */
+
+/* Returns 0 if F12 was pressed, 1 for button1, 2 for button2 */
+int newtWinChoice(char * title, char * button1, char * button2,
+ char * text, ...);
+/* Returns 0 if F12 was pressed, 1 for button1, 2 for button2,
+ 3 for button3 */
+int newtWinTernary(char * title, char * button1, char * button2,
+ char * button3, char * message, ...);
+
+/* Returns the button number pressed, 0 on F12 */
+int newtWinMenu(char * title, char * text, int suggestedWidth, int flexDown,
+ int flexUp, int maxListHeight, char ** items, int * listItem,
+ char * button1, ...);
+
+struct newtWinEntry {
+ char * text;
+ char ** value; /* may be initialized to set default */
+ int flags;
+};
+
+/* Returns the button number pressed, 0 on F12. The final values are
+ dynamically allocated, and need to be freed. */
+int newtWinEntries(char * title, char * text, int suggestedWidth, int flexDown,
+ int flexUp, int dataWidth,
+ struct newtWinEntry * items, char * button1, ...);
+
+#ifdef __cplusplus
+} /* End of extern "C" { */
+#endif
+
+#endif /* H_NEWT */
diff --git a/mininewt/newt_pr.h b/mininewt/newt_pr.h
new file mode 100644
index 000000000..258322d1e
--- /dev/null
+++ b/mininewt/newt_pr.h
@@ -0,0 +1,83 @@
+#ifndef H_NEWT_PR
+#define H_NEWT_PR
+
+#define COLORSET_ROOT NEWT_COLORSET_ROOT
+#define COLORSET_BORDER NEWT_COLORSET_BORDER
+#define COLORSET_WINDOW NEWT_COLORSET_WINDOW
+#define COLORSET_SHADOW NEWT_COLORSET_SHADOW
+#define COLORSET_TITLE NEWT_COLORSET_TITLE
+#define COLORSET_BUTTON NEWT_COLORSET_BUTTON
+#define COLORSET_ACTBUTTON NEWT_COLORSET_ACTBUTTON
+#define COLORSET_CHECKBOX NEWT_COLORSET_CHECKBOX
+#define COLORSET_ACTCHECKBOX NEWT_COLORSET_ACTCHECKBOX
+#define COLORSET_ENTRY NEWT_COLORSET_ENTRY
+#define COLORSET_LABEL NEWT_COLORSET_LABEL
+#define COLORSET_LISTBOX NEWT_COLORSET_LISTBOX
+#define COLORSET_ACTLISTBOX NEWT_COLORSET_ACTLISTBOX
+#define COLORSET_TEXTBOX NEWT_COLORSET_TEXTBOX
+#define COLORSET_ACTTEXTBOX NEWT_COLORSET_ACTTEXTBOX
+
+int newtSetFlags(int oldFlags, int newFlags, enum newtFlagsSense sense);
+
+void newtGotorc(int row, int col);
+void newtGetrc(int * row, int * col);
+void newtGetWindowPos(int * x, int * y);
+void newtDrawBox(int left, int top, int width, int height, int shadow);
+void newtClearBox(int left, int top, int width, int height);
+
+int newtGetKey(void);
+void newtTrashScreen(void);
+
+struct newtComponent_struct {
+ /* common data */
+ int height, width;
+ int top, left;
+ int takesFocus;
+ int isMapped;
+
+ struct componentOps * ops;
+
+ newtCallback callback;
+ void * callbackData;
+
+ void * data;
+} ;
+
+enum eventResultTypes { ER_IGNORED, ER_SWALLOWED, ER_EXITFORM, ER_SETFOCUS,
+ ER_NEXTCOMP };
+struct eventResult {
+ enum eventResultTypes result;
+ union {
+ newtComponent focus;
+ } u;
+};
+
+enum eventTypes { EV_FOCUS, EV_UNFOCUS, EV_KEYPRESS, EV_MOUSE };
+enum eventSequence { EV_EARLY, EV_NORMAL, EV_LATE };
+
+struct event {
+ enum eventTypes event;
+ enum eventSequence when;
+ union {
+ int key;
+ struct {
+ enum { MOUSE_MOTION, MOUSE_BUTTON_DOWN, MOUSE_BUTTON_UP } type;
+ int x, y;
+ } mouse;
+ } u;
+} ;
+
+struct componentOps {
+ void (* draw)(newtComponent c);
+ struct eventResult (* event)(newtComponent c, struct event ev);
+ void (* destroy)(newtComponent c);
+ void (* place)(newtComponent c, int newLeft, int newTop);
+ void (* mapped)(newtComponent c, int isMapped);
+} ;
+
+void newtDefaultPlaceHandler(newtComponent c, int newLeft, int newTop);
+void newtDefaultMappedHandler(newtComponent c, int isMapped);
+struct eventResult newtDefaultEventHandler(newtComponent c,
+ struct event ev);
+
+#endif /* H_NEWT_PR */
diff --git a/mininewt/scale.c b/mininewt/scale.c
new file mode 100644
index 000000000..f898916b3
--- /dev/null
+++ b/mininewt/scale.c
@@ -0,0 +1,85 @@
+#include <slang.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+struct scale {
+ long long fullValue;
+ int charsSet;
+ unsigned int percentage;
+};
+
+static void scaleDraw(newtComponent co);
+
+static struct componentOps scaleOps = {
+ scaleDraw,
+ newtDefaultEventHandler,
+ NULL,
+ newtDefaultPlaceHandler,
+ newtDefaultMappedHandler,
+} ;
+
+newtComponent newtScale(int left, int top, int width, long long fullValue) {
+ newtComponent co;
+ struct scale * sc;
+
+ co = malloc(sizeof(*co));
+ sc = malloc(sizeof(struct scale));
+ co->data = sc;
+
+ co->ops = &scaleOps;
+
+ co->height = 1;
+ co->width = width;
+ co->top = top;
+ co->left = left;
+ co->takesFocus = 0;
+
+ sc->fullValue = fullValue;
+ sc->charsSet = 0;
+ sc->percentage = 0;
+
+ return co;
+}
+
+void newtScaleSet(newtComponent co, unsigned long long amount) {
+ struct scale * sc = co->data;
+ int newPercentage;
+
+ sc->charsSet = (amount * co->width) / sc->fullValue;
+ newPercentage = (amount * 100) / sc->fullValue;
+
+ if (newPercentage > 100)
+ newPercentage = 100;
+
+ if (newPercentage != sc->percentage) {
+ sc->percentage = newPercentage;
+ scaleDraw(co);
+ }
+}
+
+static void scaleDraw(newtComponent co) {
+ struct scale * sc = co->data;
+ int i;
+ int xlabel = (co->width-4) /2;
+ char percent[10];
+
+ if (co->top == -1) return;
+
+ newtGotorc(co->top, co->left);
+
+ sprintf(percent, "%3d%%", sc->percentage);
+
+ SLsmg_set_color(NEWT_COLORSET_FULLSCALE);
+
+ for (i = 0; i < co->width; i++) {
+ if (i == sc->charsSet)
+ SLsmg_set_color(NEWT_COLORSET_EMPTYSCALE);
+ if (i >= xlabel && i < xlabel+4)
+ SLsmg_write_char(percent[i-xlabel]);
+ else
+ SLsmg_write_char(' ');
+ }
+}
diff --git a/mininewt/scrollbar.c b/mininewt/scrollbar.c
new file mode 100644
index 000000000..1a737a409
--- /dev/null
+++ b/mininewt/scrollbar.c
@@ -0,0 +1,124 @@
+#include <slang.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+struct scrollbar {
+ int curr;
+ int cs, csThumb;
+ int arrows;
+} ;
+
+static void sbDraw(newtComponent co);
+static void sbDestroy(newtComponent co);
+static void sbDrawThumb(newtComponent co, int isOn);
+
+static struct componentOps sbOps = {
+ sbDraw,
+ newtDefaultEventHandler,
+ sbDestroy,
+ newtDefaultPlaceHandler,
+ newtDefaultMappedHandler,
+} ;
+
+void newtScrollbarSet(newtComponent co, int where, int total) {
+ struct scrollbar * sb = co->data;
+ int new;
+
+ if (sb->arrows)
+ new = (where * (co->height - 3)) / (total ? total : 1) + 1;
+ else
+ new = (where * (co->height - 1)) / (total ? total : 1);
+ if (new != sb->curr) {
+ sbDrawThumb(co, 0);
+ sb->curr = new;
+ sbDrawThumb(co, 1);
+ }
+}
+
+newtComponent newtVerticalScrollbar(int left, int top, int height,
+ int normalColorset, int thumbColorset) {
+ newtComponent co;
+ struct scrollbar * sb;
+
+ co = malloc(sizeof(*co));
+ sb = malloc(sizeof(*sb));
+ co->data = sb;
+
+ if (!strcmp(getenv("TERM"), "linux") && height >= 2) {
+ sb->arrows = 1;
+ sb->curr = 1;
+ } else {
+ sb->arrows = 0;
+ sb->curr = 0;
+ }
+ sb->cs = normalColorset;
+ sb->csThumb = thumbColorset;
+
+ co->ops = &sbOps;
+ co->isMapped = 0;
+ co->left = left;
+ co->top = top;
+ co->height = height;
+ co->width = 1;
+ co->takesFocus = 0;
+
+ return co;
+}
+
+static void sbDraw(newtComponent co) {
+ struct scrollbar * sb = co->data;
+ int i;
+
+ if (!co->isMapped) return;
+
+ SLsmg_set_color(sb->cs);
+
+ SLsmg_set_char_set(1);
+ if (sb->arrows) {
+ newtGotorc(co->top, co->left);
+ SLsmg_write_char(SLSMG_UARROW_CHAR);
+ for (i = 1; i < co->height - 1; i++) {
+ newtGotorc(i + co->top, co->left);
+ SLsmg_write_char(SLSMG_CKBRD_CHAR);
+ }
+ newtGotorc(co->top + co->height - 1, co->left);
+ SLsmg_write_char(SLSMG_DARROW_CHAR);
+ } else {
+ for (i = 0; i < co->height; i++) {
+ newtGotorc(i + co->top, co->left);
+ SLsmg_write_char(SLSMG_CKBRD_CHAR);
+ }
+ }
+
+ SLsmg_set_char_set(0);
+
+ sbDrawThumb(co, 1);
+}
+
+static void sbDrawThumb(newtComponent co, int isOn) {
+ struct scrollbar * sb = co->data;
+ SLtt_Char_Type ch = isOn ? '#' : SLSMG_CKBRD_CHAR;
+
+ if (!co->isMapped) return;
+
+ newtGotorc(sb->curr + co->top, co->left);
+ SLsmg_set_char_set(1);
+
+ /*if (isOn)
+ SLsmg_set_color(sb->csThumb);
+ else*/
+ SLsmg_set_color(sb->cs);
+
+ SLsmg_write_char(ch);
+ SLsmg_set_char_set(0);
+}
+
+static void sbDestroy(newtComponent co) {
+ struct scrollbar * sb = co->data;
+
+ free(sb);
+ free(co);
+}
diff --git a/mininewt/showchars.c b/mininewt/showchars.c
new file mode 100644
index 000000000..71d0adbd1
--- /dev/null
+++ b/mininewt/showchars.c
@@ -0,0 +1,44 @@
+#include <slang.h>
+
+void printall(int offset) {
+ int n = 0;
+ int i, j;
+
+ SLsmg_gotorc(0, offset);
+ SLsmg_write_string(" 0 1 2 3 4 5 6 7 8 9 A B C D E F");
+ for (i = 0; i < 16; i++) {
+ SLsmg_gotorc(i + 1, offset);
+ SLsmg_printf("%x", i);
+ for (j = 0; j < 16; j++) {
+ SLsmg_gotorc(i + 1, (j + 1) * 2 + offset);
+ SLsmg_write_char(n++);
+ }
+ }
+}
+
+int main(void) {
+ char n = 0;
+
+ SLtt_get_terminfo();
+
+ SLtt_Use_Ansi_Colors = 1;
+
+ SLsmg_init_smg();
+ SLang_init_tty(4, 0, 0);
+
+ SLsmg_cls();
+
+ printall(0);
+ SLsmg_set_char_set(1);
+ printall(40);
+
+ SLsmg_refresh();
+ SLang_getkey();
+
+ SLsmg_gotorc(SLtt_Screen_Rows - 1, 0);
+ SLsmg_refresh();
+ SLsmg_reset_smg();
+ SLang_reset_tty();
+
+ return 0;
+}
diff --git a/mininewt/showkey.c b/mininewt/showkey.c
new file mode 100644
index 000000000..5f465b5c2
--- /dev/null
+++ b/mininewt/showkey.c
@@ -0,0 +1,41 @@
+#include <stdio.h>
+#include <slang.h>
+
+int main(void) {
+ char n = 0;
+ int i;
+ char * buf;
+
+ SLtt_get_terminfo();
+ SLang_init_tty(4, 0, 0);
+
+ buf = SLtt_tgetstr("ku");
+ if (!buf) {
+ printf("termcap entry not found for kl\n\r");
+ } else {
+ printf("termcap entry found for kl: %s", buf);
+ while (*buf) {
+ printf("0x%02x ", *buf++);
+ }
+ printf("\n\r");
+ }
+
+ printf("\n\r");
+
+ printf("Press a key: ");
+ fflush(stdout);
+
+ SLang_input_pending(50);
+
+ printf("\n\r");
+ printf("You pressed: ");
+
+ while (SLang_input_pending(1)) {
+ i = SLang_getkey();
+ printf("0x%02x ", i);
+ }
+
+ printf("\n\r");
+
+ SLang_reset_tty();
+}
diff --git a/mininewt/snackmodule.c b/mininewt/snackmodule.c
new file mode 100644
index 000000000..14f07847d
--- /dev/null
+++ b/mininewt/snackmodule.c
@@ -0,0 +1,1245 @@
+
+#include "config.h"
+
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#endif
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include "Python.h"
+#include "newt.h"
+
+typedef struct snackWidget_s snackWidget;
+typedef struct snackGrid_s snackGrid;
+typedef struct snackForm_s snackForm;
+
+struct callbackStruct {
+ PyObject * cb, * data;
+};
+
+/* Integer to pointer, 64-bit-sane */
+#define I2P(x) ((void *)(long)(x))
+
+static struct callbackStruct suspend;
+static struct callbackStruct helpCallback;
+
+static void emptyDestructor(PyObject * s);
+
+static snackWidget * buttonWidget(PyObject * s, PyObject * args);
+static snackWidget * compactbuttonWidget(PyObject * s, PyObject * args);
+static PyObject * centeredWindow(PyObject * s, PyObject * args);
+static snackWidget * checkboxWidget(PyObject * s, PyObject * args);
+static PyObject * choiceWindow(PyObject * s, PyObject * args);
+static snackWidget * entryWidget(PyObject * s, PyObject * args);
+static PyObject * drawRootText(PyObject * s, PyObject * args);
+static PyObject * doResume(PyObject * s, PyObject * args);
+static PyObject * doSuspend(PyObject * s, PyObject * args);
+static PyObject * doSuspend(PyObject * s, PyObject * args);
+static snackForm * formCreate(PyObject * s, PyObject * args);
+static snackGrid * gridCreate(PyObject * s, PyObject * args);
+static PyObject * gridWrappedWindow(PyObject * s, PyObject * args);
+static PyObject * finishScreen(PyObject * s, PyObject * args);
+static PyObject * initScreen(PyObject * s, PyObject * args);
+static snackWidget * labelWidget(PyObject * s, PyObject * args);
+static snackWidget * listboxWidget(PyObject * s, PyObject * args);
+static PyObject * messageWindow(PyObject * s, PyObject * args);
+static PyObject * openWindow(PyObject * s, PyObject * args);
+static PyObject * popHelpLine(PyObject * s, PyObject * args);
+static PyObject * popWindow(PyObject * s, PyObject * args);
+static PyObject * pushHelpLine(PyObject * s, PyObject * args);
+static snackWidget * radioButtonWidget(PyObject * s, PyObject * args);
+static PyObject * refreshScreen(PyObject * s, PyObject * args);
+static PyObject * scaleWidget(PyObject * s, PyObject * args);
+static PyObject * scaleSet(snackWidget * s, PyObject * args);
+static PyObject * screenSize(PyObject * s, PyObject * args);
+static PyObject * setSuspendCallback(PyObject * s, PyObject * args);
+static PyObject * setHelpCallback(PyObject * s, PyObject * args);
+static PyObject * reflowText(PyObject * s, PyObject * args);
+static snackWidget * textWidget(PyObject * s, PyObject * args);
+static PyObject * ternaryWindow(PyObject * s, PyObject * args);
+static snackWidget * checkboxTreeWidget(PyObject * s, PyObject * args, PyObject * kwargs);
+
+static PyMethodDef snackModuleMethods[] = {
+ { "button", (PyCFunction) buttonWidget, METH_VARARGS, NULL },
+ { "compactbutton", (PyCFunction) compactbuttonWidget, METH_VARARGS, NULL },
+ { "checkbox", (PyCFunction) checkboxWidget, METH_VARARGS, NULL },
+ { "choice", choiceWindow, METH_VARARGS, NULL },
+ { "centeredwindow", centeredWindow, METH_VARARGS, NULL },
+ { "drawroottext", drawRootText, METH_VARARGS, NULL },
+ { "entry", (PyCFunction) entryWidget, METH_VARARGS, NULL },
+ { "finish", finishScreen, METH_VARARGS, NULL },
+ { "form", (PyCFunction) formCreate, METH_VARARGS, NULL },
+ { "grid", (PyCFunction) gridCreate, METH_VARARGS, NULL },
+ { "gridwrappedwindow", gridWrappedWindow, METH_VARARGS, NULL },
+ { "helpcallback", setHelpCallback, METH_VARARGS, NULL },
+ { "init", initScreen, METH_VARARGS, NULL },
+ { "label", (PyCFunction) labelWidget, METH_VARARGS, NULL },
+ { "listbox", (PyCFunction) listboxWidget, METH_VARARGS, NULL },
+ { "message", messageWindow, METH_VARARGS, NULL },
+ { "openwindow", openWindow, METH_VARARGS, NULL },
+ { "pophelpline", popHelpLine, METH_VARARGS, NULL },
+ { "popwindow", popWindow, METH_VARARGS, NULL },
+ { "pushhelpline", pushHelpLine, METH_VARARGS, NULL },
+ { "radiobutton", (PyCFunction) radioButtonWidget, METH_VARARGS, NULL },
+ { "reflow", (PyCFunction) reflowText, METH_VARARGS, NULL },
+ { "refresh", refreshScreen, METH_VARARGS, NULL },
+ { "resume", doResume, METH_VARARGS, NULL },
+ { "scale", scaleWidget, METH_VARARGS, NULL },
+ { "size", screenSize, METH_VARARGS, NULL },
+ { "suspend", doSuspend, METH_VARARGS, NULL },
+ { "suspendcallback", setSuspendCallback, METH_VARARGS, NULL },
+ { "ternary", ternaryWindow, METH_VARARGS, NULL },
+ { "textbox", (PyCFunction) textWidget, METH_VARARGS, NULL },
+ { "checkboxtree", (PyCFunction) checkboxTreeWidget, METH_VARARGS | METH_KEYWORDS, NULL },
+ { NULL }
+} ;
+
+struct snackGrid_s {
+ PyObject_HEAD
+ newtGrid grid;
+} ;
+
+static PyObject * gridGetAttr(PyObject * s, char * name);
+static PyObject * gridPlace(snackGrid * s, PyObject * args);
+static PyObject * gridSetField(snackGrid * s, PyObject * args);
+
+static PyMethodDef gridMethods[] = {
+ { "place", (PyCFunction) gridPlace, METH_VARARGS, NULL },
+ { "setfield", (PyCFunction) gridSetField, METH_VARARGS, NULL },
+ { NULL }
+};
+
+static PyTypeObject snackGridType = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0, /* ob_size */
+ "snackgrid", /* tp_name */
+ sizeof(snackGrid), /* tp_size */
+ 0, /* tp_itemsize */
+ emptyDestructor, /* tp_dealloc */
+ 0, /* tp_print */
+ gridGetAttr, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+};
+
+struct snackForm_s {
+ PyObject_HEAD
+ newtComponent fo;
+} ;
+
+static PyObject * formGetAttr(PyObject * s, char * name);
+static PyObject * formAdd(snackForm * s, PyObject * args);
+static PyObject * formDraw(snackForm * s, PyObject * args);
+static PyObject * formRun(snackForm * s, PyObject * args);
+static PyObject * formHotKey(snackForm * s, PyObject * args);
+static PyObject * formSetCurrent(snackForm * form, PyObject * args);
+static PyObject * formSetTimer(snackForm * form, PyObject * args);
+static PyObject * formWatchFD(snackForm * form, PyObject * args);
+
+static PyMethodDef formMethods[] = {
+ { "add", (PyCFunction) formAdd, METH_VARARGS, NULL },
+ { "draw", (PyCFunction) formDraw, METH_VARARGS, NULL },
+ { "run", (PyCFunction) formRun, METH_VARARGS, NULL },
+ { "addhotkey", (PyCFunction) formHotKey, METH_VARARGS, NULL },
+ { "setcurrent", (PyCFunction) formSetCurrent, METH_VARARGS, NULL },
+ { "settimer", (PyCFunction) formSetTimer, METH_VARARGS, NULL },
+ { "watchfd", (PyCFunction) formWatchFD, METH_VARARGS, NULL },
+ { NULL }
+};
+
+static PyTypeObject snackFormType = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0, /* ob_size */
+ "snackform", /* tp_name */
+ sizeof(snackForm), /* tp_size */
+ 0, /* tp_itemsize */
+ emptyDestructor, /* tp_dealloc */
+ 0, /* tp_print */
+ formGetAttr, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+};
+
+struct snackWidget_s {
+ PyObject_HEAD
+ newtComponent co;
+ char achar;
+ void * apointer;
+ int anint;
+ struct callbackStruct scs;
+} ;
+
+static PyObject * widgetAddCallback(snackWidget * s, PyObject * args);
+static PyObject * widgetGetAttr(PyObject * s, char * name);
+static void widgetDestructor(PyObject * s);
+static PyObject * widgetEntrySetValue(snackWidget * s, PyObject * args);
+static PyObject * widgetLabelText(snackWidget * s, PyObject * args);
+static PyObject * widgetListboxSetW(snackWidget * s, PyObject * args);
+static PyObject * widgetListboxAdd(snackWidget * s, PyObject * args);
+static PyObject * widgetListboxIns(snackWidget * s, PyObject * args);
+static PyObject * widgetListboxDel(snackWidget * s, PyObject * args);
+static PyObject * widgetListboxGet(snackWidget * s, PyObject * args);
+static PyObject * widgetListboxSet(snackWidget * s, PyObject * args);
+static PyObject * widgetListboxClear(snackWidget * s, PyObject * args);
+static PyObject * widgetTextboxText(snackWidget * s, PyObject * args);
+static PyObject * widgetCheckboxTreeAddItem(snackWidget * s, PyObject * args);
+static PyObject * widgetCheckboxTreeGetSel(snackWidget * s, PyObject * args);
+static PyObject * widgetCheckboxTreeGetCur(snackWidget * s, PyObject * args);
+static PyObject * widgetCheckboxTreeSetEntry(snackWidget * s, PyObject * args);
+static PyObject * widgetCheckboxTreeSetWidth(snackWidget * s, PyObject * args);
+static PyObject * widgetCheckboxTreeSetCurrent(snackWidget * s, PyObject * args);
+static PyObject * widgetCheckboxTreeSetEntryValue(snackWidget * s, PyObject * args);
+static PyObject * widgetCheckboxTreeGetEntryValue(snackWidget * s, PyObject * args);
+static PyObject * widgetEntrySetFlags(snackWidget * s, PyObject * args);
+static PyObject * widgetCheckboxSetFlags(snackWidget * s, PyObject * args);
+static PyObject * widgetCheckboxSetValue(snackWidget * s, PyObject * args);
+
+static PyMethodDef widgetMethods[] = {
+ { "setCallback", (PyCFunction) widgetAddCallback, METH_VARARGS, NULL },
+ { "labelText", (PyCFunction) widgetLabelText, METH_VARARGS, NULL },
+ { "textboxText", (PyCFunction) widgetTextboxText, METH_VARARGS, NULL },
+ { "entrySetValue", (PyCFunction) widgetEntrySetValue, METH_VARARGS, NULL },
+ { "listboxAddItem", (PyCFunction) widgetListboxAdd, METH_VARARGS, NULL },
+ { "listboxInsertItem", (PyCFunction) widgetListboxIns, METH_VARARGS, NULL },
+ { "listboxGetCurrent", (PyCFunction) widgetListboxGet, METH_VARARGS, NULL },
+ { "listboxSetCurrent", (PyCFunction) widgetListboxSet, METH_VARARGS, NULL },
+ { "listboxSetWidth", (PyCFunction) widgetListboxSetW, METH_VARARGS, NULL },
+ { "listboxDeleteItem", (PyCFunction) widgetListboxDel, METH_VARARGS, NULL },
+ { "listboxClear", (PyCFunction) widgetListboxClear, METH_VARARGS, NULL },
+ { "scaleSet", (PyCFunction) scaleSet, METH_VARARGS, NULL },
+ { "checkboxtreeAddItem", (PyCFunction) widgetCheckboxTreeAddItem,
+ METH_VARARGS, NULL },
+ { "checkboxtreeGetCurrent", (PyCFunction) widgetCheckboxTreeGetCur,
+ METH_VARARGS, NULL },
+ { "checkboxtreeGetEntryValue", (PyCFunction) widgetCheckboxTreeGetEntryValue,
+ METH_VARARGS, NULL },
+ { "checkboxtreeSetEntry", (PyCFunction) widgetCheckboxTreeSetEntry,
+ METH_VARARGS, NULL },
+ { "checkboxtreeSetWidth", (PyCFunction) widgetCheckboxTreeSetWidth, METH_VARARGS, NULL },
+ { "checkboxtreeSetCurrent", (PyCFunction) widgetCheckboxTreeSetCurrent,
+ METH_VARARGS, NULL },
+ { "checkboxtreeSetEntryValue", (PyCFunction) widgetCheckboxTreeSetEntryValue,
+ METH_VARARGS, NULL },
+ { "checkboxtreeGetSelection", (PyCFunction) widgetCheckboxTreeGetSel,
+ METH_VARARGS, NULL },
+ { "entrySetFlags", (PyCFunction) widgetEntrySetFlags, METH_VARARGS, NULL },
+ { "checkboxSetFlags", (PyCFunction) widgetCheckboxSetFlags, METH_VARARGS, NULL },
+ { "checkboxSetValue", (PyCFunction) widgetCheckboxSetValue, METH_VARARGS, NULL },
+ { NULL }
+};
+
+static PyTypeObject snackWidgetType = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0, /* ob_size */
+ "snackwidget", /* tp_name */
+ sizeof(snackWidget), /* tp_size */
+ 0, /* tp_itemsize */
+ widgetDestructor, /* tp_dealloc */
+ 0, /* tp_print */
+ widgetGetAttr, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+};
+
+static snackWidget * snackWidgetNew (void) {
+ snackWidget * widget;
+
+ widget = PyObject_NEW(snackWidget, &snackWidgetType);
+
+ widget->scs.cb = NULL;
+ widget->scs.data = NULL;
+
+ return widget;
+}
+
+static PyObject * initScreen(PyObject * s, PyObject * args) {
+ suspend.cb = NULL;
+ suspend.data = NULL;
+
+ newtInit();
+ newtCls();
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * finishScreen(PyObject * s, PyObject * args) {
+ Py_XDECREF (suspend.cb);
+ Py_XDECREF (suspend.data);
+
+ newtFinished();
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * refreshScreen(PyObject * s, PyObject * args) {
+ newtRefresh();
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * scaleWidget(PyObject * s, PyObject * args) {
+ snackWidget * widget;
+ int width, fullAmount;
+
+ if (!PyArg_ParseTuple(args, "ii", &width, &fullAmount)) return NULL;
+
+ widget = snackWidgetNew ();
+ widget->co = newtScale(-1, -1, width, fullAmount);
+
+ return (PyObject *) widget;
+}
+
+static PyObject * scaleSet(snackWidget * s, PyObject * args) {
+ int amount;
+
+ if (!PyArg_ParseTuple(args, "i", &amount)) return NULL;
+
+ newtScaleSet(s->co, amount);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * screenSize(PyObject * s, PyObject * args) {
+ int width, height;
+
+ if (!PyArg_ParseTuple(args, ""))
+ return NULL;
+
+ newtGetScreenSize(&width, &height);
+
+ return Py_BuildValue("(ii)", width, height);
+}
+
+static void helpCallbackMarshall(newtComponent co, void * data) {
+ PyObject * args, * result;
+
+ args = Py_BuildValue("(O)", data);
+ result = PyEval_CallObject(helpCallback.cb, args);
+ Py_DECREF (args);
+ Py_XDECREF(result);
+
+ return;
+}
+
+static void suspendCallbackMarshall(void * data) {
+ struct callbackStruct * scs = data;
+ PyObject * args, * result;
+
+ if (scs->data) {
+ args = Py_BuildValue("(O)", scs->data);
+ result = PyEval_CallObject(scs->cb, args);
+ Py_DECREF (args);
+ } else
+ result = PyEval_CallObject(scs->cb, NULL);
+
+ if (!result) {
+ PyErr_Print();
+ PyErr_Clear();
+ }
+
+ Py_XDECREF(result);
+
+ return;
+}
+
+static void callbackMarshall(newtComponent co, void * data) {
+ struct callbackStruct * scs = data;
+ PyObject * args, * result;
+
+ if (scs->data) {
+ args = Py_BuildValue("(O)", scs->data);
+ result = PyEval_CallObject(scs->cb, args);
+ Py_DECREF (args);
+ } else
+ result = PyEval_CallObject(scs->cb, NULL);
+
+ if (!result) {
+ PyErr_Print();
+ PyErr_Clear();
+ }
+
+ Py_XDECREF(result);
+
+ return;
+}
+
+static PyObject * setSuspendCallback(PyObject * s, PyObject * args) {
+ if (!PyArg_ParseTuple(args, "O|O", &suspend.cb, &suspend.data))
+ return NULL;
+
+ Py_INCREF (suspend.cb);
+ Py_XINCREF (suspend.data);
+
+ newtSetSuspendCallback(suspendCallbackMarshall, &suspend);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * setHelpCallback(PyObject * s, PyObject * args) {
+ if (!PyArg_ParseTuple(args, "O", &helpCallback.cb))
+ return NULL;
+
+ /*if (helpCallback.cb) {
+ Py_DECREF (helpCallback.cb);
+ }*/
+
+ Py_INCREF (helpCallback.cb);
+
+ newtSetHelpCallback(helpCallbackMarshall);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * drawRootText(PyObject * s, PyObject * args) {
+ int left, top;
+ char * text;
+
+ if (!PyArg_ParseTuple(args, "iis", &left, &top, &text))
+ return NULL;
+
+ newtDrawRootText(left, top, text);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * doSuspend(PyObject * s, PyObject * args) {
+ newtSuspend();
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * doResume(PyObject * s, PyObject * args) {
+ newtResume();
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * popHelpLine(PyObject * s, PyObject * args) {
+ newtPopHelpLine();
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * pushHelpLine(PyObject * s, PyObject * args) {
+ char * text;
+
+ if (!PyArg_ParseTuple(args, "s", &text))
+ return NULL;
+
+ if (!strcmp(text, "*default*"))
+ newtPushHelpLine(NULL);
+ else
+ newtPushHelpLine(text);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * reflowText(PyObject * s, PyObject * args) {
+ char * text, * new;
+ int width, minus = 5, plus = 5;
+ int realWidth, realHeight;
+ PyObject * tuple;
+
+ if (!PyArg_ParseTuple(args, "si|ii", &text, &width, &minus, &plus))
+ return NULL;
+
+ new = newtReflowText(text, width, minus, plus, &realWidth, &realHeight);
+
+ tuple = Py_BuildValue("(sii)", new, realWidth, realHeight);
+ free(new);
+
+ return tuple;
+}
+
+static PyObject * centeredWindow(PyObject * s, PyObject * args) {
+ int width, height;
+ char * title;
+
+ if (!PyArg_ParseTuple(args, "iis", &width, &height, &title))
+ return NULL;
+
+ newtCenteredWindow(width, height, title);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * gridWrappedWindow(PyObject * s, PyObject * args) {
+ snackGrid * grid;
+ char * title;
+ int x = -1, y = -1;
+
+ if (!PyArg_ParseTuple(args, "O!s|ii", &snackGridType, &grid, &title,
+ &x, &y))
+ return NULL;
+
+ if (y == -1)
+ newtGridWrappedWindow(grid->grid, title);
+ else
+ newtGridWrappedWindowAt(grid->grid, title, x, y);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * openWindow(PyObject * s, PyObject * args) {
+ int left, top, width, height;
+ char * title;
+
+ if (!PyArg_ParseTuple(args, "iiiis", &left, &top, &width, &height, &title))
+ return NULL;
+
+ newtOpenWindow(left, top, width, height, title);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * popWindow(PyObject * s, PyObject * args) {
+ newtPopWindow();
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * messageWindow(PyObject * s, PyObject * args) {
+ char * title, * text;
+ char * okbutton = "Ok";
+
+ if (!PyArg_ParseTuple(args, "ss|s", &title, &text, &okbutton))
+ return NULL;
+
+ newtWinMessage(title, okbutton, text);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * choiceWindow(PyObject * s, PyObject * args) {
+ char * title, * text;
+ char * okbutton = "Ok";
+ char * cancelbutton = "Cancel";
+ int rc;
+
+ if (!PyArg_ParseTuple(args, "ss|ss", &title, &text, &okbutton,
+ &cancelbutton))
+ return NULL;
+
+ rc = newtWinChoice(title, okbutton, cancelbutton, text);
+
+ return Py_BuildValue("i", rc);
+}
+
+static PyObject * ternaryWindow(PyObject * s, PyObject * args) {
+ char * title, * text, * button1, * button2, * button3;
+ int rc;
+
+ if (!PyArg_ParseTuple(args, "sssss", &title, &text, &button1, &button2,
+ &button3))
+ return NULL;
+
+ rc = newtWinTernary(title, button1, button2, button3, text);
+
+ return Py_BuildValue("i", rc);
+}
+
+static snackWidget * buttonWidget(PyObject * s, PyObject * args) {
+ snackWidget * widget;
+ char * label;
+
+ if (!PyArg_ParseTuple(args, "s", &label)) return NULL;
+
+ widget = snackWidgetNew ();
+ widget->co = newtButton(-1, -1, label);
+
+ return widget;
+}
+
+static snackWidget * compactbuttonWidget(PyObject * s, PyObject * args) {
+ snackWidget * widget;
+ char * label;
+
+ if (!PyArg_ParseTuple(args, "s", &label)) return NULL;
+
+ widget = snackWidgetNew ();
+ widget->co = newtCompactButton(-1, -1, label);
+
+ return widget;
+}
+
+static snackWidget * labelWidget(PyObject * s, PyObject * args) {
+ char * label;
+ snackWidget * widget;
+
+ if (!PyArg_ParseTuple(args, "s", &label)) return NULL;
+
+ widget = snackWidgetNew ();
+ widget->co = newtLabel(-1, -1, label);
+
+ return widget;
+}
+
+static PyObject * widgetLabelText(snackWidget * s, PyObject * args) {
+ char * label;
+
+ if (!PyArg_ParseTuple(args, "s", &label)) return NULL;
+
+ newtLabelSetText(s->co, label);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * widgetTextboxText(snackWidget * s, PyObject * args) {
+ char * text;
+
+ if (!PyArg_ParseTuple(args, "s", &text)) return NULL;
+
+ newtTextboxSetText(s->co, text);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static snackWidget * listboxWidget(PyObject * s, PyObject * args) {
+ snackWidget * widget;
+ int height;
+ int doScroll = 0, returnExit = 0, showCursor = 0 ;
+
+ if (!PyArg_ParseTuple(args, "i|iii", &height, &doScroll, &returnExit, &showCursor))
+ return NULL;
+
+ widget = snackWidgetNew ();
+ widget->co = newtListbox(-1, -1, height,
+ (doScroll ? NEWT_FLAG_SCROLL : 0) |
+ (returnExit ? NEWT_FLAG_RETURNEXIT : 0) |
+ (showCursor ? NEWT_FLAG_SHOWCURSOR : 0)
+ );
+ widget->anint = 1;
+
+ return widget;
+}
+
+static snackWidget * textWidget(PyObject * s, PyObject * args) {
+ char * text;
+ int width, height;
+ int scrollBar = 0;
+ int wrap = 0;
+ snackWidget * widget;
+
+ if (!PyArg_ParseTuple(args, "iis|ii", &width, &height, &text, &scrollBar, &wrap))
+ return NULL;
+
+ widget = snackWidgetNew ();
+ widget->co = newtTextbox(-1, -1, width, height,
+ (scrollBar ? NEWT_FLAG_SCROLL : 0) |
+ (wrap ? NEWT_FLAG_WRAP : 0));
+ newtTextboxSetText(widget->co, text);
+
+ return widget;
+}
+
+static snackWidget * radioButtonWidget(PyObject * s, PyObject * args) {
+ snackWidget * widget, * group;
+ char * text;
+ int isOn;
+
+ if (!PyArg_ParseTuple(args, "sOi", &text, &group, &isOn))
+ return NULL;
+
+ widget = snackWidgetNew ();
+
+ if ((PyObject *) group == Py_None)
+ widget->co = newtRadiobutton(-1, -1, text, isOn, NULL);
+ else
+ widget->co = newtRadiobutton(-1, -1, text, isOn, group->co);
+
+ return widget;
+}
+
+static snackWidget * checkboxWidget(PyObject * s, PyObject * args) {
+ snackWidget * widget;
+ char * text;
+ int isOn;
+
+ if (!PyArg_ParseTuple(args, "si", &text, &isOn)) return NULL;
+
+ widget = snackWidgetNew ();
+ widget->co = newtCheckbox(-1, -1, text, isOn ? '*' : ' ', NULL,
+ &widget->achar);
+
+ return widget;
+}
+
+static PyObject * widgetCheckboxSetFlags(snackWidget * s, PyObject * args) {
+ int flag, sense;
+
+ if (!PyArg_ParseTuple(args, "ii", &flag, &sense)) return NULL;
+
+ newtCheckboxSetFlags(s->co, flag, sense);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * widgetCheckboxSetValue(snackWidget * s, PyObject * args) {
+ char *value;
+
+ if (!PyArg_ParseTuple(args, "s", &value)) return NULL;
+
+ newtCheckboxSetValue(s->co, *value);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static snackWidget * entryWidget(PyObject * s, PyObject * args) {
+ snackWidget * widget;
+ int width;
+ char * initial;
+ int isHidden, isScrolled, returnExit, isPassword;
+
+ if (!PyArg_ParseTuple(args, "isiiii", &width, &initial,
+ &isHidden, &isPassword, &isScrolled, &returnExit)) return NULL;
+
+ widget = snackWidgetNew ();
+ widget->co = newtEntry(-1, -1, initial, width, (char **) &widget->apointer,
+ (isHidden ? NEWT_FLAG_HIDDEN : 0) |
+ (isPassword ? NEWT_FLAG_PASSWORD : 0) |
+ (returnExit ? NEWT_FLAG_RETURNEXIT : 0) |
+ (isScrolled ? NEWT_FLAG_SCROLL : 0));
+
+ return widget;
+}
+
+static snackForm * formCreate(PyObject * s, PyObject * args) {
+ snackForm * form;
+ PyObject * help = Py_None;
+
+ if (!PyArg_ParseTuple(args, "|O", &help)) return NULL;
+
+ if (help == Py_None)
+ help = NULL;
+
+ form = PyObject_NEW(snackForm, &snackFormType);
+ form->fo = newtForm(NULL, help, 0);
+
+ return form;
+}
+
+static snackGrid * gridCreate(PyObject * s, PyObject * args) {
+ int rows, cols;
+ snackGrid * grid;
+
+ if (!PyArg_ParseTuple(args, "ii", &cols, &rows)) return NULL;
+
+ grid = PyObject_NEW(snackGrid, &snackGridType);
+ grid->grid = newtCreateGrid(cols, rows);
+
+ return grid;
+}
+
+static PyObject * gridGetAttr(PyObject * s, char * name) {
+ return Py_FindMethod(gridMethods, s, name);
+}
+
+static PyObject * gridPlace(snackGrid * grid, PyObject * args) {
+ int x, y;
+
+ if (!PyArg_ParseTuple(args, "ii", &x, &y)) return NULL;
+
+ newtGridPlace(grid->grid, x, y);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * gridSetField(snackGrid * grid, PyObject * args) {
+ snackWidget * w;
+ snackGrid * g;
+ int x, y;
+ int pLeft = 0, pTop = 0, pRight = 0, pBottom = 0;
+ int anchorFlags = 0, growFlags = 0;
+
+ if (!PyArg_ParseTuple(args, "iiO|(iiii)ii", &x, &y,
+ &w, &pLeft, &pTop, &pRight, &pBottom,
+ &anchorFlags, &growFlags))
+ return NULL;
+
+ if (w->ob_type == &snackWidgetType) {
+ newtGridSetField(grid->grid, x, y, NEWT_GRID_COMPONENT,
+ w->co, pLeft, pTop, pRight, pBottom, anchorFlags,
+ growFlags);
+ } else {
+ g = (snackGrid *) w;
+ newtGridSetField(grid->grid, x, y, NEWT_GRID_SUBGRID,
+ g->grid, pLeft, pTop, pRight, pBottom, anchorFlags,
+ growFlags);
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * formGetAttr(PyObject * s, char * name) {
+ return Py_FindMethod(formMethods, s, name);
+}
+
+static PyObject * formDraw(snackForm * s, PyObject * args) {
+ newtDrawForm(s->fo);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * formAdd(snackForm * s, PyObject * args) {
+ snackWidget * w;
+ int size = PyTuple_Size(args), i;
+
+ if (!size) {
+ /* this is a hack, I should give an error directly */
+ if (!PyArg_ParseTuple(args, "O!", &snackWidgetType, &w))
+ return NULL;
+ }
+
+ for (i = 0; i < size; i++) {
+ w = (snackWidget *) PyTuple_GET_ITEM(args, i);
+ newtFormAddComponent(s->fo, w->co);
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * formRun(snackForm * s, PyObject * args) {
+ struct newtExitStruct result;
+
+ newtFormRun(s->fo, &result);
+
+ if (result.reason == NEWT_EXIT_HOTKEY)
+ return Py_BuildValue("(si)", "hotkey", result.u.key);
+ else if (result.reason == NEWT_EXIT_TIMER)
+ return Py_BuildValue("(si)", "timer", 0);
+ else if (result.reason == NEWT_EXIT_FDREADY)
+ return Py_BuildValue("(si)", "fdready", result.u.watch);
+ else
+ return Py_BuildValue("(si)", "widget", result.u.co);
+}
+
+static PyObject * formHotKey(snackForm * s, PyObject * args) {
+ int key;
+
+ if (!PyArg_ParseTuple(args, "i", &key))
+ return NULL;
+
+ newtFormAddHotKey(s->fo, key);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * formSetTimer(snackForm * form, PyObject * args) {
+ int millisecs;
+
+ if (!PyArg_ParseTuple(args, "i", &millisecs))
+ return NULL;
+
+ newtFormSetTimer(form->fo, millisecs);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * formWatchFD(snackForm * form, PyObject * args) {
+ int fd, fdflags;
+
+ if (!PyArg_ParseTuple(args, "ii", &fd, &fdflags))
+ return NULL;
+
+ newtFormWatchFd(form->fo, fd, fdflags);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * formSetCurrent(snackForm * form, PyObject * args) {
+ snackWidget * w;
+
+ if (!PyArg_ParseTuple(args, "O", &w))
+ return NULL;
+
+ newtFormSetCurrent(form->fo, w->co);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * widgetGetAttr(PyObject * s, char * name) {
+ snackWidget * w = (snackWidget *) s;
+
+ if (!strcmp(name, "key")) {
+ return Py_BuildValue("i", w->co);
+ } else if (!strcmp(name, "entryValue")) {
+ return Py_BuildValue("s", w->apointer);
+ } else if (!strcmp(name, "checkboxValue")) {
+ return Py_BuildValue("i", w->achar == ' ' ? 0 : 1);
+ } else if (!strcmp(name, "radioValue")) {
+ return Py_BuildValue("i", newtRadioGetCurrent(w->co));
+ }
+
+ return Py_FindMethod(widgetMethods, s, name);
+}
+
+static void widgetDestructor(PyObject * o) {
+ snackWidget * s = (snackWidget *) o;
+
+ Py_XDECREF (s->scs.cb);
+ Py_XDECREF (s->scs.data);
+
+ PyMem_DEL(o);
+}
+
+static PyObject * widgetAddCallback(snackWidget * s, PyObject * args) {
+ s->scs.cb = NULL;
+ s->scs.data = NULL;
+
+ if (!PyArg_ParseTuple(args, "O|O", &s->scs.cb, &s->scs.data))
+ return NULL;
+
+ Py_INCREF (s->scs.cb);
+ Py_XINCREF (s->scs.data);
+
+ newtComponentAddCallback(s->co, callbackMarshall, &s->scs);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * widgetEntrySetValue(snackWidget * s, PyObject * args) {
+ char * val;
+
+ if (!PyArg_ParseTuple(args, "s", &val))
+ return NULL;
+
+ newtEntrySet(s->co, val, 1);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * widgetEntrySetFlags(snackWidget * s, PyObject * args) {
+ int flag, sense;
+
+ if (!PyArg_ParseTuple(args, "ii", &flag, &sense)) return NULL;
+
+ newtEntrySetFlags(s->co, flag, sense);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+static PyObject * widgetListboxAdd(snackWidget * s, PyObject * args) {
+ char * text;
+
+ if (!PyArg_ParseTuple(args, "s", &text))
+ return NULL;
+
+ newtListboxAddEntry(s->co, text, I2P(s->anint));
+
+ return PyInt_FromLong(s->anint++);
+}
+
+static PyObject * widgetListboxIns(snackWidget * s, PyObject * args) {
+ char * text;
+ int key;
+
+ if (!PyArg_ParseTuple(args, "si", &text, &key))
+ return NULL;
+
+ newtListboxInsertEntry(s->co, text, I2P(s->anint), I2P(key));
+
+ return PyInt_FromLong(s->anint++);
+}
+
+static PyObject * widgetListboxDel(snackWidget * s, PyObject * args) {
+ int key;
+
+ if (!PyArg_ParseTuple(args, "i", &key))
+ return NULL;
+
+ newtListboxDeleteEntry(s->co, I2P(key));
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * widgetListboxGet(snackWidget * s, PyObject * args) {
+ if (!PyArg_ParseTuple(args, ""))
+ return NULL;
+
+ return PyInt_FromLong((long) newtListboxGetCurrent(s->co));
+}
+
+static PyObject * widgetListboxSet(snackWidget * s, PyObject * args) {
+ int index;
+
+ if (!PyArg_ParseTuple(args, "i", &index))
+ return NULL;
+
+ newtListboxSetCurrentByKey(s->co, I2P(index));
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * widgetListboxSetW(snackWidget * s, PyObject * args) {
+ int width;
+
+ if (!PyArg_ParseTuple(args, "i", &width))
+ return NULL;
+
+ newtListboxSetWidth(s->co, width);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * widgetListboxClear(snackWidget * s, PyObject * args) {
+ if (!PyArg_ParseTuple(args, ""))
+ return NULL;
+
+ newtListboxClear(s->co);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static void emptyDestructor(PyObject * s) {
+}
+
+static snackWidget * checkboxTreeWidget(PyObject * s, PyObject * args, PyObject * kwargs) {
+ int height;
+ int scrollBar = 0;
+ int hide_checkbox = 0;
+ int unselectable = 0;
+ int flags;
+ snackWidget * widget;
+ const char *kw[] = {"height", "scrollbar", "hide_checkbox", "unselectable", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|iii", (char **) kw,
+ &height, &scrollBar, &hide_checkbox, &unselectable))
+ return NULL;
+
+ flags = (scrollBar ? NEWT_FLAG_SCROLL : 0) |
+ (hide_checkbox ? NEWT_CHECKBOXTREE_HIDE_BOX : 0) |
+ (unselectable ? NEWT_CHECKBOXTREE_UNSELECTABLE : 0);
+
+ widget = snackWidgetNew ();
+ widget->co = newtCheckboxTree(-1, -1, height, flags);
+
+ widget->anint = 1;
+
+ return widget;
+}
+
+static PyObject * widgetCheckboxTreeAddItem(snackWidget * s, PyObject * args) {
+ char * text;
+ int selected = 0;
+ PyObject * pathList, * o;
+ int len;
+ int * path;
+ int i;
+
+ if (!PyArg_ParseTuple(args, "sOi", &text, &pathList, &selected))
+ return NULL;
+
+ len = PyTuple_Size(pathList);
+ path = alloca(sizeof(*path) * (len + 1));
+ for (i = 0; i < len; i++) {
+ o = PyTuple_GetItem(pathList, i);
+ path[i] = PyInt_AsLong(o);
+ }
+ path[len] = NEWT_ARG_LAST;
+
+ newtCheckboxTreeAddArray(s->co, text, I2P(s->anint),
+ selected ? NEWT_FLAG_SELECTED : 0, path);
+
+ return PyInt_FromLong(s->anint++);
+}
+
+static PyObject * widgetCheckboxTreeGetCur(snackWidget * s, PyObject * args) {
+ if (!PyArg_ParseTuple(args, ""))
+ return NULL;
+
+ return PyInt_FromLong((long)newtCheckboxTreeGetCurrent(s->co));
+}
+
+static PyObject * widgetCheckboxTreeSetEntry(snackWidget * s, PyObject * args) {
+ int data;
+ char *text;
+
+ if (!PyArg_ParseTuple(args, "is", &data, &text)) return NULL;
+
+ newtCheckboxTreeSetEntry(s->co, I2P(data), text);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * widgetCheckboxTreeSetWidth(snackWidget * s, PyObject * args) {
+ int width;
+
+ if (!PyArg_ParseTuple(args, "i", &width))
+ return NULL;
+
+ newtCheckboxTreeSetWidth(s->co, width);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * widgetCheckboxTreeSetCurrent(snackWidget * s, PyObject * args) {
+ int data;
+
+ if (!PyArg_ParseTuple(args, "i", &data)) return NULL;
+
+ newtCheckboxTreeSetCurrent(s->co, I2P(data));
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * widgetCheckboxTreeSetEntryValue(snackWidget * s, PyObject * args) {
+ int data;
+ int isOn = 1;
+
+ if (!PyArg_ParseTuple(args, "i|i", &data, &isOn)) return NULL;
+
+ newtCheckboxTreeSetEntryValue(s->co, I2P(data),
+ isOn ? NEWT_CHECKBOXTREE_SELECTED :
+ NEWT_CHECKBOXTREE_UNSELECTED);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * widgetCheckboxTreeGetEntryValue(snackWidget * s, PyObject * args) {
+ int data;
+ int isOn = 0;
+ int isBranch = 0;
+ char selection;
+
+ if (!PyArg_ParseTuple(args, "i", &data)) return NULL;
+
+ selection = newtCheckboxTreeGetEntryValue(s->co, I2P(data));
+
+ if (selection == -1) return NULL;
+
+ switch (selection) {
+ case NEWT_CHECKBOXTREE_EXPANDED:
+ isOn = 1;
+ case NEWT_CHECKBOXTREE_COLLAPSED:
+ isBranch = 1;
+ break;
+ case NEWT_CHECKBOXTREE_UNSELECTED:
+ break;
+ default:
+ isOn = 1;
+ break;
+ }
+ return Py_BuildValue("(ii)", isBranch, isOn);
+}
+
+static PyObject * widgetCheckboxTreeGetSel(snackWidget * s,
+ PyObject * args) {
+ void ** selection;
+ int numselected;
+ int i;
+ PyObject * sel;
+
+ if (!PyArg_ParseTuple(args, ""))
+ return NULL;
+
+ selection = (void **) newtCheckboxTreeGetSelection(s->co, &numselected);
+
+ sel = PyList_New(0);
+
+ if (!selection) {
+ return sel;
+ }
+
+ sel = PyList_New(0);
+ for (i = 0; i < numselected; i++) {
+ PyList_Append(sel, PyInt_FromLong((long) selection[i]));
+ }
+ free(selection);
+
+ return sel;
+}
+
+void init_snack(void) {
+ PyObject * d, * m;
+
+ m = Py_InitModule("_snack", snackModuleMethods);
+ d = PyModule_GetDict(m);
+
+ PyDict_SetItemString(d, "ANCHOR_LEFT", PyInt_FromLong(NEWT_ANCHOR_LEFT));
+ PyDict_SetItemString(d, "ANCHOR_TOP", PyInt_FromLong(NEWT_ANCHOR_TOP));
+ PyDict_SetItemString(d, "ANCHOR_RIGHT", PyInt_FromLong(NEWT_ANCHOR_RIGHT));
+ PyDict_SetItemString(d, "ANCHOR_BOTTOM",
+ PyInt_FromLong(NEWT_ANCHOR_BOTTOM));
+ PyDict_SetItemString(d, "GRID_GROWX", PyInt_FromLong(NEWT_GRID_FLAG_GROWX));
+ PyDict_SetItemString(d, "GRID_GROWY", PyInt_FromLong(NEWT_GRID_FLAG_GROWY));
+
+ PyDict_SetItemString(d, "FD_READ", PyInt_FromLong(NEWT_FD_READ));
+ PyDict_SetItemString(d, "FD_WRITE", PyInt_FromLong(NEWT_FD_WRITE));
+ PyDict_SetItemString(d, "FD_EXCEPT", PyInt_FromLong(NEWT_FD_EXCEPT));
+
+ PyDict_SetItemString(d, "FORM_EXIT_HOTKEY", PyString_FromString("hotkey"));
+ PyDict_SetItemString(d, "FORM_EXIT_WIDGET", PyString_FromString("widget"));
+ PyDict_SetItemString(d, "FORM_EXIT_TIMER", PyString_FromString("timer"));
+ PyDict_SetItemString(d, "FORM_EXIT_FDREADY", PyString_FromString("fdready"));
+
+ PyDict_SetItemString(d, "KEY_F1", PyInt_FromLong(NEWT_KEY_F1));
+ PyDict_SetItemString(d, "KEY_F2", PyInt_FromLong(NEWT_KEY_F2));
+ PyDict_SetItemString(d, "KEY_F3", PyInt_FromLong(NEWT_KEY_F3));
+ PyDict_SetItemString(d, "KEY_F4", PyInt_FromLong(NEWT_KEY_F4));
+ PyDict_SetItemString(d, "KEY_F5", PyInt_FromLong(NEWT_KEY_F5));
+ PyDict_SetItemString(d, "KEY_F6", PyInt_FromLong(NEWT_KEY_F6));
+ PyDict_SetItemString(d, "KEY_F7", PyInt_FromLong(NEWT_KEY_F7));
+ PyDict_SetItemString(d, "KEY_F8", PyInt_FromLong(NEWT_KEY_F8));
+ PyDict_SetItemString(d, "KEY_F9", PyInt_FromLong(NEWT_KEY_F9));
+ PyDict_SetItemString(d, "KEY_F10", PyInt_FromLong(NEWT_KEY_F10));
+ PyDict_SetItemString(d, "KEY_F11", PyInt_FromLong(NEWT_KEY_F11));
+ PyDict_SetItemString(d, "KEY_F12", PyInt_FromLong(NEWT_KEY_F12));
+
+ PyDict_SetItemString(d, "FLAG_DISABLED", PyInt_FromLong(NEWT_FLAG_DISABLED));
+ PyDict_SetItemString(d, "FLAGS_SET", PyInt_FromLong(NEWT_FLAGS_SET));
+ PyDict_SetItemString(d, "FLAGS_RESET", PyInt_FromLong(NEWT_FLAGS_RESET));
+ PyDict_SetItemString(d, "FLAGS_TOGGLE", PyInt_FromLong(NEWT_FLAGS_TOGGLE));
+}
diff --git a/mininewt/textbox.c b/mininewt/textbox.c
new file mode 100644
index 000000000..dc42dc558
--- /dev/null
+++ b/mininewt/textbox.c
@@ -0,0 +1,410 @@
+#include <ctype.h>
+#include <slang.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "newt.h"
+#include "newt_pr.h"
+
+struct textbox {
+ char ** lines;
+ int numLines;
+ int linesAlloced;
+ int doWrap;
+ newtComponent sb;
+ int topLine;
+ int textWidth;
+};
+
+static char * expandTabs(const char * text);
+static void textboxDraw(newtComponent co);
+static void addLine(newtComponent co, const char * s, int len);
+static void doReflow(const char * text, char ** resultPtr, int width,
+ int * badness, int * heightPtr);
+static struct eventResult textboxEvent(newtComponent c,
+ struct event ev);
+static void textboxDestroy(newtComponent co);
+static void textboxPlace(newtComponent co, int newLeft, int newTop);
+static void textboxMapped(newtComponent co, int isMapped);
+
+static struct componentOps textboxOps = {
+ textboxDraw,
+ textboxEvent,
+ textboxDestroy,
+ textboxPlace,
+ textboxMapped,
+} ;
+
+static void textboxMapped(newtComponent co, int isMapped) {
+ struct textbox * tb = co->data;
+
+ co->isMapped = isMapped;
+ if (tb->sb)
+ tb->sb->ops->mapped(tb->sb, isMapped);
+}
+
+static void textboxPlace(newtComponent co, int newLeft, int newTop) {
+ struct textbox * tb = co->data;
+
+ co->top = newTop;
+ co->left = newLeft;
+
+ if (tb->sb)
+ tb->sb->ops->place(tb->sb, co->left + co->width - 1, co->top);
+}
+
+void newtTextboxSetHeight(newtComponent co, int height) {
+ co->height = height;
+}
+
+int newtTextboxGetNumLines(newtComponent co) {
+ struct textbox * tb = co->data;
+
+ return (tb->numLines);
+}
+
+newtComponent newtTextboxReflowed(int left, int top, char * text, int width,
+ int flexDown, int flexUp, int flags) {
+ newtComponent co;
+ char * reflowedText;
+ int actWidth, actHeight;
+
+ reflowedText = newtReflowText(text, width, flexDown, flexUp,
+ &actWidth, &actHeight);
+
+ co = newtTextbox(left, top, actWidth, actHeight, NEWT_FLAG_WRAP);
+ newtTextboxSetText(co, reflowedText);
+ free(reflowedText);
+
+ return co;
+}
+
+newtComponent newtTextbox(int left, int top, int width, int height, int flags) {
+ newtComponent co;
+ struct textbox * tb;
+
+ co = malloc(sizeof(*co));
+ tb = malloc(sizeof(*tb));
+ co->data = tb;
+
+ co->ops = &textboxOps;
+
+ co->height = height;
+ co->top = top;
+ co->left = left;
+ co->takesFocus = 0;
+ co->width = width;
+
+ tb->doWrap = flags & NEWT_FLAG_WRAP;
+ tb->numLines = 0;
+ tb->linesAlloced = 0;
+ tb->lines = NULL;
+ tb->topLine = 0;
+ tb->textWidth = width;
+
+ if (flags & NEWT_FLAG_SCROLL) {
+ co->width += 2;
+ tb->sb = newtVerticalScrollbar(co->left + co->width - 1, co->top,
+ co->height, COLORSET_TEXTBOX, COLORSET_TEXTBOX);
+ } else {
+ tb->sb = NULL;
+ }
+
+ return co;
+}
+
+static char * expandTabs(const char * text) {
+ int bufAlloced = strlen(text) + 40;
+ char * buf, * dest;
+ const char * src;
+ int bufUsed = 0;
+ int linePos = 0;
+ int i;
+
+ buf = malloc(bufAlloced + 1);
+ for (src = text, dest = buf; *src; src++) {
+ if ((bufUsed + 10) > bufAlloced) {
+ bufAlloced += strlen(text) / 2;
+ buf = realloc(buf, bufAlloced + 1);
+ dest = buf + bufUsed;
+ }
+ if (*src == '\t') {
+ i = 8 - (linePos & 8);
+ memset(dest, ' ', i);
+ dest += i, bufUsed += i, linePos += i;
+ } else {
+ if (*src == '\n')
+ linePos = 0;
+ else
+ linePos++;
+
+ *dest++ = *src;
+ bufUsed++;
+ }
+ }
+
+ *dest = '\0';
+ return buf;
+}
+
+#define iseuckanji(c) (0xa1 <= (unsigned char)(c&0xff) && (unsigned char)(c&0xff) <= 0xfe)
+
+static void doReflow(const char * text, char ** resultPtr, int width,
+ int * badness, int * heightPtr) {
+ char * result = NULL;
+ const char * chptr, * end;
+ int i;
+ int howbad = 0;
+ int height = 0;
+ int kanji = 0;
+
+ if (resultPtr) {
+ /* XXX I think this will work */
+ result = malloc(strlen(text) + (strlen(text) / width) + 2);
+ *result = '\0';
+ }
+
+ while (*text) {
+ kanji = 0;
+ end = strchr(text, '\n');
+ if (!end)
+ end = text + strlen(text);
+
+ while (*text && text <= end) {
+ if (end - text < width) {
+ if (result) {
+ strncat(result, text, end - text);
+ strcat(result, "\n");
+ height++;
+ }
+
+ if (end - text < (width / 2))
+ howbad += ((width / 2) - (end - text)) / 2;
+ text = end;
+ if (*text) text++;
+ } else {
+ chptr = text;
+ kanji = 0;
+ for ( i = 0; i < width - 1; i++ ) {
+ if ( !iseuckanji(*chptr)) {
+ kanji = 0;
+ } else if ( kanji == 1 ) {
+ kanji = 2;
+ } else {
+ kanji = 1;
+ }
+ chptr++;
+ }
+ if (kanji == 0) {
+ while (chptr > text && !isspace(*chptr)) chptr--;
+ while (chptr > text && isspace(*chptr)) chptr--;
+ chptr++;
+ }
+
+ if (chptr-text == 1 && !isspace(*chptr))
+ chptr = text + width - 1;
+
+ if (chptr > text)
+ howbad += width - (chptr - text) + 1;
+ if (result) {
+ if (kanji == 1) {
+ strncat(result, text, chptr - text + 1 );
+ chptr++;
+ kanji = 0;
+ } else {
+ strncat(result, text, chptr - text );
+ }
+ strcat(result, "\n");
+ height++;
+ }
+
+ if (isspace(*chptr))
+ text = chptr + 1;
+ else
+ text = chptr;
+ while (isspace(*text)) text++;
+ }
+ }
+ }
+
+ if (badness) *badness = howbad;
+ if (resultPtr) *resultPtr = result;
+ if (heightPtr) *heightPtr = height;
+}
+
+char * newtReflowText(char * text, int width, int flexDown, int flexUp,
+ int * actualWidth, int * actualHeight) {
+ int min, max;
+ int i;
+ char * result;
+ int minbad, minbadwidth, howbad;
+ char * expandedText;
+
+ expandedText = expandTabs(text);
+
+ if (flexDown || flexUp) {
+ min = width - flexDown;
+ max = width + flexUp;
+
+ minbad = -1;
+ minbadwidth = width;
+
+ for (i = min; i <= max; i++) {
+ doReflow(expandedText, NULL, i, &howbad, NULL);
+
+ if (minbad == -1 || howbad < minbad) {
+ minbad = howbad;
+ minbadwidth = i;
+ }
+ }
+
+ width = minbadwidth;
+ }
+
+ doReflow(expandedText, &result, width, NULL, actualHeight);
+ free(expandedText);
+ if (actualWidth) *actualWidth = width;
+ return result;
+}
+
+void newtTextboxSetText(newtComponent co, const char * text) {
+ const char * start, * end;
+ struct textbox * tb = co->data;
+ char * reflowed, * expanded;
+ int badness, height;
+
+ if (tb->lines) {
+ free(tb->lines);
+ tb->linesAlloced = tb->numLines = 0;
+ }
+
+ expanded = expandTabs(text);
+
+ if (tb->doWrap) {
+ doReflow(expanded, &reflowed, tb->textWidth, &badness, &height);
+ free(expanded);
+ expanded = reflowed;
+ }
+
+ for (start = expanded; *start; start++)
+ if (*start == '\n') tb->linesAlloced++;
+
+ /* This ++ leaves room for an ending line w/o a \n */
+ tb->linesAlloced++;
+ tb->lines = malloc(sizeof(char *) * tb->linesAlloced);
+
+ start = expanded;
+ while ((end = strchr(start, '\n'))) {
+ addLine(co, start, end - start);
+ start = end + 1;
+ }
+
+ if (*start)
+ addLine(co, start, strlen(start));
+
+ free(expanded);
+
+ newtTrashScreen();
+}
+
+/* This assumes the buffer is allocated properly! */
+static void addLine(newtComponent co, const char * s, int len) {
+ struct textbox * tb = co->data;
+
+ if (len > tb->textWidth) len = tb->textWidth;
+
+ tb->lines[tb->numLines] = malloc(tb->textWidth + 1);
+ memset(tb->lines[tb->numLines], ' ', tb->textWidth);
+ memcpy(tb->lines[tb->numLines], s, len);
+ tb->lines[tb->numLines++][tb->textWidth] = '\0';
+}
+
+static void textboxDraw(newtComponent c) {
+ int i;
+ struct textbox * tb = c->data;
+ int size;
+
+ if (tb->sb) {
+ size = tb->numLines - c->height;
+ newtScrollbarSet(tb->sb, tb->topLine, size ? size : 0);
+ tb->sb->ops->draw(tb->sb);
+ }
+
+ SLsmg_set_color(NEWT_COLORSET_TEXTBOX);
+
+ for (i = 0; (i + tb->topLine) < tb->numLines && i < c->height; i++) {
+ newtGotorc(c->top + i, c->left);
+ SLsmg_write_string(tb->lines[i + tb->topLine]);
+ }
+}
+
+static struct eventResult textboxEvent(newtComponent co,
+ struct event ev) {
+ struct textbox * tb = co->data;
+ struct eventResult er;
+
+ er.result = ER_IGNORED;
+
+ if (ev.when == EV_EARLY && ev.event == EV_KEYPRESS && tb->sb) {
+ newtTrashScreen();
+ switch (ev.u.key) {
+ case NEWT_KEY_UP:
+ if (tb->topLine) tb->topLine--;
+ textboxDraw(co);
+ er.result = ER_SWALLOWED;
+ break;
+
+ case NEWT_KEY_DOWN:
+ if (tb->topLine < (tb->numLines - co->height)) tb->topLine++;
+ textboxDraw(co);
+ er.result = ER_SWALLOWED;
+ break;
+
+ case NEWT_KEY_PGDN:
+ tb->topLine += co->height;
+ if (tb->topLine > (tb->numLines - co->height)) {
+ tb->topLine = tb->numLines - co->height;
+ if (tb->topLine < 0) tb->topLine = 0;
+ }
+ textboxDraw(co);
+ er.result = ER_SWALLOWED;
+ break;
+
+ case NEWT_KEY_PGUP:
+ tb->topLine -= co->height;
+ if (tb->topLine < 0) tb->topLine = 0;
+ textboxDraw(co);
+ er.result = ER_SWALLOWED;
+ break;
+ }
+ }
+ if (ev.when == EV_EARLY && ev.event == EV_MOUSE && tb->sb) {
+ /* Top scroll arrow */
+ if (ev.u.mouse.x == co->width && ev.u.mouse.y == co->top) {
+ if (tb->topLine) tb->topLine--;
+ textboxDraw(co);
+
+ er.result = ER_SWALLOWED;
+ }
+ /* Bottom scroll arrow */
+ if (ev.u.mouse.x == co->width &&
+ ev.u.mouse.y == co->top + co->height - 1) {
+ if (tb->topLine < (tb->numLines - co->height)) tb->topLine++;
+ textboxDraw(co);
+
+ er.result = ER_SWALLOWED;
+ }
+ }
+ return er;
+}
+
+static void textboxDestroy(newtComponent co) {
+ int i;
+ struct textbox * tb = co->data;
+
+ for (i = 0; i < tb->numLines; i++)
+ free(tb->lines[i]);
+ free(tb->lines);
+ free(tb);
+ free(co);
+}
diff --git a/mininewt/whiptail.c b/mininewt/whiptail.c
new file mode 100644
index 000000000..7a7bda280
--- /dev/null
+++ b/mininewt/whiptail.c
@@ -0,0 +1,232 @@
+/* a reasonable dialog */
+
+#include <fcntl.h>
+#include <popt.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "dialogboxes.h"
+#include "newt.h"
+
+enum mode { MODE_NONE, MODE_INFOBOX, MODE_MSGBOX, MODE_YESNO, MODE_CHECKLIST,
+ MODE_INPUTBOX, MODE_RADIOLIST, MODE_MENU, MODE_GAUGE };
+
+#define OPT_MSGBOX 1000
+#define OPT_CHECKLIST 1001
+#define OPT_YESNO 1002
+#define OPT_INPUTBOX 1003
+#define OPT_FULLBUTTONS 1004
+#define OPT_MENU 1005
+#define OPT_RADIOLIST 1006
+#define OPT_GAUGE 1007
+#define OPT_INFOBOX 1008
+
+static void usage(void) {
+ fprintf(stderr, "whiptail: bad parameters (see man dialog(1) for details)\n");
+ exit(1);
+}
+
+int main(int argc, const char ** argv) {
+ enum mode mode = MODE_NONE;
+ poptContext optCon;
+ int arg;
+ const char * optArg;
+ const char * text;
+ const char * nextArg;
+ char * end;
+ int height;
+ int width;
+ int fd = -1;
+ int needSpace = 0;
+ int noCancel = 0;
+ int noItem = 0;
+ int clear = 0;
+ int scrollText = 0;
+ int rc = 1;
+ int flags = 0;
+ int defaultNo = 0;
+ int separateOutput = 0;
+ char * result;
+ char ** selections, ** next;
+ char * title = NULL;
+ char * backtitle = NULL;
+ struct poptOption optionsTable[] = {
+ { "backtitle", '\0', POPT_ARG_STRING, &backtitle, 0 },
+ { "checklist", '\0', 0, 0, OPT_CHECKLIST },
+ { "clear", '\0', 0, &clear, 0 },
+ { "defaultno", '\0', 0, &defaultNo, 0 },
+ { "inputbox", '\0', 0, 0, OPT_INPUTBOX },
+ { "fb", '\0', 0, 0, OPT_FULLBUTTONS },
+ { "fullbuttons", '\0', 0, 0, OPT_FULLBUTTONS },
+ { "gauge", '\0', 0, 0, OPT_GAUGE },
+ { "infobox", '\0', 0, 0, OPT_INFOBOX },
+ { "menu", '\0', 0, 0, OPT_MENU },
+ { "msgbox", '\0', 0, 0, OPT_MSGBOX },
+ { "nocancel", '\0', 0, &noCancel, 0 },
+ { "noitem", '\0', 0, &noItem, 0 },
+ { "radiolist", '\0', 0, 0, OPT_RADIOLIST },
+ { "scrolltext", '\0', 0, &scrollText, 0 },
+ { "separate-output", '\0', 0, &separateOutput, 0 },
+ { "title", '\0', POPT_ARG_STRING, &title, 0 },
+ { "yesno", '\0', 0, 0, OPT_YESNO },
+ { 0, 0, 0, 0, 0 }
+ };
+
+ optCon = poptGetContext("whiptail", argc, argv, optionsTable, 0);
+
+ while ((arg = poptGetNextOpt(optCon)) > 0) {
+ optArg = poptGetOptArg(optCon);
+
+ switch (arg) {
+ case OPT_INFOBOX:
+ if (mode != MODE_NONE) usage();
+ mode = MODE_INFOBOX;
+ break;
+
+ case OPT_MENU:
+ if (mode != MODE_NONE) usage();
+ mode = MODE_MENU;
+ break;
+
+ case OPT_MSGBOX:
+ if (mode != MODE_NONE) usage();
+ mode = MODE_MSGBOX;
+ break;
+
+ case OPT_RADIOLIST:
+ if (mode != MODE_NONE) usage();
+ mode = MODE_RADIOLIST;
+ break;
+
+ case OPT_CHECKLIST:
+ if (mode != MODE_NONE) usage();
+ mode = MODE_CHECKLIST;
+ break;
+
+ case OPT_FULLBUTTONS:
+ useFullButtons(1);
+ break;
+
+ case OPT_YESNO:
+ if (mode != MODE_NONE) usage();
+ mode = MODE_YESNO;
+ break;
+
+ case OPT_GAUGE:
+ if (mode != MODE_NONE) usage();
+ mode = MODE_GAUGE;
+ break;
+
+ case OPT_INPUTBOX:
+ if (mode != MODE_NONE) usage();
+ mode = MODE_INPUTBOX;
+ break;
+ }
+ }
+
+ if (arg < -1) {
+ fprintf(stderr, "%s: %s\n",
+ poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
+ poptStrerror(arg));
+ exit(1);
+ }
+
+ if (mode == MODE_NONE) usage();
+
+ if (!(text = poptGetArg(optCon))) usage();
+
+ if (!(nextArg = poptGetArg(optCon))) usage();
+ height = strtoul(nextArg, &end, 10);
+ if (*end) usage();
+
+ if (!(nextArg = poptGetArg(optCon))) usage();
+ width = strtoul(nextArg, &end, 10);
+ if (*end) usage();
+
+ if (mode == MODE_GAUGE) {
+ fd = dup(0);
+ close(0);
+ if (open("/dev/tty", O_RDWR) != 0) perror("open /dev/tty");
+ }
+
+ newtInit();
+ newtCls();
+ width -= 2;
+ height -= 2;
+ newtOpenWindow((80 - width) / 2, (24 - height) / 2, width, height, title);
+
+ if (backtitle)
+ newtDrawRootText(0, 0, backtitle);
+
+ if (noCancel) flags |= FLAG_NOCANCEL;
+ if (noItem) flags |= FLAG_NOITEM;
+ if (scrollText) flags |= FLAG_SCROLL_TEXT;
+ if (defaultNo) flags |= FLAG_DEFAULT_NO;
+
+ switch (mode) {
+ case MODE_MSGBOX:
+ rc = messageBox(text, height, width, MSGBOX_MSG, flags);
+ break;
+
+ case MODE_INFOBOX:
+ rc = messageBox(text, height, width, MSGBOX_INFO, flags);
+ break;
+
+ case MODE_YESNO:
+ rc = messageBox(text, height, width, MSGBOX_YESNO, flags);
+ break;
+
+ case MODE_INPUTBOX:
+ rc = inputBox(text, height, width, optCon, flags, &result);
+ if (!rc) fprintf(stderr, "%s", result);
+ break;
+
+ case MODE_MENU:
+ rc = listBox(text, height, width, optCon, flags, &result);
+ if (!rc) fprintf(stderr, "%s", result);
+ break;
+
+ case MODE_RADIOLIST:
+ rc = checkList(text, height, width, optCon, 1, flags, &selections);
+ if (!rc) {
+ fprintf(stderr, "%s", selections[0]);
+ free(selections);
+ }
+ break;
+
+ case MODE_CHECKLIST:
+ rc = checkList(text, height, width, optCon, 0, flags, &selections);
+
+ if (!rc) {
+ for (next = selections; *next; next++) {
+ if (!separateOutput) {
+ if (needSpace) putc(' ', stderr);
+ fprintf(stderr, "\"%s\"", *next);
+ needSpace = 1;
+ } else {
+ fprintf(stderr, "%s\n", *next);
+ }
+ }
+
+ free(selections);
+ }
+ break;
+
+ case MODE_GAUGE:
+ rc = gauge(text, height, width, optCon, fd, flags);
+ break;
+
+ default:
+ usage();
+ }
+
+ if (rc == -1) usage();
+
+ if (clear)
+ newtPopWindow();
+ newtFinished();
+
+ return rc;
+}
diff --git a/mininewt/whiptcl.c b/mininewt/whiptcl.c
new file mode 100644
index 000000000..f137d791c
--- /dev/null
+++ b/mininewt/whiptcl.c
@@ -0,0 +1,296 @@
+#include <string.h>
+#include <stdlib.h>
+
+#include "dialogboxes.h"
+#include "newt.h"
+#include "popt.h"
+#include "tcl.h"
+
+enum mode { MODE_NONE, MODE_MSGBOX, MODE_YESNO, MODE_CHECKLIST, MODE_INPUTBOX,
+ MODE_RADIOLIST, MODE_MENU };
+
+#define OPT_MSGBOX 1000
+#define OPT_CHECKLIST 1001
+#define OPT_YESNO 1002
+#define OPT_INPUTBOX 1003
+#define OPT_MENU 1005
+#define OPT_RADIOLIST 1006
+
+static char * setBacktext(ClientData data, Tcl_Interp * interp,
+ char * name1, char * name2, int flags);
+static char * setHelptext(ClientData data, Tcl_Interp * interp,
+ char * name1, char * name2, int flags);
+static char * setFullButtons(ClientData data, Tcl_Interp * interp,
+ char * name1, char * name2, int flags);
+
+static int wtFinish(ClientData clientData, Tcl_Interp * interp, int argc,
+ char ** argv) {
+ newtFinished();
+
+ return TCL_OK;
+}
+
+static int wtInit(ClientData clientData, Tcl_Interp * interp, int argc,
+ char ** argv) {
+ newtInit();
+ newtCls();
+
+ newtPushHelpLine("");
+
+ Tcl_TraceVar(interp, "whiptcl_backtext",
+ TCL_TRACE_WRITES | TCL_GLOBAL_ONLY, setBacktext, NULL);
+ Tcl_TraceVar(interp, "whiptcl_helpline",
+ TCL_TRACE_WRITES | TCL_TRACE_UNSETS | TCL_GLOBAL_ONLY,
+ setHelptext, NULL);
+ Tcl_TraceVar(interp, "whiptcl_fullbuttons",
+ TCL_TRACE_WRITES | TCL_TRACE_UNSETS | TCL_GLOBAL_ONLY,
+ setFullButtons, NULL);
+
+ Tcl_SetVar(interp, "whiptcl_helpline", "", TCL_GLOBAL_ONLY);
+ Tcl_SetVar(interp, "whiptcl_fullbuttons", "1", TCL_GLOBAL_ONLY);
+
+ return TCL_OK;
+}
+
+static int wtCmd(ClientData clientData, Tcl_Interp * interp, int argc,
+ char ** argv) {
+ enum mode mode = MODE_NONE;
+ poptContext optCon;
+ int arg;
+ const char * optArg;
+ const char * text;
+ const char * nextArg;
+ char * end;
+ int height;
+ int width;
+ int noCancel = 0;
+ int noItem = 0;
+ int scrollText = 0;
+ int rc = 0;
+ int flags = 0;
+ int defaultNo = 0;
+ char * result;
+ char ** selections, ** next;
+ char * title = NULL;
+ struct poptOption optionsTable[] = {
+ { "checklist", '\0', 0, 0, OPT_CHECKLIST },
+ { "defaultno", '\0', 0, &defaultNo, 0 },
+ { "inputbox", '\0', 0, 0, OPT_INPUTBOX },
+ { "menu", '\0', 0, 0, OPT_MENU },
+ { "msgbox", '\0', 0, 0, OPT_MSGBOX },
+ { "nocancel", '\0', 0, &noCancel, 0 },
+ { "noitem", '\0', 0, &noItem, 0 },
+ { "radiolist", '\0', 0, 0, OPT_RADIOLIST },
+ { "scrolltext", '\0', 0, &scrollText, 0 },
+ { "title", '\0', POPT_ARG_STRING, &title, 0 },
+ { "yesno", '\0', 0, 0, OPT_YESNO },
+ { 0, 0, 0, 0, 0 }
+ };
+
+ optCon = poptGetContext("whiptcl", argc, argv, optionsTable, 0);
+
+ while ((arg = poptGetNextOpt(optCon)) > 0) {
+ optArg = poptGetOptArg(optCon);
+
+ switch (arg) {
+ case OPT_MENU:
+ if (mode != MODE_NONE) rc = -1;
+ mode = MODE_MENU;
+ break;
+
+ case OPT_MSGBOX:
+ if (mode != MODE_NONE) rc = -1;
+ mode = MODE_MSGBOX;
+ break;
+
+ case OPT_RADIOLIST:
+ if (mode != MODE_NONE) rc = -1;
+ mode = MODE_RADIOLIST;
+ break;
+
+ case OPT_CHECKLIST:
+ if (mode != MODE_NONE) rc = -1;
+ mode = MODE_CHECKLIST;
+ break;
+
+ case OPT_YESNO:
+ if (mode != MODE_NONE) rc = -1;
+ mode = MODE_YESNO;
+ break;
+
+ case OPT_INPUTBOX:
+ if (mode != MODE_NONE) rc = -1;
+ mode = MODE_INPUTBOX;
+ break;
+ }
+ }
+
+ if (arg < -1) {
+ /* this could buffer oveflow, bug we're not setuid so I don't care */
+ interp->result = malloc(200);
+ interp->freeProc = TCL_DYNAMIC;
+ sprintf(interp->result, "%s: %s\n",
+ poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
+ poptStrerror(arg));
+
+ return TCL_ERROR;
+ }
+
+ if (mode == MODE_NONE) {
+ interp->result = "no dialog mode was specified";
+ return TCL_ERROR;
+ } else if (rc) {
+ interp->result = "multiple modes were specified";
+ return TCL_ERROR;
+ }
+
+ if (!(text = poptGetArg(optCon))) {
+ interp->result = "missing text parameter";
+ return TCL_ERROR;
+ }
+
+ if (!(nextArg = poptGetArg(optCon))) {
+ interp->result = "height missing";
+ return TCL_ERROR;
+ }
+ height = strtoul(nextArg, &end, 10);
+ if (*end) {
+ interp->result = "height is not a number";
+ return TCL_ERROR;
+ }
+
+ if (!(nextArg = poptGetArg(optCon))) {
+ interp->result = "width missing";
+ return TCL_ERROR;
+ }
+ width = strtoul(nextArg, &end, 10);
+ if (*end) {
+ interp->result = "width is not a number";
+ return TCL_ERROR;
+ }
+
+ width -= 2;
+ height -= 2;
+ newtOpenWindow((80 - width) / 2, (24 - height) / 2, width, height, title);
+
+ if (noCancel) flags |= FLAG_NOCANCEL;
+ if (noItem) flags |= FLAG_NOITEM;
+ if (scrollText) flags |= FLAG_SCROLL_TEXT;
+ if (defaultNo) flags |= FLAG_DEFAULT_NO;
+
+ switch (mode) {
+ case MODE_MSGBOX:
+ rc = messageBox(text, height, width, MSGBOX_MSG, flags);
+ break;
+
+ case MODE_YESNO:
+ rc = messageBox(text, height, width, MSGBOX_YESNO, flags);
+ if (rc == DLG_OKAY)
+ interp->result = "yes";
+ else
+ interp->result = "no";
+ if (rc == DLG_ERROR) rc = 0;
+ break;
+
+ case MODE_INPUTBOX:
+ rc = inputBox(text, height, width, optCon, flags, &result);
+ if (!rc) {
+ interp->result = strdup(result);
+ interp->freeProc = TCL_DYNAMIC;
+ }
+ break;
+
+ case MODE_MENU:
+ rc = listBox(text, height, width, optCon, flags, &result);
+ if (!rc) {
+ interp->result = strdup(result);
+ interp->freeProc = TCL_DYNAMIC;
+ }
+ break;
+
+ case MODE_RADIOLIST:
+ rc = checkList(text, height, width, optCon, 1, flags, &selections);
+ if (!rc) {
+ interp->result = strdup(selections[0]);
+ interp->freeProc = TCL_DYNAMIC;
+ }
+ break;
+
+ case MODE_CHECKLIST:
+ rc = checkList(text, height, width, optCon, 0, flags, &selections);
+
+ if (!rc) {
+ for (next = selections; *next; next++)
+ Tcl_AppendElement(interp, *next);
+
+ free(selections);
+ }
+ break;
+
+ case MODE_NONE:
+ /* this can't happen */
+ }
+
+ newtPopWindow();
+
+ if (rc == DLG_ERROR) {
+ interp->result = "bad paramter for whiptcl dialog box";
+ return TCL_ERROR;
+ }
+
+ Tcl_SetVar(interp, "whiptcl_canceled", (rc == DLG_CANCEL) ? "1" : "0",
+ 0);
+
+ return TCL_OK;
+}
+
+static char * setBacktext(ClientData data, Tcl_Interp * interp,
+ char * name1, char * name2, int flags) {
+ static char blankLine[81] = " "
+ " ";
+
+ newtDrawRootText(0, 0, blankLine);
+ newtDrawRootText(0, 0, Tcl_GetVar(interp, "whiptcl_backtext",
+ TCL_GLOBAL_ONLY));
+
+ return NULL;
+}
+
+static char * setHelptext(ClientData data, Tcl_Interp * interp,
+ char * name1, char * name2, int flags) {
+ char * text = Tcl_GetVar(interp, "whiptcl_helpline", TCL_GLOBAL_ONLY);
+
+ if (!text)
+ text = "";
+ else if (!strlen(text))
+ text = NULL;
+
+ newtPopHelpLine();
+ newtPushHelpLine(text);
+
+ return NULL;
+}
+
+static char * setFullButtons(ClientData data, Tcl_Interp * interp,
+ char * name1, char * name2, int flags) {
+ char * val = Tcl_GetVar(interp, "whiptcl_fullbuttons", TCL_GLOBAL_ONLY);
+ int rc;
+ int state;
+
+ if ((rc = Tcl_ExprBoolean(interp, val, &state))) {
+ Tcl_FreeResult(interp);
+ return "whiptcl_fullbuttons may only contain a boolean value";
+ }
+
+ useFullButtons(state);
+
+ return NULL;
+}
+
+int Whiptcl_Init(Tcl_Interp * interp) {
+ Tcl_CreateCommand(interp, "whiptcl_finish", wtFinish, NULL, NULL);
+ Tcl_CreateCommand(interp, "whiptcl_init", wtInit, NULL, NULL);
+ Tcl_CreateCommand(interp, "whiptcl_cmd", wtCmd, NULL, NULL);
+
+ return TCL_OK;
+}
diff --git a/mininewt/windows.c b/mininewt/windows.c
new file mode 100644
index 000000000..792d3ed76
--- /dev/null
+++ b/mininewt/windows.c
@@ -0,0 +1,275 @@
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "errno.h"
+#include "newt.h"
+
+static void * newtvwindow(char * title, char * button1, char * button2,
+ char * button3, char * message, va_list args) {
+ newtComponent b1, b2 = NULL, b3 = NULL, t, f, answer;
+ char * buf = NULL;
+ int size = 0;
+ int i = 0;
+ int scroll = 0;
+ int width, height;
+ char * flowedText;
+ newtGrid grid, buttonGrid;
+
+ do {
+ size += 1000;
+ if (buf) free(buf);
+ buf = malloc(size);
+ i = vsnprintf(buf, size, message, args);
+ } while (i >= size || i == -1);
+
+ flowedText = newtReflowText(buf, 35, 5, 5, &width, &height);
+ if (height > 6) {
+ free(flowedText);
+ flowedText = newtReflowText(buf, 60, 5, 5, &width, &height);
+ }
+ free(buf);
+
+ if (height > 12) {
+ height = 12;
+ scroll = NEWT_FLAG_SCROLL;
+ }
+ t = newtTextbox(-1, -1, width, height, NEWT_TEXTBOX_WRAP | scroll);
+ newtTextboxSetText(t, flowedText);
+ free(flowedText);
+
+ if (button3) {
+ buttonGrid = newtButtonBar(button1, &b1, button2, &b2,
+ button3, &b3, NULL);
+ } else if (button2) {
+ buttonGrid = newtButtonBar(button1, &b1, button2, &b2, NULL);
+ } else {
+ buttonGrid = newtButtonBar(button1, &b1, NULL);
+ }
+
+ newtGridSetField(buttonGrid, 0, 0, NEWT_GRID_COMPONENT, b1,
+ 0, 0, button2 ? 1 : 0, 0, 0, 0);
+
+ grid = newtCreateGrid(1, 2);
+ newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, t, 0, 0, 0, 0, 0, 0);
+ newtGridSetField(grid, 0, 1, NEWT_GRID_SUBGRID, buttonGrid,
+ 0, 1, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
+ newtGridWrappedWindow(grid, title);
+
+ f = newtForm(NULL, NULL, 0);
+ newtFormAddComponents(f, t, b1, NULL);
+
+ if (button2)
+ newtFormAddComponent(f, b2);
+ if (button3)
+ newtFormAddComponent(f, b3);
+
+ answer = newtRunForm(f);
+ newtGridFree(grid, 1);
+
+ newtFormDestroy(f);
+ newtPopWindow();
+
+ if (answer == f)
+ return NULL;
+ else if (answer == b1)
+ return button1;
+ else if (answer == b2)
+ return button2;
+
+ return button3;
+}
+
+int newtWinChoice(char * title, char * button1, char * button2,
+ char * message, ...) {
+ va_list args;
+ void * rc;
+
+ va_start(args, message);
+ rc = newtvwindow(title, button1, button2, NULL, message, args);
+ va_end(args);
+
+ if (rc == button1)
+ return 1;
+ else if (rc == button2)
+ return 2;
+
+ return 0;
+}
+
+void newtWinMessage(char * title, char * buttonText, char * text, ...) {
+ va_list args;
+
+ va_start(args, text);
+ newtvwindow(title, buttonText, NULL, NULL, text, args);
+ va_end(args);
+}
+
+void newtWinMessagev(char * title, char * buttonText, char * text,
+ va_list argv) {
+ newtvwindow(title, buttonText, NULL, NULL, text, argv);
+}
+
+int newtWinTernary(char * title, char * button1, char * button2,
+ char * button3, char * message, ...) {
+ va_list args;
+ void * rc;
+
+ va_start(args, message);
+ rc = newtvwindow(title, button1, button2, button3, message, args);
+ va_end(args);
+
+ if (rc == button1)
+ return 1;
+ else if (rc == button2)
+ return 2;
+ else if (rc == button3)
+ return 3;
+
+ return 0;
+}
+
+/* only supports up to 50 buttons -- shucks! */
+int newtWinMenu(char * title, char * text, int suggestedWidth, int flexDown,
+ int flexUp, int maxListHeight, char ** items, int * listItem,
+ char * button1, ...) {
+ newtComponent textbox, listbox, result, form;
+ va_list args;
+ newtComponent buttons[50];
+ newtGrid grid, buttonBar;
+ int numButtons;
+ int i, rc;
+ int needScroll;
+ char * buttonName;
+
+ textbox = newtTextboxReflowed(-1, -1, text, suggestedWidth, flexDown,
+ flexUp, 0);
+
+ for (i = 0; items[i]; i++) ;
+ if (i < maxListHeight) maxListHeight = i;
+ needScroll = i > maxListHeight;
+
+ listbox = newtListbox(-1, -1, maxListHeight,
+ (needScroll ? NEWT_FLAG_SCROLL : 0) | NEWT_FLAG_RETURNEXIT);
+ for (i = 0; items[i]; i++) {
+ newtListboxAddEntry(listbox, items[i], (void *) i);
+ }
+
+ newtListboxSetCurrent(listbox, *listItem);
+
+ buttonName = button1, numButtons = 0;
+ va_start(args, button1);
+ while (buttonName) {
+ buttons[numButtons] = newtButton(-1, -1, buttonName);
+ numButtons++;
+ buttonName = va_arg(args, char *);
+ }
+
+ va_end(args);
+
+ buttonBar = newtCreateGrid(numButtons, 1);
+ for (i = 0; i < numButtons; i++) {
+ newtGridSetField(buttonBar, i, 0, NEWT_GRID_COMPONENT,
+ buttons[i],
+ i ? 1 : 0, 0, 0, 0, 0, 0);
+ }
+
+ grid = newtGridSimpleWindow(textbox, listbox, buttonBar);
+ newtGridWrappedWindow(grid, title);
+
+ form = newtForm(NULL, 0, 0);
+ newtGridAddComponentsToForm(grid, form, 1);
+ newtGridFree(grid, 1);
+
+ result = newtRunForm(form);
+
+ *listItem = ((long) newtListboxGetCurrent(listbox));
+
+ for (rc = 0; result != buttons[rc] && rc < numButtons; rc++);
+ if (rc == numButtons)
+ rc = 0; /* F12 or return-on-exit (which are the same for us) */
+ else
+ rc++;
+
+ newtFormDestroy(form);
+ newtPopWindow();
+
+ return rc;
+}
+
+/* only supports up to 50 buttons and entries -- shucks! */
+int newtWinEntries(char * title, char * text, int suggestedWidth, int flexDown,
+ int flexUp, int dataWidth,
+ struct newtWinEntry * items, char * button1, ...) {
+ newtComponent buttons[50], result, form, textw;
+ newtGrid grid, buttonBar, subgrid;
+ int numItems;
+ int rc, i;
+ int numButtons;
+ char * buttonName;
+ va_list args;
+
+ textw = newtTextboxReflowed(-1, -1, text, suggestedWidth, flexDown,
+ flexUp, 0);
+
+ for (numItems = 0; items[numItems].text; numItems++);
+
+ buttonName = button1, numButtons = 0;
+ va_start(args, button1);
+ while (buttonName) {
+ buttons[numButtons] = newtButton(-1, -1, buttonName);
+ numButtons++;
+ buttonName = va_arg(args, char *);
+ }
+
+ va_end(args);
+
+ buttonBar = newtCreateGrid(numButtons, 1);
+ for (i = 0; i < numButtons; i++) {
+ newtGridSetField(buttonBar, i, 0, NEWT_GRID_COMPONENT,
+ buttons[i],
+ i ? 1 : 0, 0, 0, 0, 0, 0);
+ }
+
+ subgrid = newtCreateGrid(2, numItems);
+ for (i = 0; i < numItems; i++) {
+ newtGridSetField(subgrid, 0, i, NEWT_GRID_COMPONENT,
+ newtLabel(-1, -1, items[i].text),
+ 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
+ newtGridSetField(subgrid, 1, i, NEWT_GRID_COMPONENT,
+ newtEntry(-1, -1, items[i].value ?
+ *items[i].value : NULL, dataWidth,
+ items[i].value, items[i].flags),
+ 1, 0, 0, 0, 0, 0);
+ }
+
+ grid = newtCreateGrid(1, 3);
+ form = newtForm(NULL, 0, 0);
+ newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, textw,
+ 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
+ newtGridSetField(grid, 0, 1, NEWT_GRID_SUBGRID, subgrid,
+ 0, 1, 0, 0, 0, 0);
+ newtGridSetField(grid, 0, 2, NEWT_GRID_SUBGRID, buttonBar,
+ 0, 1, 0, 0, 0, NEWT_GRID_FLAG_GROWX);
+ newtGridAddComponentsToForm(grid, form, 1);
+ newtGridWrappedWindow(grid, title);
+ newtGridFree(grid, 1);
+
+ result = newtRunForm(form);
+
+ for (rc = 0; rc < numItems; rc++)
+ *items[rc].value = strdup(*items[rc].value);
+
+ for (rc = 0; result != buttons[rc] && rc < numButtons; rc++);
+ if (rc == numButtons)
+ rc = 0; /* F12 */
+ else
+ rc++;
+
+ newtFormDestroy(form);
+ newtPopWindow();
+
+ return rc;
+}